Cleaners
1 day ago
Exceptions
1 day ago
Cancel.php
1 day ago
CancelUpdate.php
1 day ago
Cloning.php
1 day ago
CloningProcess.php
1 day ago
Data.php
1 day ago
Database.php
1 day ago
Delete.php
1 day ago
Directories.php
1 day ago
Files.php
1 day ago
Finish.php
1 day ago
Job.php
1 day ago
JobExecutable.php
1 day ago
Logs.php
1 day ago
PreserveDataFirstStep.php
1 day ago
PreserveDataSecondStep.php
1 day ago
ProcessLock.php
1 day ago
Scan.php
1 day ago
SearchReplace.php
1 day ago
TotalStepsAreNumberOfTables.php
1 day ago
Updating.php
1 day ago
Cloning.php
749 lines
| 1 | <?php |
| 2 | |
| 3 | namespace WPStaging\Backend\Modules\Jobs; |
| 4 | |
| 5 | use Countable; |
| 6 | use Exception; |
| 7 | use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException; |
| 8 | use WPStaging\Backup\Service\Database\DatabaseImporter; |
| 9 | use WPStaging\Core\WPStaging; |
| 10 | use WPStaging\Framework\Analytics\Actions\AnalyticsStagingCreate; |
| 11 | use WPStaging\Framework\Traits\TablePrefixValidator; |
| 12 | use WPStaging\Framework\Database\SelectedTables; |
| 13 | use WPStaging\Framework\Exceptions\WPStagingException; |
| 14 | use WPStaging\Framework\Filesystem\PathIdentifier; |
| 15 | use WPStaging\Framework\Filesystem\Scanning\ScanConst; |
| 16 | use WPStaging\Framework\Security\AccessToken; |
| 17 | use WPStaging\Framework\Utils\Urls; |
| 18 | use WPStaging\Framework\Utils\Sanitize; |
| 19 | use WPStaging\Framework\Adapter\Directory; |
| 20 | use WPStaging\Framework\Facades\Hooks; |
| 21 | use WPStaging\Framework\Utils\Strings; |
| 22 | use WPStaging\Framework\Utils\WpDefaultDirectories; |
| 23 | use WPStaging\Staging\Sites; |
| 24 | |
| 25 | use function WPStaging\functions\debug_log; |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | class Cloning extends Job |
| 32 | { |
| 33 | use TablePrefixValidator; |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | const WPSTG_REQUEST = 'wpstg_cloning'; |
| 39 | |
| 40 | |
| 41 | const FILTER_CLONE_EXCLUDED_FILES_FULL_PATH = 'wpstg.clone.excluded_files_full_path'; |
| 42 | |
| 43 | |
| 44 | const FILTER_CLONE_EXCLUDED_FILES = 'wpstg_clone_excluded_files'; |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | private $db; |
| 50 | |
| 51 | |
| 52 | |
| 53 | |
| 54 | private $dirUtils; |
| 55 | |
| 56 | |
| 57 | |
| 58 | |
| 59 | private $sitesHelper; |
| 60 | |
| 61 | |
| 62 | |
| 63 | |
| 64 | private $errorMessage; |
| 65 | |
| 66 | |
| 67 | |
| 68 | |
| 69 | protected $sanitize; |
| 70 | |
| 71 | |
| 72 | |
| 73 | |
| 74 | private $urls; |
| 75 | |
| 76 | |
| 77 | private $dirAdapter; |
| 78 | |
| 79 | |
| 80 | private $pathIdentifier; |
| 81 | |
| 82 | |
| 83 | protected $strUtil; |
| 84 | |
| 85 | |
| 86 | |
| 87 | |
| 88 | public function initialize() |
| 89 | { |
| 90 | $this->db = WPStaging::getInstance()->get("wpdb"); |
| 91 | $this->dirUtils = new WpDefaultDirectories(); |
| 92 | $this->sitesHelper = new Sites(); |
| 93 | $this->sanitize = WPStaging::make(Sanitize::class); |
| 94 | $this->urls = WPStaging::make(Urls::class); |
| 95 | $this->dirAdapter = WPStaging::make(Directory::class); |
| 96 | $this->strUtil = WPStaging::make(Strings::class); |
| 97 | $this->pathIdentifier = WPStaging::make(PathIdentifier::class); |
| 98 | } |
| 99 | |
| 100 | public function getErrorMessage(): string |
| 101 | { |
| 102 | return $this->errorMessage; |
| 103 | } |
| 104 | |
| 105 | |
| 106 | |
| 107 | |
| 108 | |
| 109 | |
| 110 | public function save(): bool |
| 111 | { |
| 112 | if (!isset($_POST) || !isset($_POST["cloneID"])) { |
| 113 | $this->errorMessage = __("clone ID missing", 'wp-staging'); |
| 114 | return false; |
| 115 | } |
| 116 | |
| 117 | |
| 118 | $this->filesIndexCache->delete(); |
| 119 | |
| 120 | |
| 121 | $this->options->root = str_replace(["\\", '/'], DIRECTORY_SEPARATOR, ABSPATH); |
| 122 | $this->options->current = null; |
| 123 | $this->options->currentClone = null; |
| 124 | |
| 125 | |
| 126 | $this->options->clone = preg_replace("#\W+#", '-', strtolower($this->sanitize->sanitizeString($_POST["cloneID"]))); |
| 127 | |
| 128 | |
| 129 | if (isset($_POST["cloneName"])) { |
| 130 | $this->options->cloneName = sanitize_text_field($_POST["cloneName"]); |
| 131 | } |
| 132 | |
| 133 | |
| 134 | if (empty($this->options->cloneName) || $this->options->cloneName === $this->options->clone) { |
| 135 | $this->options->cloneName = $this->maybeGenerateFriendlyName(); |
| 136 | } |
| 137 | |
| 138 | |
| 139 | $this->options->cloneDirectoryName = $this->sitesHelper->sanitizeDirectoryName($this->options->cloneName); |
| 140 | $result = $this->sitesHelper->isCloneExists($this->options->cloneDirectoryName); |
| 141 | if ($result !== false) { |
| 142 | $this->errorMessage = $result; |
| 143 | return false; |
| 144 | } |
| 145 | |
| 146 | $this->options->cloneNumber = 1; |
| 147 | $this->options->prefix = $this->setStagingPrefix(); |
| 148 | $this->options->includedDirectories = []; |
| 149 | $this->options->excludedDirectories = []; |
| 150 | $this->options->extraDirectories = []; |
| 151 | $this->options->excludedFiles = Hooks::applyFilters(self::FILTER_CLONE_EXCLUDED_FILES, [ |
| 152 | '.DS_Store', |
| 153 | '*.git', |
| 154 | '*.svn', |
| 155 | '*.tmp', |
| 156 | 'desktop.ini', |
| 157 | '.gitignore', |
| 158 | '*.log', |
| 159 | 'web.config', |
| 160 | '.wp-staging', |
| 161 | '.wp-staging-cloneable', |
| 162 | ]); |
| 163 | |
| 164 | $excludedFilesFullPath = [ |
| 165 | '.htaccess', |
| 166 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'db.php', |
| 167 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'object-cache.php', |
| 168 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'advanced-cache.php', |
| 169 | ]; |
| 170 | |
| 171 | $this->options->tmpExcludedGoDaddyFiles = []; |
| 172 | $muPluginsDir = trailingslashit($this->dirAdapter->getMuPluginsDirectory()); |
| 173 | if (file_exists($muPluginsDir . 'gd-system-plugin.php')) { |
| 174 | $excludedFilesFullPath[] = PathIdentifier::IDENTIFIER_MUPLUGINS . 'gd-system-plugin.php'; |
| 175 | $this->options->tmpExcludedGoDaddyFiles[] = $muPluginsDir . 'gd-system-plugin.php'; |
| 176 | } |
| 177 | |
| 178 | $this->options->excludedFilesFullPath = Hooks::applyFilters(self::FILTER_CLONE_EXCLUDED_FILES_FULL_PATH, $excludedFilesFullPath); |
| 179 | |
| 180 | $this->options->currentStep = 0; |
| 181 | |
| 182 | |
| 183 | $this->options->job = new \stdClass(); |
| 184 | $this->loadLegacyExistingClones(); |
| 185 | |
| 186 | |
| 187 | if (isset($this->options->existingClones[$this->options->clone])) { |
| 188 | $existingClone = (array)$this->options->existingClones[$this->options->clone]; |
| 189 | $this->options->cloneNumber = isset($existingClone['number']) ? (int)$existingClone['number'] : 1; |
| 190 | $this->options->prefix = !empty($existingClone['prefix']) && is_string($existingClone['prefix']) ? $existingClone['prefix'] : $this->setStagingPrefix(); |
| 191 | |
| 192 | |
| 193 | |
| 194 | } elseif (!empty($this->options->existingClones)) { |
| 195 | $this->options->cloneNumber = count($this->options->existingClones) + 1; |
| 196 | } |
| 197 | |
| 198 | $this->options->networkClone = false; |
| 199 | if ($this->isMultisiteAndPro() && is_main_site()) { |
| 200 | $this->options->networkClone = isset($_POST['networkClone']) && $this->sanitize->sanitizeBool($_POST['networkClone']); |
| 201 | } |
| 202 | |
| 203 | |
| 204 | $includedTables = isset($_POST['includedTables']) ? $this->sanitize->sanitizeString($_POST['includedTables']) : ''; |
| 205 | $excludedTables = isset($_POST['excludedTables']) ? $this->sanitize->sanitizeString($_POST['excludedTables']) : ''; |
| 206 | $selectedTablesWithoutPrefix = isset($_POST['selectedTablesWithoutPrefix']) ? $this->sanitize->sanitizeString($_POST['selectedTablesWithoutPrefix']) : ''; |
| 207 | $selectedTables = new SelectedTables($includedTables, $excludedTables, $selectedTablesWithoutPrefix); |
| 208 | $selectedTables->setAllTablesExcluded(empty($_POST['allTablesExcluded']) ? false : $this->sanitize->sanitizeBool($_POST['allTablesExcluded'])); |
| 209 | $this->options->tables = $selectedTables->getSelectedTables($this->options->networkClone); |
| 210 | |
| 211 | |
| 212 | $this->options->excludeGlobRules = []; |
| 213 | if (!empty($_POST["excludeGlobRules"])) { |
| 214 | $this->options->excludeGlobRules = $this->sanitize->sanitizeExcludeRules($_POST["excludeGlobRules"]); |
| 215 | } |
| 216 | |
| 217 | |
| 218 | $this->options->excludeSizeRules = []; |
| 219 | if (!empty($_POST["excludeSizeRules"])) { |
| 220 | $this->options->excludeSizeRules = $this->sanitize->sanitizeExcludeRules($_POST["excludeSizeRules"]); |
| 221 | } |
| 222 | |
| 223 | $this->options->uploadsSymlinked = isset($_POST['uploadsSymlinked']) && $this->sanitize->sanitizeBool($_POST['uploadsSymlinked']); |
| 224 | |
| 225 | $pluginWpContentDir = rtrim($this->dirAdapter->getPluginWpContentDirectory(), '/\\'); |
| 226 | |
| 227 | |
| 228 | |
| 229 | |
| 230 | |
| 231 | $excludedDirectories = [ |
| 232 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'cache', |
| 233 | $this->pathIdentifier->transformPathToIdentifiable($pluginWpContentDir), |
| 234 | PathIdentifier::IDENTIFIER_WP_CONTENT . WPSTG_PLUGIN_DOMAIN, |
| 235 | ]; |
| 236 | |
| 237 | |
| 238 | if (is_dir(trailingslashit($this->dirAdapter->getMuPluginsDirectory()) . 'gd-system-plugin')) { |
| 239 | $excludedDirectories[] = PathIdentifier::IDENTIFIER_MUPLUGINS . 'gd-system-plugin'; |
| 240 | $excludedDirectories[] = PathIdentifier::IDENTIFIER_MUPLUGINS . 'vendor'; |
| 241 | |
| 242 | $this->options->tmpExcludedGoDaddyFiles[] = $muPluginsDir . 'gd-system-plugin'; |
| 243 | $this->options->tmpExcludedGoDaddyFiles[] = $muPluginsDir . 'vendor'; |
| 244 | } |
| 245 | |
| 246 | |
| 247 | if ($this->options->uploadsSymlinked) { |
| 248 | $excludedDirectories[] = PathIdentifier::IDENTIFIER_UPLOADS; |
| 249 | } |
| 250 | |
| 251 | $excludedDirectoriesRequest = isset($_POST["excludedDirectories"]) ? $this->sanitize->sanitizeString($_POST["excludedDirectories"]) : ''; |
| 252 | $excludedDirectoriesRequest = $this->dirUtils->getExcludedDirectories($excludedDirectoriesRequest); |
| 253 | |
| 254 | $this->options->excludedDirectories = array_merge($excludedDirectories, $excludedDirectoriesRequest); |
| 255 | |
| 256 | |
| 257 | if (isset($_POST["extraDirectories"])) { |
| 258 | $this->options->extraDirectories = explode(ScanConst::DIRECTORIES_SEPARATOR, $this->sanitize->sanitizeString($_POST["extraDirectories"])); |
| 259 | } |
| 260 | |
| 261 | |
| 262 | $this->options->useNewAdminAccount = false; |
| 263 | $this->options->adminEmail = ''; |
| 264 | $this->options->adminPassword = ''; |
| 265 | |
| 266 | |
| 267 | $this->options->databaseServer = 'localhost'; |
| 268 | $this->options->databaseUser = ''; |
| 269 | $this->options->databasePassword = ''; |
| 270 | $this->options->databaseDatabase = ''; |
| 271 | |
| 272 | $this->options->databasePrefix = $this->isExternalDatabase() ? $this->db->prefix : ''; |
| 273 | $this->options->databaseSsl = false; |
| 274 | |
| 275 | |
| 276 | $this->options->cloneDir = ''; |
| 277 | $this->options->cloneHostname = ''; |
| 278 | |
| 279 | |
| 280 | $this->options->isEmailsAllowed = true; |
| 281 | $this->options->isCronEnabled = true; |
| 282 | $this->options->isWooSchedulerEnabled = true; |
| 283 | $this->options->isEmailsReminderEnabled = false; |
| 284 | $this->options->isAutoUpdatePlugins = false; |
| 285 | $this->setAdvancedCloningOptions(); |
| 286 | |
| 287 | $this->options->destinationDir = $this->getDestinationDir(); |
| 288 | $this->options->destinationHostname = $this->getDestinationHostname(); |
| 289 | |
| 290 | $this->options->homeHostname = $this->urls->getHomeUrlWithoutScheme(); |
| 291 | |
| 292 | |
| 293 | $this->options->isRunning = true; |
| 294 | $this->initializeLegacyStagingRun(Job::STAGING); |
| 295 | |
| 296 | |
| 297 | $this->options->ownerId = get_current_user_id(); |
| 298 | |
| 299 | $this->saveClone(); |
| 300 | |
| 301 | if (!$this->saveOptions()) { |
| 302 | return false; |
| 303 | } |
| 304 | |
| 305 | WPStaging::make(AnalyticsStagingCreate::class)->enqueueStartEvent($this->options->jobIdentifier, $this->options); |
| 306 | $this->errorMessage = ""; |
| 307 | return true; |
| 308 | } |
| 309 | |
| 310 | |
| 311 | |
| 312 | |
| 313 | |
| 314 | private function saveClone() |
| 315 | { |
| 316 | |
| 317 | $this->debugLog("Cloning: {$this->options->clone}'s clone job's data is not in database, generating data"); |
| 318 | |
| 319 | $this->options->existingClones[$this->options->clone] = [ |
| 320 | "cloneName" => $this->options->cloneName, |
| 321 | "directoryName" => $this->options->cloneDirectoryName, |
| 322 | "path" => trailingslashit($this->options->destinationDir), |
| 323 | "url" => $this->getDestinationUrl(), |
| 324 | "number" => $this->options->cloneNumber, |
| 325 | "version" => WPStaging::getVersion(), |
| 326 | "status" => "unfinished or broken (?)", |
| 327 | "prefix" => $this->options->prefix, |
| 328 | "datetime" => time(), |
| 329 | "useCustomDatabase" => $this->isExternalDatabase(), |
| 330 | "databaseUser" => $this->options->databaseUser, |
| 331 | "databasePassword" => $this->options->databasePassword, |
| 332 | "databaseDatabase" => $this->options->databaseDatabase, |
| 333 | "databaseServer" => $this->options->databaseServer, |
| 334 | "databasePrefix" => $this->options->databasePrefix, |
| 335 | "databaseSsl" => (bool)$this->options->databaseSsl, |
| 336 | "isCronEnabled" => (bool)$this->options->isCronEnabled, |
| 337 | "isEmailsAllowed" => (bool)$this->options->isEmailsAllowed, |
| 338 | "uploadsSymlinked" => (bool)$this->options->uploadsSymlinked, |
| 339 | "ownerId" => $this->options->ownerId, |
| 340 | "includedTables" => $this->options->tables, |
| 341 | "excludeSizeRules" => $this->options->excludeSizeRules, |
| 342 | "excludeGlobRules" => $this->options->excludeGlobRules, |
| 343 | "excludedDirectories" => $this->options->excludedDirectories, |
| 344 | "extraDirectories" => $this->options->extraDirectories, |
| 345 | "networkClone" => $this->isNetworkClone(), |
| 346 | 'useNewAdminAccount' => $this->options->useNewAdminAccount, |
| 347 | 'adminEmail' => $this->options->adminEmail, |
| 348 | 'adminPassword' => $this->options->adminPassword, |
| 349 | 'isWooSchedulerEnabled' => (bool)$this->options->isWooSchedulerEnabled, |
| 350 | "isEmailsReminderEnabled" => (bool)$this->options->isEmailsReminderEnabled, |
| 351 | 'isAutoUpdatePlugins' => (bool)$this->options->isAutoUpdatePlugins, |
| 352 | ]; |
| 353 | |
| 354 | if ($this->sitesHelper->updateStagingSites($this->options->existingClones) === false) { |
| 355 | $this->log("Cloning: Failed to save {$this->options->clone}'s clone job data to database'"); |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | |
| 360 | |
| 361 | |
| 362 | |
| 363 | private function getDestinationUrl(): string |
| 364 | { |
| 365 | if (!empty($this->options->cloneHostname)) { |
| 366 | return $this->options->cloneHostname; |
| 367 | } |
| 368 | |
| 369 | return trailingslashit(get_site_url()) . $this->options->cloneDirectoryName; |
| 370 | } |
| 371 | |
| 372 | |
| 373 | |
| 374 | |
| 375 | |
| 376 | private function getDestinationHostname(): string |
| 377 | { |
| 378 | if (empty($this->options->cloneHostname)) { |
| 379 | return $this->urls->getHomeUrlWithoutScheme(); |
| 380 | } |
| 381 | |
| 382 | return $this->getHostnameWithoutScheme($this->options->cloneHostname); |
| 383 | } |
| 384 | |
| 385 | |
| 386 | |
| 387 | |
| 388 | |
| 389 | |
| 390 | private function getHostnameWithoutScheme(string $string): string |
| 391 | { |
| 392 | return preg_replace('#^https?://#', '', rtrim($string, '/')); |
| 393 | } |
| 394 | |
| 395 | |
| 396 | |
| 397 | |
| 398 | |
| 399 | private function getDestinationDir(): string |
| 400 | { |
| 401 | |
| 402 | if (!empty($this->options->cloneDir) & (trailingslashit($this->options->cloneDir) === trailingslashit(WPStaging::getWPpath()))) { |
| 403 | $this->returnException('Error: Target path must be different from the root of the production website.'); |
| 404 | } |
| 405 | |
| 406 | |
| 407 | if (!empty($this->options->cloneDir)) { |
| 408 | return trailingslashit($this->options->cloneDir); |
| 409 | } |
| 410 | |
| 411 | |
| 412 | $cloneDestinationPath = $this->dirAdapter->getAbsPath() . $this->options->cloneDirectoryName; |
| 413 | |
| 414 | if (!is_writable($this->dirAdapter->getAbsPath())) { |
| 415 | $stagingSiteDirectory = $this->dirAdapter->getStagingSiteDirectoryInsideWpcontent(); |
| 416 | if ($stagingSiteDirectory === false) { |
| 417 | debug_log(esc_html('Fail to get destination directory. The staging sites destination folder cannot be created.')); |
| 418 | $this->returnException('The staging sites directory is not writable. Please choose another path.'); |
| 419 | } |
| 420 | |
| 421 | $cloneDestinationPath = trailingslashit($stagingSiteDirectory) . $this->options->cloneDirectoryName; |
| 422 | if (empty($this->options->cloneHostname)) { |
| 423 | $this->options->cloneHostname = trailingslashit($this->dirAdapter->getStagingSiteUrl()) . $this->options->cloneDirectoryName; |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | $this->options->cloneDir = trailingslashit($cloneDestinationPath); |
| 428 | return $this->options->cloneDir; |
| 429 | } |
| 430 | |
| 431 | |
| 432 | |
| 433 | |
| 434 | private function setStagingPrefix() |
| 435 | { |
| 436 | |
| 437 | |
| 438 | for ($i = 0; $i <= 10000; $i++) { |
| 439 | $this->options->prefix = !empty($this->options->existingClones) && $this->options->existingClones instanceof Countable |
| 440 | ? 'wpstg' . (count($this->options->existingClones) + $i) . '_' |
| 441 | : 'wpstg' . $i . '_'; |
| 442 | |
| 443 | $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'"; |
| 444 | $tables = $this->db->get_results($sql); |
| 445 | |
| 446 | |
| 447 | if (!$tables) { |
| 448 | return $this->options->prefix; |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | $message = sprintf("Fatal Error: Can not create staging prefix. '%s' already exists! Stopping for security reasons. Contact support@wp-staging.com", $this->options->prefix); |
| 453 | $this->returnException($message); |
| 454 | wp_die(esc_html($message)); |
| 455 | } |
| 456 | |
| 457 | |
| 458 | |
| 459 | |
| 460 | |
| 461 | |
| 462 | public function start() |
| 463 | { |
| 464 | if (!is_object($this->options)) { |
| 465 | return; |
| 466 | } |
| 467 | |
| 468 | if (!property_exists($this->options, 'currentJob') || $this->options->currentJob === null) { |
| 469 | $this->log("Cloning job finished"); |
| 470 | return true; |
| 471 | } |
| 472 | |
| 473 | $methodName = "job" . ucwords($this->options->currentJob); |
| 474 | |
| 475 | if (!method_exists($this, $methodName)) { |
| 476 | $this->log("Can't execute job; Job's method $methodName is not found"); |
| 477 | throw new JobNotFoundException($methodName); |
| 478 | } |
| 479 | |
| 480 | if ($this->options->databasePrefix === $this->db->prefix && $this->isStagingDatabaseSameAsProductionDatabase()) { |
| 481 | $this->returnException('Table prefix for staging site can not be identical to live database if staging site will be cloned into production database! Please start over and change the table prefix or destination database.'); |
| 482 | } |
| 483 | |
| 484 | if (defined('WPSTG_IS_DEV') && WPSTG_IS_DEV === true) { |
| 485 | return $this->{$methodName}(); |
| 486 | } |
| 487 | |
| 488 | $tmpPrefixes = [ |
| 489 | DatabaseImporter::TMP_DATABASE_PREFIX, |
| 490 | DatabaseImporter::TMP_DATABASE_PREFIX_TO_DROP, |
| 491 | ]; |
| 492 | |
| 493 | if (in_array($this->options->databasePrefix, $tmpPrefixes)) { |
| 494 | $this->returnException('Prefix wpstgtmp_ and wpstgbak_ are preserved by WP Staging and cannot be used for CLONING purpose! Please start over and change the table prefix.'); |
| 495 | } |
| 496 | |
| 497 | if ($this->isWpStagingReservedPrefix($this->options->databasePrefix)) { |
| 498 | $this->returnException($this->getReservedPrefixErrorMessage($this->options->databasePrefix)); |
| 499 | } |
| 500 | |
| 501 | |
| 502 | return $this->{$methodName}(); |
| 503 | } |
| 504 | |
| 505 | |
| 506 | |
| 507 | |
| 508 | |
| 509 | |
| 510 | |
| 511 | private function handleJobResponse($response, string $nextJob) |
| 512 | { |
| 513 | |
| 514 | if ($response->status !== true) { |
| 515 | return $response; |
| 516 | } |
| 517 | |
| 518 | $this->options->job = new \stdClass(); |
| 519 | $this->options->currentJob = $nextJob; |
| 520 | $this->options->currentStep = 0; |
| 521 | $this->options->totalSteps = 0; |
| 522 | |
| 523 | |
| 524 | $this->saveOptions(); |
| 525 | |
| 526 | return $response; |
| 527 | } |
| 528 | |
| 529 | |
| 530 | |
| 531 | |
| 532 | |
| 533 | |
| 534 | public function jobPreserveDataFirstStep() |
| 535 | { |
| 536 | $this->writeJobSpecificLogStartHeader(); |
| 537 | |
| 538 | $preserve = new PreserveDataFirstStep(); |
| 539 | return $this->handleJobResponse($preserve->start(), 'database'); |
| 540 | } |
| 541 | |
| 542 | |
| 543 | |
| 544 | |
| 545 | |
| 546 | |
| 547 | public function jobDatabase() |
| 548 | { |
| 549 | $database = new Database(); |
| 550 | return $this->handleJobResponse($database->start(), "SearchReplace"); |
| 551 | } |
| 552 | |
| 553 | |
| 554 | |
| 555 | |
| 556 | |
| 557 | |
| 558 | public function jobSearchReplace() |
| 559 | { |
| 560 | $searchReplace = new SearchReplace(); |
| 561 | return $this->handleJobResponse($searchReplace->start(), "PreserveDataSecondStep"); |
| 562 | } |
| 563 | |
| 564 | |
| 565 | |
| 566 | |
| 567 | |
| 568 | |
| 569 | public function jobPreserveDataSecondStep() |
| 570 | { |
| 571 | $preserve = new PreserveDataSecondStep(); |
| 572 | return $this->handleJobResponse($preserve->start(), 'directories'); |
| 573 | } |
| 574 | |
| 575 | |
| 576 | |
| 577 | |
| 578 | |
| 579 | |
| 580 | public function jobDirectories() |
| 581 | { |
| 582 | $directories = new Directories(); |
| 583 | return $this->handleJobResponse($directories->start(), "files"); |
| 584 | } |
| 585 | |
| 586 | |
| 587 | |
| 588 | |
| 589 | |
| 590 | |
| 591 | public function jobFiles() |
| 592 | { |
| 593 | $files = new Files(); |
| 594 | return $this->handleJobResponse($files->start(), "data"); |
| 595 | } |
| 596 | |
| 597 | |
| 598 | |
| 599 | |
| 600 | |
| 601 | |
| 602 | public function jobData() |
| 603 | { |
| 604 | $dataJob = $this->getDataJob(); |
| 605 | return $this->handleJobResponse($dataJob->start(), "finish"); |
| 606 | } |
| 607 | |
| 608 | |
| 609 | |
| 610 | |
| 611 | |
| 612 | |
| 613 | public function jobFinish() |
| 614 | { |
| 615 | |
| 616 | |
| 617 | |
| 618 | $accessToken = new AccessToken(); |
| 619 | $accessToken->generateNewToken(); |
| 620 | |
| 621 | $finish = new Finish(); |
| 622 | return $this->handleJobResponse($finish->start(), ''); |
| 623 | } |
| 624 | |
| 625 | |
| 626 | |
| 627 | |
| 628 | public function getDataJob(): Data |
| 629 | { |
| 630 | return new Data(); |
| 631 | } |
| 632 | |
| 633 | |
| 634 | |
| 635 | |
| 636 | protected function setAdvancedCloningOptions() |
| 637 | { |
| 638 | |
| 639 | } |
| 640 | |
| 641 | |
| 642 | |
| 643 | |
| 644 | private function writeJobSpecificLogStartHeader() |
| 645 | { |
| 646 | |
| 647 | $jobName = empty($this->options->mainJob) ? 'Unknown' : $this->options->mainJob; |
| 648 | |
| 649 | switch ($jobName) { |
| 650 | case Job::UPDATE: |
| 651 | $jobName = 'Update'; |
| 652 | break; |
| 653 | case Job::RESET: |
| 654 | $jobName = 'Reset'; |
| 655 | break; |
| 656 | case Job::STAGING: |
| 657 | $jobName = 'Cloning'; |
| 658 | break; |
| 659 | default: |
| 660 | $jobName = 'Unknown'; |
| 661 | break; |
| 662 | } |
| 663 | |
| 664 | $this->log('#################### Start ' . $jobName . ' Job ####################', 'INFO'); |
| 665 | if ($jobName !== 'Cloning' && !empty($this->options->clone)) { |
| 666 | $this->logger->info(esc_html('Staging Site ID: ' . $this->options->clone)); |
| 667 | $this->logger->info(esc_html('Staging Site: ' . $this->options->cloneName)); |
| 668 | } |
| 669 | |
| 670 | $this->logger->writeLogHeader(); |
| 671 | $this->logger->writeInstalledPluginsAndThemes(); |
| 672 | $this->addJobSettingsToLogs($jobName); |
| 673 | } |
| 674 | |
| 675 | |
| 676 | |
| 677 | |
| 678 | |
| 679 | private function maybeGenerateFriendlyName(): string |
| 680 | { |
| 681 | |
| 682 | $nameList = [ |
| 683 | "enterprise", |
| 684 | "voyager", |
| 685 | "defiant", |
| 686 | "discovery", |
| 687 | "excelsior", |
| 688 | "intrepid", |
| 689 | "constitution", |
| 690 | "reliant", |
| 691 | "grissom", |
| 692 | "yamato", |
| 693 | "excelsior", |
| 694 | "venture", |
| 695 | "cerritos", |
| 696 | "prometheus", |
| 697 | "bellerophon", |
| 698 | "sanpablo", |
| 699 | "sutherland", |
| 700 | "shenzhou", |
| 701 | "titan", |
| 702 | "reliant", |
| 703 | "stargazer", |
| 704 | "franklin", |
| 705 | "protostar", |
| 706 | ]; |
| 707 | |
| 708 | |
| 709 | shuffle($nameList); |
| 710 | |
| 711 | |
| 712 | $stagingSites = $this->sitesHelper->tryGettingStagingSites(); |
| 713 | foreach ($nameList as $name) { |
| 714 | |
| 715 | $name = sanitize_text_field($name); |
| 716 | $dirPath = ABSPATH . $name; |
| 717 | |
| 718 | if (file_exists($dirPath)) { |
| 719 | continue; |
| 720 | } |
| 721 | |
| 722 | |
| 723 | if (!$this->isStagingSiteNameExists($name, $stagingSites)) { |
| 724 | return $name; |
| 725 | } |
| 726 | } |
| 727 | |
| 728 | |
| 729 | return (string)$this->options->clone; |
| 730 | } |
| 731 | |
| 732 | |
| 733 | |
| 734 | |
| 735 | |
| 736 | |
| 737 | |
| 738 | private function isStagingSiteNameExists(string $name, array $stagingSites): bool |
| 739 | { |
| 740 | foreach ($stagingSites as $site) { |
| 741 | if ($site['directoryName'] === $name) { |
| 742 | return true; |
| 743 | } |
| 744 | } |
| 745 | |
| 746 | return false; |
| 747 | } |
| 748 | } |
| 749 |