Cleaners
5 years ago
Exceptions
5 years ago
Cancel.php
3 years ago
CancelUpdate.php
4 years ago
Cloning.php
3 years ago
CloningProcess.php
3 years ago
Data.php
3 years ago
Database.php
3 years ago
Delete.php
3 years ago
Directories.php
3 years ago
Files.php
3 years ago
Finish.php
3 years ago
Job.php
3 years ago
JobExecutable.php
3 years ago
Logs.php
3 years ago
PreserveDataFirstStep.php
3 years ago
PreserveDataSecondStep.php
3 years ago
ProcessLock.php
3 years ago
Scan.php
3 years ago
SearchReplace.php
3 years ago
TotalStepsAreNumberOfTables.php
5 years ago
Updating.php
3 years ago
Verify.php
3 years ago
Cloning.php
588 lines
| 1 | <?php |
| 2 | |
| 3 | namespace WPStaging\Backend\Modules\Jobs; |
| 4 | |
| 5 | use Countable; |
| 6 | use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException; |
| 7 | use WPStaging\Core\Utils\Helper; |
| 8 | use WPStaging\Core\WPStaging; |
| 9 | use WPStaging\Framework\Analytics\Actions\AnalyticsStagingCreate; |
| 10 | use WPStaging\Framework\Database\SelectedTables; |
| 11 | use WPStaging\Framework\Filesystem\PathIdentifier; |
| 12 | use WPStaging\Framework\Filesystem\Scanning\ScanConst; |
| 13 | use WPStaging\Framework\Security\AccessToken; |
| 14 | use WPStaging\Framework\Staging\Sites; |
| 15 | use WPStaging\Framework\Utils\Sanitize; |
| 16 | use WPStaging\Framework\Utils\SlashMode; |
| 17 | use WPStaging\Framework\Utils\WpDefaultDirectories; |
| 18 | |
| 19 | /** |
| 20 | * Class Cloning |
| 21 | * @package WPStaging\Backend\Modules\Jobs |
| 22 | */ |
| 23 | class Cloning extends Job |
| 24 | { |
| 25 | |
| 26 | /** |
| 27 | * @var object |
| 28 | */ |
| 29 | private $db; |
| 30 | |
| 31 | /** |
| 32 | * @var WpDefaultDirectories |
| 33 | */ |
| 34 | private $dirUtils; |
| 35 | |
| 36 | /** |
| 37 | * @var Sites |
| 38 | */ |
| 39 | private $sitesHelper; |
| 40 | |
| 41 | /** |
| 42 | * @var string |
| 43 | */ |
| 44 | private $errorMessage; |
| 45 | |
| 46 | /** |
| 47 | * @var Sanitize |
| 48 | */ |
| 49 | private $sanitize; |
| 50 | |
| 51 | /** |
| 52 | * Initialize is called in \Job |
| 53 | */ |
| 54 | public function initialize() |
| 55 | { |
| 56 | $this->db = WPStaging::getInstance()->get("wpdb"); |
| 57 | $this->dirUtils = new WpDefaultDirectories(); |
| 58 | $this->sitesHelper = new Sites(); |
| 59 | $this->sanitize = WPStaging::make(Sanitize::class); |
| 60 | } |
| 61 | |
| 62 | public function getErrorMessage() |
| 63 | { |
| 64 | return $this->errorMessage; |
| 65 | } |
| 66 | |
| 67 | /** |
| 68 | * Save Chosen Cloning Settings |
| 69 | * @return bool |
| 70 | * @throws \Exception |
| 71 | */ |
| 72 | public function save() |
| 73 | { |
| 74 | if (!isset($_POST) || !isset($_POST["cloneID"])) { |
| 75 | $this->errorMessage = __("clone ID missing", 'wp-staging'); |
| 76 | return false; |
| 77 | } |
| 78 | |
| 79 | // Delete files_to_copy.cache |
| 80 | $this->cache->delete("files_to_copy"); |
| 81 | |
| 82 | // Generate Options |
| 83 | // Clone ID -> timestamp (time at which this clone creation initiated) |
| 84 | $this->options->clone = preg_replace("#\W+#", '-', strtolower($this->sanitize->sanitizeString($_POST["cloneID"]))); |
| 85 | // Clone Name -> Site name that user input, if user left it empty it will be Clone ID |
| 86 | $this->options->cloneName = isset($_POST["cloneName"]) ? sanitize_text_field($_POST["cloneName"]) : ''; |
| 87 | // The slugified version of Clone Name (to use in directory creation) |
| 88 | $this->options->cloneDirectoryName = $this->sitesHelper->sanitizeDirectoryName($this->options->cloneName); |
| 89 | $result = $this->sitesHelper->isCloneExists($this->options->cloneDirectoryName); |
| 90 | if ($result !== false) { |
| 91 | $this->errorMessage = $result; |
| 92 | return false; |
| 93 | } |
| 94 | |
| 95 | $this->options->cloneNumber = 1; |
| 96 | $this->options->prefix = $this->setStagingPrefix(); |
| 97 | $this->options->includedDirectories = []; |
| 98 | $this->options->excludedDirectories = []; |
| 99 | $this->options->extraDirectories = []; |
| 100 | $this->options->excludedFiles = apply_filters('wpstg_clone_excluded_files', [ |
| 101 | '.DS_Store', |
| 102 | '*.git', |
| 103 | '*.svn', |
| 104 | '*.tmp', |
| 105 | 'desktop.ini', |
| 106 | '.gitignore', |
| 107 | '*.log', |
| 108 | 'web.config', // Important: Windows IIS configuration file. Must not be in the staging site! |
| 109 | '.wp-staging', // Determines if a site is a staging site |
| 110 | '.wp-staging-cloneable', // File that makes the staging site cloneable. |
| 111 | ]); |
| 112 | |
| 113 | $this->options->excludedFilesFullPath = apply_filters('wpstg.clone.excluded_files_full_path', [ |
| 114 | '.htaccess', |
| 115 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'db.php', |
| 116 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'object-cache.php', |
| 117 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'advanced-cache.php' |
| 118 | ]); |
| 119 | |
| 120 | $this->options->currentStep = 0; |
| 121 | |
| 122 | // Job |
| 123 | $this->options->job = new \stdClass(); |
| 124 | |
| 125 | // Check if clone data already exists and use that one |
| 126 | if (isset($this->options->existingClones[$this->options->clone])) { |
| 127 | $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number; |
| 128 | |
| 129 | $this->options->prefix = isset($this->options->existingClones[$this->options->clone]->prefix) ? $this->options->existingClones[$this->options->clone]->prefix : $this->setStagingPrefix(); |
| 130 | } |
| 131 | // Clone does not exist but there are other clones in db |
| 132 | // Get data and increment it |
| 133 | elseif (!empty($this->options->existingClones)) { |
| 134 | $this->options->cloneNumber = count($this->options->existingClones) + 1; |
| 135 | } |
| 136 | |
| 137 | $this->options->networkClone = false; |
| 138 | if ($this->isMultisiteAndPro() && is_main_site()) { |
| 139 | $this->options->networkClone = isset($_POST['networkClone']) && $this->sanitize->sanitizeBool($_POST['networkClone']); |
| 140 | } |
| 141 | |
| 142 | // Included Tables / Prefixed Table - Excluded Tables |
| 143 | $includedTables = isset($_POST['includedTables']) ? $this->sanitize->sanitizeString($_POST['includedTables']) : ''; |
| 144 | $excludedTables = isset($_POST['excludedTables']) ? $this->sanitize->sanitizeString($_POST['excludedTables']) : ''; |
| 145 | $selectedTablesWithoutPrefix = isset($_POST['selectedTablesWithoutPrefix']) ? $this->sanitize->sanitizeString($_POST['selectedTablesWithoutPrefix']) : ''; |
| 146 | $selectedTables = new SelectedTables($includedTables, $excludedTables, $selectedTablesWithoutPrefix); |
| 147 | $selectedTables->setAllTablesExcluded(empty($_POST['allTablesExcluded']) ? false : $this->sanitize->sanitizeBool($_POST['allTablesExcluded'])); |
| 148 | $this->options->tables = $selectedTables->getSelectedTables($this->options->networkClone); |
| 149 | |
| 150 | // Exclude File Size Rules |
| 151 | $this->options->excludeGlobRules = []; |
| 152 | if (!empty($_POST["excludeGlobRules"])) { |
| 153 | $this->options->excludeGlobRules = $this->sanitize->sanitizeExcludeRules($_POST["excludeGlobRules"]); |
| 154 | } |
| 155 | |
| 156 | // Exclude Glob Rules |
| 157 | $this->options->excludeSizeRules = []; |
| 158 | if (!empty($_POST["excludeSizeRules"])) { |
| 159 | $this->options->excludeSizeRules = $this->sanitize->sanitizeExcludeRules($_POST["excludeSizeRules"]); |
| 160 | } |
| 161 | |
| 162 | $this->options->uploadsSymlinked = isset($_POST['uploadsSymlinked']) && $this->sanitize->sanitizeBool($_POST['uploadsSymlinked']); |
| 163 | |
| 164 | /** |
| 165 | * @see /WPStaging/Framework/CloningProcess/ExcludedPlugins.php to exclude plugins |
| 166 | * Only add other directories here |
| 167 | */ |
| 168 | $excludedDirectories = [ |
| 169 | PathIdentifier::IDENTIFIER_WP_CONTENT . 'cache', |
| 170 | ]; |
| 171 | |
| 172 | // Add upload folder to list of excluded directories for push if symlink option is enabled |
| 173 | if ($this->options->uploadsSymlinked) { |
| 174 | $excludedDirectories[] = PathIdentifier::IDENTIFIER_UPLOADS; |
| 175 | } |
| 176 | |
| 177 | $excludedDirectoriesRequest = isset($_POST["excludedDirectories"]) ? $this->sanitize->sanitizeString($_POST["excludedDirectories"]) : ''; |
| 178 | $excludedDirectoriesRequest = $this->dirUtils->getExcludedDirectories($excludedDirectoriesRequest); |
| 179 | |
| 180 | $this->options->excludedDirectories = array_merge($excludedDirectories, $excludedDirectoriesRequest); |
| 181 | |
| 182 | // Extra Directories |
| 183 | if (isset($_POST["extraDirectories"])) { |
| 184 | $this->options->extraDirectories = explode(ScanConst::DIRECTORIES_SEPARATOR, $this->sanitize->sanitizeString($_POST["extraDirectories"])); |
| 185 | } |
| 186 | |
| 187 | $this->options->databaseServer = 'localhost'; |
| 188 | if (!empty($_POST["databaseServer"])) { |
| 189 | $this->options->databaseServer = $this->sanitize->sanitizeString($_POST["databaseServer"]); |
| 190 | } |
| 191 | |
| 192 | $this->options->databaseUser = ''; |
| 193 | if (!empty($_POST["databaseUser"])) { |
| 194 | $this->options->databaseUser = $this->sanitize->sanitizeString($_POST["databaseUser"]); |
| 195 | } |
| 196 | |
| 197 | $this->options->databasePassword = ''; |
| 198 | if (!empty($_POST["databasePassword"])) { |
| 199 | $this->options->databasePassword = $this->sanitize->sanitizePassword($_POST["databasePassword"]); |
| 200 | } |
| 201 | |
| 202 | $this->options->databaseDatabase = ''; |
| 203 | if (!empty($_POST["databaseDatabase"])) { |
| 204 | $this->options->databaseDatabase = $this->sanitize->sanitizeString($_POST["databaseDatabase"]); |
| 205 | } |
| 206 | |
| 207 | // isExternalDatabase() depends upon databaseUser and databasePassword, |
| 208 | // Make sure they are set before calling this. |
| 209 | $this->options->databasePrefix = $this->isExternalDatabase() ? $this->db->prefix : ''; |
| 210 | if (!empty($_POST["databasePrefix"])) { |
| 211 | $this->options->databasePrefix = $this->maybeAppendUnderscorePrefix($this->sanitize->sanitizeString($_POST["databasePrefix"])); |
| 212 | } |
| 213 | |
| 214 | $this->options->databaseSsl = false; |
| 215 | if (isset($_POST["databaseSsl"]) && 'true' === $this->sanitize->sanitizeString($_POST["databaseSsl"])) { |
| 216 | $this->options->databaseSsl = true; |
| 217 | } |
| 218 | |
| 219 | $this->options->cloneDir = ''; |
| 220 | if (!empty($_POST["cloneDir"])) { |
| 221 | $this->options->cloneDir = trailingslashit(wpstg_urldecode($this->sanitize->sanitizeString($_POST["cloneDir"]))); |
| 222 | } |
| 223 | |
| 224 | $this->options->cloneHostname = ''; |
| 225 | if (!empty($_POST["cloneHostname"])) { |
| 226 | $this->options->cloneHostname = trim($this->sanitize->sanitizeString($_POST["cloneHostname"])); |
| 227 | } |
| 228 | |
| 229 | // Make sure it is always enabled for free version |
| 230 | $this->options->emailsAllowed = true; |
| 231 | $this->options->cronDisabled = false; |
| 232 | |
| 233 | if (defined('WPSTGPRO_VERSION')) { |
| 234 | $this->options->emailsAllowed = apply_filters( |
| 235 | 'wpstg_cloning_email_allowed', |
| 236 | isset($_POST['emailsAllowed']) && $this->sanitize->sanitizeBool($_POST['emailsAllowed']) |
| 237 | ); |
| 238 | $this->options->cronDisabled = !empty($_POST['cronDisabled']) ? $this->sanitize->sanitizeBool($_POST['cronDisabled']) : false; |
| 239 | } |
| 240 | |
| 241 | $this->options->destinationHostname = $this->getDestinationHostname(); |
| 242 | $this->options->destinationDir = $this->getDestinationDir(); |
| 243 | |
| 244 | $helper = new Helper(); |
| 245 | $this->options->homeHostname = $helper->getHomeUrlWithoutScheme(); |
| 246 | |
| 247 | // Process lock state |
| 248 | $this->options->isRunning = true; |
| 249 | |
| 250 | // id of the user creating the clone |
| 251 | $this->options->ownerId = get_current_user_id(); |
| 252 | |
| 253 | // Save Clone data |
| 254 | $this->saveClone(); |
| 255 | |
| 256 | WPStaging::make(AnalyticsStagingCreate::class)->enqueueStartEvent($this->options->jobIdentifier, $this->options); |
| 257 | |
| 258 | $this->errorMessage = ""; |
| 259 | return $this->saveOptions(); |
| 260 | } |
| 261 | |
| 262 | /** |
| 263 | * @return bool |
| 264 | */ |
| 265 | private function isDestinationDatabaseSameAsLiveDatabase() |
| 266 | { |
| 267 | return $this->options->databaseServer === DB_HOST && $this->options->databaseDatabase === DB_NAME; |
| 268 | } |
| 269 | |
| 270 | /** |
| 271 | * Save clone data initially |
| 272 | * @return void |
| 273 | */ |
| 274 | private function saveClone() |
| 275 | { |
| 276 | // Save new clone data |
| 277 | $this->debugLog("Cloning: {$this->options->clone}'s clone job's data is not in database, generating data"); |
| 278 | |
| 279 | $this->options->existingClones[$this->options->clone] = [ |
| 280 | "cloneName" => $this->options->cloneName, |
| 281 | "directoryName" => $this->options->cloneDirectoryName, |
| 282 | "path" => trailingslashit($this->options->destinationDir), |
| 283 | "url" => $this->getDestinationUrl(), |
| 284 | "number" => $this->options->cloneNumber, |
| 285 | "version" => WPStaging::getVersion(), |
| 286 | "status" => "unfinished or broken (?)", |
| 287 | "prefix" => $this->options->prefix, |
| 288 | "datetime" => time(), |
| 289 | "databaseUser" => $this->options->databaseUser, |
| 290 | "databasePassword" => $this->options->databasePassword, |
| 291 | "databaseDatabase" => $this->options->databaseDatabase, |
| 292 | "databaseServer" => $this->options->databaseServer, |
| 293 | "databasePrefix" => $this->options->databasePrefix, |
| 294 | "databaseSsl" => (bool)$this->options->databaseSsl, |
| 295 | "cronDisabled" => (bool)$this->options->cronDisabled, |
| 296 | "emailsAllowed" => (bool)$this->options->emailsAllowed, |
| 297 | "uploadsSymlinked" => (bool)$this->options->uploadsSymlinked, |
| 298 | "ownerId" => $this->options->ownerId, |
| 299 | "includedTables" => $this->options->tables, |
| 300 | "excludeSizeRules" => $this->options->excludeSizeRules, |
| 301 | "excludeGlobRules" => $this->options->excludeGlobRules, |
| 302 | "excludedDirectories" => $this->options->excludedDirectories, |
| 303 | "extraDirectories" => $this->options->extraDirectories, |
| 304 | "networkClone" => $this->isNetworkClone(), |
| 305 | ]; |
| 306 | |
| 307 | if ($this->sitesHelper->updateStagingSites($this->options->existingClones) === false) { |
| 308 | $this->log("Cloning: Failed to save {$this->options->clone}'s clone job data to database'"); |
| 309 | } |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * Get destination Hostname depending on whether WP has been installed in sub dir or not |
| 314 | * @return string |
| 315 | */ |
| 316 | private function getDestinationUrl() |
| 317 | { |
| 318 | if (!empty($this->options->cloneHostname)) { |
| 319 | return $this->options->cloneHostname; |
| 320 | } |
| 321 | |
| 322 | return trailingslashit(get_site_url()) . $this->options->cloneDirectoryName; |
| 323 | } |
| 324 | |
| 325 | /** |
| 326 | * Return target hostname |
| 327 | * @return string |
| 328 | */ |
| 329 | private function getDestinationHostname() |
| 330 | { |
| 331 | if (empty($this->options->cloneHostname)) { |
| 332 | $helper = new Helper(); |
| 333 | return $helper->getHomeUrlWithoutScheme(); |
| 334 | } |
| 335 | return $this->getHostnameWithoutScheme($this->options->cloneHostname); |
| 336 | } |
| 337 | |
| 338 | /** |
| 339 | * Return Hostname without scheme |
| 340 | * @param string $string |
| 341 | * @return string |
| 342 | */ |
| 343 | private function getHostnameWithoutScheme($string) |
| 344 | { |
| 345 | return preg_replace('#^https?://#', '', rtrim($string, '/')); |
| 346 | } |
| 347 | |
| 348 | /** |
| 349 | * Get Destination Directory including staging subdirectory |
| 350 | * @return string |
| 351 | */ |
| 352 | private function getDestinationDir() |
| 353 | { |
| 354 | // Throw fatal error |
| 355 | if (!empty($this->options->cloneDir) & (trailingslashit($this->options->cloneDir) === trailingslashit(WPStaging::getWPpath()))) { |
| 356 | $this->returnException('Error: Target Directory must be different from the root of the production website.'); |
| 357 | die(); |
| 358 | } |
| 359 | |
| 360 | // No custom clone dir so clone path will be in subfolder of root |
| 361 | if (empty($this->options->cloneDir)) { |
| 362 | $this->options->cloneDir = trailingslashit(WPStaging::getWPpath() . $this->options->cloneDirectoryName); |
| 363 | return $this->options->cloneDir; |
| 364 | } |
| 365 | return trailingslashit($this->options->cloneDir); |
| 366 | } |
| 367 | |
| 368 | /** |
| 369 | * Make sure prefix ends with underscore |
| 370 | * |
| 371 | * @param string $string |
| 372 | * @return string |
| 373 | */ |
| 374 | private function maybeAppendUnderscorePrefix($string) |
| 375 | { |
| 376 | $lastCharacter = substr($string, -1); |
| 377 | if ($lastCharacter === '_') { |
| 378 | return $string; |
| 379 | } |
| 380 | return $string . '_'; |
| 381 | } |
| 382 | |
| 383 | /** |
| 384 | * Create a new staging prefix that does not exist in database |
| 385 | */ |
| 386 | private function setStagingPrefix() |
| 387 | { |
| 388 | // Find a new prefix that does not already exist in database. |
| 389 | // Loop through up to 1000 different possible prefixes should be enough here;) |
| 390 | for ($i = 0; $i <= 10000; $i++) { |
| 391 | $this->options->prefix = !empty($this->options->existingClones) && $this->options->existingClones instanceof Countable |
| 392 | ? 'wpstg' . (count($this->options->existingClones) + $i) . '_' |
| 393 | : 'wpstg' . $i . '_'; |
| 394 | |
| 395 | $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'"; |
| 396 | $tables = $this->db->get_results($sql); |
| 397 | |
| 398 | // Prefix does not exist. We can use it |
| 399 | if (!$tables) { |
| 400 | return $this->options->prefix; |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | $message = sprintf("Fatal Error: Can not create staging prefix. '%s' already exists! Stopping for security reasons. Contact support@wp-staging.com", $this->options->prefix); |
| 405 | $this->returnException($message); |
| 406 | wp_die(esc_html($message)); |
| 407 | } |
| 408 | |
| 409 | |
| 410 | /** |
| 411 | * Start the cloning job |
| 412 | * @throws JobNotFoundException |
| 413 | */ |
| 414 | public function start() |
| 415 | { |
| 416 | if (!property_exists($this->options, 'currentJob') || $this->options->currentJob === null) { |
| 417 | $this->log("Cloning job finished"); |
| 418 | return true; |
| 419 | } |
| 420 | |
| 421 | $methodName = "job" . ucwords($this->options->currentJob); |
| 422 | |
| 423 | if (!method_exists($this, $methodName)) { |
| 424 | $this->log("Can't execute job; Job's method $methodName is not found"); |
| 425 | throw new JobNotFoundException($methodName); |
| 426 | } |
| 427 | |
| 428 | if ($this->options->databasePrefix === $this->db->prefix && $this->isDestinationDatabaseSameAsLiveDatabase()) { |
| 429 | $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.'); |
| 430 | } |
| 431 | |
| 432 | // Call the job |
| 433 | return $this->{$methodName}(); |
| 434 | } |
| 435 | |
| 436 | /** |
| 437 | * @param object $response |
| 438 | * @param string $nextJob |
| 439 | * @return object |
| 440 | * @throws \Exception |
| 441 | */ |
| 442 | private function handleJobResponse($response, $nextJob) |
| 443 | { |
| 444 | // Job is not done |
| 445 | if ($response->status !== true) { |
| 446 | return $response; |
| 447 | } |
| 448 | |
| 449 | $this->options->job = new \stdClass(); |
| 450 | $this->options->currentJob = $nextJob; |
| 451 | $this->options->currentStep = 0; |
| 452 | $this->options->totalSteps = 0; |
| 453 | |
| 454 | // Save options |
| 455 | $this->saveOptions(); |
| 456 | |
| 457 | return $response; |
| 458 | } |
| 459 | |
| 460 | /** |
| 461 | * Copy data from staging site to temporary column to use it later |
| 462 | * @return object |
| 463 | * @throws \Exception |
| 464 | */ |
| 465 | public function jobPreserveDataFirstStep() |
| 466 | { |
| 467 | $this->writeJobSpecificLogStartHeader(); |
| 468 | |
| 469 | $preserve = new PreserveDataFirstStep(); |
| 470 | return $this->handleJobResponse($preserve->start(), 'database'); |
| 471 | } |
| 472 | |
| 473 | /** |
| 474 | * Clone Database |
| 475 | * @return object |
| 476 | * @throws \Exception |
| 477 | */ |
| 478 | public function jobDatabase() |
| 479 | { |
| 480 | $database = new Database(); |
| 481 | return $this->handleJobResponse($database->start(), "SearchReplace"); |
| 482 | } |
| 483 | |
| 484 | /** |
| 485 | * Search & Replace |
| 486 | * @return object |
| 487 | * @throws \Exception |
| 488 | */ |
| 489 | public function jobSearchReplace() |
| 490 | { |
| 491 | $searchReplace = new SearchReplace(); |
| 492 | return $this->handleJobResponse($searchReplace->start(), "PreserveDataSecondStep"); |
| 493 | } |
| 494 | |
| 495 | /** |
| 496 | * Copy tmp data back to staging site |
| 497 | * @return object |
| 498 | * @throws \Exception |
| 499 | */ |
| 500 | public function jobPreserveDataSecondStep() |
| 501 | { |
| 502 | $preserve = new PreserveDataSecondStep(); |
| 503 | return $this->handleJobResponse($preserve->start(), 'directories'); |
| 504 | } |
| 505 | |
| 506 | /** |
| 507 | * Get All Files From Selected Directories Recursively Into a File |
| 508 | * @return object |
| 509 | * @throws \Exception |
| 510 | */ |
| 511 | public function jobDirectories() |
| 512 | { |
| 513 | $directories = new Directories(); |
| 514 | return $this->handleJobResponse($directories->start(), "files"); |
| 515 | } |
| 516 | |
| 517 | /** |
| 518 | * Copy Files |
| 519 | * @return object |
| 520 | * @throws \Exception |
| 521 | */ |
| 522 | public function jobFiles() |
| 523 | { |
| 524 | $files = new Files(); |
| 525 | return $this->handleJobResponse($files->start(), "data"); |
| 526 | } |
| 527 | |
| 528 | |
| 529 | /** |
| 530 | * Replace Data |
| 531 | * @return object |
| 532 | * @throws \Exception |
| 533 | */ |
| 534 | public function jobData() |
| 535 | { |
| 536 | return $this->handleJobResponse((new Data())->start(), "finish"); |
| 537 | } |
| 538 | |
| 539 | /** |
| 540 | * Save Clone Data |
| 541 | * @return object |
| 542 | * @throws \Exception |
| 543 | */ |
| 544 | public function jobFinish() |
| 545 | { |
| 546 | // Re-generate the token when the Clone is complete. |
| 547 | // Todo: Consider adding a do_action() on jobFinish to hook here. |
| 548 | // Todo: Inject using DI |
| 549 | $accessToken = new AccessToken(); |
| 550 | $accessToken->generateNewToken(); |
| 551 | |
| 552 | $finish = new Finish(); |
| 553 | return $this->handleJobResponse($finish->start(), ''); |
| 554 | } |
| 555 | |
| 556 | /** |
| 557 | * @return void |
| 558 | */ |
| 559 | private function writeJobSpecificLogStartHeader() |
| 560 | { |
| 561 | |
| 562 | $jobName = empty($this->options->mainJob) ? 'Unknown' : $this->options->mainJob; |
| 563 | |
| 564 | switch($jobName) { |
| 565 | case 'updating': |
| 566 | $jobName = 'Update'; |
| 567 | break; |
| 568 | case 'resetting': |
| 569 | $jobName = 'Reset'; |
| 570 | break; |
| 571 | case 'cloning': |
| 572 | $jobName = 'Cloning'; |
| 573 | break; |
| 574 | default: |
| 575 | $jobName = 'Unknown'; |
| 576 | break; |
| 577 | } |
| 578 | |
| 579 | $this->log('#################### Start ' . $jobName . ' Job ####################', 'INFO'); |
| 580 | if ($jobName !== 'Cloning' && !empty($this->options->clone)) { |
| 581 | $this->logger->info(esc_html('Staging Site ID: ' . $this->options->clone)); |
| 582 | $this->logger->info(esc_html('Staging Site: ' . $this->options->cloneName)); |
| 583 | } |
| 584 | |
| 585 | $this->logger->writeLogHeader(); |
| 586 | } |
| 587 | } |
| 588 |