PluginProbe ʕ •ᴥ•ʔ
Transferito: WP Migration / 11.4.0
Transferito: WP Migration v11.4.0
trunk 11.4.0 12.0.0 13.1.0 14.0.0 14.0.11 14.0.7 14.1.0 14.1.1 14.1.2 14.1.3 14.1.4
transferito / src / Controllers / Transfer.php
transferito / src / Controllers Last commit date
Transfer.php 1 year ago
Transfer.php
3143 lines
1 <?php
2
3 namespace Transferito\Controllers;
4
5 use Transferito\Models\Core\Config;
6 use Transferito\Models\Transfer\CodeBase;
7 use Transferito\Models\Transfer\Database;
8 use Transferito\Models\Transfer\Upload;
9 use Transferito\Models\Core\Api as TransferitoAPI;
10 use Transferito\Models\Settings\Telemetry;
11
12 class Transfer {
13
14 private $codeBase;
15 private $dataBase;
16 private $upload;
17 private $api;
18 private $options;
19 private $telemetry;
20
21 public function __construct()
22 {
23 if (current_user_can('activate_plugins')) {
24 $this->api = new TransferitoAPI();
25 $this->codeBase = new CodeBase();
26 $this->dataBase = new Database();
27 $this->upload = new Upload();
28 $this->telemetry = new Telemetry();
29
30 $this->options = get_option( 'transferito_settings_option' );
31
32 add_action("wp_ajax_preparing_transfer", [ $this, "prepareDownload"]);
33 add_action("wp_ajax_start_migration", [ $this, "startMigration"]);
34 add_action("wp_ajax_clean_up_files", [ $this, "cleanUp"]);
35 add_action("wp_ajax_status_check", [ $this, "statusCheck"]);
36
37 /**
38 * @deprecated
39 */
40 add_action("wp_ajax_get_directories", [ $this, "getFTPDirectories"]);
41
42 add_action("wp_ajax_initiate_local_upload", [ $this, "initiateUpload"]);
43 add_action("wp_ajax_upload_chunk", [ $this, "uploadChunk"]);
44 add_action("wp_ajax_complete_upload", [ $this, "completeUpload"]);
45 add_action("wp_ajax_preparing_codebase", [ $this, "prepareCodebase"]);
46 add_action("wp_ajax_add_files_to_codebase_archive", [ $this, "addFilesToCodebase"]);
47 add_action("wp_ajax_codebase_completion", [ $this, "codebaseArchiveComplete"]);
48 add_action("wp_ajax_preparing_database", [ $this, "prepareDatabase"]);
49 add_action("wp_ajax_create_db_exports", [ $this, "chunkedDBExport"]);
50 add_action("wp_ajax_database_completion", [ $this, "databaseExportComplete"]);
51 add_action("wp_ajax_archive_db_exports", [ $this, "archiveDBExport"]);
52 add_action("wp_ajax_database_relocation", [ $this, "databaseRelocation"]);
53 add_action("wp_ajax_database_relocation_check", [ $this, "databaseRelocationCheck"]);
54 add_action("wp_ajax_check_archive_completion", [ $this, "checkArchiveCompletion"]);
55 add_action("wp_ajax_archive_creation", [ $this, "archiveCreation"]);
56 add_action("wp_ajax_archive_progress_check", [ $this, "archiveProgressCheck"]);
57 add_action("wp_ajax_cpanel_authentication", [ $this, "cpanelAuthentication"]);
58 add_action("wp_ajax_server_detail_validation", [ $this, "serverDetailValidation"]);
59
60 /**
61 * @deprecated
62 */
63 add_action("wp_ajax_correct_directory_validation", [ $this, "directoryValidation"]);
64
65 add_action("wp_ajax_database_detail_validation", [ $this, "databaseValidation"]);
66 add_action("wp_ajax_hide_quickstart_popup", [ $this, "hideQuickStart"]);
67 add_action("wp_ajax_send_request_form", [ $this, "sendRequestForm"]);
68 add_action("wp_ajax_log_transferito_event", [ $this, "logEvent"]);
69 add_action("wp_ajax_start_directory_search", [ $this, "startDirectoryCheck"]);
70 add_action("wp_ajax_get_directory_check_update", [ $this, "getDirectoryCheckUpdate"]);
71 add_action('wp_ajax_check_premium_api_keys', [ $this, "checkPremiumApiKeys"]);
72
73
74 /**
75 * Move to routing class
76 */
77 add_action("wp_ajax_check_current_site", [$this, "wpSiteCheck"]);
78 add_action("wp_ajax_check_cpanel_availability", [$this, "cPanelCheck"]);
79 add_action("wp_ajax_choose_migration_method", [$this, "chooseMigrationMethod"]);
80 add_action("wp_ajax_switch_mode", [$this, "switchMode"]);
81 add_action("wp_ajax_screen_route_redirection", [$this, "screenRouting"]);
82 add_action("wp_ajax_load_directory_template", [$this, "loadDirectoryTemplate"]);
83 }
84 }
85
86 public function logEvent()
87 {
88 $event = $_POST['event'];
89 $eventProperties = $_POST['eventProperties'];
90
91 $this->telemetry->pushEvent($event, $eventProperties);
92
93 wp_send_json_success([ 'logged' => true ]);
94 }
95
96 /**
97 * @deprecated
98 * @return void
99 */
100 public function getFTPDirectories()
101 {
102 /**
103 * verify nonce with every FTP Directory request
104 */
105 check_ajax_referer('get_directory_list', 'securityKey');
106
107 /**
108 * Check that the ftpInfo element exists
109 */
110 $getDirectoriesPayload = get_transient('transferito_manual_server_detail');
111
112 /**
113 * Assign the correct path to the ftp details
114 */
115 if (count($getDirectoriesPayload) > 0) {
116 $getDirectoriesPayload['path'] = $_POST['path'];
117 }
118
119
120 try {
121 /**
122 * Hit the endpoint to return the results
123 */
124 $getDirectoriesRequest = $this->api->getDirectories($getDirectoriesPayload);
125
126 /**
127 * Listen to a successful response
128 * & then filter the array to just return the directories
129 */
130 if ($getDirectoriesRequest['code'] === 200) {
131 $directoryList = $getDirectoriesRequest['message']->filelist;
132 $filteredDirectoryList = array_filter($directoryList, function($value, $key) {
133 return $value->type === 'dir';
134 }, ARRAY_FILTER_USE_BOTH);
135 wp_send_json_success([
136 'folders' => $filteredDirectoryList,
137 'port' => $getDirectoriesPayload['ftpPort']
138 ]);
139 } else if ($getDirectoriesRequest['code'] !== 200) {
140 wp_send_json_error([
141 'err' => $getDirectoriesRequest['message']->result,
142 'payload' => $getDirectoriesPayload,
143 'message' => $getDirectoriesRequest
144 ], 400);
145 }
146 } catch(\Exception $exception) {
147 wp_send_json_error('There has been an issue - If this problem persists. Contact support', 500);
148 }
149 }
150
151 public function startDirectoryCheck()
152 {
153 /**
154 * verify nonce with every FTP Directory request
155 */
156 check_ajax_referer('get_directory_list', 'securityKey');
157
158 /**
159 * Check that the ftpInfo element exists
160 */
161 $directoryCheckPayload = get_transient('transferito_manual_server_detail');
162
163 /**
164 * Get the destination server URL
165 */
166 $domain = get_transient('transferito_migration_domain');
167
168 /**
169 * Make initial Directory Check request
170 */
171 $directoryCheck = $this->api->startDirectoryCheck(array(
172 'ftpHost' => $directoryCheckPayload['ftpHost'],
173 'ftpUser' => $directoryCheckPayload['ftpUser'],
174 'ftpPass' => $directoryCheckPayload['ftpPass'],
175 'ftpPort' => $directoryCheckPayload['ftpPort'],
176 'useSFTP' => $directoryCheckPayload['useSFTP'],
177 'URL' => $domain,
178 ));
179
180 /**
181 * Check the status code
182 */
183 $httpStatusCode = $directoryCheck['code'];
184
185 /**
186 * Check we have a successful response
187 */
188 if ($httpStatusCode === 200) {
189 wp_send_json_success(array_merge((array)$directoryCheck['message'], $directoryCheckPayload));
190 }
191
192 /**
193 * If we have anything other than a 200
194 * Fail the endpoint
195 */
196 if ($httpStatusCode !== 200) {
197 wp_send_json_error($directoryCheck['message'], 400);
198 }
199
200 }
201
202 public function getDirectoryCheckUpdate()
203 {
204 /**
205 * verify nonce with every FTP Directory request
206 */
207 check_ajax_referer('get_directory_list', 'securityKey');
208
209 $url = isset($_POST['url']) ? $_POST['url'] : '';
210 $directoryCheckId = isset($_POST['directoryCheckId']) ? $_POST['directoryCheckId'] : '';
211 $directoryCheckUpdate = $this->api->getDirectoryUpdate(array(
212 'URL' => $url,
213 'directoryCheckId' => $directoryCheckId
214 ));
215
216 /**
217 * Check the status code
218 */
219 $httpStatusCode = $directoryCheckUpdate['code'];
220
221 /**
222 * If we have anything other than a 200
223 * Fail the endpoint
224 */
225 if ($httpStatusCode !== 200) {
226 wp_send_json_error($directoryCheckUpdate['message'], 400);
227 }
228
229 /**
230 * If the path has been found
231 * Update the Server Detail
232 */
233 if ($directoryCheckUpdate['message']->found) {
234 $serverDetails = get_transient('transferito_manual_server_detail');
235
236 /**
237 * Fix to add the path if the document root is the ftp path
238 */
239 if ($directoryCheckUpdate['message']->path === '' && $serverDetails['useSFTP'] === '0') {
240 $directoryCheckUpdate['message']->path = './';
241 }
242
243 /**
244 * Add the path to the server details array
245 */
246 $serverDetails['path'] = $directoryCheckUpdate['message']->path;
247 $serverDetails['ftpPath'] = $directoryCheckUpdate['message']->path;
248 $serverDetails['URL'] = $url;
249
250 /**
251 * Update the server array
252 */
253 set_transient('transferito_manual_server_detail', $serverDetails);
254 }
255
256 wp_send_json_success($directoryCheckUpdate['message']);
257 }
258
259 public function wpSiteCheck()
260 {
261 /**
262 * verify nonce with every template change call
263 */
264 check_ajax_referer('template_change', 'actionKey');
265
266 /**
267 * Clean up previous migration that may have failed
268 */
269 $this->freshStart();
270
271 $siteDetails = getDirectorySize(TRANSFERITO_ABSPATH);
272 $zipEnabled = class_exists('ZipArchive');
273 $getWPInstallationSizes = get_transient('transferito_installation_size');
274
275 /**
276 * Check if the user has exceeded the max size
277 */
278 $this->checkSiteWithinFreeTier($siteDetails);
279
280 /**
281 * Log any failures created during the getDirectorySize check
282 */
283 if (isset($getWPInstallationSizes['errors']) && count($getWPInstallationSizes['errors']) > 0) {
284 $errorMessage = implode('|', $getWPInstallationSizes['errors']);
285 $this->api->failedMigration($errorMessage);
286 }
287
288 /**
289 * Default the exec enabled flag to false
290 */
291 $execEnabled = false;
292
293 /**
294 * Get the ByPass exec usage Flag from the settings
295 */
296 $settingsOption = get_option('transferito_settings_option');
297 $bypassExecUsage = isset($settingsOption['transferito_bypass_exec_archive_creation'])
298 ? $settingsOption['transferito_bypass_exec_archive_creation']
299 : false;
300
301 /**
302 * If the flag is not set
303 * Check to see if the OS is windows
304 * If it is not - Check to see if exec can be used
305 */
306 if (!$bypassExecUsage) {
307 /**
308 * Windows HOT Fix
309 * @todo return to the original check when FULL FIX has been implemented
310 */
311 $isWindows = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
312 $execEnabled = $isWindows
313 ? false
314 : function_exists('exec') && @exec('echo EXEC') == 'EXEC';
315 }
316
317
318 $metRequirements = !$zipEnabled && !$execEnabled ? false : true;
319 $useZip = !$execEnabled;
320
321 /**
322 * Save the requirements on load
323 */
324 set_transient('transferito_requirements', [
325 'metRequirements' => $metRequirements,
326 'useZip' => $useZip
327 ]);
328
329 /**
330 * Initially default the fallback to false
331 */
332 set_transient('transferito_request_fallback', false);
333
334 /**
335 * Return the template for all users
336 */
337 $response = [
338 'htmlTemplate' => loadTemplate('parts/migration/cpanel-check', [
339 'secondaryMessage' => 'To start your migration, please choose a migration method',
340 'metRequirements' => $metRequirements,
341 'hideQuickStart' => true
342 ])
343 ];
344
345 /**
346 * Push loadScreen event to telemetry
347 */
348 $this->telemetry->pushEvent('loadScreen', [
349 'screenName' => 'DestinationURL'
350 ]);
351
352 wp_send_json_success($response);
353 }
354
355 public function switchMode()
356 {
357 $transferMethod = $_POST['method'];
358 $domain = get_transient('transferito_migration_domain');
359 $cPanelAllowed = boolval(get_transient('transferito_cpanel_allowed'));
360
361 /**
362 * Has the cpanel domain
363 */
364 $hasCpanelDomain = get_transient('transferito_cpanel_domain');
365
366 /**
367 * Set / Remove the transient based on the transfer method
368 */
369 if ($transferMethod === 'cpanel' && !$hasCpanelDomain) {
370 /**
371 * Domain
372 */
373 $updatedDomain = rtrim(trim($domain), '/');
374
375 /**
376 * cPanel admin URL
377 */
378 $cpanelAdminURL = $updatedDomain . ':2083';
379
380 /**
381 * Result from the cPanel check
382 */
383 $response = $this->api->cPanelAvailabilityCheck($cpanelAdminURL);
384
385 /**
386 * Check that the string is in the response
387 */
388 $cPanelInHTMLSource = stripos($response['message'], 'cpanel') !== false;
389
390 /**
391 * Check if we should default to cPanel
392 */
393 $cPanelAllowed = $response['code'] === 200 && $cPanelInHTMLSource;
394
395 /**
396 * Correct cPanel URL
397 */
398 $cpanelFinalAdminURLSplit = explode(':2083', $response['url']);
399
400 if ($cPanelAllowed) {
401 set_transient('transferito_cpanel_domain', $cpanelFinalAdminURLSplit[0]);
402 }
403 }
404
405 /**
406 * Update transient - For the transfer method
407 */
408 $updatedTransferMethod = $transferMethod === 'cpanel' ? 'cpanel' : 'manual';
409 set_transient('transferito_transfer_method', $updatedTransferMethod);
410
411 /**
412 * Build the part dynamically
413 */
414 $templatePath = 'parts/migration/' . $transferMethod . '/main';
415
416 /**
417 * Load the correct template based on the site size
418 */
419 $htmlTemplate = loadTemplate($templatePath, [
420 'cpanelAllowed' => $cPanelAllowed,
421 'directories' => Config::getWPContentPaths(),
422 'cpanelDetail' => get_transient('transferito_cpanel_auth_details'),
423 'cpanelCompleted' => get_transient('transferito_cpanel_auth_details_completed'),
424 'detail' => get_transient('transferito_manual_server_detail')
425 ]);
426
427 /**
428 * Push loadScreen event to telemetry
429 */
430 $this->telemetry->pushEvent('loadScreen', [
431 'screenName' => $transferMethod === 'cpanel' ? 'cPanelAuthentication' : 'FTPAuthentication'
432 ]);
433
434 /**
435 * Return the object
436 */
437 wp_send_json_success([
438 'cPanelAllowed' => $cPanelAllowed,
439 'URL' => $domain,
440 'transferMethod' => $transferMethod,
441 'htmlTemplate' => $htmlTemplate,
442 ]);
443 }
444
445 public function screenRouting()
446 {
447 try {
448 $screenRoute = $_POST['route'];
449 $serverDetail = get_transient('transferito_manual_server_detail');
450 $url = explode('://', get_transient('transferito_migration_domain'));
451 $domain = count($url) === 2 ? $url[1] : $url[0];
452 $cPanelDomainList = get_transient('transferito_cpanel_domain_selection');
453
454 $mappedScreenRoutes = [
455 'destinationURL' => loadTemplate('parts/migration/cpanel-check', [
456 'url' => $domain,
457 'mainMessage' => '',
458 'secondaryMessage' => 'To start your migration, please choose a migration method',
459 'metRequirements' => get_transient('transferito_requirements')['metRequirements'],
460 'hideQuickStart' => true
461 ]),
462 'migrationMethodSelection' => loadTemplate('parts/migration/select-migration-method', [
463 'cpanelAllowed' => get_transient('transferito_cpanel_allowed'),
464 'transferMethod' => get_transient('transferito_transfer_method')
465 ]),
466 'cpanelAuthentication' => loadTemplate('parts/migration/cpanel/main', [
467 'cpanelDetail' => get_transient('transferito_cpanel_auth_details'),
468 'cpanelCompleted' => get_transient('transferito_cpanel_auth_details_completed')
469 ]),
470 'cpanelDomainSelection' => loadTemplate('parts/migration/cpanel/domain-selection', $cPanelDomainList ? $cPanelDomainList : []),
471 'ftpAuthentication' => loadTemplate('parts/migration/manual/main', [
472 'directories' => Config::getWPContentPaths(),
473 'detail' => $serverDetail
474 ]),
475 'directorySelector' => loadTemplate('parts/migration/manual/directory-selection', []),
476 'databaseAuthentication' => loadTemplate('parts/migration/manual/database-detail', [
477 'detail' => $serverDetail,
478 'completed' => get_transient('transferito_database_detail_completed')
479 ])
480 ];
481
482 /**
483 * If the route does not exist in the mapped routes
484 *
485 * @todo throw error
486 */
487 if (!isset($mappedScreenRoutes[$screenRoute])) {
488 wp_send_json_error([
489 'message' => 'routeDoesNotExist'
490 ], 400);
491 }
492
493 /**
494 * Return the object
495 */
496 wp_send_json_success([
497 'htmlTemplate' => $mappedScreenRoutes[$screenRoute],
498 'detail' => $serverDetail
499 ]);
500 } catch (\Exception $exception) {
501 wp_send_json_error([
502 'message' => $exception->getMessage()
503 ], 400);
504 }
505 }
506
507 public function sendRequestForm()
508 {
509 check_ajax_referer('hosting_guide_request_detail', 'securityKey');
510
511 $this->api->hostingGuideRequest([
512 'email' => $_POST['data']['emailAddress'],
513 'hostingProvider' => $_POST['data']['hostingProvider'],
514 'guideName' => $_POST['data']['guideName']
515 ]);
516
517 /**
518 * Return the object
519 */
520 wp_send_json_success([ 'completed' => true ]);
521 }
522
523 public function checkPremiumApiKeys()
524 {
525 check_ajax_referer('in_plugin_premium_upgrade', 'securityKey');
526
527 try {
528 /**
529 * Check the user's API keys
530 */
531 $hasValidAPIKeys = $this->areAPIKeysValid(
532 sanitize_text_field($_POST['data']['publicKey']),
533 sanitize_text_field($_POST['data']['secretKey'])
534 );
535
536 /**
537 * If the API Keys aren't valid
538 * Throw an error
539 */
540 if (!$hasValidAPIKeys) {
541 set_transient('transferito_user_status', 'FREE');
542 throw new \Exception('NOT_VALID');
543 }
544
545 /**
546 * Get Current Options
547 */
548 $options = get_option('transferito_settings_option');
549
550 /**
551 * Update the API Keys
552 */
553 $options['public_transferito_key'] = sanitize_text_field($_POST['data']['publicKey']);
554 $options['secret_transferito_key'] = sanitize_text_field($_POST['data']['secretKey']);
555
556 /**
557 * Update the options
558 */
559 update_option('transferito_settings_option', $options);
560
561 /**
562 * Set the USER status
563 */
564 set_transient('transferito_user_status', 'PREMIUM');
565
566 wp_send_json_success([ 'validated' => true ]);
567 } catch(\Exception $exception) {
568 wp_send_json_error([ 'validated' => true ], 403);
569 }
570 }
571
572 /**
573 * @remove all functionality for quickstart
574 */
575 public function hideQuickStart()
576 {
577 set_transient('transferito_hide_quick_start_guide', true);
578
579 /**
580 * Return the object
581 */
582 wp_send_json_success(['completed' => true ]);
583 }
584
585 public function loadDirectoryTemplate()
586 {
587 $serverDetail = get_transient('transferito_manual_server_detail');
588
589 /**
590 * Push loadScreen event to telemetry
591 */
592 $this->telemetry->pushEvent('loadScreen', [
593 'screenName' => 'directorySelector'
594 ]);
595
596 /**
597 * Return success object
598 * To update the nav and change the child template
599 */
600 wp_send_json_success([
601 'template' => loadTemplate('parts/migration/manual/directory-selection', []),
602 'path' => $serverDetail['path'],
603 'navigation' => [
604 'completed' => 'transferitoNav__manualFTPDetails',
605 'active' => 'transferitoNav__manualFTPDirectorySelect'
606 ],
607 ]);
608
609 }
610
611 public function cPanelCheck()
612 {
613 /**
614 * verify nonce with every template change call
615 */
616 check_ajax_referer('cpanel_check', 'securityKey');
617
618 $localMigration = filter_var($_POST['localMigration'], FILTER_VALIDATE_BOOL);
619
620 /**
621 * If migrating to use the DesktopApp
622 */
623 if ($localMigration) {
624
625 /**
626 * Domain
627 */
628 $domain = rtrim(trim($_POST['domain']), '/');
629
630 /**
631 * Default transfer method
632 */
633 $transferMethod = 'localSiteMigration';
634
635 set_transient('transferito_transfer_method', $transferMethod);
636 set_transient('transferito_migration_domain', $domain);
637
638 /**
639 *
640 */
641 wp_send_json_success([
642 'transferMethod' => $transferMethod,
643 'cpanelAllowed' => false,
644 'securityToken' => wp_create_nonce("prepare_migration_files")
645 ]);
646
647
648 // $this->prepareLocalDownload();
649
650 die();
651 }
652
653 /**
654 *
655 */
656 if (!$localMigration) {
657 $splitURL = explode('://', $_POST['domain']);
658
659 /**
660 * Check user hasn't used double protocol
661 */
662 if (count($splitURL) !== 2) {
663 wp_send_json_error([
664 'message' => 'Failed URL Check'
665 ], 400);
666 }
667
668 /**
669 * Domain
670 */
671 $domain = rtrim(trim($_POST['domain']), '/');
672
673 /**
674 * cPanel admin URL
675 */
676 $cpanelAdminURL = $domain . ':2083';
677
678 /**
679 * Result from the cPanel check
680 */
681 $response = $this->api->cPanelAvailabilityCheck($cpanelAdminURL);
682
683 /**
684 * Check that the string is in the response
685 */
686 $cPanelInHTMLSource = stripos($response['message'], 'cpanel') !== false;
687
688 /**
689 * Check if we should default to cPanel
690 */
691 $cPanelAllowed = $response['code'] === 200 && $cPanelInHTMLSource;
692
693 /**
694 * Default transfer method
695 */
696 $transferMethod = $cPanelAllowed ? 'cpanel' : 'manual';
697
698 /**
699 * Correct cPanel URL
700 */
701 $cpanelFinalAdminURLSplit = explode(':2083', $response['url']);
702
703 /**
704 * Save the domain
705 */
706 set_transient('transferito_migration_domain', $domain);
707 set_transient('transferito_migration_unchanged_domain', $domain);
708 set_transient('transferito_cpanel_allowed', $cPanelAllowed);
709 set_transient('transferito_transfer_method', $transferMethod);
710
711 /**
712 * Only save if cPanel is allowed
713 */
714 if ($cPanelAllowed) {
715 set_transient('transferito_cpanel_domain', $cpanelFinalAdminURLSplit[0]);
716 } else {
717 set_transient('transferito_cpanel_domain', $domain);
718 }
719
720 /**
721 * Load the correct template based on whether cpanel is allowed or not
722 */
723 $htmlTemplate = loadTemplate('parts/migration/select-migration-method', [
724 'cpanelAllowed' => $cPanelAllowed,
725 'transferMethod' => $transferMethod,
726 ]);
727
728 /**
729 * Push loadScreen event to telemetry
730 */
731 $this->telemetry->pushEvent('loadScreen', [
732 'screenName' => 'selectMigrationMethod'
733 ]);
734
735 wp_send_json_success([
736 't' => $cpanelFinalAdminURLSplit[0],
737 'cPanelAllowed' => $cPanelAllowed,
738 'URL' => $domain,
739 'transferMethod' => $transferMethod,
740 'htmlTemplate' => $htmlTemplate,
741 ]);
742 }
743 }
744
745 public function cpanelAuthentication()
746 {
747 try {
748 check_ajax_referer('cpanel_migration', 'securityKey');
749
750 /**
751 * Get the domain
752 */
753 $domain = get_transient('transferito_cpanel_domain');
754
755 /**
756 * Get the destination URL
757 */
758 $destinationURL = get_transient('transferito_migration_domain');
759
760 /**
761 * Split the destination URL into a domain via the protocol
762 */
763 $splitDestinationURL = explode('//', $destinationURL);
764
765 /**
766 * Get the destination Domain
767 */
768 $destinationDomain = count($splitDestinationURL) === 2 ? $splitDestinationURL[1] : $destinationURL;
769
770 /**
771 * Pull the auth details
772 */
773 $cPanelDetails = $_POST['auth'];
774 $cPanelDetails['cpanelPass'] = $cPanelDetails['cpanelPass'];
775 $cPanelDetails['cPanelUseApiToken'] = isset($cPanelDetails['cPanelUseApiToken']) ? false : true;
776
777 /**
778 * Updated the cPanel array
779 */
780 $updatedAuthArray = array_merge($cPanelDetails, [ 'cpanelHost' => $domain ]);
781
782 /**
783 * Make a request to the endpoint to get a list of the available domains
784 */
785 $authResult = $this->api->cPanelAuth($updatedAuthArray);
786
787 /**
788 * If there is an error authenticating
789 */
790 if ($authResult['code'] !== 200) {
791 throw new \Exception(stripslashes($authResult['message']));
792 }
793
794 /**
795 * Get the list of selectable domains
796 */
797 $availableDomains = $authResult['message'];
798
799 /**
800 * Save the cPanel details
801 */
802 set_transient('transferito_cpanel_auth_details', $cPanelDetails);
803
804 /**
805 * Update the completed flag
806 */
807 set_transient('transferito_cpanel_auth_details_completed', true);
808
809 /**
810 * Push loadScreen event to telemetry
811 */
812 $this->telemetry->pushEvent('loadScreen', [
813 'screenName' => 'cPanelDomainSelection'
814 ]);
815
816 /**
817 * Assign the data needed for the template to a variable to save
818 */
819 $domainSelectionOptions = [
820 'domain' => $destinationDomain,
821 'domains' => $availableDomains,
822 'username' => $cPanelDetails['cpanelUser'],
823 'password' => $cPanelDetails['cpanelPass'],
824 'apiToken' => $cPanelDetails['cPanelApiToken'],
825 'useApiToken' => $cPanelDetails['cPanelUseApiToken'],
826 'URL' => $domain,
827 ];
828
829 /**
830 * Save the domain selection data needed for the template
831 */
832 set_transient('transferito_cpanel_domain_selection', $domainSelectionOptions);
833
834 /**
835 * Return success object
836 * To update the nav and change the child template
837 */
838 wp_send_json_success([
839 'template' => loadTemplate('parts/migration/cpanel/domain-selection', $domainSelectionOptions)
840 ]);
841
842 } catch(\Exception $exception) {
843 wp_send_json_error([
844 'template' => loadTemplate('parts/migration/cpanel/main', [
845 'showErrorPopup' => true
846 ]),
847 ], 400);
848 }
849 }
850
851 public function serverDetailValidation()
852 {
853 try {
854 check_ajax_referer('manual_migration_server_detail', 'securityKey');
855
856 /**
857 * Pull the server details
858 */
859 $serverDetails = $_POST['serverDetails'];
860
861 /**
862 * Updated the server details array
863 */
864 $updatedServerDetailArray = array_merge($serverDetails, [ 'ftpPath' => '.' ]);
865
866 /**
867 * Set the server detail as a transient
868 */
869 set_transient('transferito_manual_server_detail', $updatedServerDetailArray);
870
871 /**
872 * Make a request to the endpoint to get a list of the available domains
873 */
874 $serverDetailResult = $this->api->ftpValidation($updatedServerDetailArray);
875
876 /**
877 * Fail when the FTP connection fails
878 */
879 if ($serverDetailResult['code'] !== 200) {
880 throw new \Exception('API_REQUEST_FAILURE');
881 }
882
883 /**
884 * Fail when the FTP connection fails
885 */
886 if (!$serverDetailResult['message']) {
887 throw new \Exception('FALSEY_RESPONSE');
888 }
889
890 /**
891 * Fail when the has connected property isn't present
892 */
893 if (!property_exists($serverDetailResult['message'], 'hasConnected')) {
894 throw new \Exception('PROPERTY_MISSING');
895 }
896
897 /**
898 * Fail when the FTP connection fails
899 */
900 if (!$serverDetailResult['message']->hasConnected) {
901 throw new \Exception('FTP_CONNECTION_FAILURE');
902 }
903
904 /**
905 * Push loadScreen event to telemetry
906 */
907 $this->telemetry->pushEvent('loadScreen', [
908 'screenName' => 'directorySelector'
909 ]);
910
911 /**
912 * Set the server detail as a transient
913 */
914 $updatedServerDetailArray['ftpPort'] = (string) $serverDetailResult['message']->ftpPort;
915 $updatedServerDetailArray['useSFTP'] = (string) $serverDetailResult['message']->useSFTP;
916 set_transient('transferito_manual_server_detail', $updatedServerDetailArray);
917
918 /**
919 * Return success object
920 * To update the nav and change the child template
921 */
922 wp_send_json_success([
923 'template' => loadTemplate('parts/migration/manual/directory-selection', []),
924 'useSFTP' => $updatedServerDetailArray['useSFTP']
925 ]);
926
927 } catch (\Exception $exception) {
928 wp_send_json_error([
929 'connected' => false,
930 ], 400);
931 }
932 }
933
934 public function directoryValidation()
935 {
936 try {
937 check_ajax_referer('manual_migration_directory_selection', 'securityKey');
938
939 /**
940 * Check that the ftpInfo element exists
941 */
942 $serverDetail = get_transient('transferito_manual_server_detail');
943
944 /**
945 * Get the saved domain to use as the domain to check
946 */
947 $domain = get_transient('transferito_migration_domain');
948
949 /**
950 * Create the updated server detail
951 */
952 $directoryCheckPayload = array_merge($serverDetail, [
953 'path' => $_POST['directory'],
954 'URL' => $domain
955 ]);
956
957 /**
958 * update the ftpPath from the payload
959 */
960 $directoryCheckPayload['ftpPath'] = $_POST['directory'];
961
962 /**
963 * Save the updated server detail
964 */
965 set_transient('transferito_manual_server_detail', $directoryCheckPayload);
966
967 /**
968 * Response from the directory check
969 */
970 $response = $this->api->directoryCheck($directoryCheckPayload);
971
972 /**
973 *
974 */
975 // if ($response['code'] !== 200) {
976 // throw new \Exception('FAILED_CORRECT_DIRECTORY_CHECK');
977 // }
978
979 /**
980 * Push loadScreen event to telemetry
981 */
982 // $this->telemetry->pushEvent('loadScreen', [
983 // 'screenName' => 'databaseAuthentication'
984 // ]);
985
986 /**
987 * Return success object
988 *
989 * @todo Update the message -> check to see if the return message has the property correctDirectory
990 */
991 wp_send_json_success($response['message']);
992
993 } catch (\Exception $exception) {
994 wp_send_json_error([
995 'error' => $exception->getMessage(),
996 'template' => loadTemplate('parts/migration/manual/directory-selection', []),
997 ], 400);
998 }
999 }
1000
1001 public function databaseValidation()
1002 {
1003 try {
1004 check_ajax_referer('manual_migration_database_detail', 'securityKey');
1005
1006 /**
1007 * Check that the ftpInfo element exists
1008 */
1009 $serverDetail = get_transient('transferito_manual_server_detail');
1010
1011 /**
1012 * Merge the array
1013 */
1014 $databaseTestPayload = array_merge($serverDetail, $_POST['databaseDetail']);
1015
1016 /**
1017 * Exclude database
1018 */
1019 $excludeDatabase = isset($_POST['databaseDetail']['exclude_database_transfer']) && $_POST['databaseDetail']['exclude_database_transfer'] === 'true';
1020
1021 /**
1022 * Assign the domain flag to the new payload
1023 */
1024 $databaseTestPayload['domain'] = $databaseTestPayload['URL'];
1025
1026 /**
1027 * Update the server detail transient
1028 */
1029 set_transient('transferito_manual_server_detail', $databaseTestPayload);
1030
1031 /**
1032 * Add check that db detail has been completed
1033 */
1034 set_transient('transferito_database_detail_completed', true);
1035
1036 /**
1037 * Only do the DB check if the database isn't excluded
1038 */
1039 if (!$excludeDatabase) {
1040 /**
1041 * Make a request to the database validation endpoint
1042 */
1043 $response = $this->api->databaseValidation($databaseTestPayload);
1044
1045 /**
1046 * Check to see whether the DB details have failed
1047 */
1048 if ($response['code'] !== 200) {
1049 throw new \Exception('FAILED_DATABASE_CHECK');
1050 }
1051 }
1052
1053 /**
1054 * Final additions to the payload
1055 */
1056 $migrationDetail = array_merge($databaseTestPayload, [
1057 'transferMethod' => 'ftp',
1058 'transferType' => 'manual'
1059 ]);
1060
1061 /**
1062 * Pass the full details and nonce to validate the call
1063 */
1064 wp_send_json_success([
1065 'migrationDetail' => array_map('stripslashes', $migrationDetail),
1066 'securityKey' => wp_create_nonce("prepare_migration_files")
1067 ]);
1068
1069 } catch (\Exception $exception) {
1070 /**
1071 * Get the server detail
1072 */
1073 $serverDetail = get_transient('transferito_manual_server_detail');
1074
1075 /**
1076 *
1077 */
1078 wp_send_json_error([
1079 'template' => loadTemplate('parts/migration/manual/database-detail', [
1080 'detail' => $serverDetail,
1081 'completed' => get_transient('transferito_database_detail_completed')
1082 ]),
1083 ], 400);
1084 }
1085 }
1086
1087 public function chooseMigrationMethod()
1088 {
1089 /**
1090 * verify nonce with every template change call
1091 */
1092 check_ajax_referer('migration_choice', 'actionKey');
1093
1094 $freeTierUser = (!$this->options['public_transferito_key'] || !$this->options['secret_transferito_key']);
1095 $mainMessage = stripslashes('We are creating a backup of your current WordPress installation');
1096 $secondaryMessage = stripslashes('Please wait.. This may take a few minutes, do not close this window or refresh the page');
1097
1098 $htmlTemplate = ($_POST['data']['migrationType'] === 'useCpanel')
1099 ? loadTemplate('parts/migration/cpanel-validation', [
1100 'mainMessage' => $mainMessage,
1101 'secondaryMessage' => $secondaryMessage
1102 ])
1103 : loadTemplate('parts/migration/transfer-detail-entry', [
1104 'mainMessage' => $mainMessage,
1105 'secondaryMessage' => $secondaryMessage,
1106 'freeMigration' => $freeTierUser,
1107 'directories' => Config::getWPContentPaths()
1108 ]);
1109
1110 $siteCheckResponse = [ 'htmlTemplate' => $htmlTemplate ];
1111
1112 wp_send_json_success($siteCheckResponse);
1113 }
1114
1115 public function statusCheck()
1116 {
1117 $response = $this->api->getStatus(sanitize_text_field($_POST['token']));
1118 $responseMessage = $response['message'];
1119
1120 /**
1121 * Check the migration
1122 */
1123 if ($response["code"] === 200) {
1124 $startCleanUp = get_transient('transferito_cleanup_after_completion');
1125 $isCompleted = (isset($responseMessage->status))
1126 ? $responseMessage->status === 'completed' || $responseMessage->status === 'completed.with.errors'
1127 : false;
1128
1129 if ($responseMessage->status === 'completed' && $startCleanUp) {
1130 delete_transient('transferito_cleanup_after_completion');
1131 }
1132
1133 wp_send_json_success([
1134 'metadata' => $responseMessage->metaData,
1135 'statuses' => $responseMessage->all,
1136 'status' => $responseMessage->status,
1137 'completed' => $isCompleted
1138 ]);
1139
1140 } else {
1141 wp_send_json_error($responseMessage->error, $response['code']);
1142 }
1143 }
1144
1145 public function prepareDownload()
1146 {
1147 try {
1148 check_ajax_referer('prepare_migration_files', 'security');
1149
1150 $settings = get_option('transferito_settings_option');
1151
1152 /**
1153 * Site size info
1154 */
1155 $siteDetails = getDirectorySize(TRANSFERITO_ABSPATH);
1156 $siteSizeInfo = get_transient('transferito_installation_size');
1157 $siteSize = $siteSizeInfo ? $siteSizeInfo : [];
1158
1159 /**
1160 * Check the user's API keys
1161 */
1162 $hasValidAPIKeys = $this->areAPIKeysValid(
1163 $settings['public_transferito_key'],
1164 $settings['secret_transferito_key']
1165 );
1166
1167 /**
1168 * Get the Transfer Method
1169 */
1170 $transferMethod = $_POST['migrationDetails']['transferMethod'];
1171
1172 /**
1173 * Fire the required upgrade flow
1174 */
1175 if (!$hasValidAPIKeys && $siteDetails['maxSizeExceeded']) {
1176 wp_send_json_success(array_merge([
1177 'message' => '<strong>PLEASE DO NOT</strong> navigate away or reload this page while your migration is in process. Doing so will stop your migration.',
1178 'force' => true,
1179 'useZipFallback' => false,
1180 'created' => true,
1181 'excludeDatabase' => false,
1182 'upgradeRequired' => true,
1183 'htmlTemplate' => loadTemplate('parts/migration/progress/main',
1184 array_merge(
1185 [
1186 'backupPrepare' => true,
1187 'backupInstallation' => true,
1188 'uploadBackup' => false,
1189 'downloadBackup' => true,
1190 'extractBackup' => true,
1191 'installDatabase' => true,
1192 'finalizeInstallation' => true,
1193 'completed' => true
1194 ],
1195 [
1196 'method' => ''
1197 ]
1198 )
1199 )
1200 ], $siteSize));
1201
1202 die();
1203 }
1204
1205 /**
1206 * Set as a FREE User
1207 */
1208 if (!$hasValidAPIKeys) {
1209 $this->api->setFreeUser();
1210 }
1211
1212 /**
1213 * If a local migration forward to the migration method
1214 */
1215 if ($transferMethod === 'localSiteMigration') {
1216 $this->prepareLocalDownload($hasValidAPIKeys);
1217 die();
1218 }
1219
1220 /**
1221 * @DoNotRemove
1222 * Important as it creates the access file to check whether the migration will be an upload
1223 */
1224 Config::getCorrectPath();
1225
1226 $forceUpload = isset($settings['transferito_force_upload']) ? $settings['transferito_force_upload'] : false;
1227 $migrationDetails = $_POST['migrationDetails'];
1228 $excludeDatabase = isset($migrationDetails['exclude_database_transfer'])
1229 ? $migrationDetails['exclude_database_transfer']
1230 : null;
1231 $folderPaths = isset($migrationDetails['folder_path'])
1232 ? array_map('sanitize_text_field', wp_unslash($migrationDetails['folder_path']))
1233 : null;
1234 $destinationURL = isset($migrationDetails['domain'])
1235 ? sanitize_text_field($migrationDetails['domain'])
1236 : null;
1237 $selectedFolderEnabled = ($folderPaths !== null);
1238 $backupDirectory = bin2hex(openssl_random_pseudo_bytes(8));
1239
1240 /**
1241 * Get the current domain & add it to the migrationDetails
1242 */
1243 $migrationDetails['currentDomain'] = site_url();
1244
1245 /**
1246 * Add the check to see if the options are selected
1247 */
1248 $disableWPObjectCache = isset($settings['transferito_disable_wordpress_cache'])
1249 ? $settings['transferito_disable_wordpress_cache']
1250 : false;
1251 $ignoreMalcareWAF = isset($settings['transferito_malcare_waf_plugin_fix'])
1252 ? $settings['transferito_malcare_waf_plugin_fix']
1253 : false;
1254
1255 /**
1256 * Find the functions file - To Disable the WP Object Cache
1257 */
1258 if ($disableWPObjectCache) {
1259 $this->disableWPObjectCache();
1260 }
1261
1262 /**
1263 * Find the user.ini file - To Disable MalCare WAF
1264 */
1265 if ($ignoreMalcareWAF) {
1266 $this->disableAutoPrependOption();
1267 }
1268
1269
1270 /**
1271 * Set the destination URL transient
1272 */
1273 set_transient('transferito_migration_domain', $destinationURL);
1274
1275 /**
1276 * Check if we can download directly from the server, unless the force upload flag is checked
1277 */
1278 if ($forceUpload) {
1279 $siteAccessed = false;
1280 } else {
1281 $sampleArchiveFilename = bin2hex(random_bytes(16)) . '.zip';
1282
1283 /**
1284 * Copy file
1285 */
1286 if (copy(TRANSFERITO_PATH . 'sample.zip', TRANSFERITO_ABSPATH . $sampleArchiveFilename)) {
1287 /**
1288 * Request to check the direct download
1289 */
1290 $directDownload = $this->api->directDownloadCheck([
1291 "transferMethod" => $migrationDetails['transferMethod'],
1292 'ftpHost' => isset($migrationDetails['ftpHost']) ? $migrationDetails['ftpHost'] : null,
1293 'ftpUser' => isset($migrationDetails['ftpUser']) ? $migrationDetails['ftpUser'] : null,
1294 'ftpPass' => isset($migrationDetails['ftpPass']) ? $migrationDetails['ftpPass'] : null,
1295 'ftpPort' => isset($migrationDetails['ftpPort']) ? $migrationDetails['ftpPort'] : null,
1296 'path' => isset($migrationDetails['ftpPath']) ? $migrationDetails['ftpPath'] : null,
1297 'useSFTP' => isset($migrationDetails['useSFTP']) ? $migrationDetails['useSFTP'] : null,
1298 "cpanelHost" => isset($migrationDetails['cpanelHost']) ? $migrationDetails['cpanelHost'] : null,
1299 "cpanelUser" => isset($migrationDetails['cpanelUser']) ? $migrationDetails['cpanelUser'] : null,
1300 "cpanelPass" => isset($migrationDetails['cpanelPass']) ? $migrationDetails['cpanelPass'] : null,
1301 "domain" => $destinationURL,
1302 "cpanelApiToken" => isset($migrationDetails['cpanelApiToken']) ? $migrationDetails['cpanelApiToken'] : null,
1303 "useApiToken" => isset($migrationDetails['useApiToken']) ? $migrationDetails['useApiToken'] : null,
1304 'currentURL' => site_url(),
1305 'destinationURL' => isset($migrationDetails['URL']) ? $migrationDetails['URL'] : null,
1306 'filename' => $sampleArchiveFilename,
1307 ]);
1308
1309 /**
1310 * Assign the result to
1311 */
1312 $siteAccessed = $directDownload['message']->canDownload;
1313
1314 /**
1315 * Remove the sample file
1316 */
1317 unlink(TRANSFERITO_ABSPATH . $sampleArchiveFilename);
1318 } else {
1319 $siteAccessed = false;
1320 }
1321 }
1322
1323 /**
1324 * Add the local flag to the ftp details
1325 */
1326 $migrationDetails['isLocal'] = $siteAccessed;
1327
1328 /**
1329 * If the folder path is set and the transfer type is manual
1330 * Then validate the
1331 */
1332 $additionalData = [];
1333 if (isset($migrationDetails['folder_path']) && $migrationDetails['transferType'] === 'manual') {
1334 $additionalData['folder_path'] = array_map('sanitize_text_field', wp_unslash($migrationDetails['folder_path']));
1335 }
1336
1337 /**
1338 * Clean text fields before create migration request
1339 */
1340 $migrationPayload = array_merge($migrationDetails, $additionalData);
1341 $migrationPayload['isLocal'] = $siteAccessed;
1342 $migrationPayload['currentPath'] = ABSPATH;
1343
1344 /**
1345 * Create a migration and return a token
1346 */
1347 $createdMigration = $this->api->createMigration($migrationPayload);
1348
1349 /**
1350 * Fail gracefully if there is an issue creating the migration
1351 */
1352 if ($createdMigration['code'] !== 200) {
1353 $message = (property_exists($createdMigration['message'], 'result'))
1354 ? $createdMigration['message']->result
1355 : 'We are unable to create your migration. If this issue persists, please contact support.';
1356 throw new \Exception(stripslashes($message));
1357 }
1358
1359 /**
1360 * Set transients to use with the failure endpoint
1361 */
1362 set_transient('transferito_migration_token', $createdMigration['message']->token);
1363 set_transient('transferito_migration_timestamp', $createdMigration['message']->timestamp);
1364
1365 /**
1366 * Get the migration token
1367 */
1368 $migrationToken = $createdMigration['message']->token;
1369
1370 /**
1371 * Final Domain
1372 */
1373 $finalDomain = $createdMigration['message']->domain;
1374
1375 /**
1376 * If we can contact the site
1377 * Then check the server requirements
1378 */
1379 if ($siteAccessed) {
1380 /**
1381 * Create the test file & token
1382 */
1383 $testFile = Config::createTestFile();
1384
1385 /**
1386 * Check the destination server info
1387 */
1388 $serverRequirements = $this->api->checkDestinationServerRequirements([
1389 'token' => $migrationToken,
1390 'timestamp' => $createdMigration['message']->timestamp,
1391 'fileURL' => $testFile['url'],
1392 'fileHash' => $testFile['hash']
1393 ]);
1394
1395 /**
1396 * Fallback
1397 * If the server req check fails
1398 */
1399 if ($serverRequirements['code'] !== 200) {
1400 $uploadToS3 = true;
1401 } else {
1402 /**
1403 * Check the site access again
1404 * If it is a local environment - or if the module allowed is wget - Then default to S3
1405 */
1406 $uploadToS3 = !$serverRequirements['message']->pullDirect;
1407 }
1408 }
1409
1410 /**
1411 * If we can not reach the site
1412 * Upload directly to S3 bucket
1413 */
1414 if (!$siteAccessed) {
1415 $uploadToS3 = true;
1416 }
1417
1418 /**
1419 * Set transient for backup status
1420 */
1421 set_transient('transferito_backup_status', [
1422 'databaseBackupComplete' => $excludeDatabase ? true : false,
1423 'databaseExportComplete' => $excludeDatabase ? true : false,
1424 'codebaseBackupComplete' => false,
1425 'excludedDatabase' => $excludeDatabase
1426 ]);
1427
1428 /**
1429 * Set transient with transfer detail
1430 */
1431 set_transient('transferito_transfer_detail', [
1432 'isLocalEnv' => $uploadToS3,
1433 'selectedFolders' => $selectedFolderEnabled,
1434 'folders' => $folderPaths,
1435 'directory' => $backupDirectory,
1436 'token' => $migrationToken,
1437 'timestamp' => $createdMigration['message']->timestamp,
1438 'fromUrl' => site_url(),
1439 'newUrl' => $finalDomain
1440 ]);
1441
1442 /**
1443 * Set the transient for the destination site URL
1444 */
1445 set_transient('transferito_final_destination_url', $finalDomain);
1446
1447 /**
1448 * Available steps to pass to the template
1449 */
1450 $progressSteps = [
1451 'backupPrepare' => true,
1452 'backupInstallation' => true,
1453 'uploadBackup' => $uploadToS3,
1454 'downloadBackup' => true,
1455 'extractBackup' => true,
1456 'installDatabase' => !$excludeDatabase,
1457 'finalizeInstallation' => true,
1458 'completed' => true
1459 ];
1460
1461 /**
1462 * Get the requirement transient
1463 */
1464 $transferitoRequirements = get_transient('transferito_requirements');
1465
1466 /**
1467 * Push Migration detail event to telemetry
1468 */
1469 $this->telemetry->pushEvent('migrationDetails', [
1470 'uploadBackup' => $uploadToS3,
1471 'localMigration' => $uploadToS3,
1472 'databaseExcluded' => $excludeDatabase,
1473 'selectedFolders' => $selectedFolderEnabled,
1474 'migrationMethod' => $migrationDetails['transferMethod'],
1475 'siteSize' => isset($siteSize['totalSize']) ? $siteSize['totalSize'] : 0,
1476 'cPanelAPIToken' => isset($migrationDetails['cpanelApiToken']) ? $migrationDetails['cpanelApiToken'] : false
1477 ]);
1478
1479 /**
1480 * Push loadScreen event to telemetry
1481 */
1482 $this->telemetry->pushEvent('loadScreen', [
1483 'screenName' => 'migrationInProgress'
1484 ]);
1485
1486 wp_send_json_success(array_merge([
1487 'message' => '<strong>PLEASE DO NOT</strong> navigate away or reload this page while your migration is in process. Doing so will stop your migration.',
1488 'force' => $forceUpload,
1489 'useZipFallback' => $transferitoRequirements['useZip'],
1490 'created' => true,
1491 'excludeDatabase' => $excludeDatabase,
1492 'upgradeRequired' => false,
1493 'htmlTemplate' => loadTemplate('parts/migration/progress/main',
1494 array_merge($progressSteps, [ 'method' => $migrationDetails['transferMethod']] )
1495 )
1496 ], $siteSize));
1497
1498 } catch (\Exception $exception) {
1499 /**
1500 * Push loadScreen event to telemetry
1501 */
1502 $this->telemetry->pushEvent('failedMigration', [
1503 'migrationStatus' => 'prepareDownload',
1504 'errorMessage' => $exception->getMessage()
1505 ]);
1506 $errorMessage = 'prepareDownload: ' . $exception->getMessage();
1507 $this->api->failedMigration($errorMessage);
1508 delete_transient('transferito_transfer_detail');
1509 wp_send_json_error([
1510 'message' => $exception->getMessage(),
1511 'error' => $exception->getTraceAsString(),
1512 'line' => $exception->getLine()
1513 ], 400);
1514 }
1515 }
1516
1517 private function prepareLocalDownload($premiumUser)
1518 {
1519 try {
1520
1521 /**
1522 * Fire the required upgrade flow
1523 */
1524 if (!$premiumUser) {
1525 wp_send_json_success([
1526 'message' => '<strong>PLEASE DO NOT</strong> navigate away or reload this page while your migration is in process. Doing so will stop your migration.',
1527 'force' => true,
1528 'useZipFallback' => false,
1529 'created' => true,
1530 'excludeDatabase' => false,
1531 'upgradeRequired' => true,
1532 'htmlTemplate' => loadTemplate('parts/migration/progress/main',
1533 array_merge(
1534 [
1535 'backupPrepare' => true,
1536 'backupInstallation' => true,
1537 'uploadBackup' => false,
1538 'downloadBackup' => true,
1539 'extractBackup' => true,
1540 'installDatabase' => true,
1541 'finalizeInstallation' => true,
1542 'completed' => true
1543 ],
1544 [
1545 'method' => ''
1546 ]
1547 )
1548 )
1549 ]);
1550
1551 die();
1552 }
1553
1554
1555 /**
1556 * @DoNotRemove
1557 * Important as it creates the access file to check whether the migration will be an upload
1558 */
1559 Config::getCorrectPath();
1560
1561 $transferMethod = 'localSiteMigration';
1562 $settings = get_option('transferito_settings_option');
1563 $destinationURL = get_transient('transferito_migration_domain');
1564 $backupDirectory = bin2hex(openssl_random_pseudo_bytes(8));
1565
1566 /**
1567 * Add the check to see if the options are selected
1568 */
1569 $disableWPObjectCache = isset($settings['transferito_disable_wordpress_cache'])
1570 ? $settings['transferito_disable_wordpress_cache']
1571 : false;
1572 $ignoreMalcareWAF = isset($settings['transferito_malcare_waf_plugin_fix'])
1573 ? $settings['transferito_malcare_waf_plugin_fix']
1574 : false;
1575
1576 /**
1577 * Find the functions file - To Disable the WP Object Cache
1578 */
1579 if ($disableWPObjectCache) {
1580 $this->disableWPObjectCache();
1581 }
1582
1583 /**
1584 * Find the user.ini file - To Disable MalCare WAF
1585 */
1586 if ($ignoreMalcareWAF) {
1587 $this->disableAutoPrependOption();
1588 }
1589
1590 /**
1591 * Set the destination URL transient
1592 */
1593 set_transient('transferito_migration_domain', $destinationURL);
1594
1595 /**
1596 * Create a migration and return a token
1597 */
1598 $createdMigration = $this->api->createMigration([
1599 'currentDomain' => site_url(),
1600 'transferMethod' => $transferMethod,
1601 'domain' => $destinationURL,
1602 'isLocal' => true,
1603 'currentPath' => ABSPATH
1604 ]);
1605
1606 /**
1607 * Fail gracefully if there is an issue creating the migration
1608 */
1609 if ($createdMigration['code'] !== 200) {
1610 $message = (property_exists($createdMigration['message'], 'result'))
1611 ? $createdMigration['message']->result
1612 : 'We are unable to create your migration. If this issue persists, please contact support.';
1613 throw new \Exception(stripslashes($message));
1614 }
1615
1616 /**
1617 * Set transients to use with the failure endpoint
1618 */
1619 set_transient('transferito_migration_token', $createdMigration['message']->token);
1620 set_transient('transferito_migration_timestamp', $createdMigration['message']->timestamp);
1621
1622 /**
1623 * Get the migration token
1624 */
1625 $migrationToken = $createdMigration['message']->token;
1626
1627 /**
1628 * Final Domain
1629 */
1630 $finalDomain = $createdMigration['message']->domain;
1631
1632 /**
1633 * Set transient for backup status
1634 */
1635 set_transient('transferito_backup_status', [
1636 'databaseBackupComplete' => false,
1637 'databaseExportComplete' => false,
1638 'codebaseBackupComplete' => false,
1639 'excludedDatabase' => false
1640 ]);
1641
1642 /**
1643 * Set transient with transfer detail
1644 */
1645 set_transient('transferito_transfer_detail', [
1646 'isLocalEnv' => true, // Defaulted to true as will always upload to S3 in this instance
1647 'selectedFolders' => false,
1648 'folders' => null, // No folders have been selected set directly to null
1649 'directory' => $backupDirectory,
1650 'token' => $migrationToken,
1651 'timestamp' => $createdMigration['message']->timestamp,
1652 'fromUrl' => site_url(),
1653 'newUrl' => $finalDomain
1654 ]);
1655
1656 /**
1657 * Set the transient for the destination site URL
1658 */
1659 set_transient('transferito_final_destination_url', $finalDomain);
1660
1661 /**
1662 * Available steps to pass to the template
1663 */
1664 $progressSteps = [
1665 'backupPrepare' => true,
1666 'backupInstallation' => true,
1667 'uploadBackup' => true,
1668 'downloadBackup' => true,
1669 'extractBackup' => true,
1670 'installDatabase' => true,
1671 'finalizeInstallation' => true,
1672 'completed' => true
1673 ];
1674
1675 /**
1676 * Get the requirement transient
1677 */
1678 $transferitoRequirements = get_transient('transferito_requirements');
1679
1680 /**
1681 * Site size info
1682 */
1683 $siteSizeInfo = get_transient('transferito_installation_size');
1684 $siteSize = $siteSizeInfo ? $siteSizeInfo : [];
1685
1686 /**
1687 * Push Migration detail event to telemetry
1688 */
1689 $this->telemetry->pushEvent('migrationDetails', [
1690 'uploadBackup' => true,
1691 'localMigration' => true,
1692 'databaseExcluded' => false,
1693 'selectedFolders' => false,
1694 'migrationMethod' => $transferMethod,
1695 'siteSize' => isset($siteSize['totalSize']) ? $siteSize['totalSize'] : 0,
1696 'cPanelAPIToken' => false
1697 ]);
1698
1699 /**
1700 * Push loadScreen event to telemetry
1701 */
1702 $this->telemetry->pushEvent('loadScreen', [
1703 'screenName' => 'migrationInProgress'
1704 ]);
1705
1706 wp_send_json_success(array_merge([
1707 'message' => '<strong>PLEASE DO NOT</strong> navigate away or reload this page while your migration is in process. Doing so will stop your migration.',
1708 'force' => true,
1709 'useZipFallback' => $transferitoRequirements['useZip'],
1710 'created' => true,
1711 'excludeDatabase' => false,
1712 'htmlTemplate' => loadTemplate('parts/migration/progress/main',
1713 array_merge(
1714 $progressSteps,
1715 [
1716 'method' => 'localSiteMigration'
1717 ]
1718 )
1719 )
1720 ], $siteSize));
1721
1722
1723 } catch (\Exception $exception) {
1724
1725 /**
1726 * @todo Implement a failure screen - If the migration creation fails
1727 */
1728
1729
1730 /**
1731 * Push loadScreen event to telemetry
1732 */
1733 $this->telemetry->pushEvent('failedMigration', [
1734 'migrationStatus' => 'prepareDownload',
1735 'errorMessage' => $exception->getMessage()
1736 ]);
1737 $errorMessage = 'prepareLocalDownload: ' . $exception->getMessage();
1738 $this->api->failedMigration($errorMessage);
1739 delete_transient('transferito_transfer_detail');
1740 wp_send_json_error($exception->getMessage(), 400);
1741 }
1742
1743 }
1744
1745 public function prepareCodebase()
1746 {
1747 try {
1748 check_ajax_referer('prepare_migration_files', 'security');
1749
1750 $transferDetail = get_transient('transferito_transfer_detail');
1751 $fileListCreated = $this->codeBase->createFileList($transferDetail['selectedFolders'], $transferDetail['folders']);
1752 $zipPaths = $this->codeBase->createArchivePath();
1753
1754 /**
1755 * Throw the error if the zip paths are not an array
1756 */
1757 if (is_string($zipPaths)) {
1758 throw new \Exception($zipPaths);
1759 }
1760
1761 /**
1762 * Set transient for zip creation paths
1763 */
1764 set_transient('transferito_codebase_archive', $zipPaths);
1765
1766 /**
1767 * Get the site size
1768 */
1769 $siteSizeInfo = get_transient('transferito_installation_size');
1770
1771 wp_send_json_success(array_merge($fileListCreated, $siteSizeInfo));
1772
1773 } catch(\Exception $exception) {
1774 /**
1775 * Push loadScreen event to telemetry
1776 */
1777 $this->telemetry->pushEvent('failedMigration', [
1778 'migrationStatus' => 'prepareCodebase',
1779 'errorMessage' => $exception->getMessage()
1780 ]);
1781 $errorMessage = 'prepareCodebase: ' . $exception->getMessage();
1782 $this->api->failedMigration($errorMessage);
1783 wp_send_json_error($exception->getMessage(), 400);
1784 }
1785 }
1786
1787 public function addFilesToCodebase()
1788 {
1789 try {
1790 check_ajax_referer('prepare_migration_files', 'security');
1791
1792 /**
1793 * Check to see if the client passed the add db flag flag is passed in to
1794 */
1795 $dbExportFileListPath = isset($_POST['addDatabaseExports']) ? DIRECTORY_SEPARATOR . 'db_import' : '';
1796 $zipDetail = get_transient('transferito_codebase_archive');
1797 $jsonFileName = TRANSFERITO_UPLOAD_PATH . $dbExportFileListPath . DIRECTORY_SEPARATOR . 'json' . DIRECTORY_SEPARATOR . 'file_list_' . $_POST['currentFileIndex'] . '.json';
1798 $jsonFile = file_get_contents($jsonFileName);
1799
1800 if (!file_exists($jsonFileName)) {
1801 throw new \Exception('Something has gone wrong. We can not find the requested back up file list.');
1802 }
1803
1804 if (!$jsonFile) {
1805 throw new \Exception('Something has gone wrong. We can not read requested back up file list.');
1806 }
1807
1808 $files = json_decode($jsonFile);
1809 $addedToArchive = $this->codeBase->addFileToArchive($zipDetail['path'], $files);
1810
1811 /**
1812 * If the response isn't truthy throw
1813 */
1814 if ($addedToArchive !== true) {
1815 throw new \Exception($addedToArchive);
1816 }
1817
1818 wp_send_json_success($zipDetail);
1819 } catch(\Exception $exception) {
1820 wp_send_json_error($exception->getMessage(), 400);
1821 }
1822 }
1823
1824 public function codebaseArchiveComplete()
1825 {
1826 try {
1827 check_ajax_referer('prepare_migration_files', 'security');
1828
1829 /**
1830 * Get the related transients
1831 */
1832 $backupStatus = get_transient('transferito_backup_status');
1833 $transferDetail = get_transient('transferito_transfer_detail');
1834 $zipDetail = get_transient('transferito_codebase_archive');
1835
1836 /**
1837 * Update the backup array
1838 * Notification of the codebase archive completed
1839 */
1840 $backupStatus['codebaseBackupComplete'] = true;
1841
1842 /**
1843 * Update the code path with the archive path or url
1844 */
1845 $uploadS3 = $transferDetail['isLocalEnv'];
1846 $transferDetail['archive'] = $uploadS3 ? $zipDetail['path'] : $zipDetail['url'];
1847
1848 /**
1849 * Update the transients with the updated values
1850 */
1851 set_transient('transferito_backup_status', $backupStatus);
1852 set_transient('transferito_transfer_detail', $transferDetail);
1853
1854 wp_send_json_success([
1855 'codebaseArchived' => true,
1856 'excludeDatabase' => $backupStatus['excludedDatabase']
1857 ]);
1858
1859 } catch (\Exception $exception) {
1860 wp_send_json_error($exception->getMessage(), 400);
1861 }
1862 }
1863
1864 public function prepareDatabase()
1865 {
1866 try {
1867 check_ajax_referer('prepare_migration_files', 'security');
1868
1869 /**
1870 * Prepare a table map that allows the chunked db database export
1871 */
1872 $tableMap = $this->dataBase->prepareTableMap();
1873
1874 /**
1875 * If the table map can not be created
1876 * Throw the error
1877 */
1878 if (!$tableMap) {
1879 throw new \Exception('We were in the process of preparing to back up your database but this has failed.');
1880 }
1881
1882 /**
1883 * Set the table map as a transient
1884 */
1885 set_transient('transferito_database_table_map', $tableMap);
1886
1887 /**
1888 * Return an array
1889 * Notifying the client of the table creation
1890 */
1891 wp_send_json_success([ 'tableMapCreated' => true ]);
1892
1893 } catch(\Exception $exception) {
1894 /**
1895 * Push loadScreen event to telemetry
1896 */
1897 $this->telemetry->pushEvent('failedMigration', [
1898 'migrationStatus' => 'prepareDatabase',
1899 'errorMessage' => $exception->getMessage()
1900 ]);
1901 $errorMessage = 'prepareDatabase: ' . $exception->getMessage();
1902 $this->api->failedMigration($errorMessage);
1903 wp_send_json_error($exception->getMessage(), 400);
1904 }
1905 }
1906
1907 public function chunkedDBExport()
1908 {
1909 try {
1910 check_ajax_referer('prepare_migration_files', 'security');
1911
1912 /**
1913 * Validate the first run flag and convert it to a boolean
1914 */
1915 $firstRun = filter_var($_POST['firstRun'], FILTER_VALIDATE_BOOLEAN);
1916
1917 /**
1918 * Pull the export progress data
1919 */
1920 $getDBProgress = get_transient('transferito_db_export_progress');
1921 $exportProgress = $getDBProgress ? $getDBProgress : [];
1922
1923 /**
1924 * On the first run - No arguments needed
1925 */
1926 if ($firstRun) {
1927 $exportResult = $this->dataBase->chunkedDBExport();
1928 }
1929
1930 /**
1931 * If it isn't the first run
1932 * Pass in the export progress
1933 */
1934 if (!$firstRun) {
1935 $exportResult = $this->dataBase->chunkedDBExport(
1936 $exportProgress['fileIndex'],
1937 $exportProgress['currentRowIndex'],
1938 $exportProgress['tableIndex']
1939 );
1940 }
1941
1942 /**
1943 * If the export fails - throw
1944 */
1945 if (!$exportResult) {
1946 throw new \Exception('We are unable to backup a part of your database.');
1947 }
1948
1949 /**
1950 * Return an array
1951 * Notifying the client of the status of the export
1952 */
1953 $mergedArray = array_merge($exportResult, $exportProgress, [ 'firstRun' => $firstRun ]);
1954 wp_send_json_success($mergedArray);
1955
1956 } catch(\Exception $exception) {
1957 wp_send_json_error($exception->getMessage(), 400);
1958 }
1959 }
1960
1961 public function databaseExportComplete()
1962 {
1963 try {
1964 check_ajax_referer('prepare_migration_files', 'security');
1965
1966 /**
1967 * Get the related transients
1968 */
1969 $backupStatus = get_transient('transferito_backup_status');
1970
1971 /**
1972 * Update the backup array
1973 * Notification of the database export completion
1974 */
1975 $backupStatus['databaseExportComplete'] = true;
1976
1977 /**
1978 * Get the requirement transient
1979 */
1980 $transferitoRequirements = get_transient('transferito_requirements');
1981
1982 /**
1983 * Update the transients with the updated values
1984 */
1985 set_transient('transferito_backup_status', $backupStatus);
1986
1987 wp_send_json_success([
1988 'databaseExported' => true ,
1989 'useZipFallback' => $transferitoRequirements['useZip'],
1990 ]);
1991
1992 } catch (\Exception $exception) {
1993 wp_send_json_error($exception->getMessage(), 400);
1994 }
1995 }
1996
1997 public function databaseRelocation()
1998 {
1999 try {
2000 check_ajax_referer('prepare_migration_files', 'security');
2001
2002 $this->dataBase->moveDatabaseFiles();
2003
2004 wp_send_json_success([ 'moved' => true ]);
2005
2006 } catch (\Exception $exception) {
2007 wp_send_json_error(stripslashes('We could not move your database files'), 400);
2008 }
2009 }
2010
2011 public function databaseRelocationCheck()
2012 {
2013 try {
2014 check_ajax_referer('prepare_migration_files', 'security');
2015
2016 /**
2017 * Pull the pid
2018 */
2019 $databaseMovePID = get_transient('transferito_database_relocation_pid');
2020
2021 /**
2022 * Get the site size
2023 */
2024 $siteSizeInfo = get_transient('transferito_installation_size');
2025
2026 wp_send_json_success([
2027 'completed' => checkJobHasCompleted($databaseMovePID),
2028 'siteInfo' => $siteSizeInfo
2029 ]);
2030
2031 } catch (\Exception $exception) {
2032 wp_send_json_error(stripslashes('We can not move your database files'), 400);
2033 }
2034 }
2035
2036 public function archiveCreation()
2037 {
2038 try {
2039 check_ajax_referer('prepare_migration_files', 'security');
2040
2041 /**
2042 * Pull the transfer detail to get the selected folder information
2043 */
2044 $transferDetail = get_transient('transferito_transfer_detail');
2045
2046 /**
2047 * Start the archive
2048 */
2049 $zipPaths = $this->codeBase->createExecArchive($transferDetail['selectedFolders'], $transferDetail['folders']);
2050
2051 /**
2052 * Set transient for zip creation paths
2053 */
2054 set_transient('transferito_codebase_archive', $zipPaths);
2055
2056 wp_send_json_success([ 'archiveCreationStarted' => true ]);
2057
2058 } catch (\Exception $exception) {
2059 /**
2060 * Push loadScreen event to telemetry
2061 */
2062 $this->telemetry->pushEvent('failedMigration', [
2063 'migrationStatus' => 'archiveCreation',
2064 'errorMessage' => $exception->getMessage()
2065 ]);
2066 $errorMessage = 'archiveCreation: ' . $exception->getMessage();
2067 $this->api->failedMigration($errorMessage);
2068 wp_send_json_error(stripslashes('We can not create a backup of your site'), 400);
2069 }
2070 }
2071
2072 public function archiveProgressCheck()
2073 {
2074 try {
2075
2076 check_ajax_referer('prepare_migration_files', 'security');
2077
2078 /**
2079 * Pull the PID for the progress file
2080 */
2081 $archiveCreationPID = get_transient('transferito_codebase_archive_pid');
2082
2083 /**
2084 * Get the file name
2085 */
2086 $progressFile = TRANSFERITO_UPLOAD_PATH . '/.archive-process';
2087
2088 /**
2089 * Get the archives
2090 */
2091 $archives = get_transient('transferito_codebase_archive');
2092
2093 /**
2094 * Get info for the archive path
2095 */
2096 $archiveInfo = pathinfo($archives['path']);
2097
2098 /**
2099 * Progress value
2100 */
2101 $progressValue = null;
2102
2103 /**
2104 * Set the archive result
2105 */
2106 $archiveResult = [];
2107
2108 /**
2109 * If the file is TAR
2110 * Read the amount of files
2111 */
2112 if ($archiveInfo['extension'] === 'tar') {
2113 /**
2114 * Pull the information about the installation
2115 */
2116 $installationInfo = get_transient('transferito_installation_size');
2117
2118 /**
2119 * Get the amount of lines in the progress file
2120 */
2121 $file = new \SplFileObject($progressFile, 'r');
2122 $file->seek(PHP_INT_MAX);
2123 $progressAmount = $file->key() + 1;
2124
2125 /**
2126 * Calculate the percentage of the archive creation
2127 */
2128 $progressValue = ($progressAmount / $installationInfo['amountOfFiles']) * 100;
2129 }
2130
2131 /**
2132 * If the archive is ZIP
2133 * Calculate the progress of the archive creation based on the zip verbose file structure
2134 */
2135 if ($archiveInfo['extension'] === 'zip') {
2136 /**
2137 * Get the last line of the progress file
2138 */
2139 $lastLine = transferitoGetLastLine($progressFile);
2140
2141 /**
2142 * Get everything within the brackets
2143 */
2144 preg_match("/\[(.*?)\]/", $lastLine, $match);
2145
2146 /**
2147 * If there is a match
2148 * Process the logic to calculate the progress
2149 */
2150 if (count($match) === 2) {
2151 /**
2152 * Remove all spaces from string
2153 */
2154 $cleanValue = str_replace(' ', '', $match[1]);
2155
2156 /**
2157 * Split the progress values
2158 */
2159 $values = explode('/', $cleanValue);
2160
2161 /**
2162 * Check that the 2 elements exist in the array
2163 */
2164 if (count($values) === 2) {
2165 /**
2166 * The amount completed via the zip
2167 */
2168 $completedAmount = preg_split('/(?<=[0-9])(?=[a-z]+)/i', $values[0]);
2169
2170 /**
2171 * The amount remaining
2172 */
2173 $remainingAmount = preg_split('/(?<=[0-9])(?=[a-z]+)/i', $values[1]);
2174
2175 /**
2176 * If the amount id 0 - dont count it yet
2177 */
2178 if ($completedAmount !== '0') {
2179
2180 $completedInBytes = transferitoConvertToBytes($completedAmount);
2181 $remainingInBytes = transferitoConvertToBytes($remainingAmount);
2182 $total = $completedInBytes + $remainingInBytes;
2183 $progressValue = ($total === 0) ? 0 : round(($completedInBytes / $total) * 100);
2184 }
2185 }
2186 }
2187 }
2188
2189 /**
2190 * Check if the process has completed
2191 */
2192 $completed = checkJobHasCompleted($archiveCreationPID);
2193
2194 /**
2195 * Remove the DB import directory
2196 */
2197 if ($completed) {
2198
2199 $transferDetail = get_transient('transferito_transfer_detail');
2200
2201 /**
2202 * Update the code path with the archive path or url
2203 */
2204 $uploadS3 = $transferDetail['isLocalEnv'];
2205 $transferDetail['archive'] = $uploadS3 ? $archives['path'] : $archives['url'];
2206
2207 /**
2208 * Save the archive
2209 */
2210 set_transient('transferito_transfer_detail', $transferDetail);
2211
2212 /**
2213 * Remove the import directory
2214 */
2215 $this->removeDBImportDirectory();
2216
2217 /**
2218 * Get the backup status
2219 */
2220 $backupStatus = get_transient('transferito_backup_status');
2221
2222 /**
2223 * Assign the flags to variables
2224 */
2225 $databaseExcluded = $backupStatus['excludedDatabase'];
2226
2227 /**
2228 * Result of the response when the DB is excluded
2229 */
2230 if ($databaseExcluded) {
2231 $archiveResult = $this->archiveCompletionResponse(true, false);
2232 }
2233
2234 /**
2235 * Result of the response when the DB is not excluded
2236 */
2237 if (!$databaseExcluded) {
2238 $archiveResult = $this->archiveCompletionResponse(true, true);
2239 }
2240 }
2241
2242 wp_send_json_success(array_merge([
2243 'completed' => $completed,
2244 'progress' => $progressValue
2245 ], $archiveResult));
2246
2247 } catch (\Exception $exception) {
2248 wp_send_json_error(stripslashes('We can not get the progress of your backup'), 400);
2249 }
2250 }
2251
2252 public function archiveDBExport()
2253 {
2254 try {
2255 check_ajax_referer('prepare_migration_files', 'security');
2256
2257 /**
2258 * Create the DB file list
2259 */
2260 $exportFileList = $this->dataBase->createFileList();
2261
2262 /**
2263 * Throw if any issues
2264 */
2265 if (!$exportFileList) {
2266 throw new \Exception('We are unable to create the list of database exports that wll be added to your backup.');
2267 }
2268
2269 wp_send_json_success($exportFileList);
2270
2271 } catch (\Exception $exception) {
2272 wp_send_json_error($exception->getMessage(), 400);
2273 }
2274 }
2275
2276 public function checkArchiveCompletion()
2277 {
2278 try {
2279 check_ajax_referer('prepare_migration_files', 'security');
2280
2281 /**
2282 * Get the backup status
2283 */
2284 $backupStatus = get_transient('transferito_backup_status');
2285
2286 /**
2287 * Check that there is a backup status available
2288 */
2289 if (!$backupStatus) {
2290 throw new \Exception('There was an error retrieving your backup information');
2291 }
2292
2293 /**
2294 * Assign the flags to variables
2295 */
2296 $databaseExcluded = $backupStatus['excludedDatabase'];
2297
2298 /**
2299 * Default the archive result
2300 */
2301 $archiveResult = $this->archiveCompletionResponse(false, false);
2302
2303 /**
2304 * Result of the response when the DB is excluded
2305 */
2306 if ($databaseExcluded && $backupStatus['codebaseBackupComplete']) {
2307 $archiveResult = $this->archiveCompletionResponse(true, false);
2308 }
2309
2310 /**
2311 * Result of the response when the DB is not excluded
2312 */
2313 if (!$databaseExcluded && $backupStatus['codebaseBackupComplete'] && $backupStatus['databaseExportComplete']) {
2314 $archiveResult = $this->archiveCompletionResponse(true, true);
2315 }
2316
2317 /**
2318 * Notify the client whether or not the migration should be started or the db exports need to be zipped
2319 */
2320 wp_send_json_success($archiveResult);
2321
2322 } catch (\Exception $exception) {
2323 wp_send_json_error($exception->getMessage(), 400);
2324 }
2325 }
2326
2327 public function initiateUpload()
2328 {
2329 check_ajax_referer('start_upload', 'security');
2330
2331 $transferDetail = get_transient('transferito_transfer_detail');
2332
2333 try {
2334 scandir(TRANSFERITO_UPLOAD_PATH);
2335
2336 /**
2337 * Create an array to hold the backups
2338 */
2339 $backup = [];
2340
2341 /**
2342 * Start the upload for the codebase archive
2343 */
2344 try {
2345 $codebaseUploadId = $this->upload->startUpload();
2346 } catch(\Exception $ex) {
2347 throw new \Exception($ex->getMessage());
2348 }
2349
2350 /**
2351 * Add all the relevant detail to the $backup array
2352 */
2353 $backup['archive'] = [
2354 'type' => 'codebase',
2355 'parts' => $this->getFileParts($transferDetail['archive']),
2356 'uploadId' => $codebaseUploadId
2357 ];
2358
2359 /**
2360 * Send response
2361 */
2362 wp_send_json_success([
2363 'backup' => $backup
2364 ]);
2365
2366 } catch (\Exception $exception) {
2367 /**
2368 * Push failedMigration event to telemetry
2369 */
2370 $this->telemetry->pushEvent('failedMigration', [
2371 'migrationStatus' => 'AWSInitiateUpload',
2372 'errorMessage' => $exception->getMessage()
2373 ]);
2374 $errorMessage = 'AWSInitiateUpload: ' . $exception->getMessage();
2375 $this->api->failedMigration($errorMessage);
2376 wp_send_json_error($errorMessage, 400);
2377 }
2378
2379 }
2380
2381 public function uploadChunk()
2382 {
2383 try {
2384 $transferDetail = get_transient('transferito_transfer_detail');
2385
2386 /**
2387 * Get the correct file
2388 */
2389 $filePath = $transferDetail['archive'];
2390
2391 /**
2392 * Get the part number
2393 */
2394 $partNumber = filter_var($_POST['partNumber'], FILTER_VALIDATE_INT);
2395
2396 /**
2397 * Get the chunk size
2398 */
2399 $chunkSize = Config::getChunkSize();
2400
2401 /**
2402 * Set FilePointer
2403 */
2404 $filePointer = ($partNumber - 1) * $chunkSize;
2405
2406 /**
2407 * Get the file
2408 */
2409 $file = fopen($filePath , 'rb');
2410
2411 /**
2412 * Set the file pointer
2413 */
2414 fseek($file, $filePointer);
2415
2416 /**
2417 * Get the chunk
2418 */
2419 $chunk = fread($file, $chunkSize);
2420
2421 /**
2422 * Close the file
2423 */
2424 fclose($file);
2425
2426 unset($file);
2427
2428 /**
2429 * Send the chunk to the API
2430 */
2431 try {
2432 $chunkUploaded = $this->upload->uploadChunk($partNumber, $chunk);
2433 } catch(\Exception $ex) {
2434 throw new \Exception($ex->getMessage());
2435 }
2436
2437 unset($chunk);
2438
2439
2440 /**
2441 * Send response
2442 */
2443 wp_send_json_success([
2444 'uploaded' => true,
2445 'partNumber' => $partNumber
2446 ]);
2447
2448 } catch (\Exception $exception) {
2449 /**
2450 * Push failedMigration event to telemetry
2451 */
2452 $this->telemetry->pushEvent('failedMigration', [
2453 'migrationStatus' => 'AWSUploadChunk',
2454 'errorMessage' => $exception->getMessage()
2455 ]);
2456 $errorMessage = 'AWSUploadChunk: ' . $exception->getMessage();
2457 $this->api->failedMigration($errorMessage);
2458 wp_send_json_error('There was an error uploading your chunk', 400);
2459 }
2460 }
2461
2462 public function completeUpload()
2463 {
2464 try {
2465 /**
2466 * Pull the transfer detail
2467 */
2468 $transferDetail = get_transient('transferito_transfer_detail');
2469
2470 /**
2471 * Call the upload complete end point
2472 */
2473 try {
2474 $uploadInfo = $this->upload->completeUpload();
2475 } catch(\Exception $ex) {
2476 throw new \Exception($ex->getMessage());
2477 }
2478
2479 /**
2480 * Assign the upload to the migration
2481 */
2482 $completeUpload = $this->api->completeUpload([
2483 'filename' => $uploadInfo['path'],
2484 'token' => $transferDetail['token'],
2485 'timestamp' => $transferDetail['timestamp']
2486 ]);
2487
2488 /**
2489 * If the upload completion failed
2490 */
2491 if ($completeUpload['code'] !== 200) {
2492 throw new \Exception(stripslashes('Your upload can not be assigned to your migration.'));
2493 }
2494
2495 /**
2496 * Set the publicly accessible path for the backup
2497 */
2498 $transferDetail['archive'] = $uploadInfo['URL'];
2499
2500 /**
2501 * Set transient with transfer detail
2502 */
2503 set_transient('transferito_transfer_detail', $transferDetail);
2504
2505 /**
2506 * Send response
2507 */
2508 wp_send_json_success([
2509 'htmlTemplate' => loadTemplate('parts/loading', [
2510 'showMigrationImage' => true,
2511 'mainMessage' => stripslashes('We have successfully backed up your WordPress installation'),
2512 'secondaryMessage' => 'We are currently migrating your site to your new destination',
2513 ]),
2514 'securityKey' => wp_create_nonce('start_migration')
2515 ]);
2516
2517 } catch (\Exception $exception) {
2518 /**
2519 * Push failedMigration event to telemetry
2520 */
2521 $this->telemetry->pushEvent('failedMigration', [
2522 'migrationStatus' => 'AWSCompleteUpload',
2523 'errorMessage' => $exception->getMessage()
2524 ]);
2525 $errorMessage = 'AWSCompleteUpload: ' . $exception->getMessage();
2526 $this->api->failedMigration($errorMessage);
2527
2528 wp_send_json_error('There was an error completing your upload', 400);
2529 }
2530 }
2531
2532 public function startMigration()
2533 {
2534 check_ajax_referer('start_migration', 'security');
2535
2536 $settings = get_option('transferito_settings_option');
2537 $chunkSize = isset($settings['transferito_chunk_size']) ? $settings['transferito_chunk_size'] : '10';
2538 $transferDetail = get_transient('transferito_transfer_detail');
2539 $installationInfo = get_transient('transferito_installation_size');
2540 $dbCharsetInfo = get_transient('transferito_database_charset_info');
2541
2542 /**
2543 * Check if the migration is a local migration or not
2544 */
2545 $localMigration = get_transient('transferito_transfer_method') === 'localSiteMigration';
2546
2547 delete_transient('transferito_transfer_detail');
2548 delete_transient('transferito_database_charset_info');
2549
2550 /**
2551 * Check the user's API keys
2552 */
2553 $hasValidAPIKeys = $this->areAPIKeysValid(
2554 $settings['public_transferito_key'],
2555 $settings['secret_transferito_key']
2556 );
2557
2558 /**
2559 * Set as a FREE User
2560 */
2561 if (!$hasValidAPIKeys) {
2562 $this->api->setFreeUser();
2563 }
2564
2565 /**
2566 * Create the payload to send to the API
2567 */
2568 $startMigrationPayload = [
2569 'chunkSize' => $chunkSize,
2570 'charset' => $dbCharsetInfo['actualCharset'],
2571 'configCharset' => $dbCharsetInfo['configCharset'],
2572 'archiveFileAmount' => $installationInfo['amountOfFiles'],
2573 'isLocal' => $transferDetail['isLocalEnv'],
2574 'archive' => $transferDetail['archive'],
2575 'backupDirectory' => $transferDetail['directory'],
2576 'token' => $transferDetail['token'],
2577 'timestamp' => $transferDetail['timestamp'],
2578 'fromUrl' => $transferDetail['fromUrl'],
2579 'currentPath' => ABSPATH
2580 ];
2581
2582 /**
2583 * Send files to API
2584 */
2585 $startMigrationRequest = $this->api->startMigration($startMigrationPayload);
2586 $statusCode = $startMigrationRequest['code'];
2587 $response = $startMigrationRequest['message'];
2588
2589 /**
2590 * If upload notification has been successful
2591 * Add flags stop backup removal
2592 */
2593 if ($statusCode === 200) {
2594 set_transient('transferito_ignore_cleanup', true, 12 * HOUR_IN_SECONDS);
2595 set_transient('transferito_cleanup_after_completion', true, 12 * HOUR_IN_SECONDS);
2596 }
2597
2598 /**
2599 * Return response based on status
2600 */
2601 if ($statusCode === 200) {
2602 $emptyKeys = get_transient('transferito_empty_keys');
2603 $availableTransfers = get_transient('transferito_has_available_transfers');
2604 $message = ($emptyKeys || !$availableTransfers)
2605 ? 'If you navigate away from the site, your migration will continue in the background. As you\'re not a premium member, we advise that you stay on this page until your migration has completed.'
2606 : 'If you navigate away from the site, your migration will continue in the background. You will be sent an email once your migration has completed.';
2607 wp_send_json_success([
2608 'localMigration' => $localMigration,
2609 'token' => $response->token,
2610 'message' => $message
2611 ]);
2612 } else {
2613 $errorMessage = is_array($response) ? 'There has been an error starting your migration' : stripslashes($response);
2614 wp_send_json_error($errorMessage, $statusCode);
2615 }
2616 }
2617
2618 public function cleanUp($url = null)
2619 {
2620 $url = get_transient('transferito_final_destination_url');
2621 $hasError = isset($_POST['hasError']) ? $_POST['hasError'] : false;
2622 $metadata = isset($_POST['metadata']) ? $_POST['metadata'] : '';
2623 $localMigration = filter_var($_POST['localMigration'], FILTER_VALIDATE_BOOL);
2624
2625 $errors = isset($_POST['errors']) ? $_POST['errors'] : null;
2626 $failureList = [
2627 'CPANEL_CHECK_FAILED' => 'There has been an issue checking your URL',
2628 'SWITCH_METHOD_FAILED' => 'There has been an issue switching to the new migration mode',
2629 'FAILED_BACKUP_CHECK' => 'There has been an error processing a backup of your WordPress site',
2630 'FAILED_CREATE_BACKUP' => 'There has been an error creating a backup of your WordPress site',
2631 'FAILED_REMOVE_BACKUP' => 'There has been an error removing a backup of your WordPress site',
2632 'FAILED_STARTING_MIGRATION' => 'There has been an issue starting your migration',
2633 'ERROR_GETTING_STATUS' => 'There has been an issue getting the status of your migration.',
2634 'UPLOAD_START_FAILURE' => 'We have been unable to start uploading your backup to our servers',
2635 'UPLOAD_CHUNK_FAILURE' => 'An error has occurred whilst uploading your backup to our servers',
2636 'UPLOAD_COMPLETION_FAILURE' => 'We are unable to complete the upload of your backup to our servers',
2637 'USE_CUSTOM_ERROR_MESSAGE' => $errors && isset($errors['data']) ? $errors['data'] : 'There has been an issue processing your migration',
2638 ];
2639 $validError = in_array($hasError, array_keys($failureList));
2640
2641 $completionHTMLTemplate = ($localMigration)
2642 ? 'parts/migration/local-migration-completed'
2643 : 'parts/migration/completed';
2644
2645 try {
2646 clearstatcache();
2647
2648 if (file_exists(TRANSFERITO_UPLOAD_PATH)) {
2649 /**
2650 * Check if there has been an error archiving
2651 */
2652 $this->checkArchiveError();
2653
2654 /**
2655 * Remove everything in the transferito directory
2656 */
2657 $this->purgeDirectory(TRANSFERITO_UPLOAD_PATH);
2658 }
2659
2660 /**
2661 * Remove all instances of the db import directory
2662 */
2663 $this->removeDBImportDirectory();
2664
2665 /**
2666 * If the error exists
2667 */
2668 if ($validError) {
2669 $this->api->failedMigration($failureList[$hasError]);
2670 $htmlTemplate = [
2671 'error' => $failureList[$hasError],
2672 'failed' => true,
2673 ];
2674 } else {
2675 $htmlTemplate = loadTemplate($completionHTMLTemplate, [
2676 'url' => $url,
2677 'metadata' => $metadata
2678 ]);
2679 }
2680 } catch (\Exception $exception) {
2681 if ($validError) {
2682 $this->api->failedMigration($errors);
2683 $htmlTemplate = [
2684 'error' => $failureList[$hasError],
2685 'failed' => true,
2686 'secondary' => stripslashes('We have not been able to remove your backup. Please remove it manually.')
2687 ];
2688 } else {
2689 $this->api->failedMigration($failureList['FAILED_REMOVE_BACKUP']);
2690 $htmlTemplate = loadTemplate($completionHTMLTemplate, [ 'url' => $url, 'error' => 'FAILED_BACKUP_REMOVAL' ]);
2691 }
2692 }
2693
2694 $this->enableAutoPrependOption();
2695 $this->enableWPObjectCache();
2696 $this->removeTransferitoTransients();
2697
2698 wp_send_json_success([ 'htmlTemplate' => $htmlTemplate ]);
2699 }
2700
2701 private function areAPIKeysValid($publicKey, $secretKey) {
2702 $valid = null;
2703
2704 try {
2705 $planInfo = $this->api->planInformation([
2706 'publicTransferito_APIKey' => $publicKey,
2707 'secretTransferito_APIKey' => $secretKey
2708 ]);
2709 $code = $planInfo['code'];
2710
2711 /**
2712 * Success is a 200
2713 * If anything else throw an error
2714 */
2715 if ($code !== 200) {
2716 throw new \Exception('INVALID_API_KEYS');
2717 }
2718
2719 $availableTransfers = isset($planInfo['message']->availableTransfers)
2720 ? $planInfo['message']->availableTransfers
2721 : 0;
2722
2723 set_transient('transferito_has_available_transfers', ($availableTransfers !== 0));
2724
2725 $valid = ($code === 200 && $availableTransfers !== 0);
2726
2727 } catch(\Exception $exception) {
2728 $valid = false;
2729 }
2730
2731 return $valid;
2732 }
2733
2734 private function checkSiteWithinFreeTier($siteDetails)
2735 {
2736 try {
2737
2738 /**
2739 * Default the user status to FREE
2740 */
2741 $userStatus = 'FREE';
2742
2743 /**
2744 * Default if the user has valid API keys to false
2745 */
2746 $hasValidAPIKeys = false;
2747
2748 /**
2749 * Plan Check
2750 */
2751 if ($this->options && $this->options['public_transferito_key'] && $this->options['secret_transferito_key']) {
2752
2753 /**
2754 * Check the user's API keys
2755 */
2756 $hasValidAPIKeys = $this->areAPIKeysValid(
2757 $this->options['public_transferito_key'],
2758 $this->options['secret_transferito_key']
2759 );
2760
2761 /**
2762 * Only set the status if the API keys are valid
2763 */
2764 if ($hasValidAPIKeys) {
2765 $userStatus = 'PREMIUM';
2766 }
2767 }
2768
2769 /**
2770 * Save the user's status
2771 */
2772 set_transient('transferito_user_status', $userStatus);
2773
2774 /**
2775 * Only update the FREE User Options
2776 * If the user doesn't have Valid API Keys
2777 */
2778 if (!$hasValidAPIKeys) {
2779 /**
2780 * Inform the API Wrapper of the type of user
2781 */
2782 $this->api->setFreeUser();
2783 $this->api->setMaxSizeExceeded($siteDetails['maxSizeExceeded']);
2784
2785 /**
2786 * Update legend message
2787 */
2788 if ($siteDetails['maxSizeExceeded']) {
2789 /**
2790 * Push upgradeRequired event to telemetry
2791 */
2792 $this->telemetry->pushEvent('premiumUpgradeRequired', [
2793 'exceededFreeTierSize' => 'yes',
2794 ]);
2795 }
2796 }
2797
2798 } catch(\Exception $exception) {
2799 /**
2800 * Push upgradeRequired event to telemetry
2801 */
2802 $this->telemetry->pushEvent('premiumUpgradeRequired', [
2803 'exceededFreeTierSize' => 'yes',
2804 ]);
2805 }
2806 }
2807
2808 private function getFileParts($filePath)
2809 {
2810 sleep(5);
2811 getDirectorySize(TRANSFERITO_ABSPATH);
2812 clearstatcache();
2813 $fileInfo = stat($filePath);
2814 $archiveSize = $fileInfo['size'];
2815 $chunkSize = Config::getChunkSize();
2816 return ceil($archiveSize / $chunkSize);
2817 }
2818
2819 private function freshStart() {
2820 try {
2821 clearstatcache();
2822
2823 $this->enableAutoPrependOption();
2824 $this->enableWPObjectCache();
2825 $this->removeTransferitoTransients();
2826 $this->removeDBImportDirectory();
2827
2828 /**
2829 * Check if an unfinished migration still exists
2830 */
2831 if (file_exists(TRANSFERITO_UPLOAD_PATH)) {
2832 /**
2833 * Check if there has been an error archiving
2834 */
2835 $this->checkArchiveError();
2836
2837 /**
2838 * Remove everything in the transferito directory
2839 */
2840 $this->purgeDirectory(TRANSFERITO_UPLOAD_PATH);
2841 }
2842 } catch(\Exception $exception) {
2843 // do nada - for now
2844 }
2845 }
2846
2847 private function removeTransferitoTransients()
2848 {
2849 delete_transient('transferito_size_size_in_bytes');
2850 delete_transient('transferito_readable_size_size_in_bytes');
2851 delete_transient('transferito_request_fallback');
2852 delete_transient('transferito_destination_url');
2853 delete_transient('transferito_backup_status');
2854 delete_transient('transferito_transfer_detail');
2855 delete_transient('transferito_final_destination_url');
2856 delete_transient('transferito_codebase_archive');
2857 delete_transient('transferito_database_table_map');
2858 delete_transient('transferito_ignore_cleanup');
2859 delete_transient('transferito_cleanup_after_completion');
2860 delete_transient('transferito_db_export_progress');
2861 delete_transient('transferito_migration_token');
2862 delete_transient('transferito_migration_timestamp');
2863 delete_transient('transferito_migration_domain');
2864 delete_transient('transferito_migration_unchanged_domain');
2865 delete_transient('transferito_transfer_method');
2866 delete_transient('transferito_cpanel_allowed');
2867 delete_transient('transferito_cpanel_domain');
2868 delete_transient('transferito_manual_server_detail');
2869 delete_transient('transferito_use_backup_fallback');
2870 delete_transient('transferito_installation_size');
2871 delete_transient('transferito_requirements');
2872 delete_transient('transferito_database_relocation_pid');
2873 delete_transient('transferito_codebase_archive_pid');
2874 delete_transient('transferito_upload_information');
2875 delete_transient('transferito_database_charset_info');
2876 delete_transient('transferito_cpanel_auth_details');
2877 delete_transient('transferito_empty_keys');
2878 delete_transient('transferito_has_available_transfers');
2879 delete_transient('transferito_database_detail_completed');
2880 delete_transient('transferito_cpanel_auth_details_completed');
2881 delete_transient('transferito_archive_extension');
2882 delete_transient('transferito_cpanel_domain_selection');
2883 delete_transient('transferito_object_cache_filter_present');
2884 delete_transient('transferito_auto_prepend_option_disabled');
2885
2886 }
2887
2888 private function archiveCompletionResponse($backupsCompleted, $zipDBExport)
2889 {
2890 /**
2891 * Get the Transfer Detail
2892 */
2893 $transferDetail = get_transient('transferito_transfer_detail');
2894
2895 /**
2896 * Get the local Env flag
2897 */
2898 $localEnv = $transferDetail['isLocalEnv'];
2899
2900 /**
2901 * Information for the client
2902 */
2903 $information = null;
2904
2905 /**
2906 * If the zip DB Export is not needed
2907 */
2908 if ($backupsCompleted) {
2909 /**
2910 * If the site can not be reached - Then upload the archive
2911 */
2912 if ($localEnv) {
2913 $information = [
2914 'htmlTemplate' => loadTemplate('parts/migration/upload-progress', [
2915 'title' => 'Upload in progress. Please wait...',
2916 'mainMessage' => stripslashes('We are uploading a backup of your site to our secure servers.'),
2917 'secondaryMessage' => stripslashes('Please wait.. This may take a few minutes, do not close this window or refresh the page'),
2918 ]),
2919 'securityKey' => wp_create_nonce('start_upload'),
2920 'uploadFiles' => true,
2921 ];
2922 }
2923
2924 /**
2925 * If the site can be reached - Then pull direct
2926 */
2927 if (!$localEnv) {
2928 $information = [
2929 'htmlTemplate' => loadTemplate('parts/loading', [
2930 'showMigrationImage' => true,
2931 'mainMessage' => stripslashes('We have successfully backed up your WordPress installation'),
2932 'secondaryMessage' => 'We are currently migrating your site to your new destination',
2933 ]),
2934 'securityKey' => wp_create_nonce('start_migration'),
2935 'uploadFiles' => false,
2936 ];
2937 }
2938 }
2939
2940 return [
2941 'backupComplete' => $backupsCompleted,
2942 'zipDatabaseExport' => $zipDBExport,
2943 'information' => $information
2944 ];
2945 }
2946
2947 private function removeDBImportDirectory()
2948 {
2949 $importDirectory = TRANSFERITO_ABSPATH . 'transferito_import';
2950
2951 /**
2952 * If the Directory exists
2953 */
2954 if (file_exists($importDirectory)) {
2955 array_map('unlink', array_filter(glob($importDirectory . '/*')));
2956 rmdir($importDirectory);
2957 }
2958 }
2959
2960 private function purgeDirectory($directory)
2961 {
2962 if (!$directory) {
2963 return true;
2964 }
2965
2966 clearstatcache();
2967
2968 $it = new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::SKIP_DOTS);
2969 $files = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
2970 foreach($files as $file) {
2971 if ($file->isDir()){
2972 rmdir($file->getRealPath());
2973 } else {
2974 unlink($file->getRealPath());
2975 }
2976 }
2977
2978 clearstatcache();
2979
2980 rmdir($directory);
2981
2982 return true;
2983 }
2984
2985 private function checkArchiveError()
2986 {
2987 $archiveErrorPath = TRANSFERITO_UPLOAD_PATH . DIRECTORY_SEPARATOR . '.archive-error';
2988 $archiveErrorRootPath = TRANSFERITO_ABSPATH . '.archive-error';
2989 $errorFileExists = file_exists($archiveErrorPath);
2990
2991 if ($errorFileExists) {
2992 $hasErrors = strlen(file_get_contents($archiveErrorPath)) > 0;
2993
2994 /**
2995 * If the file has errors
2996 * Then move the archive error file to the root directory
2997 */
2998 if ($hasErrors) {
2999 rename($archiveErrorPath, $archiveErrorRootPath);
3000 }
3001 }
3002 }
3003
3004 private function disableAutoPrependOption()
3005 {
3006 $autoPrependOptionData = getPrependOptionNameData();
3007 $userIniFilePath = $autoPrependOptionData['path'];
3008 $userIniFileExists = file_exists($userIniFilePath);
3009
3010 /**
3011 * Only proceed with the user.ini modification if the file exists
3012 */
3013 if ($userIniFileExists) {
3014 try {
3015
3016 $prependOptionName = $autoPrependOptionData['text'];
3017 $commentedPrependOptionName = $autoPrependOptionData['commented'];
3018 $userIniFile = file_get_contents($userIniFilePath);
3019 $optionExists = str_contains($userIniFile, $prependOptionName);
3020
3021 /**
3022 * If there isn't an auto_prepend option throw a graceful error
3023 */
3024 if (!$optionExists) {
3025 throw new \Exception('AUTO_PREPEND_MODIFICATION_NOT_REQUIRED');
3026 }
3027
3028 /**
3029 * Check to see if the option has been commented previously
3030 */
3031 $optionPreviouslyCommentedExists = str_contains($userIniFile, $commentedPrependOptionName);
3032
3033 /**
3034 * If a comment doesn't exist - modify the file
3035 */
3036 if (!$optionPreviouslyCommentedExists) {
3037 $modifiedUserIni = str_replace($prependOptionName, $commentedPrependOptionName, $userIniFile);
3038 file_put_contents($userIniFilePath, $modifiedUserIni);
3039 }
3040
3041 set_transient('transferito_auto_prepend_option_disabled', true);
3042
3043 } catch(\Exception $exception) {
3044 set_transient('transferito_auto_prepend_option_disabled', false);
3045 }
3046 }
3047 }
3048
3049 private function disableWPObjectCache()
3050 {
3051 $objectCacheFilterData = getObjectCacheFilterData();
3052
3053 /**
3054 * Only make this change if the function file exists
3055 */
3056 if (file_exists($objectCacheFilterData['path'])) {
3057 try {
3058 $cacheFilterExists = str_contains(file_get_contents($objectCacheFilterData['path']), $objectCacheFilterData['text']);
3059
3060 /**
3061 * If the filter isn't already in the PHP file
3062 */
3063 if (!$cacheFilterExists) {
3064 $filterModified = PHP_EOL . $objectCacheFilterData['text'] . PHP_EOL;
3065 file_put_contents($objectCacheFilterData['path'], $filterModified, FILE_APPEND | LOCK_EX);
3066 }
3067
3068 /**
3069 * Set the transient, so we can decide whether we need to revert the file
3070 */
3071 set_transient('transferito_object_cache_filter_present', true);
3072 } catch (\Exception $exception) {
3073 set_transient('transferito_object_cache_filter_present', false);
3074 }
3075 }
3076 }
3077
3078 private function enableAutoPrependOption()
3079 {
3080 $autoPrependOptionStatus = get_transient('transferito_auto_prepend_option_disabled');
3081
3082 /**
3083 * Only enable the option if the file transient status if truthy
3084 */
3085 if ($autoPrependOptionStatus) {
3086 $autoPrependOptionData = getPrependOptionNameData();
3087
3088 /**
3089 * Check the file exists
3090 */
3091 if (file_exists($autoPrependOptionData['path'])) {
3092 try {
3093 $userIniFile = file_get_contents($autoPrependOptionData['path']);
3094 $commentedOptionExists = str_contains($userIniFile, $autoPrependOptionData['commented']);
3095
3096 /**
3097 * Check to see that the commented option is present
3098 */
3099 if ($commentedOptionExists) {
3100 $modifiedUserIniFile = str_replace($autoPrependOptionData['commented'], $autoPrependOptionData['text'], $userIniFile);
3101 file_put_contents($autoPrependOptionData['path'], $modifiedUserIniFile);
3102 }
3103 } catch(\Exception $exception) {
3104 // handle gracefullu
3105 }
3106 }
3107 }
3108 }
3109
3110 private function enableWPObjectCache()
3111 {
3112 $wpObjectCacheStatus = get_transient('transferito_object_cache_filter_present');
3113
3114 /**
3115 * Only enable if the status is truthy
3116 */
3117 if ($wpObjectCacheStatus) {
3118 $objectCacheFilterData = getObjectCacheFilterData();
3119
3120 /**
3121 * Check the file exists
3122 */
3123 if (file_exists($objectCacheFilterData['path'])) {
3124 try {
3125 $functionsFile = file_get_contents($objectCacheFilterData['path']);
3126 $cacheFilterExists = str_contains($functionsFile, $objectCacheFilterData['text']);
3127
3128 /**
3129 * If the filter lives in the functions file, remove it
3130 */
3131 if ($cacheFilterExists) {
3132 $modifiedFunctionsFile = str_replace($objectCacheFilterData['text'], '', $functionsFile);
3133 file_put_contents($objectCacheFilterData['path'], $modifiedFunctionsFile);
3134 }
3135 } catch(\Exception $exception) {
3136 // Fail gracefully
3137 }
3138 }
3139 }
3140 }
3141
3142 }
3143