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