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