local.php
1018 lines
| 1 | <?php |
| 2 | |
| 3 | // Namespace |
| 4 | namespace BMI\Plugin\Staging; |
| 5 | |
| 6 | // Use |
| 7 | use BMI\Plugin\Backup_Migration_Plugin as BMP; |
| 8 | use BMI\Plugin\Checker\BMI_Checker as Checker; |
| 9 | use BMI\Plugin\Database\BMI_Search_Replace_Engine as BMISearchReplace; |
| 10 | |
| 11 | // Exit on direct access |
| 12 | if (!defined('ABSPATH')) exit; |
| 13 | |
| 14 | // Require controller |
| 15 | require_once BMI_INCLUDES . '/staging/controller.php'; |
| 16 | |
| 17 | /** |
| 18 | * Subclass of main staging controller (local handler) |
| 19 | */ |
| 20 | class BMI_StagingLocal extends BMI_Staging { |
| 21 | |
| 22 | protected $data = []; |
| 23 | protected $step = 0; |
| 24 | private $filesList = null; |
| 25 | private $dirsList = null; |
| 26 | private $rootLength = 0; |
| 27 | private $excludedDirectories = []; |
| 28 | |
| 29 | public function __construct($name, $initialize = false) { |
| 30 | |
| 31 | parent::__construct(...func_get_args()); |
| 32 | if ($initialize) $this->initialization(); |
| 33 | |
| 34 | } |
| 35 | |
| 36 | public function continueProcess() { |
| 37 | |
| 38 | if (isset($this->siteConfig['step'])) { |
| 39 | $this->step = intval($this->siteConfig['step']); |
| 40 | } else { |
| 41 | $this->step = null; |
| 42 | } |
| 43 | |
| 44 | if (!is_numeric($this->step)) { |
| 45 | |
| 46 | // End with error |
| 47 | $this->log(__('Step code was not provided for the request, prevents continuation of the process...'), 'ERROR'); |
| 48 | $this->log('Step code was not provided for the request, prevents continuation of the process...', 'VERBOSE'); |
| 49 | $this->log('#201', 'END-CODE'); |
| 50 | return ['status' => 'error']; |
| 51 | |
| 52 | } |
| 53 | |
| 54 | // Default error |
| 55 | $translatedMainError = __('Something unexpected happened, we need to abort the process.', 'backup-backup'); |
| 56 | $englishMainError = 'Something unexpected happened, we need to abort the process (#207).'; |
| 57 | |
| 58 | // Step controller |
| 59 | if ($this->step == 1) $this->prepareFilesAndDatabase(); |
| 60 | else if ($this->step == 2) $this->duplicateDatabase(); |
| 61 | else if ($this->step == 3) $this->searchReplace(); |
| 62 | else if ($this->step == 4) $this->databaseFinishedCopyFiles(); |
| 63 | else if ($this->step == 5) $this->setupWpConfigAndLoginScript(); |
| 64 | else if ($this->step == 6) $this->performFinish(); |
| 65 | else if (isset($this->step) && is_numeric($this->step)) $this->sendSuccess(); |
| 66 | else $this->returnError($translatedMainError, $englishMainError); |
| 67 | |
| 68 | } |
| 69 | |
| 70 | private function getAllLiveTables() { |
| 71 | |
| 72 | global $wpdb; |
| 73 | $tables = []; |
| 74 | |
| 75 | $allTables = $wpdb->get_results('SHOW TABLES'); |
| 76 | |
| 77 | foreach ($allTables as $table) { |
| 78 | foreach ($table as $name) $tables[] = $name; |
| 79 | } |
| 80 | |
| 81 | return $tables; |
| 82 | |
| 83 | } |
| 84 | |
| 85 | private function checkIfPrefixCanBeUsed($tables, $prefix) { |
| 86 | |
| 87 | $sizeOfPrefix = strlen($prefix); |
| 88 | |
| 89 | for ($i = 0; $i < sizeof($tables); ++$i) { |
| 90 | $name = $tables[$i]; |
| 91 | |
| 92 | if (substr($name, 0, $sizeOfPrefix) == $prefix) return false; |
| 93 | if (strpos($name, $prefix)) return false; |
| 94 | } |
| 95 | |
| 96 | return $prefix; |
| 97 | |
| 98 | } |
| 99 | |
| 100 | private function generateUniquePrefix() { |
| 101 | return 'bmstg' . substr(time(), -4) . '_'; |
| 102 | } |
| 103 | |
| 104 | private function generateDatabasePrefix() { |
| 105 | |
| 106 | $tables = $this->getAllLiveTables(); |
| 107 | $prefix = $this->generateUniquePrefix(); |
| 108 | |
| 109 | $i = 0; |
| 110 | |
| 111 | while ($this->checkIfPrefixCanBeUsed($tables, $prefix) === false && $i <= 3) { |
| 112 | sleep(1); |
| 113 | $prefix = $this->generateUniquePrefix(); |
| 114 | |
| 115 | $i++; |
| 116 | } |
| 117 | |
| 118 | if ($i >= 3) return 'error'; |
| 119 | return $prefix; |
| 120 | |
| 121 | } |
| 122 | |
| 123 | private function createDatabasePrefixAndInitDir() { |
| 124 | |
| 125 | $path = trailingslashit(ABSPATH) . $this->name; |
| 126 | |
| 127 | $this->log(__('Preparing constants and staging details', 'backup-backup'), 'STEP'); |
| 128 | |
| 129 | // Directory creation |
| 130 | $this->log(__('Creating root directory of new site', 'backup-backup')); |
| 131 | if (file_exists($path) && is_dir($path)) { |
| 132 | $translated = __('Seems like desired directory of staging site already exist, try with different staging site name.', 'backup-backup'); |
| 133 | $english = 'Seems like desired directory of staging site already exist, try with different staging site name.'; |
| 134 | $this->returnError($translated, $english); |
| 135 | } |
| 136 | |
| 137 | @mkdir($path, 0755); |
| 138 | touch($path . DIRECTORY_SEPARATOR . '.bmi_staging'); |
| 139 | |
| 140 | $this->log(__('Path of new website:', 'backup-backup') . ' ' . $path, 'SUCCESS'); |
| 141 | |
| 142 | // Generation of database prefix |
| 143 | $this->log(__('Generating database prefix', 'backup-backup')); |
| 144 | $dbPrefix = $this->generateDatabasePrefix(); |
| 145 | if ($dbPrefix == 'error') { |
| 146 | $translated = __('There was an error during database prefix generation, maybe all generated were already used, try again.', 'backup-backup'); |
| 147 | $english = 'There was an error during database prefix generation, maybe all generated were already used, try again.'; |
| 148 | $this->returnError($translated, $english); |
| 149 | } |
| 150 | $this->log(__('Prefix of new site will be:', 'backup-backup') . ' ' . $dbPrefix, 'SUCCESS'); |
| 151 | |
| 152 | $this->config[$this->name]['name'] = $this->name; |
| 153 | $this->config[$this->name]['prefix'] = $dbPrefix; |
| 154 | |
| 155 | // Password for first log in |
| 156 | $this->log(__('Generating first log in password', 'backup-backup')); |
| 157 | $password = $this->getRandomPassword(); |
| 158 | $this->log(__('Password created and saved.', 'backup-backup'), 'SUCCESS'); |
| 159 | |
| 160 | // Set initial configuration |
| 161 | $this->log(__('Initializing configuration of the website', 'backup-backup'), 'STEP'); |
| 162 | $this->initialConfiguration($dbPrefix, $password); |
| 163 | $this->log(__('Configuration created', 'backup-backup'), 'SUCCESS'); |
| 164 | |
| 165 | } |
| 166 | |
| 167 | private function initialConfiguration($dbPrefix, $password) { |
| 168 | |
| 169 | global $table_prefix; |
| 170 | |
| 171 | $ip = $this->getIpAddress(); |
| 172 | |
| 173 | // Basic for all |
| 174 | $this->siteConfig['name'] = $this->name; // Name of that staging site |
| 175 | $this->siteConfig['url'] = home_url($this->name); // URL to the website |
| 176 | $this->siteConfig['root_source'] = trailingslashit(ABSPATH); // ABSPATH of source website |
| 177 | $this->siteConfig['root_staging'] = untrailingslashit(ABSPATH) . DIRECTORY_SEPARATOR . $this->name; // ABSPATH of staging site |
| 178 | $this->siteConfig['db_prefix'] = $dbPrefix; // Database prefix of that site |
| 179 | $this->siteConfig['creation_date'] = time(); // Creation date and time of that staging site |
| 180 | $this->siteConfig['password'] = $password; // Password for password-less login |
| 181 | $this->siteConfig['creator_ip'] = $ip; // IP of user who created it |
| 182 | $this->siteConfig['login_ip'] = $ip; // IP for autologin script (limit password-less login to only that IP) |
| 183 | $this->siteConfig['login_user_id'] = get_current_user_id(); // User ID for password less authentication |
| 184 | $this->siteConfig['source_home_url'] = home_url(); // Homepage URL of source website |
| 185 | $this->siteConfig['source_site_url'] = site_url(); // Website (admin) URL of source website |
| 186 | $this->siteConfig['source_db_prefix'] = $table_prefix; // Database prefix of source website |
| 187 | |
| 188 | // TasteWP |
| 189 | $this->siteConfig['communication_secret'] = 'local'; // Local if it's not TasteWP website // Secret code to get authless access to website |
| 190 | $this->siteConfig['expiration_time'] = 'never'; // Never if it's not TasteWP website // Expiration time of the website |
| 191 | |
| 192 | } |
| 193 | |
| 194 | private function getExcludedFilesAndDirectories($abspath = false) { |
| 195 | |
| 196 | $excludedDirectories = []; |
| 197 | |
| 198 | if ($abspath) { |
| 199 | $excludedDirectories = $this->getAllStagingSiteDirectories(); |
| 200 | } |
| 201 | |
| 202 | $excludedDirectories[] = '.'; |
| 203 | $excludedDirectories[] = '..'; |
| 204 | $excludedDirectories[] = 'wp-config.php'; |
| 205 | $excludedDirectories[] = '.DS_Store'; |
| 206 | $excludedDirectories[] = '.quarantine'; |
| 207 | $excludedDirectories[] = '.git'; |
| 208 | $excludedDirectories[] = '.tmb'; |
| 209 | $excludedDirectories[] = 'node_modules'; |
| 210 | $excludedDirectories[] = 'debug.log'; |
| 211 | |
| 212 | return $excludedDirectories; |
| 213 | |
| 214 | } |
| 215 | |
| 216 | private function getAbspathFiles($path) { |
| 217 | |
| 218 | $excludedDirectories = $this->getExcludedFilesAndDirectories(true); |
| 219 | $topFiles = array_diff(scandir($path), $excludedDirectories); |
| 220 | |
| 221 | return $topFiles; |
| 222 | |
| 223 | } |
| 224 | |
| 225 | private function processFiles($prefixPath, &$files) { |
| 226 | |
| 227 | $dirs = []; |
| 228 | |
| 229 | foreach ($files as $index => $file) { |
| 230 | $path = $prefixPath . $file; |
| 231 | if (strpos($path, BMI_BACKUPS_ROOT) !== false) continue; |
| 232 | if (is_link($path)) continue; |
| 233 | if (is_dir($path)) { |
| 234 | if (!(is_readable($path) && is_writable($path))) continue; |
| 235 | if (file_exists(trailingslashit($path) . '.bmi_staging')) continue; |
| 236 | $this->siteConfig['total_size'] += 4096; |
| 237 | $this->siteConfig['total_directories'] += 1; |
| 238 | fwrite($this->dirsList, $file . "\n"); |
| 239 | $dirs[] = $path; |
| 240 | } else if (is_file($path)) { |
| 241 | if (!is_readable($path)) continue; |
| 242 | $this->siteConfig['total_size'] += filesize($path); |
| 243 | $this->siteConfig['total_files'] += 1; |
| 244 | fwrite($this->filesList, $file . "\n"); |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | return $dirs; |
| 249 | |
| 250 | } |
| 251 | |
| 252 | private function processDirectoryRecursively($dir) { |
| 253 | |
| 254 | if (!(is_readable($dir) && is_writable($dir))) return; |
| 255 | |
| 256 | $files = array_diff(scandir($dir), $this->excludedDirectories); |
| 257 | |
| 258 | foreach ($files as $key => $value) { |
| 259 | $path = $dir . DIRECTORY_SEPARATOR . $value; |
| 260 | if (strpos($path, BMI_BACKUPS_ROOT) !== false) continue; |
| 261 | if (is_link($path)) continue; |
| 262 | if (is_dir($path)) { |
| 263 | $this->siteConfig['total_size'] += 4096; |
| 264 | $this->siteConfig['total_directories'] += 1; |
| 265 | fwrite($this->dirsList, substr($path, $this->rootLength) . "\n"); |
| 266 | if (!file_exists(trailingslashit($path) . '.bmi_staging')) { |
| 267 | $this->processDirectoryRecursively($path); |
| 268 | } |
| 269 | } else if (is_file($path)) { |
| 270 | if (!is_readable($path)) continue; |
| 271 | $this->siteConfig['total_size'] += filesize($path); |
| 272 | $this->siteConfig['total_files'] += 1; |
| 273 | fwrite($this->filesList, substr($path, $this->rootLength) . "\n"); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | } |
| 278 | |
| 279 | private function processFilesRecursively($leftDirs) { |
| 280 | |
| 281 | $this->rootLength = strlen(trailingslashit(ABSPATH)); |
| 282 | $this->excludedDirectories = $this->getExcludedFilesAndDirectories(); |
| 283 | |
| 284 | for ($i = 0; $i < sizeof($leftDirs); ++$i) { |
| 285 | $this->processDirectoryRecursively($leftDirs[$i]); |
| 286 | } |
| 287 | |
| 288 | } |
| 289 | |
| 290 | private function getTablesForDuplication() { |
| 291 | |
| 292 | global $wpdb, $table_prefix; |
| 293 | |
| 294 | $currentPrefixes = $this->getAllStagingSitePrefixes(); |
| 295 | $relatedTables = []; |
| 296 | |
| 297 | $sql = "SELECT (DATA_LENGTH + INDEX_LENGTH) as `size`, TABLE_NAME AS `name` FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s;"; |
| 298 | $sql = $wpdb->prepare($sql, array(DB_NAME)); |
| 299 | |
| 300 | $tables = $wpdb->get_results($sql); |
| 301 | foreach ($tables as $tableObject) { |
| 302 | |
| 303 | $name = $tableObject->name; |
| 304 | $size = $tableObject->size; |
| 305 | |
| 306 | if (substr($name, 0, strlen($table_prefix)) != $table_prefix) { |
| 307 | $this->log('Ommiting this table: ' . $name, 'verbose'); |
| 308 | continue; |
| 309 | } else { |
| 310 | $this->log('Adding this table: ' . $name, 'verbose'); |
| 311 | } |
| 312 | |
| 313 | $tableOfStagingSite = false; |
| 314 | for ($i = 0; $i < sizeof($currentPrefixes); ++$i) { |
| 315 | $subPrefix = $currentPrefixes[$i]; |
| 316 | if ($table_prefix != $subPrefix && substr($name, 0, strlen($subPrefix)) == $subPrefix) { |
| 317 | $tableOfStagingSite = true; |
| 318 | break; |
| 319 | } |
| 320 | } |
| 321 | if ($tableOfStagingSite) { |
| 322 | $this->log('Excluding this table as part of staging site: ' . $name, 'verbose'); |
| 323 | continue; |
| 324 | } |
| 325 | |
| 326 | $this->siteConfig['total_db_size'] += intval($size); |
| 327 | $relatedTables[$name] = $this->siteConfig['db_prefix'] . substr($name, strlen($table_prefix)); |
| 328 | |
| 329 | } |
| 330 | |
| 331 | return $relatedTables; |
| 332 | |
| 333 | } |
| 334 | |
| 335 | private function updateUserRolesInOptions() { |
| 336 | |
| 337 | global $wpdb; |
| 338 | |
| 339 | // Update option name |
| 340 | $sql = "UPDATE %i SET `option_name` = %s WHERE `option_name` = %s;"; |
| 341 | $newOptionTable = $this->siteConfig['db_prefix'] . 'options'; |
| 342 | $newOptionName = $this->siteConfig['db_prefix'] . 'user_roles'; |
| 343 | $oldOptionName = $this->siteConfig['source_db_prefix'] . 'user_roles'; |
| 344 | |
| 345 | $sql = $wpdb->prepare($sql, [$newOptionTable, $newOptionName, $oldOptionName]); |
| 346 | $wpdb->query($sql); |
| 347 | |
| 348 | if ($wpdb->last_error !== '') { |
| 349 | $translated = __('There was an error during update of user roles:', 'backup-backup') . ' ' . $wpdb->last_error; |
| 350 | $english = 'There was an error during update of user roles:' . ' ' . $wpdb->last_error; |
| 351 | return $this->returnError($translated, $english); |
| 352 | } |
| 353 | |
| 354 | $sql = "DELETE FROM %i WHERE `option_name` = 'BMI::STORAGE::LOCAL::PATH';"; |
| 355 | $sql = $wpdb->prepare($sql, [$newOptionTable]); |
| 356 | $wpdb->query($sql); |
| 357 | |
| 358 | if ($wpdb->last_error !== '') { |
| 359 | $translated = __('There was an error during BMI config hard removal:', 'backup-backup') . ' ' . $wpdb->last_error; |
| 360 | $english = 'There was an error during BMI config hard removal:' . ' ' . $wpdb->last_error; |
| 361 | return $this->returnError($translated, $english); |
| 362 | } |
| 363 | |
| 364 | } |
| 365 | |
| 366 | private function duplicateTableAlternative($source, $destination) { |
| 367 | |
| 368 | global $wpdb; |
| 369 | |
| 370 | // Remove failed table if created |
| 371 | $sql = "DROP TABLE IF EXISTS %i;"; |
| 372 | $sql = $wpdb->prepare($sql, [$destination]); |
| 373 | $wpdb->query($sql); |
| 374 | |
| 375 | if ($wpdb->last_error !== '') { |
| 376 | $translated = __('There was an error during previous destination table removal:', 'backup-backup') . ' ' . $wpdb->last_error; |
| 377 | $english = 'There was an error during previous destination table removal:' . ' ' . $wpdb->last_error; |
| 378 | return $this->returnError($translated, $english); |
| 379 | } |
| 380 | |
| 381 | // Create new table |
| 382 | $sql = "CREATE TABLE %i LIKE %i;"; |
| 383 | $sql = $wpdb->prepare($sql, [$destination, $source]); |
| 384 | $wpdb->query($sql); |
| 385 | |
| 386 | if ($wpdb->last_error !== '') { |
| 387 | $translated = __('There was an error during database table creation:', 'backup-backup') . ' ' . $wpdb->last_error; |
| 388 | $english = 'There was an error during database table creation:' . ' ' . $wpdb->last_error; |
| 389 | return $this->returnError($translated, $english); |
| 390 | } |
| 391 | |
| 392 | // Duplicate data |
| 393 | $sql = "INSERT INTO %i SELECT * from %i;"; |
| 394 | $sql = $wpdb->prepare($sql, [$destination, $source]); |
| 395 | $wpdb->query($sql); |
| 396 | |
| 397 | if ($wpdb->last_error !== '') { |
| 398 | $translated = __('There was an error during database table data duplication:', 'backup-backup') . ' ' . $wpdb->last_error; |
| 399 | $english = 'There was an error during database table data duplication:' . ' ' . $wpdb->last_error; |
| 400 | return $this->returnError($translated, $english); |
| 401 | } |
| 402 | |
| 403 | } |
| 404 | |
| 405 | private function duplicateTable($source, $destination) { |
| 406 | |
| 407 | global $wpdb; |
| 408 | |
| 409 | // Create new table |
| 410 | $sql = "SHOW CREATE TABLE %i;"; |
| 411 | $sql = $wpdb->prepare($sql, [$source]); |
| 412 | $sourceCreate = $wpdb->get_row($sql); |
| 413 | $isTable = isset($sourceCreate->{'Create Table'}); |
| 414 | if ($isTable) { |
| 415 | $sourceCreate->{'Create Table'} = str_ireplace('CREATE TABLE `' . $source, 'CREATE TABLE IF NOT EXISTS `' . $destination, $sourceCreate->{'Create Table'}); |
| 416 | $wpdb->query($sourceCreate->{'Create Table'}); |
| 417 | //Insert data |
| 418 | $sql = "INSERT INTO %i SELECT * from %i;"; |
| 419 | $sql = $wpdb->prepare($sql, [$destination, $source]); |
| 420 | $wpdb->query($sql); |
| 421 | } else { |
| 422 | $sql = "CREATE TABLE %i AS SELECT * FROM %i;"; |
| 423 | $sql = $wpdb->prepare($sql, [$destination, $source]); |
| 424 | $wpdb->query($sql); |
| 425 | } |
| 426 | |
| 427 | |
| 428 | |
| 429 | if ($wpdb->last_error !== '') { |
| 430 | $this->duplicateTableAlternative($source, $destination); |
| 431 | } |
| 432 | |
| 433 | if ($wpdb->last_error !== '') { |
| 434 | $translated = __('There was an error during database table creation:', 'backup-backup') . ' ' . $wpdb->last_error; |
| 435 | $english = 'There was an error during database table creation:' . ' ' . $wpdb->last_error; |
| 436 | return $this->returnError($translated, $english); |
| 437 | } |
| 438 | |
| 439 | } |
| 440 | |
| 441 | private function parseDomain($domain, $removeWWW = true) { |
| 442 | |
| 443 | if (substr($domain, 0, 8) == 'https://') $domain = substr($domain, 8); |
| 444 | if (substr($domain, 0, 7) == 'http://') $domain = substr($domain, 7); |
| 445 | if ($removeWWW === true) { |
| 446 | if (substr($domain, 0, 4) == 'www.') $domain = substr($domain, 4); |
| 447 | } |
| 448 | $domain = untrailingslashit($domain); |
| 449 | |
| 450 | return $domain; |
| 451 | |
| 452 | } |
| 453 | |
| 454 | private function performSearchReplace($table, $from, $to, $start = 0, $end = 0, $limitColumns = false) { |
| 455 | |
| 456 | $replaceEngine = new BMISearchReplace([$table], $start, $end, true); |
| 457 | |
| 458 | $stats = $replaceEngine->perform($from, $to, $limitColumns); |
| 459 | |
| 460 | $this->siteConfig['totalTables'] += $stats['tables']; |
| 461 | $this->siteConfig['totalRows'] += $stats['rows']; |
| 462 | $this->siteConfig['totalChanges'] += $stats['change']; |
| 463 | $this->siteConfig['totalUpdates'] += $stats['updates']; |
| 464 | |
| 465 | $this->siteConfig['currentTableTotalUpdates'] += $stats['updates']; |
| 466 | $this->siteConfig['currentSearchReplacePage'] = $stats['currentPage']; |
| 467 | $this->siteConfig['totalSearchReplacePages'] = $stats['totalPages']; |
| 468 | |
| 469 | $replaceEngine = null; |
| 470 | |
| 471 | } |
| 472 | |
| 473 | public function requestDelete() { |
| 474 | return $this->abort(true); |
| 475 | } |
| 476 | |
| 477 | // Step: 0 (initialization of the staging site, create entry) |
| 478 | private function initialization() { |
| 479 | |
| 480 | $this->log('Step 0 - Initialization of the process', 'VERBOSE'); |
| 481 | |
| 482 | $this->log(__('Name of subsite:', 'backup-backup') . ' ' . $this->name); |
| 483 | $this->log(__('Expected URL of subsite:', 'backup-backup') . ' ' . home_url($this->name)); |
| 484 | |
| 485 | $this->printInitialLogs(); |
| 486 | |
| 487 | $this->createDatabasePrefixAndInitDir(); |
| 488 | if ($this->wasError) return; |
| 489 | |
| 490 | // Set progress to do something |
| 491 | $this->progress(4); |
| 492 | |
| 493 | // Set next step to be 1 |
| 494 | $this->setContinuation(1); |
| 495 | |
| 496 | } |
| 497 | |
| 498 | // Step: 1 (preparation of file list and database recipes) |
| 499 | private function prepareFilesAndDatabase() { |
| 500 | |
| 501 | // Create list of all files and directories |
| 502 | if (!isset($this->siteConfig['batch']) || $this->siteConfig['batch'] == 1) { |
| 503 | $this->log(__('Scanning all files on your website, it may take a while...', 'backup-backup'), 'STEP'); |
| 504 | |
| 505 | $pathDirsListFile = BMI_TMP . DIRECTORY_SEPARATOR . '.staging_directories'; |
| 506 | $pathFilesListFile = BMI_TMP . DIRECTORY_SEPARATOR . '.staging_files'; |
| 507 | |
| 508 | $this->siteConfig['total_size'] = 0; |
| 509 | $this->siteConfig['total_files'] = 0; |
| 510 | $this->siteConfig['total_directories'] = 0; |
| 511 | |
| 512 | if (file_exists($pathDirsListFile)) @unlink($pathDirsListFile); |
| 513 | if (file_exists($pathFilesListFile)) @unlink($pathFilesListFile); |
| 514 | |
| 515 | $this->filesList = fopen($pathFilesListFile, 'a'); |
| 516 | $this->dirsList = fopen($pathDirsListFile, 'a'); |
| 517 | |
| 518 | $topLevelFiles = $this->getAbspathFiles(ABSPATH); |
| 519 | $leftDirs = $this->processFiles(trailingslashit(ABSPATH), $topLevelFiles); |
| 520 | |
| 521 | $this->processFilesRecursively($leftDirs); |
| 522 | |
| 523 | fclose($this->filesList); |
| 524 | fclose($this->dirsList); |
| 525 | |
| 526 | $this->log(__('All files scanned and prepared for duplication...', 'backup-backup'), 'SUCCESS'); |
| 527 | $this->progress(10); |
| 528 | |
| 529 | $this->setContinuation(1, 2); |
| 530 | } |
| 531 | |
| 532 | // Display details about scan and check database size |
| 533 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 2) { |
| 534 | $this->log(__('Looking for database tables that should be duplicated and their sizes...', 'backup-backup'), 'STEP'); |
| 535 | |
| 536 | $this->siteConfig['total_db_size'] = 0; |
| 537 | $this->siteConfig['tables'] = $this->getTablesForDuplication(); |
| 538 | $this->siteConfig['amountOfTables'] = sizeof($this->siteConfig['tables']); |
| 539 | $this->siteConfig['sumOfTotalSize'] = intval($this->siteConfig['total_db_size']) + intval($this->siteConfig['total_size']); |
| 540 | |
| 541 | $this->log(__('Amount of files to duplicate:', 'backup-backup') . ' ' . $this->siteConfig['total_files']); |
| 542 | $this->log(__('Amount of directories to duplicate:', 'backup-backup') . ' ' . $this->siteConfig['total_directories']); |
| 543 | $this->log(__('Amount of tables to duplicate:', 'backup-backup') . ' ' . $this->siteConfig['amountOfTables']); |
| 544 | $this->log(__('Size of database to duplicate:', 'backup-backup') . ' ' . BMP::humanSize(intval($this->siteConfig['total_db_size']))); |
| 545 | $this->log(__('Size of files to duplicate:', 'backup-backup') . ' ' . BMP::humanSize(intval($this->siteConfig['total_size']))); |
| 546 | $this->log(__('Total duplication size:', 'backup-backup') . ' ' . BMP::humanSize($this->siteConfig['sumOfTotalSize'])); |
| 547 | $this->log(__('Tables prepared for duplication...', 'backup-backup'), 'SUCCESS'); |
| 548 | |
| 549 | $this->log(__('Checking if there is enough space for the staging site...', 'backup-backup'), 'STEP'); |
| 550 | $this->log(__('Space checking may take a while', 'backup-backup')); |
| 551 | |
| 552 | $this->progress(15); |
| 553 | |
| 554 | $this->setContinuation(1, 3); |
| 555 | } |
| 556 | |
| 557 | // Check if there is enough space for duplication |
| 558 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 3) { |
| 559 | require_once BMI_INCLUDES . '/check/checker.php'; |
| 560 | $checker = new Checker($this->logger); |
| 561 | |
| 562 | $bytes = intval(intval($this->siteConfig['sumOfTotalSize']) * 1.1); |
| 563 | $this->log(str_replace('%s2', BMP::humanSize($bytes), str_replace('%s1', $bytes, __('Checking in total: %s1 bytes (%s2)', 'backup-backup')))); |
| 564 | |
| 565 | if (!$checker->check_free_space($bytes, true)) { |
| 566 | |
| 567 | $translated = __('There is not enough space on your server in order to create staging site.', 'backup-backup'); |
| 568 | $english = 'There is not enough space on your server in order to create staging site.'; |
| 569 | return $this->returnError($translated, $english); |
| 570 | |
| 571 | } else { |
| 572 | |
| 573 | $this->log(__("Confirmed, there is more than enough space, checked: ", 'backup-backup') . ($bytes) . __(" bytes", 'backup-backup'), 'SUCCESS'); |
| 574 | |
| 575 | } |
| 576 | |
| 577 | $this->progress(20); |
| 578 | |
| 579 | // Set next batch to start step 2 |
| 580 | $this->log('Setting new step for next request to 2 @ batch 1', 'VERBOSE'); |
| 581 | $this->setContinuation(2); |
| 582 | |
| 583 | } |
| 584 | |
| 585 | } |
| 586 | |
| 587 | // Step: 2 (duplicate database) |
| 588 | private function duplicateDatabase() { |
| 589 | |
| 590 | if (!isset($this->siteConfig['finishedTables'])) { |
| 591 | $this->siteConfig['finishedTables'] = []; |
| 592 | } |
| 593 | |
| 594 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 1) { |
| 595 | $this->log(__('Duplicating database tables...', 'backup-backup'), 'STEP'); |
| 596 | } |
| 597 | |
| 598 | $startTime = time(); |
| 599 | foreach ($this->siteConfig['tables'] as $source_table => $destination_table) { |
| 600 | |
| 601 | $this->duplicateTable($source_table, $destination_table); |
| 602 | $this->log(str_replace('%s1', $source_table, str_replace('%s2', $destination_table, __('Table %s1 cloned as %s2', 'backup-backup')))); |
| 603 | |
| 604 | $this->siteConfig['finishedTables'][] = $destination_table; |
| 605 | unset($this->siteConfig['tables'][$source_table]); |
| 606 | |
| 607 | $processPercentage = intval((sizeof($this->siteConfig['finishedTables']) / $this->siteConfig['amountOfTables']) * 20); |
| 608 | $this->progress(20 + $processPercentage); |
| 609 | |
| 610 | if ((time() - $startTime) >= 4) { |
| 611 | $this->setContinuation(2, (intval($this->siteConfig['batch']) + 1)); |
| 612 | break; |
| 613 | } |
| 614 | |
| 615 | } |
| 616 | |
| 617 | if (sizeof($this->siteConfig['tables']) == 0) { |
| 618 | unset($this->siteConfig['tables']); |
| 619 | } |
| 620 | |
| 621 | if (!isset($this->siteConfig['tables'])) { |
| 622 | $this->log(__('All tables were successfully duplicated', 'backup-backup'), 'SUCCESS'); |
| 623 | $this->setContinuation(3); |
| 624 | } |
| 625 | |
| 626 | } |
| 627 | |
| 628 | // Step: 3 (search & replace of new tables) |
| 629 | private function searchReplace() { |
| 630 | |
| 631 | require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'search-replace.php'; |
| 632 | |
| 633 | // Domain |
| 634 | $sourceURL = $this->parseDomain($this->siteConfig['source_home_url']); |
| 635 | $destinationURL = $this->parseDomain($this->siteConfig['url']); |
| 636 | |
| 637 | // Paths |
| 638 | $sourceABSPATH = untrailingslashit($this->siteConfig['root_source']); |
| 639 | $destinationABSPATH = untrailingslashit($this->siteConfig['root_staging']); |
| 640 | |
| 641 | // Items to be replaced |
| 642 | $replaces = [ |
| 643 | ['from' => $sourceABSPATH, 'to' => $destinationABSPATH], |
| 644 | ['from' => $sourceURL, 'to' => $destinationURL], |
| 645 | ['from' => $this->siteConfig['source_db_prefix'], 'to' => $this->siteConfig['db_prefix']] |
| 646 | ]; |
| 647 | |
| 648 | $variants = [ |
| 649 | __("Batch for path adjustment (%s/%s) updated: %s fields.", 'backup-backup'), |
| 650 | __("Batch for domain adjustments (%s/%s) updated: %s fields.", 'backup-backup'), |
| 651 | __("Batch for prefix key adjustments (%s/%s) updated: %s fields.", 'backup-backup') |
| 652 | ]; |
| 653 | |
| 654 | $variantsEmpty = [ |
| 655 | __("Path replacements are not required for table: %s", 'backup-backup'), |
| 656 | __("Domain replacements are not required for table: %s", 'backup-backup'), |
| 657 | __("Prefix key replacements are not required for table: %s", 'backup-backup') |
| 658 | ]; |
| 659 | |
| 660 | // Table for replacement |
| 661 | if (isset($this->siteConfig['finishedTables']) && sizeof($this->siteConfig['finishedTables']) > 0) { |
| 662 | |
| 663 | // Get first table from duplicated tables |
| 664 | $table = $this->siteConfig['finishedTables'][0]; |
| 665 | |
| 666 | } else { |
| 667 | |
| 668 | // All tables processed, search replace finished |
| 669 | unset($this->siteConfig['finishedTables']); |
| 670 | $this->setContinuation(4); |
| 671 | |
| 672 | } |
| 673 | |
| 674 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 1) { |
| 675 | $this->log(__('Performing database search replace on duplicated tables...', 'backup-backup'), 'STEP'); |
| 676 | |
| 677 | $pagesize = '?'; |
| 678 | if (defined('BMI_MAX_SEARCH_REPLACE_PAGE')) $pagesize = BMI_MAX_SEARCH_REPLACE_PAGE; |
| 679 | $this->log(__('Page size for that process: ', 'backup-backup') . $pagesize, 'INFO'); |
| 680 | |
| 681 | $this->siteConfig['totalTables'] = 0; |
| 682 | $this->siteConfig['totalRows'] = 0; |
| 683 | $this->siteConfig['totalChanges'] = 0; |
| 684 | $this->siteConfig['totalUpdates'] = 0; |
| 685 | |
| 686 | $this->siteConfig['currentSearchReplaceItem'] = 0; |
| 687 | $this->siteConfig['currentTableTotalUpdates'] = 0; |
| 688 | $this->siteConfig['currentSearchReplacePage'] = 0; |
| 689 | $this->siteConfig['totalSearchReplacePages'] = 0; |
| 690 | |
| 691 | $this->setContinuation(3, 2); |
| 692 | } |
| 693 | |
| 694 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 2) { |
| 695 | |
| 696 | // Give details of current process |
| 697 | if ($this->siteConfig['currentSearchReplaceItem'] == 0 && $this->siteConfig['currentSearchReplacePage'] == 0) { |
| 698 | $this->log(sprintf(__('Performing search replace for table: %s', 'backup-backup'), $table), 'STEP'); |
| 699 | } |
| 700 | |
| 701 | // Control time of the process |
| 702 | $startTime = time(); |
| 703 | $tableCompleted = false; |
| 704 | $maxExecutionTime = 5; |
| 705 | |
| 706 | for ($i = $this->siteConfig['currentSearchReplaceItem']; $i < sizeof($replaces); ++$i) { |
| 707 | |
| 708 | $this->siteConfig['currentSearchReplaceItem'] = $i; |
| 709 | if ((time() - $startTime) >= $maxExecutionTime) break; |
| 710 | $tableCompleted = false; |
| 711 | |
| 712 | $from = $replaces[$i]['from']; |
| 713 | $to = $replaces[$i]['to']; |
| 714 | |
| 715 | while ($tableCompleted === false && (time() - $startTime) < $maxExecutionTime) { |
| 716 | |
| 717 | // Progress |
| 718 | $start = $this->siteConfig['currentSearchReplacePage']; |
| 719 | $end = $this->siteConfig['totalSearchReplacePages']; |
| 720 | |
| 721 | // Path replace for current table |
| 722 | if ($i == 2) { |
| 723 | if (strpos($table, 'usermeta') !== false) { |
| 724 | $this->performSearchReplace($table, $from, $to, $start, $end, ['meta_key']); |
| 725 | } |
| 726 | } else { |
| 727 | $this->performSearchReplace($table, $from, $to, $start, $end); |
| 728 | } |
| 729 | |
| 730 | // Handle batch logs |
| 731 | if ($this->siteConfig['currentTableTotalUpdates'] == 0 && $this->siteConfig['totalSearchReplacePages'] == 0) { |
| 732 | $this->log(sprintf($variantsEmpty[$i], $table), 'INFO'); |
| 733 | } else { |
| 734 | $st = $this->siteConfig['currentSearchReplacePage']; |
| 735 | $en = $this->siteConfig['totalSearchReplacePages']; |
| 736 | $this->log(sprintf($variants[$i], $st, $en, $this->siteConfig['currentTableTotalUpdates'])); |
| 737 | $this->siteConfig['currentTableTotalUpdates'] = 0; |
| 738 | } |
| 739 | |
| 740 | // Done of that table |
| 741 | if ($this->siteConfig['currentSearchReplacePage'] >= $this->siteConfig['totalSearchReplacePages']) { |
| 742 | if ($i >= sizeof($replaces) - 1) { |
| 743 | unset($this->siteConfig['finishedTables'][0]); |
| 744 | $this->siteConfig['finishedTables'] = array_values($this->siteConfig['finishedTables']); |
| 745 | $this->log(sprintf(__('Search replace for table %s finished', 'backup-backup'), $table), 'SUCCESS'); |
| 746 | $this->siteConfig['currentSearchReplaceItem'] = 0; |
| 747 | |
| 748 | $processPercentage = intval((($this->siteConfig['amountOfTables'] - sizeof($this->siteConfig['finishedTables'])) / $this->siteConfig['amountOfTables']) * 20); |
| 749 | $this->progress(40 + $processPercentage); |
| 750 | } |
| 751 | |
| 752 | $this->siteConfig['currentTableTotalUpdates'] = 0; |
| 753 | $this->siteConfig['currentSearchReplacePage'] = 0; |
| 754 | $this->siteConfig['totalSearchReplacePages'] = 0; |
| 755 | $tableCompleted = true; |
| 756 | } |
| 757 | |
| 758 | } |
| 759 | |
| 760 | if (!$tableCompleted) break; |
| 761 | |
| 762 | } |
| 763 | |
| 764 | if ($tableCompleted && sizeof($this->siteConfig['finishedTables']) == 0) $this->setContinuation(3, 3); // If path replacement finished |
| 765 | else $this->setContinuation(3, 2); // If path raplecement didnt finish, continue next batch (time exceed 5 seconds) |
| 766 | |
| 767 | } |
| 768 | |
| 769 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 3) $this->setContinuation(4); |
| 770 | |
| 771 | } |
| 772 | |
| 773 | // Step: 4 (summary of S&R and file duplication) |
| 774 | private function databaseFinishedCopyFiles() { |
| 775 | |
| 776 | $totalBatchExecution = 5; // 5 seconds |
| 777 | $milestoneUpdate = 500; // per 500 files/directories |
| 778 | $batchLimit = $milestoneUpdate + 1; // Limit of files/directories per batch |
| 779 | |
| 780 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 1) { |
| 781 | |
| 782 | // Remove unused variables |
| 783 | unset($this->siteConfig['currentSearchReplaceItem']); |
| 784 | unset($this->siteConfig['currentTableTotalUpdates']); |
| 785 | unset($this->siteConfig['currentSearchReplacePage']); |
| 786 | unset($this->siteConfig['totalSearchReplacePages']); |
| 787 | |
| 788 | // Display summary of search replace |
| 789 | $this->log(__('Displaying summary of search replace process', 'backup-backup'), 'STEP'); |
| 790 | $this->log(sprintf(__('Search replace processed %s tables in total', 'backup-backup'), $this->siteConfig['totalTables'])); |
| 791 | $this->log(sprintf(__('In total it processed %s rows', 'backup-backup'), $this->siteConfig['totalRows'])); |
| 792 | $this->log(sprintf(__('After all it changed only %s columns', 'backup-backup'), $this->siteConfig['totalChanges'])); |
| 793 | $this->log(sprintf(__('Which results in %s changes in total of all cells', 'backup-backup'), $this->siteConfig['totalUpdates'])); |
| 794 | |
| 795 | // Remove unused variables |
| 796 | unset($this->siteConfig['totalTables']); |
| 797 | unset($this->siteConfig['totalRows']); |
| 798 | unset($this->siteConfig['totalChanges']); |
| 799 | unset($this->siteConfig['totalUpdates']); |
| 800 | |
| 801 | // Update user roles in options table |
| 802 | $this->updateUserRolesInOptions(); |
| 803 | |
| 804 | $this->log(__('Search replace of all tables finished successfully', 'backup-backup'), 'SUCCESS'); |
| 805 | |
| 806 | // Go to new process without new batch request |
| 807 | $this->siteConfig['batch'] = 2; |
| 808 | |
| 809 | } |
| 810 | |
| 811 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 2) { |
| 812 | |
| 813 | if (!isset($this->siteConfig['dirSeek']) || $this->siteConfig['dirSeek'] == 0) { |
| 814 | $this->log(__('Duplication of directories to staging site', 'backup-backup'), 'STEP'); |
| 815 | $this->siteConfig['dirSeek'] = 0; |
| 816 | } |
| 817 | |
| 818 | $pathDirsListFile = BMI_TMP . DIRECTORY_SEPARATOR . '.staging_directories'; |
| 819 | |
| 820 | $file = new \SplFileObject($pathDirsListFile); |
| 821 | $file->seek($file->getSize()); |
| 822 | |
| 823 | $startTime = time(); |
| 824 | $currentSeekedElements = 0; |
| 825 | $totalLines = $file->key() + 1; |
| 826 | $stagingRoot = trailingslashit($this->siteConfig['root_staging']); |
| 827 | $file->seek($this->siteConfig['dirSeek']); |
| 828 | |
| 829 | while (!$file->eof()) { |
| 830 | |
| 831 | if ((time() - $startTime) > $totalBatchExecution || $currentSeekedElements > $batchLimit) break; |
| 832 | |
| 833 | $file->seek($this->siteConfig['dirSeek']); |
| 834 | $path = $stagingRoot . trim($file->current()); |
| 835 | |
| 836 | if (!(file_exists($path) && is_dir($path))) @mkdir($path); |
| 837 | if ($this->siteConfig['dirSeek'] % $milestoneUpdate === 0 && $this->siteConfig['dirSeek'] != 0) { |
| 838 | $processPercentageTotal = number_format(($this->siteConfig['dirSeek'] / $this->siteConfig['total_directories']) * 100, 2); |
| 839 | $this->log(sprintf( |
| 840 | __('Directory creation milestone: %s/%s (%s)', 'backup-backup'), |
| 841 | $this->siteConfig['dirSeek'], |
| 842 | $this->siteConfig['total_directories'], |
| 843 | $processPercentageTotal . '%' |
| 844 | )); |
| 845 | $processPercentage = intval(($this->siteConfig['dirSeek'] / $this->siteConfig['total_directories']) * 5); |
| 846 | $this->progress(60 + $processPercentage); |
| 847 | } |
| 848 | |
| 849 | $this->siteConfig['dirSeek']++; |
| 850 | $currentSeekedElements++; |
| 851 | |
| 852 | } |
| 853 | |
| 854 | if ($this->siteConfig['dirSeek'] >= $this->siteConfig['total_directories']) { |
| 855 | unlink($pathDirsListFile); |
| 856 | unset($this->siteConfig['dirSeek']); |
| 857 | $this->log(sprintf( |
| 858 | __('Directory creation milestone: %s/%s (%s)', 'backup-backup'), |
| 859 | $this->siteConfig['total_directories'], |
| 860 | $this->siteConfig['total_directories'], |
| 861 | '100%' |
| 862 | )); |
| 863 | $this->progress(65); |
| 864 | $this->setContinuation(4, 3); |
| 865 | } else { |
| 866 | $this->setContinuation(4, 2); |
| 867 | } |
| 868 | |
| 869 | } |
| 870 | |
| 871 | if (isset($this->siteConfig['batch']) && $this->siteConfig['batch'] == 3) { |
| 872 | |
| 873 | if (!isset($this->siteConfig['fileSeek']) || $this->siteConfig['fileSeek'] == 0) { |
| 874 | $this->log(__('Duplication of files to staging site', 'backup-backup'), 'STEP'); |
| 875 | $this->log(__('Duplication of files make take a while', 'backup-backup')); |
| 876 | $this->log(__('Disclaimer: ZIP Archives are not getting cloned on staging sites', 'backup-backup'), 'WARN'); |
| 877 | $this->siteConfig['fileSeek'] = 0; |
| 878 | } |
| 879 | |
| 880 | $pathFilesListFile = BMI_TMP . DIRECTORY_SEPARATOR . '.staging_files'; |
| 881 | |
| 882 | $file = new \SplFileObject($pathFilesListFile); |
| 883 | $file->seek($file->getSize()); |
| 884 | |
| 885 | $startTime = time(); |
| 886 | $currentSeekedElements = 0; |
| 887 | $totalLines = $file->key() + 1; |
| 888 | $sourceRoot = trailingslashit($this->siteConfig['root_source']); |
| 889 | $stagingRoot = trailingslashit($this->siteConfig['root_staging']); |
| 890 | $file->seek($this->siteConfig['fileSeek']); |
| 891 | $disallowedExtensions = ['zip', 'tar', 'gz', 'tmp', 'rar', '7z']; |
| 892 | |
| 893 | while (!$file->eof()) { |
| 894 | |
| 895 | if ((time() - $startTime) > $totalBatchExecution || $currentSeekedElements > $batchLimit) break; |
| 896 | |
| 897 | $file->seek($this->siteConfig['fileSeek']); |
| 898 | $path = trim($file->current()); |
| 899 | |
| 900 | if (file_exists($sourceRoot . $path) && !file_exists($stagingRoot . $path)) { |
| 901 | $arrayWithExtension = explode('.', $path); |
| 902 | $ext = strtolower(array_pop($arrayWithExtension)); |
| 903 | if (!in_array($ext, $disallowedExtensions) && strpos($path, 'backup-migration-config.php') === false) { |
| 904 | @copy($sourceRoot . $path, $stagingRoot . $path); |
| 905 | } |
| 906 | } |
| 907 | |
| 908 | if ($this->siteConfig['fileSeek'] % $milestoneUpdate === 0 && $this->siteConfig['fileSeek'] != 0) { |
| 909 | $processPercentageTotal = number_format(($this->siteConfig['fileSeek'] / $this->siteConfig['total_files']) * 100, 2); |
| 910 | $this->log(sprintf( |
| 911 | __('File duplication milestone: %s/%s (%s)', 'backup-backup'), |
| 912 | $this->siteConfig['fileSeek'], |
| 913 | $this->siteConfig['total_files'], |
| 914 | $processPercentageTotal . '%' |
| 915 | )); |
| 916 | $processPercentage = intval(($this->siteConfig['fileSeek'] / $this->siteConfig['total_files']) * 25); |
| 917 | $this->progress(65 + $processPercentage); |
| 918 | } |
| 919 | |
| 920 | $this->siteConfig['fileSeek']++; |
| 921 | $currentSeekedElements++; |
| 922 | |
| 923 | } |
| 924 | |
| 925 | if ($this->siteConfig['fileSeek'] >= $this->siteConfig['total_files']) { |
| 926 | unlink($pathFilesListFile); |
| 927 | unset($this->siteConfig['fileSeek']); |
| 928 | $this->log(sprintf( |
| 929 | __('File duplication milestone: %s/%s (%s)', 'backup-backup'), |
| 930 | $this->siteConfig['total_files'], |
| 931 | $this->siteConfig['total_files'], |
| 932 | '100%' |
| 933 | )); |
| 934 | $this->progress(90); |
| 935 | $this->setContinuation(5); |
| 936 | } else { |
| 937 | $this->setContinuation(4, 3); |
| 938 | } |
| 939 | |
| 940 | } |
| 941 | |
| 942 | } |
| 943 | |
| 944 | // Step: 5 (setup passwordless login script and paste adjusted wp-config) |
| 945 | private function setupWpConfigAndLoginScript() { |
| 946 | |
| 947 | $this->copyOverPasswordLessScript(); |
| 948 | |
| 949 | $this->log(__('Inserting wp-config.php file for staging site', 'backup-backup'), 'STEP'); |
| 950 | |
| 951 | $sourceWPConfig = trailingslashit($this->siteConfig['root_source']) . 'wp-config.php'; |
| 952 | $destinationWPConfig = trailingslashit($this->siteConfig['root_staging']) . 'wp-config.php'; |
| 953 | |
| 954 | $previousPrefix = $this->siteConfig['source_db_prefix']; |
| 955 | $destinationPrefix = $this->siteConfig['db_prefix']; |
| 956 | |
| 957 | $previousRoot = untrailingslashit($this->siteConfig['root_source']); |
| 958 | $destinationRoot = untrailingslashit($this->siteConfig['root_staging']); |
| 959 | |
| 960 | $sourceURL = $this->parseDomain($this->siteConfig['source_home_url']); |
| 961 | $destinationURL = $this->parseDomain($this->siteConfig['url']); |
| 962 | |
| 963 | $wpconfig = file_get_contents($sourceWPConfig); |
| 964 | |
| 965 | // Table Prefix |
| 966 | $this->log(__('Replacing table prefix in wp-config.php', 'backup-backup')); |
| 967 | if (strpos($wpconfig, '"' . $previousPrefix . '";') !== false) { |
| 968 | $wpconfig = str_replace('"' . $previousPrefix . '";', '"' . $destinationPrefix . '";', $wpconfig); |
| 969 | } elseif (strpos($wpconfig, "'" . $previousPrefix . "';") !== false) { |
| 970 | $wpconfig = str_replace("'" . $previousPrefix . "';", "'" . $destinationPrefix . "';", $wpconfig); |
| 971 | } |
| 972 | |
| 973 | // Paths e.g. for wp_debug_log |
| 974 | $this->log(__('Adjusting paths in wp-config.php', 'backup-backup')); |
| 975 | if (strpos($wpconfig, '"' . $previousRoot . '";') !== false) { |
| 976 | $wpconfig = str_replace('"' . $previousRoot . '";', '"' . $destinationRoot . '";', $wpconfig); |
| 977 | } elseif (strpos($wpconfig, "'" . $previousRoot . "';") !== false) { |
| 978 | $wpconfig = str_replace("'" . $previousRoot . "';", "'" . $destinationRoot . "';", $wpconfig); |
| 979 | } |
| 980 | |
| 981 | // Paths e.g. for wp_home & wp_siteurl |
| 982 | $this->log(__('Adjusting domains in wp-config.php', 'backup-backup')); |
| 983 | $wpconfig = explode("\n", $wpconfig); |
| 984 | for ($i = 0; $i < sizeof($wpconfig); ++$i) { |
| 985 | |
| 986 | $line = $wpconfig[$i]; |
| 987 | |
| 988 | if (strpos($line, 'WP_SITEURL') !== false || strpos($line, 'WP_HOME') !== false) { |
| 989 | $wpconfig[$i] = str_replace($sourceURL, $destinationURL, $line); |
| 990 | } |
| 991 | |
| 992 | } |
| 993 | |
| 994 | $wpconfig = implode("\n", $wpconfig); |
| 995 | |
| 996 | file_put_contents($destinationWPConfig, $wpconfig); |
| 997 | $this->log(__('File adjustments for wp-config.php finished successfully', 'backup-backup'), 'SUCCESS'); |
| 998 | |
| 999 | $this->setContinuation(6); |
| 1000 | |
| 1001 | } |
| 1002 | |
| 1003 | // Step: 6 (cleanup and misc) |
| 1004 | private function performFinish() { |
| 1005 | |
| 1006 | $this->cleanup(); |
| 1007 | $this->setContinuation(7); |
| 1008 | |
| 1009 | } |
| 1010 | |
| 1011 | public function __destruct() { |
| 1012 | |
| 1013 | parent::__destruct(); |
| 1014 | |
| 1015 | } |
| 1016 | |
| 1017 | } |
| 1018 |