| 
									
										
										
										
											2020-04-09 23:58:40 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Console\Commands; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use Illuminate\Console\Command; | 
					
						
							|  |  |  | use Illuminate\Database\Connection; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class UpdateUrl extends Command | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The name and signature of the console command. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @var string | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $signature = 'bookstack:update-url | 
					
						
							|  |  |  |                             {oldUrl : URL to replace} | 
					
						
							|  |  |  |                             {newUrl : URL to use as the replacement}'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * The console command description. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @var string | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $description = 'Find and replace the given URLs in your BookStack database'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected $db; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Create a new command instance. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return void | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function __construct(Connection $db) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->db = $db; | 
					
						
							|  |  |  |         parent::__construct(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Execute the console command. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function handle() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $oldUrl = str_replace("'", '', $this->argument('oldUrl')); | 
					
						
							|  |  |  |         $newUrl = str_replace("'", '', $this->argument('newUrl')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $urlPattern = '/https?:\/\/(.+)/'; | 
					
						
							|  |  |  |         if (!preg_match($urlPattern, $oldUrl) || !preg_match($urlPattern, $newUrl)) { | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             $this->error('The given urls are expected to be full urls starting with http:// or https://'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 23:58:40 +08:00
										 |  |  |             return 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!$this->checkUserOkayToProceed($oldUrl, $newUrl)) { | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $columnsToUpdateByTable = [ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'attachments' => ['path'], | 
					
						
							|  |  |  |             'pages'       => ['html', 'text', 'markdown'], | 
					
						
							|  |  |  |             'images'      => ['url'], | 
					
						
							|  |  |  |             'settings'    => ['value'], | 
					
						
							|  |  |  |             'comments'    => ['html', 'text'], | 
					
						
							| 
									
										
										
										
											2020-04-09 23:58:40 +08:00
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($columnsToUpdateByTable as $table => $columns) { | 
					
						
							|  |  |  |             foreach ($columns as $column) { | 
					
						
							| 
									
										
										
										
											2021-02-12 07:14:37 +08:00
										 |  |  |                 $changeCount = $this->replaceValueInTable($table, $column, $oldUrl, $newUrl); | 
					
						
							| 
									
										
										
										
											2020-04-09 23:58:40 +08:00
										 |  |  |                 $this->info("Updated {$changeCount} rows in {$table}->{$column}"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-12 07:14:37 +08:00
										 |  |  |         $jsonColumnsToUpdateByTable = [ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             'settings' => ['value'], | 
					
						
							| 
									
										
										
										
											2021-02-12 07:14:37 +08:00
										 |  |  |         ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($jsonColumnsToUpdateByTable as $table => $columns) { | 
					
						
							|  |  |  |             foreach ($columns as $column) { | 
					
						
							|  |  |  |                 $oldJson = trim(json_encode($oldUrl), '"'); | 
					
						
							|  |  |  |                 $newJson = trim(json_encode($newUrl), '"'); | 
					
						
							|  |  |  |                 $changeCount = $this->replaceValueInTable($table, $column, $oldJson, $newJson); | 
					
						
							|  |  |  |                 $this->info("Updated {$changeCount} JSON encoded rows in {$table}->{$column}"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |         $this->info('URL update procedure complete.'); | 
					
						
							| 
									
										
										
										
											2021-02-12 07:14:37 +08:00
										 |  |  |         $this->info('============================================================================'); | 
					
						
							|  |  |  |         $this->info('Be sure to run "php artisan cache:clear" to clear any old URLs in the cache.'); | 
					
						
							|  |  |  |         $this->info('============================================================================'); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 23:58:40 +08:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-12 07:14:37 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Perform a find+replace operations in the provided table and column. | 
					
						
							|  |  |  |      * Returns the count of rows changed. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function replaceValueInTable(string $table, string $column, string $oldUrl, string $newUrl): int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $oldQuoted = $this->db->getPdo()->quote($oldUrl); | 
					
						
							|  |  |  |         $newQuoted = $this->db->getPdo()->quote($newUrl); | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-12 07:14:37 +08:00
										 |  |  |         return $this->db->table($table)->update([ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |             $column => $this->db->raw("REPLACE({$column}, {$oldQuoted}, {$newQuoted})"), | 
					
						
							| 
									
										
										
										
											2021-02-12 07:14:37 +08:00
										 |  |  |         ]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 23:58:40 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Warn the user of the dangers of this operation. | 
					
						
							|  |  |  |      * Returns a boolean indicating if they've accepted the warnings. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function checkUserOkayToProceed(string $oldUrl, string $newUrl): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $dangerWarning = "This will search for \"{$oldUrl}\" in your database and replace it with  \"{$newUrl}\".\n"; | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |         $dangerWarning .= 'Are you sure you want to proceed?'; | 
					
						
							|  |  |  |         $backupConfirmation = 'This operation could cause issues if used incorrectly. Have you made a backup of your existing database?'; | 
					
						
							| 
									
										
										
										
											2020-04-09 23:58:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return $this->confirm($dangerWarning) && $this->confirm($backupConfirmation); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |