PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.1.2
Backup Migration v2.1.2
2.1.6 2.1.5.2 trunk 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.6.1 1.4.7 1.4.8 1.4.9 1.4.9.1 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.5.1
backup-backup / includes / ajax.php
backup-backup / includes Last commit date
banner 3 months ago bodies 3 months ago check 3 months ago cli 3 months ago cron 3 months ago dashboard 3 months ago database 3 months ago external 3 months ago extracter 3 months ago htaccess 3 months ago notices 3 months ago progress 3 months ago scanner 3 months ago staging 3 months ago traits 3 months ago uploader 3 months ago vendor 3 months ago zipper 3 months ago .htaccess 3 months ago activation.php 3 months ago ajax.php 3 months ago ajax_offline.php 3 months ago analyst.php 3 months ago backup-process.php 3 months ago class-backup-method-mananger.php 3 months ago cli-handler.php 3 months ago compatibility.php 3 months ago config.php 3 months ago constants.php 3 months ago file-explorer.php 3 months ago initializer.php 3 months ago logger.php 3 months ago offline.php 3 months ago
ajax.php
6041 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin;
5
6 // Exit on direct access
7 if (!defined('ABSPATH')) exit;
8
9 // Uses
10 use BMI\Plugin\Backup_Migration_Plugin as BMP;
11 use BMI\Plugin\BMI_Logger as Logger;
12 use BMI\Plugin\Checker\BMI_Checker as Checker;
13 use BMI\Plugin\Checker\System_Info as SI;
14 use BMI\Plugin\CRON\BMI_Crons as Crons;
15 use BMI\Plugin\Dashboard as Dashboard;
16 use BMI\Plugin\Extracter\BMI_Extracter as Extracter;
17 use BMI\Plugin\Progress\BMI_MigrationProgress as MigrationProgress;
18 use BMI\Plugin\Progress\BMI_ZipProgress as Progress;
19 use BMI\Plugin\Progress\BMI_StagingProgress as StagingProgress;
20 use BMI\Plugin\Scanner\BMI_BackupsScanner as Backups;
21 use BMI\Plugin\Scanner\BMI_FileScanner as Scanner;
22 use BMI\Plugin\Zipper\BMI_Zipper as Zipper;
23 use BMI\Plugin\PHPCLI\Checker as PHPCLICheck;
24 use BMI\Plugin\External\BMI_External_Storage as ExternalStorage;
25 use BMI\Plugin\External\BMI_External_Storage_Premium as ExternalStoragePremium;
26 use BMI\Plugin\Staging\BMI_Staging_TasteWP as StagingTasteWP;
27 use BMI\Plugin\Staging\BMI_StagingLocal as StagingLocal;
28 use BMI\Plugin\Heart\BMI_Backup_Heart as Bypasser;
29 use BMI\Plugin\Staging\BMI_Staging as Staging;
30 use BMI\Plugin\Checker\Compatibility as Compatibility;
31 use BMI\Plugin\External\BMI_External_BackupBliss as BackupBliss;
32 use BMI\Plugin\BMI_File_Explorer as File_Explorer;
33 use BMI\Plugin\External\BMI_External_Dropbox as Dropbox;
34 use BMI\Plugin\External\BMI_External_GDrive as GDrive;
35 use BMI\Plugin\External\BMI_External_FTP as FTP;
36 use BMI\Plugin\External\BMI_External_S3 as S3;
37
38 /**
39 * Ajax Handler for BMI
40 */
41 class BMI_Ajax {
42
43 private $gdrive_access_token = false;
44 public $post;
45 public $zip_progress;
46 public $migration_progress;
47 public $lock_cli;
48 public $lastCurlCode;
49
50 public $total_size_for_backup = 0;
51 public $total_size_for_backup_in_mb = 0;
52 public $total_excluded_size_for_backup = 0;
53 public $ignoredDirectoriesSize = 0;
54
55 public function __construct($initializedWithCLI = false) {
56
57 // Initialize CRON if wasn't done earlier
58 $this->shareDomainForAutoCron();
59
60 // Return if it's not post
61 if (empty($_POST)) {
62 $this->post = ['f' => 'unknown_method'];
63 return;
64 }
65
66 // Sanitize User Input
67 $this->post = BMP::sanitize($_POST);
68
69 if (!isset($this->post['f'])) {
70 if (is_object($this->post) || is_array($this->post)) $this->post['f'] = 'unknown_method';
71 else $this->post = ['f' => 'unknown_method'];
72 }
73
74 // Check nonce for non PHP CLI usage (ignore while self requested via previously verified nonce to PHP CLI)
75 if (check_ajax_referer('backup-migration-ajax', 'nonce', false) === false && $initializedWithCLI === false) {
76 return wp_send_json_error(['reason' => 'not authorized request']);
77 }
78
79 // Log Handler Call (Verbose)
80 Logger::debug(__("Running POST Function: ", 'backup-backup') . $this->post['f']);
81
82 // Create backup folder
83 if (!file_exists(BMI_BACKUPS)) {
84 mkdir(BMI_BACKUPS, 0755, true);
85 }
86
87 // Create background logs file
88 $backgroundLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'background-errors.' . BMI_LOGS_SUFFIX . '.log';
89 if (!file_exists($backgroundLogsPath)) {
90 @touch($backgroundLogsPath);
91 }
92
93 if (!isset($this->post['f'])) {
94 return;
95 }
96
97 // Handle User Request If Known And Sanitize Response
98 if ($this->post['f'] == 'scan-directory') {
99 BMP::res($this->dirSize());
100 } elseif ($this->post['f'] == 'create-backup') {
101 BMP::res($this->prepareAndMakeBackup());
102 } elseif ($this->post['f'] == 'reset-latest') {
103 BMP::res($this->resetLatestLogs());
104 } elseif ($this->post['f'] == 'get-current-backups') {
105 BMP::res($this->getBackupsList());
106 } elseif ($this->post['f'] == 'restore-backup') {
107 BMP::res($this->restoreBackup());
108 } elseif ($this->post['f'] == 'is-running-backup') {
109 BMP::res($this->isRunningBackup());
110 } elseif ($this->post['f'] == 'stop-backup') {
111 BMP::res($this->stopBackup());
112 } elseif ($this->post['f'] == 'download-backup') {
113 BMP::res($this->handleQuickMigration());
114 } elseif ($this->post['f'] == 'migration-locked') {
115 BMP::res($this->isMigrationLocked());
116 } elseif ($this->post['f'] == 'upload-backup') {
117 BMP::res($this->handleChunkUpload());
118 } elseif ($this->post['f'] == 'delete-backup') {
119 BMP::res($this->removeBackupFile());
120 } elseif ($this->post['f'] == 'save-storage') {
121 BMP::res($this->saveStorageConfig());
122 } elseif ($this->post['f'] == 'save-file-config') {
123 BMP::res($this->saveFilesConfig());
124 } elseif ($this->post['f'] == 'save-other-options') {
125 BMP::res($this->saveOtherOptions());
126 } elseif ($this->post['f'] == 'store-config') {
127 BMP::res($this->saveStorageTypeConfig());
128 } elseif ($this->post['f'] == 'unlock-backup') {
129 BMP::res($this->toggleBackupLock(true));
130 } elseif ($this->post['f'] == 'lock-backup') {
131 BMP::res($this->toggleBackupLock(false));
132 } elseif ($this->post['f'] == 'get-dynamic-names') {
133 BMP::res($this->getDynamicNames());
134 } elseif ($this->post['f'] == 'reset-configuration') {
135 BMP::res($this->resetConfiguration());
136 } elseif ($this->post['f'] == 'get-site-data') {
137 BMP::res($this->getSiteData());
138 } elseif ($this->post['f'] == 'send-test-mail') {
139 BMP::res($this->sendTestMail());
140 } elseif ($this->post['f'] == 'calculate-cron') {
141 BMP::res($this->calculateCron());
142 } elseif ($this->post['f'] == 'dismiss-error-notice') {
143 BMP::res($this->dismissErrorNotice());
144 } elseif ($this->post['f'] == 'fix_uname_issues') {
145 BMP::res($this->fixUnameFunction());
146 } elseif ($this->post['f'] == 'revert_uname_issues') {
147 BMP::res($this->revertUnameProcess());
148 } elseif ($this->post['f'] == 'continue_restore_process') {
149 BMP::res($this->continueRestoreProcess());
150 } elseif ($this->post['f'] == 'htaccess-litespeed') {
151 BMP::res($this->fixLitespeed());
152 } elseif ($this->post['f'] == 'force-backup-to-stop') {
153 BMP::res($this->forceBackupToStop());
154 } elseif ($this->post['f'] == 'force-restore-to-stop') {
155 BMP::res($this->forceRestoreToStop());
156 } elseif ($this->post['f'] == 'staging-local-name') {
157 BMP::res($this->checkStagingLocalName());
158 } elseif ($this->post['f'] == 'staging-start-local-creation') {
159 BMP::res($this->startLocalStagingCreation());
160 } elseif ($this->post['f'] == 'staging-local-creation-process') {
161 BMP::res($this->localStagingCreationProcess());
162 } elseif ($this->post['f'] == 'staging-tastewp-creation-process') {
163 BMP::res($this->tastewpStagingCreation());
164 } elseif ($this->post['f'] == 'staging-rename-display') {
165 BMP::res($this->stagingRename());
166 } elseif ($this->post['f'] == 'staging-prepare-login') {
167 BMP::res($this->stagingPrepareLogin());
168 } elseif ($this->post['f'] == 'staging-delete-permanently') {
169 BMP::res($this->stagingDelete());
170 } elseif ($this->post['f'] == 'staging-get-updated-list') {
171 BMP::res($this->stagingSitesGetList());
172 } elseif ($this->post['f'] == 'send-troubleshooting-logs') {
173 BMP::res($this->sendTroubleshootingDetails());
174 } elseif ($this->post['f'] == 'log-sharing-details') {
175 BMP::res($this->logSharing());
176 } elseif ($this->post['f'] == 'get-latest-backup') {
177 BMP::res($this->getLatestBackupFile());
178 } elseif ($this->post['f'] == 'front-end-ajax-error') {
179 BMP::res($this->frontEndAjaxError());
180 } elseif ($this->post['f'] == 'backup-browser-method') {
181 BMP::res($this->backupBrowserMethodHandler());
182 } elseif ($this->post['f'] == 'debugging') {
183 BMP::res($this->debugging());
184 } elseif ($this->post['f'] == 'check-disk-space') {
185 BMP::res($this->checkDiskSpace());
186 } elseif ($this->post['f'] == 'check-comptability') {
187 BMP::res($this->checkCompatibility());
188 } elseif ($this->post['f'] == 'clean-up-after-error'){
189 BMP::res($this->cleanUpAfterError());
190 } elseif ($this->post['f'] == 'clicked-on-plugin-review') {
191 BMP::res($this->clickedOnPluginReview());
192 } elseif ($this->post['f'] == 'keep-dropbox-connection') {
193 BMP::res($this->keepDropboxToken());
194 } elseif ($this->post['f'] == 'get-dropbox-token') {
195 BMP::res($this->getDropboxToken());
196 } elseif ($this->post['f'] == 'disconnect-dropbox') {
197 BMP::res($this->disconnectDropboxToken());
198 } elseif ($this->post['f'] == 'verify-dropbox-connection') {
199 BMP::res($this->verifyDropboxConnection());
200 } elseif ($this->post['f'] == 'download-dropbox-backup') {
201 BMP::res($this->downloadCloudBackupV2());
202 } elseif ($this->post['f'] == 'dismiss-dropbox-notice') {
203 BMP::res($this->dismissDropboxNotice());
204 } elseif ($this->post['f'] == 'get-gdrive-token') {
205 BMP::res($this->getGDriveToken());
206 } elseif ($this->post['f'] == 'keep-gdrive-connection') {
207 BMP::res($this->keepGDriveToken());
208 } elseif ($this->post['f'] == 'verify-gdrive-connection') {
209 BMP::res($this->verifyGDriveConnection());
210 } elseif ($this->post['f'] == 'disconnect-gdrive') {
211 BMP::res($this->disconnectGDriveToken());
212 } elseif ($this->post['f'] == 'get-ftp-config') {
213 BMP::res($this->connectToConfig());
214 } elseif ($this->post['f'] == 'disconnect-ftp') {
215 BMP::res($this->disconnectFtp());
216 } elseif ($this->post['f'] == 'save-aws-config') {
217 BMP::res($this->saveAWSConfig());
218 } elseif ($this->post['f'] == 'disconnect-aws') {
219 BMP::res($this->disconnectAWS());
220 } elseif ($this->post['f'] == 'verify-aws-connection') {
221 BMP::res($this->verifyAWSConnection());
222 } elseif ($this->post['f'] == 'save-wasabi-config') {
223 BMP::res($this->saveWasabiConfig());
224 } elseif ($this->post['f'] == 'disconnect-wasabi') {
225 BMP::res($this->disconnectWasabi());
226 } elseif ($this->post['f'] == 'verify-wasabi-connection') {
227 BMP::res($this->verifyWasabiConnection());
228 } elseif ($this->post['f'] == 'manually-enqueue-upload') {
229 BMP::res($this->manuallyEnqueueUpload());
230 } elseif ($this->post['f'] == 'resync-with-ping-server') {
231 BMP::res($this->resyncWithPingServer());
232 }
233 elseif (substr($this->post['f'], 0, 3) === "bb-") {
234 require_once BMI_INCLUDES . '/external/backupbliss.php';
235 $backupBliss = new BackupBliss();
236 BMP::res($backupBliss->process(substr($this->post['f'], 3), $this->post));
237 } elseif ($this->post['f'] == 'check-not-uploaded-backups') {
238 do_action('bmi_ajax_offline', $this->post);
239 } elseif($this->post['f'] == 'download-cloud-backup') {
240 if (isset($this->post['storage']) && ($this->post['storage'] == 'backupbliss' ||
241 $this->post['storage'] == 'googledrive' || $this->post['storage'] == 'ftp'))
242 BMP::res($this->downloadCloudBackup());
243 //Forward it to premium plugin for other cloud downloads
244 elseif (has_action('bmi_premium_ajax')) {
245 do_action('bmi_premium_ajax', $this->post);
246 }
247 }
248
249
250 //If none of the action matches it executes premium ajax if it exists
251 elseif (has_action('bmi_premium_ajax')) {
252 do_action('bmi_premium_ajax', $this->post);
253 }
254
255 }
256
257 /**
258 * getFtpConfig
259 *
260 * @return string[] Token
261 */
262 private function connectToConfig()
263 {
264 // Safely retrieve POST values
265 $host = isset($this->post['bmip-ftp-host']) ? trim($this->post['bmip-ftp-host']) : false;
266 $dir = isset($this->post['bmip-ftp-backup-dir']) ? trim($this->post['bmip-ftp-backup-dir']) : '';
267 $port = isset($this->post['bmip-ftp-host-port']) && is_numeric($this->post['bmip-ftp-host-port']) ? (int)trim($this->post['bmip-ftp-host-port']) : 21;
268 $password = isset($this->post['bmip-ftp-password']) ? trim($this->post['bmip-ftp-password']) : false;
269 $userName = isset($this->post['bmip-ftp-username']) ? trim($this->post['bmip-ftp-username']) : false;
270
271 if (!$host) {
272 return ['status' => 'error', 'msg' => 'FTP Host is required and cannot be empty', 'errors' => 1];
273 }
274
275 if (!$userName) {
276 return ['status' => 'error', 'msg' => 'FTP Username is required and cannot be empty', 'errors' => 1];
277 }
278
279 if (!$password) {
280 return ['status' => 'error', 'msg' => 'FTP Password is required and cannot be empty', 'errors' => 1];
281 }
282
283 if ($dir[0] !== '/') {
284 $dir = '/' . $dir;
285 }
286
287
288 if (!function_exists('ftp_connect')) {
289 return [
290 'msg' => "FTP functions are not available on your server. Please make sure the FTP extension for PHP is installed and enabled.",
291 'status' => 'error',
292 'errors' => 1
293 ];
294 }
295
296 $ftp = ftp_connect($host, $port, 10);
297 if (!$ftp) {
298 return [
299 'msg' => "Could not connect to FTP server at $host on port $port. Please check the hostname and port.",
300 'status' => 'error',
301 'errors' => 1
302 ];
303 }
304
305 $login_result = @ftp_login($ftp, $userName, $password);
306 if (!$login_result) {
307 ftp_close($ftp);
308 return [
309 'msg' => 'Invalid FTP username or password. Please check your credentials.',
310 'status' => 'error',
311 'errors' => 1
312 ];
313 }
314
315 ftp_pasv($ftp, true);
316
317 // Try to change to the directory or create it if not found
318 if (!@ftp_chdir($ftp, $dir)) {
319 if (!@ftp_mkdir($ftp, $dir)) {
320 ftp_close($ftp);
321 return [
322 'msg' => "The backup directory '$dir' does not exist and could not be created. Please ensure you have the correct permissions to create directories on the FTP server.",
323 'status' => 'error',
324 'errors' => 1
325 ];
326 }
327 }
328
329 // Change into the backup directory
330 if (!@ftp_chdir($ftp, $dir)) {
331 ftp_close($ftp);
332 return [
333 'msg' => "Unable to navigate to the backup directory '$dir'. Please ensure it exists and has the correct permissions.",
334 'status' => 'error',
335 'errors' => 1
336 ];
337 }
338
339 // Permission check: Upload and download a temporary file
340 $testFile = 'bmi_ftp_test_' . uniqid() . '.txt';
341 $localTempPath = BMI_TMP . DIRECTORY_SEPARATOR . $testFile;
342 file_put_contents($localTempPath, "Permission check");
343
344 $upload = @ftp_put($ftp, $testFile, $localTempPath, FTP_ASCII);
345 $download = false;
346
347 if ($upload) {
348 // Try to download back to confirm read access
349 $downloadPath = $localTempPath . '_download';
350 $download = @ftp_get($ftp, $downloadPath, $testFile, FTP_ASCII);
351 }
352
353 // Cleanup
354 $delete = @ftp_delete($ftp, $testFile);
355
356 @unlink($localTempPath);
357 if (isset($downloadPath) && file_exists($downloadPath)) {
358 @unlink($downloadPath);
359 }
360
361 if (!$upload) {
362 ftp_close($ftp);
363 return [
364 'msg' => "Connected successfully, but upload permission check failed. Unable to upload files in '$dir'.",
365 'status' => 'error',
366 'errors' => 1
367 ];
368 }
369
370 if (!$download) {
371 ftp_close($ftp);
372 return [
373 'msg' => "Connected successfully, but download permission check failed. Unable to download files from '$dir'.",
374 'status' => 'error',
375 'errors' => 1
376 ];
377 }
378
379 if (!$delete) {
380 ftp_close($ftp);
381 return [
382 'msg' => "Connected successfully, but delete permission check failed. Unable to delete files in '$dir'.",
383 'status' => 'error',
384 'errors' => 1
385 ];
386 }
387
388 // Store the config and close connection
389 Dashboard\bmi_set_config('STORAGE::EXTERNAL::FTP', "true");
390
391 update_option('bmi_pro_ftp_host', $host);
392 update_option('bmi_pro_ftp_username', $userName);
393 update_option('bmi_pro_ftp_backup_dir', $dir);
394 update_option('bmi_pro_ftp_port', $port);
395 update_option('bmi_pro_ftp_password', $password);
396
397 ftp_close($ftp);
398
399 return [
400 'status' => 'success',
401 'errors' => 0
402 ];
403 }
404
405 private function disconnectFtp()
406 {
407 delete_option('bmi_pro_ftp_host');
408 delete_option('bmi_pro_ftp_backup_dir');
409 delete_option('bmi_pro_ftp_port');
410 delete_option('bmi_pro_ftp_username');
411 delete_option('bmi_pro_ftp_password');
412 Dashboard\bmi_set_config('STORAGE::EXTERNAL::FTP', "false");
413 return ['status' => 'success'];
414 }
415
416 private function getDropboxToken()
417 {
418
419 $bytes = random_bytes(36);
420 $token = bin2hex($bytes);
421
422 update_option('bmip_dropbox', $token);
423 return ['token' => $token];
424 }
425
426 private function keepDropboxToken()
427 {
428
429 $receivedToken = $this->post['receivedToken'];
430 $receivedAuthCode = $this->post['receivedClientID'];
431
432 $currentToken = get_option('bmip_dropbox', false);
433
434 if ($currentToken === $receivedToken) {
435
436 update_option('bmip_dropbox_auth_code', $receivedAuthCode);
437 return ['status' => 'success'];
438 } else {
439
440 return ['status' => 'token_mismatch'];
441 }
442 }
443
444 private function verifyDropboxConnection()
445 {
446
447 require_once BMI_INCLUDES . '/external/dropbox.php';
448
449 $dropbox = new Dropbox();
450 return $dropbox->verifyConnection();
451 }
452
453 private function disconnectDropboxToken()
454 {
455 require_once BMI_INCLUDES . '/external/dropbox.php';
456
457 $dropbox = new Dropbox();
458 $dropbox->disconnect();
459 delete_option($dropbox->dropboxAuthCodeOption);
460 delete_option($dropbox->dropboxId);
461 delete_transient($dropbox->dropboxAccessToken);
462 Dashboard\bmi_set_config('STORAGE::EXTERNAL::DROPBOX', 'false');
463
464 return ['status' => 'success'];
465 }
466
467
468 private function downloadCloudBackupV2()
469 {
470
471 require_once BMI_INCLUDES . '/progress/migration.php';
472
473 $secret = isset($this->post['secret']) ? $this->post['secret'] : false;
474 $startRestoreProcess = isset($this->post['startRestoreProcess']) ? $this->post['startRestoreProcess'] : 'true';
475 $lock = BMI_BACKUPS . '/.migration_lock';
476
477 if (file_exists($lock) && (time() - filemtime($lock)) < 1) {
478 $lockContent = file_get_contents($lock);
479 if ($lockContent !== $secret) {
480 return ['status' => 'msg', 'why' => __('Download process is currently running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
481 }
482 }
483
484 $externalStorage = null;
485 switch($this->post['f']){
486 case 'download-dropbox-backup':
487 require_once BMI_INCLUDES . '/external/dropbox.php';
488 $externalStorage = new Dropbox();
489 break;
490 default:
491 return ['status' => 'error'];
492 }
493 $fileId = isset($this->post['fileId']) ? $this->post['fileId'] : false; // Required
494 $md5 = isset($this->post['md5']) ? $this->post['md5'] : false; // Required
495 $step = isset($this->post['step']) ? intval($this->post['step']) : 0; // Required
496 $size = isset($this->post['size']) ? intval($this->post['size']) : false;
497 $fileName = isset($this->post['filename']) ? $this->post['filename'] : false;
498 $writePath = isset($this->post['writepath']) ? $this->post['writepath'] : false;
499 $chunkSize = isset($this->post['chunksize']) && (intval($this->post['chunksize']) != 0) ? intval($this->post['chunksize']) : BMP::getAvailableMemoryInBytes() / 4;
500 $migration = new MigrationProgress(($step === 0) ? false : true);
501
502
503 $migration->start();
504
505 if ($step === 0) {
506 $migration->log((__('Backup & Migration version: ', 'backup-backup') . BMI_VERSION));
507 $migration->log(__('Creating lock file', 'backup-backup'));
508 $secret = $this->randomString();
509 file_put_contents($lock, $secret);
510
511 $migration->log('Download intialized', 'INFO');
512 $migration->log('Getting backup details from cloud...', 'STEP');
513
514 $backupDetails = $externalStorage->getFileMeta($fileId);
515 if (!isset($backupDetails['name'])) $backupDetails['name'] = $fileId;
516
517
518 if ($backupDetails == false) {
519 $migration->log('It seem like I was unable to get backup details from cloud.', 'ERROR');
520 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
521 if (file_exists($lock)) @unlink($lock);
522
523 $migration->log('error_during_downloading_backup', 'verbose');
524 $migration->log('#002', 'END-CODE');
525 $migration->end();
526
527 return ['status' => 'error'];
528 }
529
530 $manifest = BMI_BACKUPS . DIRECTORY_SEPARATOR . $md5 . '.json';
531 $manifestContent = $externalStorage->getFileContent($md5 . '.json');
532 if ($manifestContent == false) {
533 $migration->log('It seem like I was unable to get backup manifest from cloud.', 'ERROR');
534 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
535 if (file_exists($lock)) @unlink($lock);
536
537 $migration->log('error_during_downloading_backup', 'verbose');
538 $migration->log('#002', 'END-CODE');
539 $migration->end();
540
541 return ['status' => 'error'];
542 }
543 file_put_contents($manifest, $manifestContent);
544
545
546 $size = intval($backupDetails['size']);
547 $fileName = $backupDetails['name'];
548
549 $migration->log('Backup details received!', 'SUCCESS');
550 $migration->log('Backup original name: ' . $fileName, 'INFO');
551 $migration->log('Starting download process...', 'STEP');
552
553 $availableMemory = BMP::getAvailableMemoryInBytes();
554 $bytesPerRequest = intval($availableMemory / 4);
555
556
557 $migration->log('Single batch will use up to: ' . $bytesPerRequest . ' bytes (~' . intval($bytesPerRequest / 1024 / 1024 / 2) . ' MBs)', 'INFO');
558
559 $fileIterator = 2;
560 $extension = pathinfo($fileName, PATHINFO_EXTENSION);
561 $fileName = pathinfo($fileName, PATHINFO_FILENAME);
562 if ($extension == 'gz') {
563 $fileName = pathinfo($fileName, PATHINFO_FILENAME);
564 $extension = 'tar.gz';
565 }
566
567 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $fileName . '.' . $extension;
568 $finalName = $fileName . '.' . $extension;
569
570 while (file_exists($backupDestinationPath)) {
571 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $fileName . '-' . $fileIterator . '.' . $extension;
572 $fileIterator++;
573 }
574
575 $originalFilename = $finalName;
576
577 $backupDestinationPath .= '.crdownload';
578 } else {
579 $bytesPerRequest = intval($chunkSize);
580 $backupDestinationPath = $writePath;
581 $originalFilename = $fileName;
582 }
583
584 $totalBatches = ceil($size / (256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2)));
585
586 if ($totalBatches <= $step) {
587 $migration->log('Verifying MD5 checksum of downloaded file...', 'STEP');
588
589 rename($backupDestinationPath, str_replace('.crdownload', '', $backupDestinationPath));
590 $backupDestinationPath = str_replace('.crdownload', '', $backupDestinationPath);
591
592 $local_md5 = md5_file($backupDestinationPath);
593 if (file_exists($backupDestinationPath) && $local_md5 == $md5) {
594
595
596 $migration->log('Downloaded MD5: ' . $local_md5, 'INFO');
597 $migration->log('Expected MD5: ' . $md5, 'INFO');
598 $migration->log('File MD5 checksum is correct!', 'SUCCESS');
599 } else {
600
601 $migration->log('File MD5 checksum is NOT correct!', 'ERROR');
602 $migration->log('Downloaded MD5: ' . $local_md5, 'ERROR');
603 $migration->log('Expected MD5: ' . $md5, 'ERROR');
604 $migration->log('Downloaded file path: ' . $backupDestinationPath, 'ERROR');
605 $migration->log('File exist?: ' . (file_exists($backupDestinationPath) ? "Yes" : "No?"), 'ERROR');
606 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
607 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
608 if (file_exists($lock)) @unlink($lock);
609
610 $migration->log('error_during_downloading_backup', 'verbose');
611 $migration->log('#002', 'END-CODE');
612 $migration->end();
613
614 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
615 return ['status' => 'error'];
616 }
617
618 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
619 if (file_exists($lock)) @unlink($lock);
620 if ($startRestoreProcess == 'true') {
621 $migration->log('Download process finished!', 'SUCCESS');
622 $migration->log('Requesting restoration process...', 'STEP');
623
624 $migration->log('#205', 'END-CODE');
625 } else {
626 $migration->log('Download process finished!', 'SUCCESS');
627 $migration->log('#206', 'END-CODE');
628 }
629
630 $migration->progress(100);
631 $migration->end();
632
633 return ['status' => 'success', 'finished' => 'true', 'filename' => $originalFilename];
634 } else {
635
636 $chunkSize = 256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2);
637 $startRange = ($step * $chunkSize);
638 if ($step !== 0) $startRange = $startRange + 1;
639 $endRange = (($step + 1) * $chunkSize);
640 if ($endRange > $size) $endRange = $size;
641 $currentRange = $startRange . '-' . $endRange;
642 $percentage = intval(($endRange / $size) * 100);
643
644 $contents = $externalStorage->getFileContent($fileId, $currentRange);
645
646 if ($contents == false) {
647
648 $migration->log('It seem like I was unable to get backup content from cloud.', 'ERROR');
649 $migration->log('For security reasons, I will remove the file (if exist) and stop the process...', 'ERROR');
650 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
651 if (file_exists($lock)) @unlink($lock);
652
653 $migration->log('error_during_downloading_backup', 'verbose');
654 $migration->log('#002', 'END-CODE');
655 $migration->end();
656
657 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
658 return ['status' => 'error'];
659 }
660
661 if ((is_dir(dirname($backupDestinationPath)) && file_exists($backupDestinationPath)) || $step === 0) {
662
663 $backupFile = fopen($backupDestinationPath, 'ab');
664 fwrite($backupFile, $contents);
665 unset($contents);
666 fclose($backupFile);
667 } else {
668
669 $migration->log('File is not writable or directory does not exist.', 'ERROR');
670 $migration->log('File: ' . basename($backupDestinationPath), 'ERROR');
671 $migration->log('Dirname: ' . dirname($backupDestinationPath), 'ERROR');
672 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
673 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
674 if (file_exists($lock)) @unlink($lock);
675
676 $migration->log('error_during_downloading_backup', 'verbose');
677 $migration->log('#002', 'END-CODE');
678 $migration->end();
679
680 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
681 return ['status' => 'error'];
682 }
683
684 $migration->log('Download progress (' . ($step + 1) . '/' . $totalBatches . '): ' . $endRange . '/' . $size . ' (' . $percentage . '%)', 'INFO');
685 $migration->progress($percentage);
686 $migration->end();
687
688 return [
689 'status' => 'success',
690 'size' => $size,
691 'md5' => $md5,
692 'finished' => 'false',
693 'originalFilename' => $originalFilename,
694 'writepath' => $backupDestinationPath,
695 'chunksize' => $bytesPerRequest,
696 'secret' => $secret
697 ];
698 }
699 }
700
701 /**
702 * getGDriveToken - Generates client sided auth token
703 *
704 * @return string Token
705 */
706 private function getGDriveToken()
707 {
708
709 $bytes = random_bytes(36);
710 $token = bin2hex($bytes);
711 $backupDirectoryPath = $this->post['backupDirectoryPath'];
712 if (!preg_match("/^[a-zA-Z0-9\_\ \-\.]+$/", $backupDirectoryPath)) {
713 return ['status' => 'msg', 'why' => __('Entered directory name does not match allowed characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
714 }
715
716 if (strlen(trim($backupDirectoryPath)) < 3) {
717 return ['status' => 'msg', 'why' => __('Entered directory name is too short, min 3 characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
718 }
719
720 if (strlen(trim($backupDirectoryPath)) > 48) {
721 return ['status' => 'msg', 'why' => __('Entered directory name is too long, max 48 characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
722 }
723
724 update_option('bmi_pro_gd_token', $token);
725 Dashboard\bmi_set_config('STORAGE::EXTERNAL::GDRIVE::DIRNAME', $backupDirectoryPath);
726
727 return [ 'status' => 'success', 'token' => $token];
728 }
729
730 /**
731 * keepGDriveToken - Saves Client Token for GDrive API - BMI API communication
732 *
733 * @return json status
734 */
735 private function keepGDriveToken()
736 {
737
738 $receivedToken = $this->post['receivedToken'];
739 $receivedClientID = $this->post['receivedClientID'];
740
741 $currentToken = get_option('bmi_pro_gd_token', false);
742
743 if ($currentToken === $receivedToken) {
744
745 update_option('bmi_pro_gd_client_id', $receivedClientID);
746 return ['status' => 'success'];
747 } else {
748
749 return ['status' => 'token_mismatch'];
750 }
751 }
752
753 /**
754 * getGDriveConnectionStatus - Returns Connection Status for PHP
755 *
756 * @return boolean true on connected | false on disconnected
757 */
758 public function getGDriveConnectionStatus()
759 {
760
761 $status = $this->verifyGDriveConnection();
762 if (isset($status['result']) && $status['result'] == 'connected') {
763 return true;
764 } else {
765 return false;
766 }
767 }
768
769 /**
770 * verifyGDriveConnection - Checks if the GDrive is still granted and tokens are not expired
771 *
772 * @return json rtoken
773 */
774 private function verifyGDriveConnection()
775 {
776
777 // Install Drive Keys
778 $tempKeyDriveFile = BMI_TMP . DIRECTORY_SEPARATOR . 'driveKeys.php';
779 if (file_exists($tempKeyDriveFile)) {
780
781 $driveKeys = file_get_contents($tempKeyDriveFile);
782
783 if (strpos($driveKeys, "\n") !== false) {
784
785 $lines = explode("\n", $driveKeys);
786
787 if (sizeof($lines) == 4) {
788 $pro_gd_token = substr($lines[1], 2);
789 $pro_gd_client_id = substr($lines[2], 2);
790
791 if (function_exists('wp_load_alloptions')) {
792 wp_load_alloptions(true);
793 }
794 delete_option('bmi_pro_gd_token');
795 delete_option('bmi_pro_gd_client_id');
796 if (function_exists('wp_load_alloptions')) {
797 wp_load_alloptions(true);
798 }
799 update_option('bmi_pro_gd_token', $pro_gd_token);
800 update_option('bmi_pro_gd_client_id', $pro_gd_client_id);
801 }
802 }
803
804 if (strpos(site_url(), 'tastewp') !== false) {
805 if (function_exists('wp_load_alloptions')) {
806 wp_load_alloptions(true);
807 }
808
809 update_option('__tastewp_redirection_performed', true);
810 update_option('auto_smart_tastewp_redirect_performed', 1);
811 update_option('tastewp_auto_activated', true);
812 update_option('__tastewp_sub_requested', true);
813 }
814
815 unlink($tempKeyDriveFile);
816 }
817
818 $baseurl = home_url();
819 if (substr($baseurl, 0, 4) != 'http') {
820 if (is_ssl()) $baseurl = 'https://' . home_url();
821 else $baseurl = 'http://' . home_url();
822 }
823
824 $client_token = get_option('bmi_pro_gd_client_id', '');
825 $site_token = get_option('bmi_pro_gd_token', '');
826
827 if (strlen($site_token) < 60 || strlen($client_token) < 60) {
828 return ['status' => 'success', 'result' => 'disconnected'];
829 }
830
831 $url = 'https://authentication.backupbliss.com/v1/gdrive/verify';
832 $response = wp_remote_post($url, array(
833 'method' => 'POST',
834 'timeout' => 15,
835 'redirection' => 2,
836 'httpversion' => '1.0',
837 'blocking' => true,
838 'body' => array(
839 'client_id' => get_option('bmi_pro_gd_client_id', ''),
840 'site_token' => get_option('bmi_pro_gd_token', ''),
841 'redirect_uri' => $baseurl,
842 'force_refresh' => get_transient('bmip_gd_issue') === 'auth_error' && get_transient('bmi_pro_access_token') !== false
843 )
844 ));
845
846 $res = 'disconnected';
847 if (is_wp_error($response)) {
848 $error_message = $response->get_error_message();
849 Logger::error('[BMI PRO] Something went wrong during GDrive connection verification:' . $error_message);
850 return ['status' => 'error', 'result' => 'disconnected'];
851 } else {
852 $result = json_decode($response['body']);
853 if (isset($result->status)) {
854 if (isset($result->expiration) && isset($result->access_token)) {
855 $expiresInSeconds = intval($result->expiration) - intval(microtime(true));
856 $accessToken = $result->access_token;
857 set_transient('bmi_pro_access_token', $accessToken, $expiresInSeconds);
858 }
859
860 if ($result->status == 'disconnected') {
861 $res = 'disconnected';
862 if (get_transient('bmip_gd_issue') === 'auth_error' && get_transient('bmi_pro_access_token') !== false) {
863 set_transient('bmip_gd_issue', 'auth_error_disconnected');
864 delete_transient('bmi_pro_access_token');
865 }
866 }
867 if ($result->status == 'connected'){
868 $res = 'connected';
869 if (in_array(get_transient('bmip_gd_issue'), ['auth_error', 'auth_error_disconnected'])) delete_transient('bmip_gd_issue');
870 }
871 if ($result->status == 'error') $res = 'disconnected';
872 }
873 return ['status' => 'success', 'result' => $res];
874 }
875 }
876
877 /**
878 * removeGDriveConnection - Removed GDrive connection from BMI API
879 *
880 * @return json rtoken
881 */
882 private function removeGDriveConnection()
883 {
884
885 $baseurl = home_url();
886 if (substr($baseurl, 0, 4) != 'http') {
887 if (is_ssl()) $baseurl = 'https://' . home_url();
888 else $baseurl = 'http://' . home_url();
889 }
890
891 $client_token = get_option('bmi_pro_gd_client_id', '');
892 $site_token = get_option('bmi_pro_gd_token', '');
893
894 if (strlen($site_token) < 60 || strlen($client_token) < 60) {
895 return ['status' => 'success'];
896 }
897
898 $url = 'https://authentication.backupbliss.com/v1/gdrive/disconnect';
899 $response = wp_remote_post($url, array(
900 'method' => 'POST',
901 'timeout' => 15,
902 'redirection' => 2,
903 'httpversion' => '1.0',
904 'blocking' => true,
905 'body' => array(
906 'client_id' => get_option('bmi_pro_gd_client_id', ''),
907 'site_token' => get_option('bmi_pro_gd_token', ''),
908 'redirect_uri' => $baseurl
909 )
910 ));
911
912 if (is_wp_error($response)) {
913 $error_message = $response->get_error_message();
914 Logger::error('[BMI PRO] Something went wrong during GDrive removal process:' . $error_message);
915 return ['status' => 'error'];
916 }
917 }
918
919 /**
920 * disconnectGDriveToken - Removes connection with GDrive API
921 *
922 * @return json status
923 */
924 private function disconnectGDriveToken()
925 {
926
927 $this->removeGDriveConnection();
928 delete_option('bmi_pro_gd_client_id');
929 delete_option('bmi_pro_gd_token');
930 delete_transient('bmi_pro_access_token');
931 Dashboard\bmi_set_config('STORAGE::EXTERNAL::GDRIVE', 'false');
932
933 return ['status' => 'success'];
934 }
935
936 private function dismissDropboxNotice()
937 {
938 update_option('bmip_dropbox_dismiss_issue', true);
939 return ['status' => 'success'];
940 }
941
942 public function saveAWSConfig()
943 {
944 $accessKey = isset($this->post['access-key']) ? $this->post['access-key'] : '';
945 $secretKey = isset($this->post['secret-key']) ? $this->post['secret-key'] : '';
946 $bucket = isset($this->post['bucket']) ? $this->post['bucket'] : '';
947 $sse = isset($this->post['sse']) ? $this->post['sse'] : '';
948 $storageClass = isset($this->post['storage-class']) ? $this->post['storage-class'] : 'STANDARD';
949 $path = isset($this->post['path']) ? $this->post['path'] : '';
950 $path = trim($path, '/');
951 $region = isset($this->post['region']) ? $this->post['region'] : '';
952
953 // VALIDATE INPUTS
954 if (empty($accessKey) || empty($secretKey) || empty($bucket) || empty($region)) {
955 return ['status' => 'error', 'msg' => __('Please fill all the required fields.', 'backup-backup')];
956 }
957
958 if (!preg_match('/^[a-zA-Z0-9-]*$/', $bucket)) {
959 return ['status' => 'error', 'msg' => __('Bucket name can only contain letters, numbers and hyphens.', 'backup-backup')];
960 }
961
962 if (!in_array($storageClass, ['STANDARD', 'STANDARD_IA', 'REDUCED_REDUNDANCY'])) {
963 return ['status' => 'error', 'msg' => __('Invalid storage class.', 'backup-backup')];
964 }
965
966 if (!in_array($sse, ['AES256', ''])) {
967 return ['status' => 'error', 'msg' => __('Invalid server-side encryption.', 'backup-backup')];
968 }
969
970 if (!in_array($region, [
971 'us-east-1','us-east-2','us-west-1','us-west-2','af-south-1','ap-east-1','ap-south-1','ap-northeast-3','ap-northeast-2','ap-southeast-1','ap-southeast-2','ap-northeast-1','ca-central-1','eu-central-1','eu-west-1','eu-west-2','eu-south-1','eu-west-3','eu-north-1','me-south-1','sa-east-1'
972 ])) {
973 return ['status' => 'error', 'msg' => __('Invalid region.', 'backup-backup')];
974 }
975
976 // Test the connection
977 require_once BMI_INCLUDES . '/external/s3.php';
978 $s3 = new S3('aws');
979
980 $testConnection = $s3->testConnection( $accessKey, $secretKey, $bucket, $region, $path, $storageClass, $sse);
981
982 if ($testConnection['status'] == 'error') {
983 return ['status' => 'error', 'msg' => $testConnection['error']];
984 }
985
986 Dashboard\bmi_set_config('STORAGE::EXTERNAL::AWS', 'true');
987 update_option('bmip_aws_access_key', $accessKey);
988 update_option('bmip_aws_secret_key', $secretKey);
989 update_option('bmip_aws_bucket', $bucket);
990 update_option('bmip_aws_storage_class', $storageClass);
991 update_option('bmip_aws_path', $path);
992 update_option('bmip_aws_sse', $sse);
993 set_transient('bmip_aws_connection_status', true, HOUR_IN_SECONDS);
994 update_option('bmip_aws_region', $region);
995
996 return ['status' => 'success'];
997 }
998
999 public function disconnectAWS()
1000 {
1001
1002 require_once BMI_INCLUDES . '/external/s3.php';
1003 $s3 = new S3('aws');
1004 $s3->disconnect();
1005
1006 return ['status' => 'success'];
1007 }
1008
1009 /**
1010 * Verify AWS S3 connection
1011 *
1012 * @return array
1013 */
1014 private function verifyAWSConnection()
1015 {
1016 require_once BMI_INCLUDES . '/external/s3.php';
1017 $s3 = new S3('aws');
1018 $status = $s3->verifyConnection();
1019 if ($status['result'] == 'connected') {
1020 return [
1021 'status' => 'success',
1022 'result' => 'connected',
1023 'configs' => $s3->retrieveS3Configs(),
1024 ];
1025 }
1026 return [
1027 'status' => 'success',
1028 'result' => 'disconnected',
1029 ];
1030 }
1031
1032 /**
1033 * Save the selected files, directories and tables for restore process
1034 * required post data:
1035 * - access-key
1036 * - secret-key
1037 * - bucket
1038 * - region
1039 * - path (OPTIONAL)
1040 *
1041 *
1042 * @return array{msg: mixed, status: string|array{msg: string, status: string}|array{status: string}}
1043 */
1044 public function saveWasabiConfig()
1045 {
1046 $accessKey = isset($this->post['access-key']) ? $this->post['access-key'] : '';
1047 $secretKey = isset($this->post['secret-key']) ? $this->post['secret-key'] : '';
1048 $bucket = isset($this->post['bucket']) ? $this->post['bucket'] : '';
1049 $path = isset($this->post['path']) ? $this->post['path'] : '';
1050 $path = trim($path, '/');
1051 $region = isset($this->post['region']) ? $this->post['region'] : '';
1052
1053 // VALIDATE INPUTS
1054 if (empty($accessKey) || empty($secretKey) || empty($bucket) || empty($region)) {
1055 return ['status' => 'error', 'msg' => __('Please fill all the required fields.', 'backup-backup')];
1056 }
1057
1058 // Test the connection
1059 require_once BMI_INCLUDES . '/external/s3.php';
1060 $s3 = new S3('wasabi');
1061
1062 $testConnection = $s3->testConnection($accessKey, $secretKey, $bucket, $region, $path);
1063
1064 if ($testConnection['status'] == 'error') {
1065 return ['status' => 'error', 'msg' => $testConnection['error']];
1066 }
1067
1068 Dashboard\bmi_set_config('STORAGE::EXTERNAL::WASABI', 'true');
1069 update_option('bmip_wasabi_access_key', $accessKey);
1070 update_option('bmip_wasabi_secret_key', $secretKey);
1071 update_option('bmip_wasabi_bucket', $bucket);
1072 update_option('bmip_wasabi_path', $path);
1073 update_option('bmip_wasabi_sse', '');
1074 update_option('bmip_wasabi_storage_class', 'STANDARD');
1075 set_transient('bmip_wasabi_connection_status', true, HOUR_IN_SECONDS);
1076 update_option('bmip_wasabi_region', $region);
1077
1078 return ['status' => 'success'];
1079 }
1080
1081 public function disconnectWasabi()
1082 {
1083 require_once BMI_INCLUDES . '/external/s3.php';
1084 $s3 = new S3('wasabi');
1085 $s3->disconnect();
1086
1087 return ['status' => 'success'];
1088 }
1089
1090 private function verifyWasabiConnection()
1091 {
1092 require_once BMI_INCLUDES . '/external/s3.php';
1093 $s3 = new S3('wasabi');
1094 $status = $s3->verifyConnection();
1095 if ($status['result'] == 'connected') {
1096 return [
1097 'status' => 'success',
1098 'result' => 'connected',
1099 'configs' => $s3->retrieveS3Configs(),
1100 ];
1101 }
1102 return [
1103 'status' => 'success',
1104 'result' => 'disconnected',
1105 ];
1106 }
1107
1108 /**
1109 * shareDomainForAutoCron - Allows our API to keep scheduled backups on time
1110 *
1111 * @return array format:{status: string, msg?: string}
1112 *
1113 */
1114 private function shareDomainForAutoCron($force = false)
1115 {
1116
1117 $cron_shared = get_option('bmi_cron_new_domain_done', false);
1118 if (($cron_shared || get_transient('bmi_cron_share_attempted')) && !$force) return ['status' => 'success'];
1119 set_transient('bmi_cron_share_attempted', true, HOUR_IN_SECONDS);
1120 $baseurl = home_url();
1121 if (substr($baseurl, 0, 4) != 'http') {
1122 if (is_ssl()) $baseurl = 'https://' . home_url();
1123 else $baseurl = 'http://' . home_url();
1124 }
1125
1126 $sk = get_option('bmi_sk_keepalive');
1127 if (empty($sk)) {
1128 $sk = wp_generate_password(32, false);
1129 update_option('bmi_sk_keepalive', $sk);
1130 }
1131
1132 $url = 'https://authentication.backupbliss.com/v2/crons/connect';
1133 $response = wp_remote_post($url, array(
1134 'method' => 'POST',
1135 'timeout' => 15,
1136 'redirection' => 2,
1137 'httpversion' => '1.0',
1138 'blocking' => true,
1139 'body' => array('site' => $baseurl, 'sk' => $sk)
1140 ));
1141
1142 if (!is_wp_error($response)) {
1143 $response = json_decode($response['body'], true);
1144 if (isset($response['status']) && $response['status'] === 'success') {
1145 update_option('bmi_cron_new_domain_done', true);
1146 return ['status' => 'success'];
1147 } elseif (isset($response['status']) && $response['status'] === 'error' && $response['message']=== 'Handshake failed - Invalid SK or Site unreachable') {
1148 Logger::error('Site is locally hosted or could not be reached by Backup & Migration API for cron verification. Cron jobs might not work as expected.');
1149 update_option('bmi_cron_new_domain_done', true);
1150 return ['status' => 'error', 'msg' => 'Site is locally hosted or could not be reached by Backup & Migration API for cron verification. Cron jobs might not work as expected.'];
1151 } else {
1152 Logger::error('Unknown error occurred during cron domain sharing.');
1153 $responseMsg = isset($response['message']) ? $response['message'] : 'Unknown error occurred during cron domain sharing.';
1154 Logger::error('Response message: ' . $responseMsg);
1155 return ['status' => 'error', 'msg' => $responseMsg];
1156 }
1157 }
1158 Logger::error('Unknown error occurred during cron domain sharing.');
1159 $responseMsg = wp_remote_retrieve_response_message($response) ? wp_remote_retrieve_response_message($response) : 'Unknown error occurred during cron domain sharing.';
1160 Logger::error('Response message: ' . $responseMsg);
1161 return ['status' => 'error', 'msg' => $responseMsg];
1162 }
1163
1164 /**
1165 * randomString - Generates "random" string
1166 *
1167 * @return string "random"
1168 */
1169 private function randomString($length = 64)
1170 {
1171
1172 $chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1173 $str = "";
1174
1175 for ($i = 0; $i < $length; ++$i) {
1176
1177 $str .= $chars[mt_rand(0, strlen($chars) - 1)];
1178 }
1179
1180 return $str;
1181 }
1182
1183 /**
1184 * downloadCloudBackup - Downloads Cloud Backup to Local Storage
1185 *
1186 * @return json status
1187 */
1188 private function downloadCloudBackup()
1189 {
1190
1191 $secret = false;
1192 if (isset($this->post['secret'])) $secret = $this->post['secret'];
1193
1194 $lock = BMI_BACKUPS . '/.migration_lock';
1195 if (file_exists($lock) && (time() - filemtime($lock)) < 1) {
1196 $lockContent = file_get_contents($lock);
1197 if ($lockContent !== $secret) {
1198 return ['status' => 'msg', 'why' => __('Download process is currently running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
1199 }
1200 }
1201
1202 require_once BMI_INCLUDES . '/progress/migration.php';
1203
1204 $step = intval($this->post['step']);
1205 $storage = $this->post['storage'];
1206 $startRestoreProcess = isset($this->post['startRestoreProcess']) ? $this->post['startRestoreProcess'] : 'true';
1207
1208 $clearFile = ($step === 0) ? false : true;
1209 $migration = new MigrationProgress($clearFile);
1210 $migration->start();
1211
1212 if ($storage == 'backupbliss') {
1213
1214 require_once BMI_INCLUDES . '/external/backupbliss.php';
1215 $backupbliss = new BackupBliss();
1216
1217 $backupDetails = false;
1218 $fileId = $this->post['fileId'];
1219
1220 if ($step === 0 || (!isset($this->post['size']) || $this->post['size'] == false || !is_numeric($this->post['size']))) {
1221
1222 $migration->log((__('Backup & Migration version: ', 'backup-backup') . BMI_VERSION));
1223 $migration->log(__('Creating lock file', 'backup-backup'));
1224 $secret = $this->randomString();
1225 file_put_contents($lock, $secret);
1226
1227 $migration->log('Download intialized', 'INFO');
1228 $migration->log('Getting backup details from BackupBliss...', 'STEP');
1229 $backupDetails = $backupbliss->getFileDetailByName($fileId);
1230
1231 if (!$backupDetails) {
1232
1233 $migration->log("Couldn't fetch backup details from cloud.", 'ERROR');
1234 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1235 if (file_exists($lock)) @unlink($lock);
1236
1237 $migration->log('error_during_downloading_backup', 'verbose');
1238 $migration->log('#002', 'END-CODE');
1239 $migration->end();
1240
1241 return ['status' => 'error'];
1242 }
1243
1244 $size = intval($backupDetails['size']);
1245 $originalFilename = $backupDetails['name'];
1246
1247 $migration->log('Backup details received!', 'SUCCESS');
1248 $migration->log('Backup original name: ' . $originalFilename, 'INFO');
1249 $migration->log('Starting download process...', 'STEP');
1250
1251 $availableMemory = BMP::getAvailableMemoryInBytes();
1252 $bytesPerRequest = intval($availableMemory / 4);
1253
1254 $migration->log('Single batch will use up to: ' . $bytesPerRequest . ' bytes (~' . intval($bytesPerRequest / 1024 / 1024 / 2) . ' MBs)', 'INFO');
1255
1256 $fileIterator = 2;
1257 $originalFilenameInfo = pathinfo($originalFilename);
1258 $extension = $originalFilenameInfo['extension'];
1259 $originalFilename = $originalFilenameInfo['filename'];
1260 if ($originalFilenameInfo['extension'] == 'gz') {
1261 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
1262 $extension = 'tar.gz';
1263 }
1264
1265 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '.' . $extension;
1266 $finalName = $originalFilename . '.' . $extension;
1267
1268 while (file_exists($backupDestinationPath)) {
1269 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '-' . $fileIterator . '.' . $extension;
1270 $finalName = $originalFilename . '-' . $fileIterator . '.' . $extension;
1271 $fileIterator++;
1272 }
1273
1274 $originalFilename = $finalName;
1275
1276 $backupDestinationPath .= '.crdownload';
1277
1278 } else {
1279
1280 $size = intval($this->post['size']);
1281 $originalFilename = $this->post['filename'];
1282 $backupDestinationPath = $this->post['writepath'];
1283 $bytesPerRequest = intval($this->post['chunksize']);
1284 }
1285
1286 $md5 = $this->post['md5'];
1287
1288 $totalBatches = ceil($size / (256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2)));
1289
1290 if ($totalBatches <= $step) {
1291
1292 $migration->log('Download process finished!', 'SUCCESS');
1293 $migration->log('Verifying MD5 checksum of downloaded file...', 'STEP');
1294
1295 rename($backupDestinationPath, str_replace('.crdownload', '', $backupDestinationPath));
1296 $backupDestinationPath = str_replace('.crdownload', '', $backupDestinationPath);
1297
1298
1299 $local_md5 = hash_file('md5', $backupDestinationPath);
1300 if (file_exists($backupDestinationPath) && $local_md5 == $md5) {
1301
1302 $migration->log('Downloaded MD5: ' . $local_md5, 'INFO');
1303 $migration->log('Expected MD5: ' . $md5, 'INFO');
1304 $migration->log('File MD5 checksum is correct!', 'SUCCESS');
1305 } else {
1306
1307 $migration->log('File MD5 checksum is NOT correct!', 'ERROR');
1308 $migration->log('Downloaded MD5: ' . $local_md5, 'ERROR');
1309 $migration->log('Expected MD5: ' . $md5, 'ERROR');
1310 $migration->log('Downloaded file path: ' . $backupDestinationPath, 'ERROR');
1311 $migration->log('File exist?: ' . (file_exists($backupDestinationPath) ? "Yes" : "No?"), 'ERROR');
1312 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1313 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1314 if (file_exists($lock)) @unlink($lock);
1315
1316 $migration->log('error_during_downloading_backup', 'verbose');
1317 $migration->log('#002', 'END-CODE');
1318 $migration->end();
1319
1320 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1321 return ['status' => 'error'];
1322 }
1323
1324 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1325 if (file_exists($lock)) @unlink($lock);
1326 if ($startRestoreProcess == 'true') {
1327 $migration->log('Requesting restoration process...', 'STEP');
1328
1329 $migration->log('#205', 'END-CODE');
1330 } else {
1331 $migration->log('Download process finished!', 'SUCCESS');
1332 $migration->log('#206', 'END-CODE');
1333 }
1334 $migration->progress(100);
1335 $migration->end();
1336
1337 return ['status' => 'success', 'finished' => 'true', 'filename' => $originalFilename];
1338 } else {
1339
1340 $chunkSize = 256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2);
1341 $startRange = ($step * $chunkSize);
1342 if ($step !== 0) $startRange = $startRange + 1;
1343 $endRange = (($step + 1) * $chunkSize);
1344 if ($endRange > $size) $endRange = $size;
1345 $percentage = intval(($endRange / $size) * 100);
1346
1347 $data = $backupbliss->getFile($fileId, $startRange, $endRange);
1348
1349 if (!$data["file_detail"] || !$data["file_data"]) {
1350
1351 $migration->log("Couldn't fetch backup file from cloud.", 'ERROR');
1352 $migration->log('For security reasons, I will remove the file (if exist) and stop the process...', 'ERROR');
1353 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1354 if (file_exists($lock)) @unlink($lock);
1355
1356 $migration->log('error_during_downloading_backup', 'verbose');
1357 $migration->log('#002', 'END-CODE');
1358 $migration->end();
1359
1360 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1361 return ['status' => 'error'];
1362 }
1363
1364 if ((is_dir(dirname($backupDestinationPath)) && file_exists($backupDestinationPath)) || $step === 0) {
1365
1366 $backupFile = fopen($backupDestinationPath, 'ab');
1367 fwrite($backupFile, $data['file_data']);
1368 fclose($backupFile);
1369 } else {
1370
1371 $migration->log('File is not writable or directory does not exist.', 'ERROR');
1372 $migration->log('File: ' . basename($backupDestinationPath), 'ERROR');
1373 $migration->log('Dirname: ' . dirname($backupDestinationPath), 'ERROR');
1374 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1375 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1376 if (file_exists($lock)) @unlink($lock);
1377
1378 $migration->log('error_during_downloading_backup', 'verbose');
1379 $migration->log('#002', 'END-CODE');
1380 $migration->end();
1381
1382 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1383 return ['status' => 'error'];
1384 }
1385
1386 $migration->log('Download progress (' . ($step + 1) . '/' . $totalBatches . '): ' . $endRange . '/' . $size . ' (' . $percentage . '%)', 'INFO');
1387 $migration->progress($percentage);
1388 $migration->end();
1389
1390 return [
1391 'status' => 'success',
1392 'size' => $size,
1393 'md5' => $md5,
1394 'finished' => 'false',
1395 'originalFilename' => $originalFilename,
1396 'writepath' => $backupDestinationPath,
1397 'chunksize' => $bytesPerRequest,
1398 'secret' => $secret
1399 ];
1400 }
1401 }
1402
1403 if ($storage == 'googledrive') {
1404
1405 require_once BMI_INCLUDES . '/external/google-drive.php';
1406 $gdrive = new GDrive();
1407
1408 $backupDetails = false;
1409 $fileId = $this->post['fileId'];
1410
1411 if ($step === 0 || (!isset($this->post['size']) || $this->post['size'] == false || !is_numeric($this->post['size']))) {
1412
1413 $migration->log((__('Backup & Migration version: ', 'backup-backup') . BMI_VERSION));
1414 $migration->log(__('Creating lock file', 'backup-backup'));
1415 $secret = $this->randomString();
1416 file_put_contents($lock, $secret);
1417
1418 $migration->log('Download intialized', 'INFO');
1419 $migration->log('Getting backup details from Google Drive...', 'STEP');
1420 $backupDetails = $gdrive->getGoogleDriveFileMeta($fileId);
1421
1422 if ($backupDetails == false || !isset($backupDetails['data']) || $backupDetails['data'] == false) {
1423
1424 $migration->log('It seem like I was unable to get backup details from cloud.', 'ERROR');
1425 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1426 if (file_exists($lock)) @unlink($lock);
1427
1428 $migration->log('error_during_downloading_backup', 'verbose');
1429 $migration->log('#002', 'END-CODE');
1430 $migration->end();
1431
1432 return ['status' => 'error'];
1433 }
1434
1435 $size = intval($backupDetails['data']->size);
1436 $md5 = $backupDetails['data']->md5Checksum;
1437 $originalFilename = $backupDetails['data']->originalFilename;
1438
1439 $migration->log('Backup details received!', 'SUCCESS');
1440 $migration->log('Backup original name: ' . $originalFilename, 'INFO');
1441 $migration->log('Starting download process...', 'STEP');
1442
1443 $availableMemory = BMP::getAvailableMemoryInBytes();
1444 $bytesPerRequest = intval($availableMemory / 4);
1445
1446 $migration->log('Single batch will use up to: ' . $bytesPerRequest . ' bytes (~' . intval($bytesPerRequest / 1024 / 1024 / 2) . ' MBs)', 'INFO');
1447
1448 $fileIterator = 2;
1449 $extension = pathinfo($originalFilename, PATHINFO_EXTENSION);
1450 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
1451 if ($extension == 'gz') {
1452 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
1453 $extension = 'tar.gz';
1454 }
1455 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '.' . $extension;
1456 $finalName = $originalFilename . '.' . $extension;
1457
1458 while (file_exists($backupDestinationPath)) {
1459 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '-' . $fileIterator . '.' . $extension;
1460 $finalName = $originalFilename . '-' . $fileIterator . '.' . $extension;
1461 $fileIterator++;
1462 }
1463
1464 $originalFilename = $finalName;
1465
1466 $backupDestinationPath .= '.crdownload';
1467
1468 } else {
1469
1470 $size = intval($this->post['size']);
1471 $md5 = $this->post['md5'];
1472 $originalFilename = $this->post['filename'];
1473 $backupDestinationPath = $this->post['writepath'];
1474 $bytesPerRequest = intval($this->post['chunksize']);
1475 }
1476
1477 $totalBatches = ceil($size / (256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2)));
1478
1479 if ($totalBatches <= $step) {
1480
1481 $migration->log('Download process finished!', 'SUCCESS');
1482 $migration->log('Verifying MD5 checksum of downloaded file...', 'STEP');
1483
1484 rename($backupDestinationPath, str_replace('.crdownload', '', $backupDestinationPath));
1485 $backupDestinationPath = str_replace('.crdownload', '', $backupDestinationPath);
1486
1487
1488 $local_md5 = md5_file($backupDestinationPath);
1489 if (file_exists($backupDestinationPath) && $local_md5 == $md5) {
1490
1491 $migration->log('Downloaded MD5: ' . $local_md5, 'INFO');
1492 $migration->log('Expected MD5: ' . $md5, 'INFO');
1493 $migration->log('File MD5 checksum is correct!', 'SUCCESS');
1494 } else {
1495
1496 $migration->log('File MD5 checksum is NOT correct!', 'ERROR');
1497 $migration->log('Downloaded MD5: ' . $local_md5, 'ERROR');
1498 $migration->log('Expected MD5: ' . $md5, 'ERROR');
1499 $migration->log('Downloaded file path: ' . $backupDestinationPath, 'ERROR');
1500 $migration->log('File exist?: ' . (file_exists($backupDestinationPath) ? "Yes" : "No?"), 'ERROR');
1501 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1502 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1503 if (file_exists($lock)) @unlink($lock);
1504
1505 $migration->log('error_during_downloading_backup', 'verbose');
1506 $migration->log('#002', 'END-CODE');
1507 $migration->end();
1508
1509 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1510 return ['status' => 'error'];
1511 }
1512
1513 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1514 if (file_exists($lock)) @unlink($lock);
1515 if ($startRestoreProcess == 'true') {
1516 $migration->log('Requesting restoration process...', 'STEP');
1517
1518 $migration->log('#205', 'END-CODE');
1519 } else {
1520 $migration->log('Download process finished!', 'SUCCESS');
1521 $migration->log('#206', 'END-CODE');
1522 }
1523
1524 $migration->progress(100);
1525 $migration->end();
1526
1527 return ['status' => 'success', 'finished' => 'true', 'filename' => $originalFilename];
1528 } else {
1529
1530 $chunkSize = 256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2);
1531 $startRange = ($step * $chunkSize);
1532 if ($step !== 0) $startRange = $startRange + 1;
1533 $endRange = (($step + 1) * $chunkSize);
1534 if ($endRange > $size) $endRange = $size;
1535 $currentRange = $startRange . '-' . $endRange;
1536 $percentage = intval(($endRange / $size) * 100);
1537
1538 $contents = $gdrive->getGoogleDriveFileContents($fileId, $currentRange);
1539
1540 if ($contents == false || !isset($contents['data']) || $contents['data'] == false) {
1541
1542 $migration->log('It seem like I was unable to get backup content from cloud.', 'ERROR');
1543 $migration->log('For security reasons, I will remove the file (if exist) and stop the process...', 'ERROR');
1544 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1545 if (file_exists($lock)) @unlink($lock);
1546
1547 $migration->log('error_during_downloading_backup', 'verbose');
1548 $migration->log('#002', 'END-CODE');
1549 $migration->end();
1550
1551 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1552 return ['status' => 'error'];
1553 }
1554
1555 if ((is_dir(dirname($backupDestinationPath)) && file_exists($backupDestinationPath)) || $step === 0) {
1556
1557 $backupFile = fopen($backupDestinationPath, 'ab');
1558 fwrite($backupFile, $contents['data']);
1559 fclose($backupFile);
1560 } else {
1561
1562 $migration->log('File is not writable or directory does not exist.', 'ERROR');
1563 $migration->log('File: ' . basename($backupDestinationPath), 'ERROR');
1564 $migration->log('Dirname: ' . dirname($backupDestinationPath), 'ERROR');
1565 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1566 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1567 if (file_exists($lock)) @unlink($lock);
1568
1569 $migration->log('error_during_downloading_backup', 'verbose');
1570 $migration->log('#002', 'END-CODE');
1571 $migration->end();
1572
1573 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1574 return ['status' => 'error'];
1575 }
1576
1577 $migration->log('Download progress (' . ($step + 1) . '/' . $totalBatches . '): ' . $endRange . '/' . $size . ' (' . $percentage . '%)', 'INFO');
1578 $migration->progress($percentage);
1579 $migration->end();
1580
1581 return [
1582 'status' => 'success',
1583 'size' => $size,
1584 'md5' => $md5,
1585 'finished' => 'false',
1586 'originalFilename' => $originalFilename,
1587 'writepath' => $backupDestinationPath,
1588 'chunksize' => $bytesPerRequest,
1589 'secret' => $secret
1590 ];
1591 }
1592 }
1593
1594 if ($storage == 'ftp') {
1595
1596 require_once BMI_INCLUDES . '/external/ftp.php';
1597 $ftp = new FTP();
1598
1599 $backupDetails = false;
1600 $fileId = $this->post['fileId'];
1601
1602 if ($step === 0 || (!isset($this->post['size']) || $this->post['size'] == false || !is_numeric($this->post['size']))) {
1603
1604 $migration->log((__('Backup & Migration version: ', 'backup-backup') . BMI_VERSION));
1605 $migration->log(__('Creating lock file', 'backup-backup'));
1606 $secret = $this->randomString();
1607 file_put_contents($lock, $secret);
1608
1609 $migration->log('Download intialized', 'INFO');
1610 $migration->log('Getting backup details from FTP...', 'STEP');
1611 $backupDetails = $ftp->getFtpDriveFileMeta($fileId);
1612
1613 if ($backupDetails == false || !isset($backupDetails['data']) || $backupDetails['data'] == false) {
1614
1615 $migration->log('It seem like I was unable to get backup details from cloud.', 'ERROR');
1616 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1617 if (file_exists($lock)) @unlink($lock);
1618
1619 $migration->log('#002', 'END-CODE');
1620 $migration->end();
1621
1622 return ['status' => 'error'];
1623 }
1624
1625 $size = intval($backupDetails['data']['size']);
1626
1627 $originalFilename = $backupDetails['data']['name'];
1628
1629 $migration->log('Backup details received!', 'SUCCESS');
1630 $migration->log('Backup original name: ' . $originalFilename, 'INFO');
1631 $migration->log('Starting download process...', 'STEP');
1632
1633 $availableMemory = BMP::getAvailableMemoryInBytes();
1634 $bytesPerRequest = intval($availableMemory / 4);
1635
1636 $migration->log('Single batch will use up to: ' . $bytesPerRequest . ' bytes (~' . intval($bytesPerRequest / 1024 / 1024 / 2) . ' MBs)', 'INFO');
1637
1638 $fileIterator = 2;
1639 $extension = pathinfo($originalFilename, PATHINFO_EXTENSION);
1640 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
1641 if ($extension == 'gz') {
1642 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
1643 $extension = 'tar.gz';
1644 }
1645 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '.' . $extension;
1646 $finalName = $originalFilename . '.' . $extension;
1647
1648 while (file_exists($backupDestinationPath)) {
1649 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '-' . $fileIterator . '.' . $extension;
1650 $finalName = $originalFilename . '-' . $fileIterator . '.' . $extension;
1651 $fileIterator++;
1652 }
1653
1654 $originalFilename = $finalName;
1655
1656 $backupDestinationPath .= '.crdownload';
1657
1658 } else {
1659
1660 $size = intval($this->post['size']);
1661 $md5 = $this->post['md5'];
1662 $originalFilename = $this->post['filename'];
1663 $backupDestinationPath = $this->post['writepath'];
1664 $bytesPerRequest = intval($this->post['chunksize']);
1665 }
1666
1667 $totalBatches = ceil($size / (256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2)));
1668 $md5 = $this->post['md5'];
1669
1670 if ($totalBatches <= $step) {
1671 $migration->log('Download process finished!', 'SUCCESS');
1672 $migration->log('Verifying MD5 checksum of downloaded file...', 'STEP');
1673
1674 rename($backupDestinationPath, str_replace('.crdownload', '', $backupDestinationPath));
1675 $backupDestinationPath = str_replace('.crdownload', '', $backupDestinationPath);
1676
1677 $local_md5 = md5_file($backupDestinationPath);
1678 if (file_exists($backupDestinationPath) && $local_md5 == $md5) {
1679
1680 $migration->log('Downloaded MD5: ' . $local_md5, 'INFO');
1681 $migration->log('Expected MD5: ' . $md5, 'INFO');
1682 $migration->log('File MD5 checksum is correct!', 'SUCCESS');
1683 } else {
1684
1685 $migration->log('File MD5 checksum is NOT correct!', 'ERROR');
1686 $migration->log('Downloaded MD5: ' . $local_md5, 'ERROR');
1687 $migration->log('Expected MD5: ' . $md5, 'ERROR');
1688 $migration->log('Downloaded file path: ' . $backupDestinationPath, 'ERROR');
1689 $migration->log('File exist?: ' . (file_exists($backupDestinationPath) ? "Yes" : "No?"), 'ERROR');
1690 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1691 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1692 if (file_exists($lock)) @unlink($lock);
1693
1694 $migration->log('#002', 'END-CODE');
1695 $migration->end();
1696
1697 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1698 return ['status' => 'error'];
1699 }
1700
1701 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1702 if (file_exists($lock)) @unlink($lock);
1703 if ($startRestoreProcess == 'true') {
1704 $migration->log('Requesting restoration process...', 'STEP');
1705
1706 $migration->log('#205', 'END-CODE');
1707 } else {
1708 $migration->log('Download process finished!', 'SUCCESS');
1709 $migration->log('#206', 'END-CODE');
1710 }
1711 $migration->progress(100);
1712 $migration->end();
1713
1714 return ['status' => 'success', 'finished' => 'true', 'filename' => $originalFilename];
1715 } else {
1716 $chunkSize = 256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2);
1717 $startRange = ($step * $chunkSize);
1718 if ($step !== 0) $startRange = $startRange + 1;
1719 $endRange = (($step + 1) * $chunkSize);
1720 if ($endRange > $size) $endRange = $size;
1721 $percentage = intval(($endRange / $size) * 100);
1722
1723 $contents = $ftp->getFtpDriveFileContents($fileId, $startRange, $endRange);
1724 // wp_send_json($contents);
1725 if ($contents == false || !isset($contents['data']) || $contents['data'] == false) {
1726
1727 $migration->log('It seem like I was unable to get backup content from cloud.', 'ERROR');
1728 $migration->log('For security reasons, I will remove the file (if exist) and stop the process...', 'ERROR');
1729 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1730 if (file_exists($lock)) @unlink($lock);
1731
1732 $migration->log('#002', 'END-CODE');
1733 $migration->end();
1734
1735 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1736 return ['status' => 'error'];
1737 }
1738
1739 if ((is_dir(dirname($backupDestinationPath)) && file_exists($backupDestinationPath)) || $step === 0) {
1740
1741 $backupFile = fopen($backupDestinationPath, 'ab');
1742 fwrite($backupFile, $contents['data']);
1743 fclose($backupFile);
1744 } else {
1745
1746 $migration->log('File is not writable or directory does not exist.', 'ERROR');
1747 $migration->log('File: ' . basename($backupDestinationPath), 'ERROR');
1748 $migration->log('Dirname: ' . dirname($backupDestinationPath), 'ERROR');
1749 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1750 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1751 if (file_exists($lock)) @unlink($lock);
1752
1753 $migration->log('#002', 'END-CODE');
1754 $migration->end();
1755
1756 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1757 return ['status' => 'error'];
1758 }
1759
1760 $migration->log('Download progress (' . ($step + 1) . '/' . $totalBatches . '): ' . $endRange . '/' . $size . ' (' . $percentage . '%)', 'INFO');
1761 $migration->progress($percentage);
1762 $migration->end();
1763
1764 return [
1765 'status' => 'success',
1766 'size' => $size,
1767 'md5' => $md5,
1768 'finished' => 'false',
1769 'originalFilename' => $originalFilename,
1770 'writepath' => $backupDestinationPath,
1771 'chunksize' => $bytesPerRequest,
1772 'secret' => $secret
1773 ];
1774 }
1775 }
1776
1777 if ($storage == 's3'){
1778
1779 require_once BMI_INCLUDES . '/external/s3.php';
1780 $provider = $this->post['provider'];
1781 $s3 = new S3($provider);
1782
1783 $backupDetails = false;
1784 $fileId = $this->post['fileId'];
1785 $md5 = $this->post['md5'];
1786
1787 if ($step === 0 || (!isset($this->post['size']) || $this->post['size'] == false || !is_numeric($this->post['size']))) {
1788 $migration->log((__('Backup & Migration version: ', 'backup-backup') . BMI_VERSION));
1789 $migration->log(__('Creating lock file', 'backup-backup'));
1790 $secret = $this->randomString();
1791 file_put_contents($lock, $secret);
1792
1793 $migration->log('Download initialized', 'INFO');
1794 $migration->log('Getting backup details from S3...', 'STEP');
1795 $backupDetails = $s3->getFileMeta($fileId);
1796
1797 if ($backupDetails == false) {
1798 $migration->log('It seems like I was unable to get backup details from cloud.', 'ERROR');
1799 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1800 if (file_exists($lock)) @unlink($lock);
1801
1802 $migration->log('error_during_downloading_backup', 'verbose');
1803 $migration->log('#002', 'END-CODE');
1804 $migration->end();
1805
1806 return ['status' => 'error'];
1807 }
1808
1809 $size = intval($backupDetails['size']);
1810 $originalFilename = $fileId;
1811
1812 $migration->log('Backup details received!', 'SUCCESS');
1813 $migration->log('Backup original name: ' . $originalFilename, 'INFO');
1814 $migration->log('Starting download process...', 'STEP');
1815
1816 $availableMemory = BMP::getAvailableMemoryInBytes();
1817 $bytesPerRequest = intval($availableMemory / 4);
1818
1819 $migration->log('Single batch will use up to: ' . $bytesPerRequest . ' bytes (~' . intval($bytesPerRequest / 1024 / 1024 / 2) . ' MBs)', 'INFO');
1820
1821 $fileIterator = 2;
1822
1823 $extension = pathinfo($originalFilename, PATHINFO_EXTENSION);
1824 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
1825 if ($extension == 'gz') {
1826 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
1827 $extension = 'tar.gz';
1828 }
1829
1830 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '.' . $extension;
1831 $finalName = $originalFilename . '.' . $extension;
1832
1833 while (file_exists($backupDestinationPath)) {
1834 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '-' . $fileIterator . '.' . $extension;
1835 $finalName = $originalFilename . '-' . $fileIterator . '.' . $extension;
1836 $fileIterator++;
1837 }
1838
1839 $originalFilename = $finalName;
1840 $backupDestinationPath .= '.crdownload';
1841
1842 } else {
1843 $size = intval($this->post['size']);
1844 $md5 = $this->post['md5'];
1845 $originalFilename = $this->post['filename'];
1846 $backupDestinationPath = $this->post['writepath'];
1847 $bytesPerRequest = intval($this->post['chunksize']);
1848 }
1849
1850 $totalBatches = ceil($size / (256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2)));
1851
1852 if ($totalBatches <= $step) {
1853 $migration->log('Download process finished!', 'SUCCESS');
1854 $migration->log('Verifying MD5 checksum of downloaded file...', 'STEP');
1855
1856 rename($backupDestinationPath, str_replace('.crdownload', '', $backupDestinationPath));
1857 $backupDestinationPath = str_replace('.crdownload', '', $backupDestinationPath);
1858
1859 $local_md5 = md5_file($backupDestinationPath);
1860 if (file_exists($backupDestinationPath) && $local_md5 == $md5) {
1861 $migration->log('Downloaded MD5: ' . $local_md5, 'INFO');
1862 $migration->log('Expected MD5: ' . $md5, 'INFO');
1863 $migration->log('File MD5 checksum is correct!', 'SUCCESS');
1864 } else {
1865 $migration->log('File MD5 checksum is NOT correct!', 'ERROR');
1866 $migration->log('Downloaded MD5: ' . $local_md5, 'ERROR');
1867 $migration->log('Expected MD5: ' . $md5, 'ERROR');
1868 $migration->log('Downloaded file path: ' . $backupDestinationPath, 'ERROR');
1869 $migration->log('File exist?: ' . (file_exists($backupDestinationPath) ? "Yes" : "No?"), 'ERROR');
1870 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1871 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1872 if (file_exists($lock)) @unlink($lock);
1873
1874 $migration->log('error_during_downloading_backup', 'verbose');
1875 $migration->log('#002', 'END-CODE');
1876 $migration->end();
1877
1878 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1879 return ['status' => 'error'];
1880 }
1881
1882 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1883 if (file_exists($lock)) @unlink($lock);
1884 if ($startRestoreProcess == 'true') {
1885 $migration->log('Requesting restoration process...', 'STEP');
1886
1887 $migration->log('#205', 'END-CODE');
1888 } else {
1889 $migration->log('Download process finished!', 'SUCCESS');
1890 $migration->log('#206', 'END-CODE');
1891 }
1892
1893 $migration->progress(100);
1894 $migration->end();
1895
1896 return ['status' => 'success', 'finished' => 'true', 'filename' => $originalFilename];
1897 } else {
1898 $chunkSize = 256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2);
1899 $startRange = ($step * $chunkSize);
1900 if ($step !== 0) $startRange = $startRange + 1;
1901 $endRange = (($step + 1) * $chunkSize);
1902 if ($endRange > $size) $endRange = $size;
1903 $percentage = intval(($endRange / $size) * 100);
1904
1905 $contents = $s3->getFileContent($fileId, strval($startRange) . '-' . strval($endRange));
1906
1907 if ($contents == false) {
1908 $migration->log('It seems like I was unable to get backup content from cloud.', 'ERROR');
1909 $migration->log('For security reasons, I will remove the file (if exist) and stop the process...', 'ERROR');
1910 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1911 if (file_exists($lock)) @unlink($lock);
1912
1913 $migration->log('error_during_downloading_backup', 'verbose');
1914 $migration->log('#002', 'END-CODE');
1915 $migration->end();
1916
1917 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1918 return ['status' => 'error'];
1919 }
1920
1921 if ((is_dir(dirname($backupDestinationPath)) && file_exists($backupDestinationPath)) || $step === 0) {
1922 $backupFile = fopen($backupDestinationPath, 'ab');
1923 fwrite($backupFile, $contents);
1924 fclose($backupFile);
1925 } else {
1926 $migration->log('File is not writable or directory does not exist.', 'ERROR');
1927 $migration->log('File: ' . basename($backupDestinationPath), 'ERROR');
1928 $migration->log('Dirname: ' . dirname($backupDestinationPath), 'ERROR');
1929 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
1930 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1931 if (file_exists($lock)) @unlink($lock);
1932
1933 $migration->log('error_during_downloading_backup', 'verbose');
1934 $migration->log('#002', 'END-CODE');
1935 $migration->end();
1936
1937 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
1938 return ['status' => 'error'];
1939 }
1940
1941 $migration->log('Download progress (' . ($step + 1) . '/' . $totalBatches . '): ' . $endRange . '/' . $size . ' (' . $percentage . '%)', 'INFO');
1942 $migration->progress($percentage);
1943 $migration->end();
1944
1945 return [
1946 'status' => 'success',
1947 'size' => $size,
1948 'md5' => $md5,
1949 'finished' => 'false',
1950 'originalFilename' => $originalFilename,
1951 'writepath' => $backupDestinationPath,
1952 'chunksize' => $bytesPerRequest,
1953 'secret' => $secret
1954 ];
1955 }
1956 }
1957
1958 if (file_exists($lock)) @unlink($lock);
1959 return ['status' => 'error'];
1960 }
1961
1962 public function siteURL() {
1963 $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
1964 $domainName = $_SERVER['HTTP_HOST'];
1965
1966 return $protocol . $domainName;
1967 }
1968
1969 public function checkIfPHPCliExist(&$logger) {
1970
1971 $shouldContinue = apply_filters('bmi_cli_enabled', true);
1972 if ($shouldContinue === false) {
1973 $logger->log(__('PHP CLI is disabled manually, plugin will omit all PHP CLI steps.', 'backup-backup'), 'warn');
1974 return false;
1975 }
1976
1977
1978 if (defined('BMI_CLI_ENABLED')) {
1979 $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
1980 if ($cliEnabled === false) {
1981 $logger->log(__('PHP CLI is disabled manually, plugin will omit all PHP CLI steps.', 'backup-backup'), 'warn');
1982 return false;
1983 }
1984 }
1985
1986 $logger->log(__('Looking for PHP CLI executable file.', 'backup-backup'), 'step');
1987 require_once BMI_INCLUDES . '/cli/php_cli_finder.php';
1988 $checker = new PHPCLICheck();
1989 $result = $checker->findPHP();
1990
1991 if ($result === false) {
1992
1993 if (!defined('BMI_CLI_ENABLED')) define('BMI_CLI_ENABLED', false);
1994 if (!defined('BMI_CLI_EXECUTABLE')) define('BMI_CLI_EXECUTABLE', false);
1995 if ($checker->ini_disabled === true) {
1996 $logger->log(__('PHP CLI is disabled in your php.ini file, the process may be unstable.', 'backup-backup'), 'warn');
1997 } else {
1998 $logger->log(__('Could not find proper PHP CLI executable, this process may be unstable.', 'backup-backup'), 'warn');
1999 }
2000
2001 return false;
2002
2003 } else {
2004
2005 if (!defined('BMI_CLI_ENABLED')) define('BMI_CLI_ENABLED', apply_filters('bmi_cli_enabled', true));
2006 if (!defined('BMI_CLI_EXECUTABLE')) define('BMI_CLI_EXECUTABLE', $result['executable']);
2007
2008 $logger->log(__('PHP CLI Filename: ', 'backup-backup') . basename($result['executable']), 'info');
2009 $logger->log(__('PHP CLI Version: ', 'backup-backup') . $result['version'] . ' ' . $result['brand'], 'info');
2010 $logger->log(__('PHP CLI Memory limit: ', 'backup-backup') . $result['memory'], 'info');
2011 $logger->log(__('PHP CLI Execution limit: ', 'backup-backup') . $result['max_exec'], 'info');
2012 $logger->log(__('We properly detected PHP CLI executable file.', 'backup-backup'), 'success');
2013
2014 return $result;
2015
2016 }
2017
2018 }
2019
2020 public function getDatabaseSize() {
2021
2022 global $wpdb;
2023 $prefix = $wpdb->prefix;
2024
2025 $result = $wpdb->get_results($wpdb->prepare("SELECT SUM(DATA_LENGTH + INDEX_LENGTH) AS `bytes` FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s;", DB_NAME));
2026
2027 return intval($result[0]->bytes);
2028
2029 }
2030
2031 public function dirSize() {
2032
2033 // Folder
2034 $f = $this->post['folder'];
2035
2036 // Bytes
2037 $bytes = 0;
2038 $excludedBytes = 0;
2039
2040 $emptyVar = [ 'this_is_empty_array' ];
2041 $allowed = [ 'plugins', 'uploads', 'themes', 'contents_others', 'wordpress' ];
2042
2043 if (in_array($f, $allowed)) {
2044
2045 // Get list of staging sites for exclusion rules
2046 require_once BMI_INCLUDES . '/staging/controller.php';
2047 $staging = new Staging('..ajax..');
2048 $stagingSites = $staging->getStagingSites(true);
2049
2050 $files = $this->scanFilesForBackup($emptyVar, $stagingSites, $f);
2051 $files = $this->parseFilesForBackup($files, $emptyVar, false, true);
2052
2053 $bytes = $this->total_size_for_backup;
2054 $excludedBytes = $this->total_excluded_size_for_backup;
2055 set_transient('bmi_latest_size_' . $f, $bytes);
2056 } elseif ($f == 'database') {
2057
2058 $bytes = $this->getDatabaseSize();
2059 set_transient('bmi_latest_size_' . $f, $bytes);
2060 }
2061
2062 return [ 'bytes' => $bytes, 'excluded' => $excludedBytes, 'readable' => BMP::humanSize($bytes) ];
2063
2064 }
2065
2066 public function backupErrorHandler() {
2067 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
2068
2069 if (BMI_DEBUG) {
2070 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (ERROR HANDLER #1):');
2071 error_log(print_r($errno, true));
2072 error_log(print_r($errstr, true));
2073 error_log(print_r($errfile, true));
2074 error_log(print_r($errline, true));
2075 }
2076
2077 if (strpos($errstr, 'deprecated') !== false) return;
2078 if (strpos($errstr, 'php_uname') !== false) return;
2079 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false && $errno != E_ERROR) return;
2080
2081 if ($errno != E_ERROR && $errno != E_CORE_ERROR && $errno != E_COMPILE_ERROR && $errno != E_USER_ERROR && $errno != E_RECOVERABLE_ERROR) {
2082
2083 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false) return;
2084 Logger::error(__('There was an error before request shutdown (but it was not logged to restore log)', 'backup-backup'));
2085 Logger::error(__('Error message: ', 'backup-backup') . $errstr);
2086 Logger::error(__('Error file/line: ', 'backup-backup') . $errfile . '|' . $errline);
2087 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $errno);
2088 return;
2089
2090 }
2091 if (strpos($errfile, 'backup-backup') === false) {
2092 Logger::error(__("Restore process was not aborted because this error is not related to Backup Migration.", 'backup-backup'));
2093 $this->zip_progress->log(__("There was an error not related to Backup Migration Plugin.", 'backup-backup'), 'warn');
2094 $this->zip_progress->log(__("Message: ", 'backup-backup') . $errstr, 'warn');
2095 $this->zip_progress->log(__("Backup will not be aborted because of this.", 'backup-backup'), 'warn');
2096 return;
2097 }
2098 if (strpos($errstr, 'unlink(') !== false) {
2099 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
2100 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#02' . '|' . $errno);
2101 Logger::error($errstr);
2102 return;
2103 }
2104 if (strpos($errfile, 'pclzip') !== false) {
2105 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
2106 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#03' . '|' . $errno);
2107 Logger::error($errstr);
2108 return;
2109 }
2110 if (strpos($errstr, 'rename(') !== false) {
2111 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
2112 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#04' . '|' . $errno);
2113 Logger::error($errstr);
2114 $this->zip_progress->log(__("Cannot move: ", 'backup-backup') . $errstr, 'warn');
2115 return;
2116 }
2117
2118 $this->zip_progress->log(__("There was an error during backup:", 'backup-backup'), 'error');
2119 $this->zip_progress->log(__("Message: ", 'backup-backup') . $errstr, 'error');
2120 $this->zip_progress->log(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline, 'error');
2121 $this->zip_progress->log(__('Unfortunately we had to remove the backup (if partly created).', 'backup-backup'), 'error');
2122
2123 $backup = $GLOBALS['bmi_current_backup_name'];
2124 $backup_path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $backup;
2125 if (file_exists($backup_path)) @unlink($backup_path);
2126 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running');
2127 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort');
2128
2129 $this->zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
2130 $this->zip_progress->log(__("#002", 'backup-backup'), 'end-code');
2131 $this->zip_progress->end();
2132
2133 $GLOBALS['bmi_error_handled'] = true;
2134 BMP::res(['status' => 'error', 'error' => $errstr]);
2135 exit;
2136
2137 }, E_ALL);
2138 }
2139
2140 public function migrationErrorHandler() {
2141 set_exception_handler(function ($exception) {
2142 if (BMI_DEBUG) {
2143 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (EXCEPTION HANDLER #1):');
2144 error_log(print_r($exception, true));
2145 }
2146
2147 $this->migration_progress->log(__("Restore exception: ", 'backup-backup') . $exception->getMessage(), 'warn');
2148 Logger::log(__("Restore exception: ", 'backup-backup') . $exception->getMessage());
2149 });
2150 }
2151
2152 public function migrationExceptionHandler() {
2153 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
2154
2155 if (BMI_DEBUG) {
2156 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (ERROR HANDLER #2):');
2157 error_log(print_r($errno, true));
2158 error_log(print_r($errstr, true));
2159 error_log(print_r($errfile, true));
2160 error_log(print_r($errline, true));
2161 }
2162
2163 if (strpos($errstr, 'deprecated') !== false) return;
2164 if (strpos($errstr, 'php_uname') !== false) return;
2165 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration' && $errno != E_ERROR) === false) return;
2166
2167 if ($errno == E_NOTICE) return;
2168 if ($errno != E_ERROR && $errno != E_CORE_ERROR && $errno != E_COMPILE_ERROR && $errno != E_USER_ERROR && $errno != E_RECOVERABLE_ERROR) {
2169 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false) return;
2170 Logger::error(__('There was an error before request shutdown (but it was not logged to restore log)', 'backup-backup'));
2171 Logger::error(__('Error message: ', 'backup-backup') . $errstr);
2172 Logger::error(__('Error file/line: ', 'backup-backup') . $errfile . '|' . $errline);
2173 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#05' . '|' . $errno);
2174 return;
2175 }
2176
2177 Logger::error(__("There was an error/warning during restore process:", 'backup-backup'));
2178 Logger::error(__("Message: ", 'backup-backup') . $errstr);
2179 Logger::error(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline);
2180 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#06' . '|' . $errno);
2181
2182 if (strpos($errfile, 'backup-backup') === false) {
2183 Logger::error(__("Restore process was not aborted because this error is not related to Backup Migration.", 'backup-backup'));
2184 $this->migration_progress->log(__("There was an error not related to Backup Migration Plugin.", 'backup-backup'), 'warn');
2185 $this->migration_progress->log(__("Message: ", 'backup-backup') . $errstr, 'warn');
2186 $this->migration_progress->log(__("Backup will not be aborted because of this.", 'backup-backup'), 'warn');
2187 return;
2188 }
2189 if (strpos($errstr, 'unlink(') !== false) {
2190 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
2191 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#07' . '|' . $errno);
2192 Logger::error($errstr);
2193 return;
2194 }
2195 if (strpos($errfile, 'pclzip') !== false) {
2196 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
2197 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#08' . '|' . $errno);
2198 Logger::error($errstr);
2199 return;
2200 }
2201 if (strpos($errstr, 'rename(') !== false) {
2202 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
2203 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#09' . '|' . $errno);
2204 Logger::error($errstr);
2205 $this->migration_progress->log(__("Cannot move: ", 'backup-backup') . $errstr, 'warn');
2206 return;
2207 }
2208
2209 $this->migration_progress->log(__("There was an error during restore process:", 'backup-backup'), 'error');
2210 $this->migration_progress->log(__("Message: ", 'backup-backup') . $errstr, 'error');
2211 $this->migration_progress->log(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline, 'error');
2212
2213 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock');
2214
2215 $this->migration_progress->log(__("Aborting restore process...", 'backup-backup'), 'step');
2216
2217 if (isset($GLOBALS['bmi_current_tmp_restore']) && !empty($GLOBALS['bmi_current_tmp_restore'])) {
2218
2219 $this->migration_progress->log(__("Cleaning up exported files...", 'backup-backup'), 'step');
2220
2221 $tmp_unique = $GLOBALS['bmi_current_tmp_restore_unique'];
2222 $dir = $GLOBALS['bmi_current_tmp_restore'];
2223 $it = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
2224 $files = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
2225
2226 $this->migration_progress->log(__('Removing ', 'backup-backup') . iterator_count($files) . __(' files', 'backup-backup'), 'INFO');
2227 foreach ($files as $file) {
2228 if ($file->isDir()) {
2229 @rmdir($file->getRealPath());
2230 } else {
2231 @unlink($file->getRealPath());
2232 }
2233 }
2234
2235 @rmdir($dir);
2236
2237 $config_file = untrailingslashit(ABSPATH) . DIRECTORY_SEPARATOR . 'wp-config.' . $tmp_unique . '.php';
2238 if (file_exists($config_file)) @unlink($config_file);
2239
2240 }
2241
2242 $this->migration_progress->log(__("#002", 'backup-backup'), 'end-code');
2243 $this->migration_progress->end();
2244
2245 $GLOBALS['bmi_error_handled'] = true;
2246 BMP::res(['status' => 'error', 'error' => $errstr]);
2247 exit;
2248
2249 }, E_ALL);
2250 }
2251
2252 public function backupExceptionHandler() {
2253 set_exception_handler(function ($exception) {
2254 if (BMI_DEBUG) {
2255 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (EXCEPTION HANDLER #2):');
2256 error_log(print_r($exception, true));
2257 }
2258
2259 $this->zip_progress->log(__("Exception: ", 'backup-backup') . $exception->getMessage(), 'warn');
2260 Logger::log(__("Exception: ", 'backup-backup') . $exception->getMessage());
2261 });
2262 }
2263
2264 public function resetLatestLogs() {
2265
2266 // Restore htaccess
2267 BMP::revertLitespeed();
2268 BMP::fixLitespeed();
2269
2270 // Check time if not bugged
2271 if (file_exists(BMI_BACKUPS . '/.running') && (time() - filemtime(BMI_BACKUPS . '/.running')) > 65) {
2272 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2273 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2274 }
2275
2276 // Check if backup is not in progress
2277 if (file_exists(BMI_BACKUPS . '/.running')) {
2278 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
2279 }
2280
2281 // Remove too large logs
2282 $completeLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.' . BMI_LOGS_SUFFIX . '.log';
2283 if (file_exists($completeLogsPath) && (filesize($completeLogsPath) / 1024 / 1024) >= 3) {
2284 @unlink($completeLogsPath);
2285 }
2286
2287 $backgroundLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'background-errors.' . BMI_LOGS_SUFFIX . '.log';
2288 if (file_exists($backgroundLogsPath) && (filesize($backgroundLogsPath) / 1024 / 1024) >= 3) {
2289 @unlink($backgroundLogsPath);
2290 }
2291
2292 @touch($completeLogsPath);
2293 @touch($backgroundLogsPath);
2294
2295 // Require logs
2296 require_once BMI_INCLUDES . '/progress/zip.php';
2297 require_once BMI_INCLUDES . '/progress/migration.php';
2298 require_once BMI_INCLUDES . '/progress/staging.php';
2299
2300 // Write initial
2301 $zip_progress = new Progress('', 0);
2302 $zip_progress->start();
2303 $zip_progress->log(__("Initializing backup...", 'backup-backup'), 'step');
2304 $zip_progress->progress('0/100');
2305 $zip_progress->end();
2306
2307 // Write initial
2308 $migration = new MigrationProgress(false);
2309 $migration->start();
2310 $migration->log(__('Initializing restore process', 'backup-backup'), 'STEP');
2311 $migration->progress('0');
2312 $migration->end();
2313
2314 // Write initial
2315 $staging = new StagingProgress(false);
2316 $staging->start();
2317 $staging->log(__('Preparing creation of staging site...', 'backup-backup'), 'STEP');
2318 $staging->progress('0');
2319 $staging->end();
2320
2321 // Return done
2322 return ['status' => 'success'];
2323 }
2324
2325 public function makeBackupName() {
2326 $name = Dashboard\bmi_get_config('BACKUP:NAME');
2327
2328 $urlparts = parse_url(home_url());
2329 $domain = str_replace('.', '-', sanitize_text_field($urlparts['host']));
2330
2331 $hash = BMP::randomString(16);
2332 $name = str_replace('%domain', $domain, $name);
2333 $name = str_replace('%hash', $hash, $name);
2334 $name = str_replace('%Y', date('Y'), $name);
2335 $name = str_replace('%M', date('M'), $name);
2336 $name = str_replace('%D', date('D'), $name);
2337 $name = str_replace('%d', date('d'), $name);
2338 $name = str_replace('%j', date('j'), $name);
2339 $name = str_replace('%m', date('m'), $name);
2340 $name = str_replace('%n', date('n'), $name);
2341 $name = str_replace('%Y', date('Y'), $name);
2342 $name = str_replace('%y', date('y'), $name);
2343 $name = str_replace('%a', date('a'), $name);
2344 $name = str_replace('%A', date('A'), $name);
2345 $name = str_replace('%B', date('B'), $name);
2346 $name = str_replace('%g', date('g'), $name);
2347 $name = str_replace('%G', date('G'), $name);
2348 $name = str_replace('%h', date('h'), $name);
2349 $name = str_replace('%H', date('H'), $name);
2350 $name = str_replace('%i', date('i'), $name);
2351 $name = str_replace('%s', date('s'), $name);
2352 $name = str_replace('%s', date('s'), $name);
2353
2354 $i = 2;
2355 $tmpname = $name;
2356
2357 while (file_exists($tmpname . '.zip')) {
2358 $tmpname = $name . '_' . $i;
2359 $i++;
2360 }
2361
2362 $name = $tmpname . '.zip';
2363
2364 if (has_filter('bmip_backup_name')) {
2365 $name = apply_filters('bmip_backup_name', $name);
2366 }
2367
2368 $GLOBALS['bmi_current_backup_name'] = $name;
2369 return $name;
2370 }
2371
2372 public function fixUnameFunction() {
2373 $file = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
2374 $backup = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip-backup.php';
2375
2376 // Make backup
2377 if (!file_exists($backup)) {
2378 @copy($file, $backup);
2379 }
2380
2381 // Replace deprecated php_uname function which is mostly disabled and cause errors
2382 $replace = file_get_contents($file);
2383 $replace = str_replace('php_uname()', '(DIRECTORY_SEPARATOR === "/" ? "linux" : "windows")', $replace);
2384 file_put_contents($file, $replace);
2385 return ['status' => 'success'];
2386 }
2387
2388 public function revertUnameProcess() {
2389 $file = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
2390 $backup = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip-backup.php';
2391 if (file_exists($backup)) {
2392 if (file_exists($file)) @unlink($file);
2393 @copy($backup, $file);
2394 }
2395 return ['status' => 'success'];
2396 }
2397
2398 public function isFunctionEnabled($func) {
2399 $disabled = explode(',', ini_get('disable_functions'));
2400 $isDisabled = in_array($func, $disabled);
2401 if (!$isDisabled && function_exists($func)) return true;
2402 else return false;
2403 }
2404
2405 public function prepareAndMakeBackup($cron = false) {
2406
2407 global $wp_version;
2408
2409 $triggerLock = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.last_triggered';
2410
2411 if ($this->isFunctionEnabled('ini_set')) {
2412 ini_set('display_errors', 1);
2413 ini_set('error_reporting', E_ALL);
2414 ini_set('log_errors', 1);
2415 ini_set('error_log', BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.' . BMI_LOGS_SUFFIX . '.log');
2416 }
2417
2418 // Double check for .space_check file
2419 if (file_exists(BMI_BACKUPS . '/.space_check')) @unlink(BMI_BACKUPS . '/.space_check');
2420
2421 // Require File Scanner
2422 require_once BMI_INCLUDES . '/progress/zip.php';
2423 require_once BMI_INCLUDES . '/check/checker.php';
2424
2425 // CLI Handler
2426 $cliHandler = trailingslashit(sanitize_text_field(BMI_INCLUDES)) . 'cli-handler.php';
2427
2428 // Backup name
2429 if (defined('BMI_CLI_ARGUMENT') && !empty(BMI_CLI_ARGUMENT)) {
2430 $name = BMI_CLI_ARGUMENT;
2431 } else {
2432 $name = $this->makeBackupName();
2433 }
2434
2435 // Progress & Logs
2436 $cliRunning = (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) ? true : false;
2437 $shouldResetLogs = !$cliRunning;
2438 if (defined('BMI_DOING_SCHEDULED_BACKUP_VIA_CLI')) {
2439 $cron = true;
2440 $shouldResetLogs = true;
2441 }
2442
2443 $clearEndCodes = false;
2444 if (isset($this->post['preserveLogs']) && ($this->post['preserveLogs'] == 'true' || $this->post['preserveLogs'] === true)) {
2445 $shouldResetLogs = false;
2446 $clearEndCodes = true;
2447 }
2448
2449 $zip_progress = new Progress($name, 100, 0, $cron, $shouldResetLogs, $clearEndCodes);
2450 $zip_progress->start();
2451
2452 // PHP CLI Check
2453 $isCLI = false;
2454 $cli_lock = BMI_BACKUPS . '/.backup_lock_cli';
2455 $cli_lock_end = BMI_BACKUPS . '/.backup_lock_cli_end';
2456 $cli_failed_lock = BMI_BACKUPS . '/.backup_lock_cli_failed';
2457
2458 if (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) {
2459
2460 $cli_result = $this->checkIfPHPCliExist($zip_progress);
2461 $functionNormal = apply_filters('bmi_function_normal', BMI_FUNCTION_NORMAL);
2462 if ($cli_result !== false && $functionNormal === true) {
2463
2464 $res = null;
2465 if (defined('BMI_DOING_SCHEDULED_BACKUP')) {
2466 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_backup_cron ' . $name . ' > /dev/null &', $res);
2467 } else {
2468 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_backup ' . $name . ' > /dev/null &', $res);
2469 }
2470 $res = implode("\n", $res);
2471
2472 sleep(3);
2473
2474 if (file_exists($cli_lock_end) && (time() - filemtime($cli_lock_end)) < 10) {
2475
2476 if (file_exists($cli_lock_end)) @unlink($cli_lock_end);
2477 if (file_exists($triggerLock)) @unlink($triggerLock);
2478 return ['status' => 'success', 'filename' => $name];
2479 exit;
2480
2481 }
2482
2483 if (!file_exists($cli_lock) || (time() - filemtime($cli_lock)) > 10) {
2484
2485 if (!file_exists(BMI_BACKUPS . '/.abort') || (time() - filemtime(BMI_BACKUPS . '/.abort')) > 10) {
2486
2487 $zip_progress->log(__("Something went wrong in PHP CLI process, backup will be continued with legacy methods.", 'backup-backup'), 'warn');
2488 if (file_exists($cli_lock)) @unlink($cli_lock);
2489 define('BMI_CLI_FAILED', true);
2490 touch($cli_failed_lock);
2491
2492 } else {
2493
2494 $zip_progress->log(__("Backup will not be continued due to manual abort by user.", 'backup-backup'), 'warn');
2495 if (file_exists($cli_lock)) @unlink($cli_lock);
2496 if (file_exists($triggerLock)) @unlink($triggerLock);
2497 return ['status' => 'msg', 'why' => __('Backup process aborted.', 'backup-backup'), 'level' => 'info'];
2498
2499 }
2500
2501 } else {
2502
2503 return ['status' => 'background', 'filename' => $name];
2504
2505 }
2506
2507 } else {
2508
2509 if ($functionNormal !== true) {
2510 $zip_progress->log(__("PHP CLI will not run due to user settings in plugin other options.", 'backup-backup'), 'warn');
2511 } else {
2512 $zip_progress->log(__("PHP CLI file cannot be executed due to unknown reason.", 'backup-backup'), 'warn');
2513 }
2514
2515 }
2516
2517 } else {
2518
2519 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
2520
2521 if (file_exists($cli_failed_lock) && (time() - filemtime($cli_failed_lock)) < 10) {
2522 exit;
2523 }
2524
2525 $isCLI = true;
2526 $zip_progress->log(__("Backup via PHP CLI initialized successfully.", 'backup-backup'), 'success');
2527 touch($cli_lock);
2528
2529 }
2530
2531 }
2532
2533 // Just in case (e.g. syntax error, we can close the file correctly)
2534 $GLOBALS['bmi_backup_progress'] = $zip_progress;
2535
2536 // Logs
2537 $zip_progress->log(__("Initializing backup...", 'backup-backup'), 'step');
2538 $zip_progress->log((__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION), 'info');
2539 $zip_progress->log(__("Site which will be backed up: ", 'backup-backup') . site_url(), 'info');
2540 $zip_progress->log(__("PHP Version: ", 'backup-backup') . PHP_VERSION, 'info');
2541 $zip_progress->log(__("WP Version: ", 'backup-backup') . $wp_version, 'info');
2542 $zip_progress->log(__("MySQL Version: ", 'backup-backup') . $GLOBALS['wpdb']->db_version(), 'info');
2543 $maxAllowedPackets = $GLOBALS['wpdb']->get_results("SHOW VARIABLES LIKE 'max_allowed_packet';");
2544 if (sizeof($maxAllowedPackets) > 0) {
2545 $zip_progress->log(__("MySQL Max Length: ", 'backup-backup') . $maxAllowedPackets[0]->Value, 'info');
2546 } else {
2547 $zip_progress->log(__("MySQL Max Length: ", 'backup-backup') . 'Unknown', 'info');
2548 }
2549 if (isset($_SERVER['SERVER_SOFTWARE']) && !empty($_SERVER['SERVER_SOFTWARE'])) {
2550 $zip_progress->log(__("Web server: ", 'backup-backup') . $_SERVER['SERVER_SOFTWARE'], 'info');
2551 } else {
2552 $zip_progress->log(__("Web server: Not available", 'backup-backup'), 'info');
2553 }
2554 $zip_progress->log(__("Max execution time (in seconds): ", 'backup-backup') . @ini_get('max_execution_time'), 'info');
2555
2556 $zip_progress->log(__("Memory limit (server): ", 'backup-backup') . @ini_get('memory_limit'), 'info');
2557 if (defined('WP_MEMORY_LIMIT')) {
2558 $zip_progress->log(__("Memory limit (wp-config): ", 'backup-backup') . WP_MEMORY_LIMIT, 'info');
2559 }
2560 if (defined('WP_MAX_MEMORY_LIMIT')) {
2561 $zip_progress->log(__("Memory limit (wp-config admin): ", 'backup-backup') . WP_MAX_MEMORY_LIMIT, 'info');
2562 }
2563
2564 if (defined('BMI_DB_MAX_ROWS_PER_QUERY')) {
2565 $zip_progress->log(__('Max rows per query (this site): ', 'backup-backup') . BMI_DB_MAX_ROWS_PER_QUERY, 'info');
2566 }
2567
2568 $zip_progress->log(__("Checking if backup dir is writable...", 'backup-backup'), 'info');
2569
2570 if (defined('BMI_DOING_SCHEDULED_BACKUP')) {
2571 $zip_progress->log(__("This process was initialized due to scheduled backup configuration...", 'backup-backup'), 'info');
2572 $zip_progress->log(__("Backup will be unlocked by default as it is not manual backup...", 'backup-backup'), 'info');
2573 $zip_progress->log('This log is triggered by SCHEDULED BACKUP and its part of automatic backup creation', 'verbose');
2574 }
2575
2576 if (defined('BMI_BACKUP_PRO')) {
2577 if (BMI_BACKUP_PRO == 1) {
2578 $zip_progress->log(__("Premium plugin is enabled and activated", 'backup-backup'), 'info');
2579 } else {
2580 $zip_progress->log(__("Premium version is enabled but not active, using free plugin.", 'backup-backup'), 'warn');
2581 }
2582 }
2583
2584 // Error handler
2585 $zip_progress->log(__("Initializing custom error handler", 'backup-backup'), 'info');
2586 $this->zip_progress = &$zip_progress;
2587 $this->backupErrorHandler();
2588 $this->backupExceptionHandler();
2589
2590 // Checker
2591 $checker = new Checker($zip_progress);
2592
2593 if (!is_writable(dirname(BMI_BACKUPS))) {
2594
2595 // Abort backup
2596 $zip_progress->log(__("Backup directory is not writable...", 'backup-backup'), 'error');
2597 $zip_progress->log(__("Path: ", 'backup-backup') . BMI_BACKUPS, 'error');
2598
2599 // Close backup
2600 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2601 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2602 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2603
2604 // Log and close log
2605 $zip_progress->log('#002', 'END-CODE');
2606 $zip_progress->end();
2607
2608 if ($isCLI === true) touch($cli_lock_end);
2609 $this->actionsAfterProcess();
2610
2611 // Return error
2612 if (file_exists($triggerLock)) @unlink($triggerLock);
2613 if ($cron == true) return ['status' => 'success'];
2614 else return ['status' => 'error'];
2615 } else {
2616 $zip_progress->log(__("Yup it is writable...", 'backup-backup'), 'success');
2617 }
2618
2619 if (!file_exists(BMI_BACKUPS)) @mkdir(BMI_BACKUPS, true);
2620
2621 // Get list of staging sites for exclusion rules
2622 require_once BMI_INCLUDES . '/staging/controller.php';
2623 $staging = new Staging('..ajax..');
2624 $stagingSites = $staging->getStagingSites(true);
2625
2626 // Get file names (huge list mostly)
2627 if (has_filter('bmip_backup_files')) {
2628 $files = apply_filters('bmip_backup_files', []);
2629 } else if ($fgwp = Dashboard\bmi_get_config('BACKUP:FILES') == 'true') {
2630 $zip_progress->log(__("Scanning files...", 'backup-backup'), 'step');
2631 $files = $this->scanFilesForBackup($zip_progress, $stagingSites);
2632 $files = $this->parseFilesForBackup($files, $zip_progress, $cron);
2633 } else {
2634 $zip_progress->log(__("Omitting files (due to settings)...", 'backup-backup'), 'warn');
2635 $files = [];
2636 }
2637
2638 $zip_progress->log(str_replace('%s', $this->total_excluded_size_for_backup, __("Total size of excluded files: %s bytes", 'backup-backup')), 'info');
2639 $zip_progress->log("Total size of excluded files (bytes): " . $this->total_excluded_size_for_backup, 'verbose');
2640
2641 // Check if there is enough space
2642 $bytes = intval($this->total_size_for_backup * 1.4);
2643 update_option('bmi_required_space', $bytes);
2644 $zip_progress->log(__("Checking free space, reserving...", 'backup-backup'), 'step');
2645 if ($this->total_size_for_backup_in_mb >= BMI_REV * 1000 && get_option('bmip_last', false) != '1') {
2646
2647 // Abort backup
2648 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
2649 $zip_progress->log(str_replace('%s', BMI_REV, __("Site weights more than %s GB.", 'backup-backup')), 'error');
2650 if (isset($this->post['f'])) {
2651 $zip_progress->log('Function: ' . print_r($this->post['f'], true), 'verbose');
2652 }
2653
2654 if (isset($_SERVER)) {
2655 $zip_progress->log('REQUEST_URI: ' . $_SERVER['REQUEST_URI'], 'verbose');
2656 $zip_progress->log('REQUEST_METHOD: ' . $_SERVER['REQUEST_METHOD'], 'verbose');
2657 }
2658
2659 if (!empty($this->post)) {
2660 $zip_progress->log(print_r($this->post, true), 'verbose');
2661 }
2662
2663 // Close backup
2664 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2665 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2666 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2667
2668 // Log and close log
2669 $zip_progress->log('#100', 'END-CODE');
2670 $zip_progress->end();
2671
2672 if ($isCLI === true) touch($cli_lock_end);
2673 $this->actionsAfterProcess();
2674
2675 // Return error
2676 if (file_exists($triggerLock)) @unlink($triggerLock);
2677 return ['status' => 'error', 'bfs' => true];
2678 }
2679
2680 $isSpaceCheckDisabled = Dashboard\bmi_get_config('OTHER:BACKUP:SPACE:CHECKING');
2681
2682 if ($isSpaceCheckDisabled) {
2683
2684 $zip_progress->log(__("Free space checking is disabled by user in settings...", 'backup-backup'), 'warn');
2685 $zip_progress->log(__("Backup will continue, trusting there is enough space...", 'backup-backup'), 'warn');
2686
2687 } else {
2688
2689 if (!$checker->check_free_space($bytes)) {
2690
2691 // Abort backup
2692 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
2693 $zip_progress->log(__("There is no space for that backup, checked: ", 'backup-backup') . ($bytes) . __(" bytes", 'backup-backup'), 'error');
2694 $zip_progress->log('not_enough_space', 'verbose');
2695
2696 // Close backup
2697 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2698 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2699 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2700
2701 // Log and close log
2702 $zip_progress->log('#002', 'END-CODE');
2703 $zip_progress->end();
2704
2705 if ($isCLI === true) touch($cli_lock_end);
2706 $this->actionsAfterProcess();
2707
2708 // Return error
2709 if (file_exists($triggerLock)) @unlink($triggerLock);
2710 if ($cron == true) return ['status' => 'msg', 'why' => __('There is not enough space for backup, please free up ' . round($bytes / 1024 / 1024, 2) . ' MB of space.', 'backup-backup')];
2711 else return ['status' => 'error'];
2712 } else {
2713 $zip_progress->log(__("Confirmed, there is more than enough space, checked: ", 'backup-backup') . ($bytes) . __(" bytes", 'backup-backup'), 'success');
2714 $zip_progress->bytes = $this->total_size_for_backup;
2715 }
2716
2717 }
2718
2719 if (Dashboard\bmi_get_config('BACKUP:DATABASE') != 'true') {
2720
2721 // $zip_progress->log(__("Database won't be backed-up due to user settings, omitting...", 'backup-backup'), 'info');
2722 // Commented as message will be shown in database backup module
2723
2724 }
2725
2726 // Log and set files length
2727 $zip_progress->log(__("Scanning done - found ", 'backup-backup') . sizeof($files) . __(" files...", 'backup-backup'), 'info');
2728 $zip_progress->files = sizeof($files);
2729
2730 // Make Backup
2731 $zip_progress->log(__("Backup initialized...", 'backup-backup'), 'success');
2732 $zip_progress->log(__("Initializing archiving system...", 'backup-backup'), 'step');
2733
2734 $resultCreateBackup = $this->createBackup($files, ABSPATH, $name, $zip_progress, $cron, $isCLI);
2735 do_action('bmp_created_backup',$resultCreateBackup);
2736 return $resultCreateBackup;
2737
2738 $bckpres = $this->createBackup($files, ABSPATH, $name, $zip_progress, $cron, $isCLI);
2739 if (file_exists($triggerLock)) @unlink($triggerLock);
2740 if ($cron == true) return ['status' => 'success'];
2741 else return $bckpres;
2742 }
2743
2744 public function fixLitespeed() {
2745 BMP::fixLitespeed();
2746
2747 return ['status' => 'success'];
2748 }
2749
2750 public function revertLitespeed() {
2751 BMP::revertLitespeed();
2752
2753 return ['status' => 'success'];
2754 }
2755
2756 public function createBackup($files, $base, $name, &$zip_progress, $cron = false, $isCLI = false) {
2757
2758 // Require File Zipper
2759 require_once BMI_INCLUDES . '/zipper/zipping.php';
2760
2761 // CLI locks
2762 $cli_lock = BMI_BACKUPS . '/.backup_lock_cli';
2763 $cli_lock_end = BMI_BACKUPS . '/.backup_lock_cli_end';
2764 $cli_failed_lock = BMI_BACKUPS . '/.backup_lock_cli_failed';
2765
2766 // Backup name
2767 $backup_path = BMI_BACKUPS . '/' . $name;
2768
2769 // Check time if not bugged
2770 if (file_exists(BMI_BACKUPS . '/.running') && (time() - filemtime(BMI_BACKUPS . '/.running')) > 65) {
2771 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2772 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2773 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2774 if ($isCLI === true && file_exists($cli_lock_end)) @unlink($cli_lock_end);
2775 }
2776
2777 if ($isCLI === true) {
2778 if (file_exists($cli_failed_lock) && (time() - filemtime($cli_failed_lock)) < 10) {
2779 exit;
2780 }
2781 }
2782
2783 // Mark as in progress
2784 if (!file_exists(BMI_BACKUPS . '/.running')) {
2785 touch(BMI_BACKUPS . '/.running');
2786 file_put_contents(BMI_BACKUPS . '/.running', $name);
2787 if ($isCLI === true) touch($cli_lock);
2788 } else {
2789 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
2790 }
2791
2792 // Initialized
2793 $zip_progress->log(__("Archive system initialized...", 'backup-backup'), 'success');
2794
2795 // Make ZIP
2796 $zipper = new Zipper();
2797 $zippy = $zipper->makeZIP($files, $backup_path, $name, $zip_progress, $cron);
2798 if (!$zippy) {
2799
2800 // Make sure it's open
2801 $zip_progress->start();
2802
2803 // Abort backup
2804 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
2805
2806 // Close backup
2807 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2808 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2809 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2810
2811 // Log and close log
2812 $zip_progress->log('#002', 'END-CODE');
2813 $zip_progress->end();
2814
2815 if ($isCLI === true) touch($cli_lock_end);
2816
2817 // Return error
2818 if (file_exists($backup_path)) @unlink($backup_path);
2819
2820 $this->actionsAfterProcess();
2821 return ['status' => 'error'];
2822 }
2823
2824 if (isset($zippy['status']) && $zippy['status'] == 'background') {
2825 return $zippy;
2826 }
2827
2828 // Backup aborted
2829 if (file_exists(BMI_BACKUPS . '/.abort')) {
2830
2831 // Make sure it's open
2832 $zip_progress->start();
2833
2834 if (file_exists($backup_path)) @unlink($backup_path);
2835 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2836 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2837 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2838
2839 // Log and close log
2840 $zip_progress->log(__("Backup process aborted.", 'backup-backup'), 'warn');
2841 $zip_progress->log('#002', 'END-CODE');
2842 $zip_progress->end();
2843
2844 if ($isCLI === true) touch($cli_lock_end);
2845 Logger::log(__("Backup process aborted.", 'backup-backup'));
2846
2847 $this->actionsAfterProcess();
2848 return ['status' => 'msg', 'why' => __('Backup process aborted.', 'backup-backup'), 'level' => 'info'];
2849 }
2850
2851 if (!file_exists($backup_path) && !$cron) {
2852
2853 // Make sure it's open
2854 $zip_progress->start();
2855
2856 // Abort backup
2857 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
2858 $zip_progress->log(__("There is no backup file...", 'backup-backup'), 'error');
2859 $zip_progress->log(__("We could not find backup file when it already should be here.", 'backup-backup'), 'error');
2860 $zip_progress->log(__("This error may be related to missing space. (filled during backup)", 'backup-backup'), 'error');
2861 $zip_progress->log(__("Path: ", 'backup-backup') . $backup_path, 'error');
2862
2863 // Close backup
2864 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2865 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2866 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2867
2868 // Log and close log
2869 $zip_progress->log('#002', 'END-CODE');
2870 $zip_progress->end();
2871
2872 if ($isCLI === true) touch($cli_lock_end);
2873 $this->actionsAfterProcess();
2874
2875 // Return error
2876 if ($cron == true) return ['status' => 'success'];
2877 else return ['status' => 'error'];
2878 }
2879
2880 // End zip log
2881 $zip_progress->log(__("New backup created and its name is: ", 'backup-backup') . $name, 'success');
2882 $zip_progress->log('#001', 'END-CODE');
2883 $zip_progress->end();
2884
2885 if ($isCLI === true) touch($cli_lock_end);
2886
2887 // Unlink progress
2888 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
2889 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
2890 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
2891
2892 // Return
2893 Logger::log(__("New backup created and its name is: ", 'backup-backup') . $name);
2894
2895 $GLOBALS['bmi_error_handled'] = true;
2896
2897 $this->actionsAfterProcess(true, 'backup', $cron);
2898 return ['status' => 'success', 'filename' => $name, 'root' => plugin_dir_url(BMI_ROOT_FILE)];
2899
2900 }
2901
2902 public function continueRestoreProcess() {
2903
2904 // BMI_RESTORE_SECRET
2905
2906 }
2907
2908 public function getBackupsList() {
2909
2910 // Require File Scanner
2911 require_once BMI_INCLUDES . '/scanner/backups.php';
2912
2913 // Get backups
2914 $backups = new Backups();
2915 $manifests = $backups->getAvailableBackups();
2916
2917 // Return files
2918 return ['status' => 'success', 'backups' => $manifests];
2919 }
2920
2921 public function sendTestMail() {
2922
2923 $email = Dashboard\bmi_get_config('OTHER:EMAIL') != false ? Dashboard\bmi_get_config('OTHER:EMAIL') : get_bloginfo('admin_email');
2924 $subject = __('Backup Migration – Example email', 'backup-backup');
2925 $message = __('This is a test email sent by the Backup Migration plugin via Troubleshooting options!', 'backup-backup');
2926
2927 try {
2928
2929 if (wp_mail($email, $subject, $message)) return [ 'status' => 'success' ];
2930 else return ['status' => 'error'];
2931
2932 } catch (\Exception $e) {
2933
2934 return ['status' => 'error'];
2935
2936 } catch (\Throwable $e) {
2937
2938 return ['status' => 'error'];
2939
2940 }
2941
2942 }
2943
2944 public function restoreBackup() {
2945
2946 global $wp_version;
2947
2948 if ($this->isFunctionEnabled('ini_set')) {
2949 ini_set('display_errors', 1);
2950 ini_set('error_reporting', E_ALL);
2951 ini_set('log_errors', 1);
2952 ini_set('error_log', BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.' . BMI_LOGS_SUFFIX . '.log');
2953 }
2954
2955
2956 // Double check for .space_check file
2957 if (file_exists(BMI_BACKUPS . '/.space_check')) @unlink(BMI_BACKUPS . '/.space_check');
2958
2959 // Require File Scanner
2960 require_once BMI_INCLUDES . '/zipper/zipping.php';
2961 require_once BMI_INCLUDES . '/extracter/extract.php';
2962 require_once BMI_INCLUDES . '/progress/migration.php';
2963 require_once BMI_INCLUDES . '/check/checker.php';
2964
2965 // Make AutoLogin possible
2966 $ip = '127.0.0.1';
2967 if (isset($_SERVER['HTTP_CLIENT_IP'])) {
2968 $ip = $_SERVER['HTTP_CLIENT_IP'];
2969 } else {
2970 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
2971 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
2972 }
2973 if ($ip === false) {
2974 if (isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
2975 }
2976 }
2977 $autoLoginMD = time() . '_' . $ip . '_' . '4u70L051n';
2978
2979 // Progress & lock file
2980 $lock = BMI_BACKUPS . '/.migration_lock';
2981 $lock_cli = BMI_BACKUPS . '/.migration_lock_cli';
2982 $autologin_file = BMI_BACKUPS . '/.autologin';
2983 $lock_cli_end = BMI_BACKUPS . '/.migration_lock_ended';
2984 $progress = BMI_BACKUPS . '/latest_migration_progress.log';
2985 $cli_last_download = BMI_BACKUPS . '/.cli_download_last';
2986
2987 $ignoreRunCheck = ((isset($this->post['ignoreRunning']) && $this->post['ignoreRunning'] == 'true') ? true : false);
2988 $isCLIRunning = (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) ? true : false;
2989 if ($isCLIRunning) $ignoreRunCheck = false;
2990
2991 if (file_exists($lock) && (time() - filemtime($lock)) < 65 && !$ignoreRunCheck) {
2992 return ['status' => 'msg', 'why' => __('The restore process is currently running, please wait till it end or once the lock file expire.', 'backup-backup'), 'level' => 'warning'];
2993 }
2994
2995 // Check if download was via CLI
2996 if ($this->post['file'] == '.cli_download' && file_exists($cli_last_download)) {
2997 $this->post['file'] = file_get_contents($cli_last_download);
2998 if (file_exists($cli_last_download)) @unlink($cli_last_download);
2999 }
3000
3001 // Logs
3002 $migration = new MigrationProgress($this->post['remote']);
3003 $migration->start();
3004
3005 if ($ignoreRunCheck) {
3006
3007 $migration->mute();
3008
3009 }
3010
3011 // Check PHP CLI
3012 if ((!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) && (!defined('BMI_CLI_REQUEST') || BMI_CLI_REQUEST === false)) {
3013
3014 $cli_result = $this->checkIfPHPCliExist($migration);
3015
3016 if ($cli_result !== false) {
3017
3018 $cliHandler = trailingslashit(sanitize_text_field(BMI_INCLUDES)) . 'cli-handler.php';
3019 $backupName = esc_attr($this->post['file']);
3020 $remoteType = 'false';
3021 if ($this->post['remote'] == 'true' || $this->post['remote'] === true) $remoteType = 'true';
3022 if (file_exists($lock_cli_end)) @unlink($lock_cli_end);
3023
3024 $res = null;
3025 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_restore ' . $backupName . ' ' . $remoteType . ' > /dev/null &', $res);
3026 $res = implode("\n", $res);
3027
3028 sleep(3);
3029
3030 if (file_exists($lock_cli_end) && (time() - filemtime($lock_cli_end)) < 10) {
3031
3032 // Put autologin
3033 file_put_contents($autologin_file, $autoLoginMD);
3034 touch($autologin_file);
3035
3036 return ['status' => 'cli', 'login' => explode('_', $autoLoginMD)[0], 'url' => site_url()];
3037 exit;
3038
3039 }
3040
3041 if (!file_exists($lock_cli) || (time() - filemtime($lock_cli)) > 10) {
3042
3043 $progressFile = null;
3044 $migration->log(__('No response from PHP CLI - plugin will try to recover the migration with traditional restore.', 'backup-backup'), 'warn');
3045 if (file_exists($lock_cli)) @unlink($lock_cli);
3046
3047 } else {
3048
3049 $progressFile = null;
3050
3051 // $migration->log(__('PHP CLI responded with correct code - we will continue via PHP CLI.', 'backup-backup'), 'info');
3052 // $migration->end();
3053
3054 // Put autologin
3055 file_put_contents($autologin_file, $autoLoginMD);
3056 touch($autologin_file);
3057
3058 return ['status' => 'cli', 'login' => explode('_', $autoLoginMD)[0], 'url' => site_url()];
3059 exit;
3060
3061 }
3062
3063 } else {
3064
3065 if (file_exists($lock_cli)) @unlink($lock_cli);
3066
3067 }
3068
3069 } else {
3070
3071 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
3072 $migration->log(__('PHP CLI: Restore process initialized, restoring...', 'backup-backup'), 'success');
3073 touch($lock_cli);
3074 } else {
3075 $migration->log(__('Restore process initialized, restoring (non-cli mode)...', 'backup-backup'), 'success');
3076 }
3077
3078 }
3079
3080 // Just in case (e.g. syntax error, we can close the file correctly)
3081 $GLOBALS['bmi_migration_progress'] = $migration;
3082
3083 // Checker
3084 $checker = new Checker($migration);
3085 $zipper = new Zipper();
3086
3087 // Handle remote
3088 if ($this->post['file']) {
3089 $migration->log(__('Restore process responded', 'backup-backup'), 'SUCCESS');
3090 }
3091
3092 // Make lock file
3093 $migration->log(__('Locking migration process', 'backup-backup'), 'SUCCESS');
3094 touch($lock);
3095
3096 // Initializing
3097 $migration->log(__('Initializing restore process', 'backup-backup'), 'STEP');
3098 $migration->log((__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION), 'info');
3099
3100 // Error handler
3101 $migration->log(__("Initializing custom error handler", 'backup-backup'), 'info');
3102
3103 // Error handler
3104 $this->migration_progress = &$migration;
3105 $this->migrationErrorHandler();
3106 $this->migrationExceptionHandler();
3107
3108 $homeURL = site_url();
3109 if (strlen($homeURL) <= 8) $homeURL = home_url();
3110 if (defined('WP_SITEURL') && strlen(WP_SITEURL) > 8) $homeURL = WP_SITEURL;
3111
3112 $migration->log(__("Site which will be restored: ", 'backup-backup') . $homeURL, 'info');
3113 $migration->log(__("PHP Version: ", 'backup-backup') . PHP_VERSION, 'info');
3114 $migration->log(__("WP Version: ", 'backup-backup') . $wp_version, 'info');
3115 $migration->log(__("MySQL Version: ", 'backup-backup') . $GLOBALS['wpdb']->db_version(), 'info');
3116 $maxAllowedPackets = $GLOBALS['wpdb']->get_results("SHOW VARIABLES LIKE 'max_allowed_packet';");
3117 if (sizeof($maxAllowedPackets) > 0) {
3118 $migration->log(__("MySQL Max Length: ", 'backup-backup') . $maxAllowedPackets[0]->Value, 'info');
3119 } else {
3120 $migration->log(__("MySQL Max Length: ", 'backup-backup') . 'Unknown', 'info');
3121 }
3122 if (isset($_SERVER['SERVER_SOFTWARE']) && !defined('BMI_USING_CLI_FUNCTIONALITY')) {
3123 $migration->log(__("Web server: ", 'backup-backup') . $_SERVER['SERVER_SOFTWARE'], 'info');
3124 } else {
3125 $migration->log(__("Web server: Not available", 'backup-backup'), 'info');
3126 }
3127 $migration->log(__("Max execution time (in seconds): ", 'backup-backup') . @ini_get('max_execution_time'), 'info');
3128
3129 $migration->log(__("Memory limit (server): ", 'backup-backup') . @ini_get('memory_limit'), 'info');
3130 if (defined('WP_MEMORY_LIMIT')) {
3131 $migration->log(__("Memory limit (wp-config): ", 'backup-backup') . WP_MEMORY_LIMIT, 'info');
3132 }
3133 if (defined('WP_MAX_MEMORY_LIMIT')) {
3134 $migration->log(__("Memory limit (wp-config admin): ", 'backup-backup') . WP_MAX_MEMORY_LIMIT, 'info');
3135 }
3136
3137 if (defined('BMI_BACKUP_PRO')) {
3138 if (BMI_BACKUP_PRO == 1) {
3139 $migration->log(__("Premium plugin is enabled and activated", 'backup-backup'), 'info');
3140 } else {
3141 $migration->log(__("Premium version is enabled but not active, using free plugin.", 'backup-backup'), 'warn');
3142 }
3143 }
3144
3145 $migration->log(__("Restore process initialized successfully.", 'backup-backup'), 'success');
3146
3147 // Check file size
3148 $zippath = BMP::fixSlashes(BMI_BACKUPS) . DIRECTORY_SEPARATOR . $this->post['file'];
3149 if (!$ignoreRunCheck) {
3150
3151 $manifest = $zipper->getZipFileContent($zippath, 'bmi_backup_manifest.json');
3152 $migration->log(__('Free space checking...', 'backup-backup'), 'STEP');
3153 $migration->log(__('Checking if there is enough amount of free space', 'backup-backup'), 'INFO');
3154
3155 $isSpaceCheckDisabled = Dashboard\bmi_get_config('OTHER:BACKUP:SPACE:CHECKING');
3156
3157 if ($isSpaceCheckDisabled) {
3158 $migration->log(__("Free space checking is disabled by user in settings...", 'backup-backup'), 'warn');
3159 $migration->log(__("Restore will continue, trusting there is enough space...", 'backup-backup'), 'warn');
3160 } else {
3161 if ($manifest) {
3162 if (isset($manifest->bytes) && $manifest->bytes) {
3163 $bytes = intval($manifest->bytes * 1.4);
3164 update_option('bmi_required_space', $bytes);
3165 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json')) {
3166 $restoreParts = json_decode(file_get_contents(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json'));
3167 if (isset($restoreParts->size) && $restoreParts->size && $restoreParts->backupName == $this->post['file']) {
3168 $bytes = intval($restoreParts->size * 1.4);
3169 }
3170 }
3171 if (!$checker->check_free_space($bytes)) {
3172 $migration->log(__('Cannot start migration process', 'backup-backup'), 'ERROR');
3173 $migration->log(__('Error: There is not enough space on the server, checked: ' . ($bytes) . ' bytes.', 'backup-backup'), 'ERROR');
3174 $migration->log("not_enough_space", 'verbose');
3175 $migration->log(__('Aborting...', 'backup-backup'), 'ERROR');
3176 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
3177
3178 if (file_exists($lock)) @unlink($lock);
3179 $migration->log('#004', 'END-CODE');
3180 $migration->end();
3181
3182 if ($isCLIRunning == true) touch($lock_cli_end);
3183 $this->actionsAfterProcess(false, 'migration');
3184
3185 return ['status' => 'error'];
3186 } else {
3187 $migration->log(__('Confirmed, there is enough space on the device, checked: ' . ($bytes) . ' bytes.', 'backup-backup'), 'SUCCESS');
3188 }
3189 }
3190 } else {
3191 $migration->log(__('Cannot start migration process', 'backup-backup'), 'ERROR');
3192 $migration->log(__('Error: File may not exist, check file name and if it still exist', 'backup-backup'), 'ERROR');
3193 $migration->log(__('Error: Could not find manifest in backup, file may be broken', 'backup-backup'), 'ERROR');
3194 $migration->log(__('Error: Btw. because of this I also cannot check free space', 'backup-backup'), 'ERROR');
3195 $migration->log(__('Used path: ', 'backup-backup') . $zippath, 'ERROR');
3196 $migration->log(__('Aborting...', 'backup-backup'), 'ERROR');
3197 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
3198
3199 if (file_exists($lock)) @unlink($lock);
3200 $migration->log('#003', 'END-CODE');
3201 $migration->end();
3202
3203 if ($isCLIRunning == true) touch($lock_cli_end);
3204 $this->actionsAfterProcess(false, 'migration');
3205
3206 return ['status' => 'error'];
3207 }
3208 }
3209
3210 }
3211
3212 if ($ignoreRunCheck) {
3213
3214 $migration->unmute();
3215
3216 }
3217
3218 // New extracter
3219 $theTmpName = ((isset($this->post['tmpname'])) ? $this->post['tmpname'] : false);
3220 $options = ((isset($this->post['options'])) ? $this->post['options'] : []);
3221 $extracter = new Extracter($this->post['file'], $migration, $theTmpName, $isCLIRunning, $options);
3222
3223 // Extract
3224 $theSecret = ((isset($this->post['secret'])) ? $this->post['secret'] : null);
3225 $isFine = $extracter->extractTo($theSecret);
3226 if (!$isFine) {
3227 $migration->log(__('Aborting...', 'backup-backup'), 'ERROR');
3228 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
3229
3230 if (file_exists($lock)) @unlink($lock);
3231 $migration->log('#002', 'END-CODE');
3232 $migration->end();
3233
3234 if ($isCLIRunning == true) touch($lock_cli_end);
3235 $this->actionsAfterProcess(false, 'migration');
3236
3237 return ['status' => 'error'];
3238 }
3239
3240 $migration->progress('100');
3241 $migration->log(__('Restore process completed', 'backup-backup'), 'SUCCESS');
3242 $migration->log(__('Finalizing restored files', 'backup-backup'), 'STEP');
3243 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
3244 if (file_exists($lock)) @unlink($lock);
3245
3246 $migration->log('#001', 'END-CODE');
3247 $migration->end();
3248
3249 if ($isCLIRunning == true) touch($lock_cli_end);
3250
3251 // Put autologin
3252 file_put_contents($autologin_file, $autoLoginMD);
3253 touch($autologin_file);
3254
3255 $this->actionsAfterProcess(true, 'migration');
3256 return ['status' => 'success', 'login' => explode('_', $autoLoginMD)[0], 'url' => site_url()];
3257 }
3258
3259 public function isRunningBackup() {
3260 $this->lock_cli = BMI_BACKUPS . '/.backup_cli_lock';
3261
3262 // Ongoing processes
3263 $ongoing = get_option('bmip_to_be_uploaded', [
3264 'current_upload' => [],
3265 'queue' => [],
3266 'failed' => []
3267 ]);
3268
3269 // Backup CLI running
3270 if (file_exists($this->lock_cli) && (time() - filemtime($this->lock_cli)) <= 3600) {
3271 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning', 'ongoing' => $ongoing];
3272 }
3273
3274 if (file_exists(BMI_BACKUPS . '/.running') && (time() - filemtime(BMI_BACKUPS . '/.running')) <= 65) {
3275 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning', 'ongoing' => $ongoing];
3276 } else {
3277 return ['status' => 'success', 'ongoing' => $ongoing];
3278 }
3279 }
3280
3281 public function stopBackup() {
3282 if (!file_exists(BMI_BACKUPS . '/.running')) {
3283 return ['status' => 'msg', 'why' => __('Backup process completed or is not running.', 'backup-backup'), 'level' => 'info'];
3284 } else {
3285 if (!file_exists(BMI_BACKUPS . '/.abort')) {
3286 touch(BMI_BACKUPS . '/.abort');
3287 }
3288
3289 return ['status' => 'success'];
3290 }
3291 }
3292
3293 public function isMigrationLocked() {
3294 $lock = BMI_BACKUPS . '/.migration_lock';
3295 $lock_cli = BMI_BACKUPS . '/.migration_lock_cli';
3296 $lock_cli_end = BMI_BACKUPS . '/.migration_lock_ended';
3297
3298 if ((file_exists($lock) && (time() - filemtime($lock)) < 65) || (file_exists($lock_cli) && (time() - filemtime($lock_cli)) < 7200)) {
3299
3300 return ['status' => 'msg', 'why' => __('Restore process is currently running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
3301
3302 } else {
3303
3304 require_once BMI_INCLUDES . '/progress/migration.php';
3305 $progress = BMI_BACKUPS . '/latest_migration_progress.log';
3306 $shouldClearLogs = true;
3307
3308 if (isset($this->post['clearLogs']) && $this->post['clearLogs'] == 'false') {
3309 $shouldClearLogs = false;
3310 }
3311
3312 if ($shouldClearLogs === true) {
3313 if (file_exists($lock_cli_end) && (time() - filemtime($lock_cli_end)) > 10) {
3314
3315 $migration = new MigrationProgress();
3316 $migration->start();
3317 $migration->log(__('Initializing restore process...', 'backup-backup'), 'STEP');
3318 $migration->end();
3319
3320 file_put_contents($progress, '0');
3321
3322 }
3323 }
3324
3325 return ['status' => 'success'];
3326
3327 }
3328 }
3329
3330 public function downloadFile($url, $dest, $progress, $lock, &$logger) {
3331 $current_percentage = 0;
3332 $previous_logged = 0;
3333 $fp = fopen($dest, 'w+');
3334
3335 $progressfile = $progress;
3336 $lockfile = $lock;
3337
3338 $ch = curl_init(rawurldecode($url));
3339 curl_setopt($ch, CURLOPT_TIMEOUT, 0);
3340
3341 curl_setopt($ch, CURLOPT_FILE, $fp);
3342 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
3343 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
3344 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
3345
3346 curl_setopt($ch, CURLOPT_NOPROGRESS, false);
3347 curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function ($resource, $download_size, $downloaded) use (&$current_percentage, &$lockfile, &$progressfile, &$logger, &$previous_logged) {
3348 if ($download_size > 0) {
3349 $new_percentage = intval(($downloaded / $download_size) * 100);
3350
3351 if (intval($current_percentage) != intval($new_percentage)) {
3352 $logger->progress($new_percentage);
3353
3354 if ($current_percentage == 0 || ($new_percentage % 5 == 0) || $new_percentage > 99) {
3355 $logger->log(sprintf(__('Download progress: %s/%s MB (%s%%)', 'backup-backup'), round($downloaded / 1024 / 1024), round($download_size / 1024 / 1024), $new_percentage), 'INFO');
3356 $previous_logged = $new_percentage;
3357 }
3358
3359 $current_percentage = $new_percentage;
3360 }
3361 }
3362 });
3363
3364 curl_exec($ch);
3365 $this->lastCurlCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
3366
3367 $error_msg = false;
3368 if (curl_errno($ch)) {
3369 $error_msg = curl_error($ch);
3370 $curl_errno = curl_errno($ch);
3371 $fileSize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
3372
3373 if ($curl_errno == CURLE_WRITE_ERROR || $curl_errno == CURLE_ABORTED_BY_CALLBACK) {
3374 $requiredSpace = $fileSize * 1.1; // Add 10% buffer
3375 update_option('bmi_required_space', $requiredSpace);
3376 $logger->log('not_enough_space', 'verbose');
3377 }
3378 }
3379
3380 curl_close($ch);
3381 fclose($fp);
3382
3383 if ($error_msg) {
3384 return $error_msg;
3385 } else {
3386 return false;
3387 }
3388 }
3389
3390 public function handleQuickMigration() {
3391 $lock = BMI_BACKUPS . '/.migration_lock';
3392 if (file_exists($lock) && (time() - filemtime($lock)) < 65) {
3393 return ['status' => 'msg', 'why' => __('Download process is currently running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
3394 }
3395
3396 require_once BMI_INCLUDES . '/progress/migration.php';
3397 require_once BMI_INCLUDES . '/zipper/zipping.php';
3398
3399 $migration = new MigrationProgress(true);
3400 $migration->start();
3401
3402 $tmp_name = 'backup_' . time() . '.zip.part';
3403
3404 // Missing URL parameter
3405 if (!isset($this->post['url'])) {
3406 wp_send_json_error();
3407 }
3408
3409 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true && defined('BMI_CLI_ARGUMENT')) {
3410
3411 $url = BMI_CLI_ARGUMENT;
3412
3413 } else {
3414
3415 $url = $this->post['url'];
3416 $startRestoreProcess = isset($this->post['startRestoreProcess']) ? $this->post['startRestoreProcess'] : 'true';
3417
3418 $url = trim(rawurlencode(sanitize_url($url, ['http', 'https']))); // or esc_attr but rawurlencode should be fine
3419
3420 // Just why not {
3421 $url = str_replace(' ', '', $url);
3422 $url = str_replace('$', '%24', $url);
3423 $url = str_replace('`', '%60', $url);
3424 $url = str_replace('"', '%22', $url);
3425 $url = str_replace('\\', '%5C', $url);
3426 $url = str_replace('&amp;', '&', $url);
3427 // }
3428
3429 }
3430
3431 $dest = BMI_BACKUPS . '/' . $tmp_name;
3432 $progress = BMI_BACKUPS . '/latest_migration_progress.log';
3433 $cli_lock = BMI_BACKUPS . '/.cli_download_lock';
3434
3435 if (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) {
3436
3437 $cli_result = $this->checkIfPHPCliExist($migration);
3438 if ($cli_result !== false) {
3439
3440 $cliHandler = trailingslashit(sanitize_text_field(BMI_INCLUDES)) . 'cli-handler.php';
3441
3442 $res = null;
3443 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_quick_migration "' . $url . '" > /dev/null &', $res);
3444 $res = implode("\n", $res);
3445
3446 sleep(2);
3447 if (file_exists($cli_lock) && (time() - filemtime($cli_lock)) < 10) {
3448
3449 if (file_exists($cli_lock)) @unlink($cli_lock);
3450 return [ 'status' => 'cli_download' ];
3451 exit;
3452
3453 }
3454
3455 }
3456
3457 } else {
3458
3459 $migration->log(__('Downloading via PHP CLI', 'backup-backup'));
3460 touch($cli_lock);
3461
3462 }
3463
3464 $migration->log((__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION));
3465 $migration->log(__('Creating lock file', 'backup-backup'));
3466 file_put_contents($lock, '');
3467 $migration->log(__('Initializing download process', 'backup-backup'), 'STEP');
3468 $downstart = microtime(true);
3469 $migration->log(__('Downloading initialized', 'backup-backup'), 'SUCCESS');
3470 $migration->log(__('Downloading remote file...', 'backup-backup'), 'STEP');
3471 $migration->log(__('Used URL: ', 'backup-backup') . rawurldecode($url), 'INFO');
3472 $fileError = $this->downloadFile($url, $dest, $progress, $lock, $migration);
3473 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
3474 if (file_exists($lock)) @unlink($lock);
3475
3476 if ($fileError) {
3477 $migration->log(__('Removing downloaded file', 'backup-backup'), 'INFO');
3478 if (file_exists($dest)) @unlink($dest);
3479 $migration->log(__('Download error', 'backup-backup'), 'ERROR');
3480
3481 if (strpos($fileError, 'Failed writing body') !== false) {
3482 $migration->log(__('Error: There is not enough space on the server', 'backup-backup'), 'ERROR');
3483 $migration->log("not_enough_space", 'verbose');
3484 } else {
3485 $migration->log(__('Error', 'backup-backup') . ': ' . $fileError, 'ERROR');
3486 }
3487
3488 $migration->log('error_during_downloading_backup', 'verbose');
3489 $migration->log('error_during_downloading_backup', 'verbose');
3490 $migration->log('#002', 'END-CODE');
3491 return ['status' => 'error'];
3492 } else {
3493 $migration->log(__('Download completed (took: ', 'backup-backup') . (microtime(true) - $downstart) . 's)', 'SUCCESS');
3494 $migration->log(__('Looking for backup manifest', 'backup-backup'), 'STEP');
3495 $zipper = new Zipper();
3496 $content = $zipper->getZipFileContent($dest, 'bmi_backup_manifest.json');
3497 if ($content) {
3498 try {
3499 $i = 1;
3500 $name = $content->name;
3501 $prepared_name = $name;
3502 $migration->log(__('Manifest found remote name: ', 'backup-backup') . $name, 'SUCCESS');
3503
3504 while (file_exists(BMI_BACKUPS . '/' . $prepared_name)) {
3505 $prepared_name = substr($name, 0, -4) . '_' . $i . '.zip';
3506 $i++;
3507 }
3508
3509 rename($dest, BMI_BACKUPS . '/' . $prepared_name);
3510 $migration->log(__('Requesting restore process', 'backup-backup'), 'STEP');
3511 $migration->progress(0);
3512 file_put_contents(BMI_BACKUPS . '/' . '.cli_download_last', $prepared_name);
3513 if ($startRestoreProcess == 'true'){
3514 $migration->log('#205', 'END-CODE');
3515 } else {
3516 $migration->log('#206', 'END-CODE');
3517 }
3518
3519 if (defined('BMI_USING_CLI_FUNCTIONALITY')) {
3520 $this->post['file'] = '.cli_download';
3521 $this->post['remote'] = true;
3522 return $this->restoreBackup();
3523 } else {
3524 return ['status' => 'success', 'name' => $prepared_name];
3525 }
3526 } catch (\Exception $e) {
3527 $migration->log(__('Error: ', 'backup-backup') . $e, 'ERROR');
3528 $migration->log(__('Removing downloaded file', 'backup-backup'), 'ERROR');
3529 if (file_exists($dest)) @unlink($dest);
3530
3531 $migration->log('error_during_downloading_backup', 'verbose');
3532 $migration->log('error_during_downloading_backup', 'verbose');
3533 $migration->log('#002', 'END-CODE');
3534 return ['status' => 'error'];
3535 } catch (\Throwable $e) {
3536 $migration->log(__('Error: ', 'backup-backup') . $e, 'ERROR');
3537 $migration->log(__('Removing downloaded file', 'backup-backup'), 'ERROR');
3538 if (file_exists($dest)) @unlink($dest);
3539
3540 $migration->log('error_during_downloading_backup', 'verbose');
3541 $migration->log('error_during_downloading_backup', 'verbose');
3542 $migration->log('#002', 'END-CODE');
3543 return ['status' => 'error'];
3544
3545 }
3546
3547 } else {
3548
3549 // $migration->log(__('Error during manifest check: ', 'backup-backup') . print_r($content, true), 'ERROR');
3550 if ($this->lastCurlCode == '403') {
3551 $migration->log(__('Backup is not available to download (Error 403).', 'backup-backup'), 'ERROR');
3552 $migration->log(__('It is restricted by remote server configuration.', 'backup-backup'), 'ERROR');
3553 } elseif ($this->lastCurlCode == '423') {
3554 $migration->log(__('Backup is locked on remote site, please unlock remote downloading.', 'backup-backup'), 'ERROR');
3555 $migration->log(__('You can find the setting in "Where shall the backup(s) be stored?" section.', 'backup-backup'), 'ERROR');
3556 } elseif ($this->lastCurlCode == '200' || $this->lastCurlCode == '404') {
3557 $migration->log(__('Backup does not exist under provided URL.', 'backup-backup'), 'ERROR');
3558 $migration->log(__('Please confirm that you can download the backup file via provided URL.', 'backup-backup'), 'ERROR');
3559 $migration->log(__('...or the manifest file does not exist in the backup.', 'backup-backup'), 'ERROR');
3560 $migration->log(__('Missing manifest means that the backup is probably invalid.', 'backup-backup'), 'ERROR');
3561 } else {
3562 $migration->log(__('Manifest file does not exist', 'backup-backup'), 'ERROR');
3563 $migration->log(__('Downloaded backup may be incomplete (missing manifest)', 'backup-backup'), 'ERROR');
3564 $migration->log(__('...or provided URL is not a direct download of ZIP file.', 'backup-backup'), 'ERROR');
3565 $migration->log(__('Removing downloaded file', 'backup-backup'), 'ERROR');
3566 }
3567
3568 if (file_exists($dest)) @unlink($dest);
3569
3570 $migration->log('error_during_downloading_backup', 'verbose');
3571 $migration->log('error_during_downloading_backup', 'verbose');
3572 $migration->log('#002', 'END-CODE');
3573 return ['status' => 'error'];
3574
3575 }
3576 }
3577 }
3578
3579 public function handleChunkUpload() {
3580 require_once BMI_INCLUDES . '/uploader/chunks.php';
3581 }
3582
3583 public function removeBackupFile() {
3584 $files = $this->post['filenames'];
3585 $deleteCloud = $this->post['deleteCloud'] === 'yes' ? true : false;
3586 $cloudDetails = $this->post['cloudDetails'];
3587
3588 $md5_file_summary_path = BMI_BACKUPS . DIRECTORY_SEPARATOR. 'md5summary.php';
3589 $md5summary = [];
3590
3591 if (file_exists($md5_file_summary_path)) {
3592 $md5summary = file_get_contents($md5_file_summary_path);
3593 $md5summary = substr($md5summary, 18, -2);
3594 if (is_serialized($md5summary)) {
3595 $md5summary = maybe_unserialize($md5summary);
3596 }
3597 }
3598
3599 if ($deleteCloud) {
3600 //Initialize externall storages for backup deletion action to be initiated
3601 require_once BMI_INCLUDES . '/external/controller.php';
3602 new ExternalStorage();
3603
3604 if (defined('BMI_BACKUP_PRO') && defined('BMI_PRO_INC')) {
3605 $proPath = BMI_PRO_INC . 'external/controller.php';
3606 if (file_exists($proPath)) {
3607 require_once $proPath;
3608 new ExternalStoragePremium();
3609 }
3610 }
3611 }
3612
3613 try {
3614 if (is_array($files)) {
3615 for ($i = 0; $i < sizeof($files); $i++) {
3616
3617 $removeByMD5 = false;
3618 $file = $files[$i];
3619 $file = preg_replace('/\.\./', '', $file);
3620
3621 if (file_exists(BMI_BACKUPS . '/' . $file)) {
3622
3623 if ($deleteCloud) {
3624 do_action('bmi_premium_remove_backup_file', md5_file(BMI_BACKUPS . '/' . $file));
3625 }
3626
3627 unlink(BMI_BACKUPS . '/' . $file);
3628
3629 } else if ($deleteCloud) $removeByMD5 = true;
3630
3631 if (isset($md5summary[$file])) {
3632 $md5s = $md5summary[$file];
3633
3634 for ($j = 0; $j < sizeof($md5s); ++$j) {
3635 $md5_file_path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $md5s[$j] . '.json';
3636 if (file_exists($md5_file_path)) {
3637 if ($deleteCloud) {
3638 do_action('bmi_premium_remove_backup_json_file', $md5s[$j] . '.json');
3639 }
3640 unlink($md5_file_path);
3641 } else if ($deleteCloud) $removeByMD5 = true;
3642 }
3643
3644 unset($md5summary[$file]);
3645 }
3646
3647 if ($deleteCloud && $removeByMD5) {
3648 if (isset($cloudDetails[$file])) {
3649 do_action('bmi_premium_remove_backup_file', $cloudDetails[$file]['md5']);
3650 do_action('bmi_premium_remove_backup_json_file', $cloudDetails[$file]['md5'] . '.json');
3651 }
3652 }
3653
3654 }
3655 }
3656 } catch (\Exception $e) {
3657 return ['status' => 'error', 'e' => $e];
3658 } catch (\Throwable $e) {
3659 return ['status' => 'error', 'e' => $e];
3660 }
3661
3662 $cacheMd5String = "<?php exit; \$x = '" . serialize($md5summary) . "';";
3663 file_put_contents($md5_file_summary_path, $cacheMd5String);
3664
3665 return ['status' => 'success'];
3666 }
3667
3668 public function saveStorageConfig() {
3669 $dir_path = $this->post['directory']; // STORAGE::LOCAL::PATH
3670 $accessible = $this->post['access']; // STORAGE::DIRECT::URL
3671 $gdrivedirname = 'BACKUP_MIGRATION_BACKUPS'; // STORAGE::EXTERNAL::GDRIVE::DIRNAME // $this->post['gdrivedirname']
3672 $curr_path = Dashboard\bmi_get_config('STORAGE::LOCAL::PATH');
3673
3674 $errors = 0;
3675 $created = false;
3676
3677 if ($dir_path == WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'backup-migration') {
3678 return ['status' => 'msg', 'why' => __('For security reasons, please add a random string to the end of the default backup directory path. This will help protect your backup files from unauthorized access.', 'backup-backup'), 'level' => 'warning'];
3679 }
3680
3681 if (!preg_match("/^[a-zA-Z0-9\_\ \-\/\.]+$/", $dir_path)) {
3682 return ['status' => 'msg', 'why' => __('Entered directory/path name does not match allowed characters (Local Storage).', 'backup-backup'), 'level' => 'warning'];
3683 }
3684
3685 if (!is_string($dir_path) || $dir_path === '' ||
3686 !(preg_match('/^[A-Z]:[\/\\\\]/i', $dir_path) || strpos($dir_path, '/') === 0)) {
3687 return ['status' => 'msg', 'why' => __('Please enter full path to the directory (Local Storage).', 'backup-backup'), 'level' => 'warning'];
3688 }
3689 if (!file_exists($dir_path)) {
3690 $created = @mkdir($dir_path, 0755, true);
3691 }
3692
3693 if (isset($this->post['backupbliss'])) {
3694 $backupblissenabled = $this->post['backupbliss'];
3695 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::backupbliss', $backupblissenabled)) {
3696 $errors++;
3697 }
3698 }
3699
3700 if (isset($this->post['dropbox'])) {
3701 $dropboxenabled = $this->post['dropbox'];
3702 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::DROPBOX', $dropboxenabled)) {
3703 $errors++;
3704 }
3705 }
3706
3707 if (isset($this->post['gdrive'])) {
3708 $gdriveenabled = $this->post['gdrive'];
3709 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::GDRIVE', $gdriveenabled)) {
3710 $errors++;
3711 }
3712
3713 if (isset($this->post['gdrivedirname'])) {
3714 $gdrivedirname = $this->post['gdrivedirname'];
3715
3716 if (!preg_match("/^[a-zA-Z0-9\_\-\.]+$/", $gdrivedirname)) {
3717 return ['status' => 'msg', 'why' => __('Entered directory name does not match allowed characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
3718 }
3719
3720 if (strlen(trim($gdrivedirname)) < 3) {
3721 return ['status' => 'msg', 'why' => __('Entered directory name is too short, min 3 characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
3722 }
3723
3724 if (strlen(trim($gdrivedirname)) > 48) {
3725 return ['status' => 'msg', 'why' => __('Entered directory name is too long, max 48 characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
3726 }
3727
3728 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::GDRIVE::DIRNAME', $gdrivedirname)) {
3729 $errors++;
3730 }
3731 }
3732 }
3733
3734 if (isset($this->post['ftp'])) {
3735 $ftpenabled = $this->post['ftp'];
3736 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::FTP', $ftpenabled)) {
3737 $errors++;
3738 }
3739
3740 if ($ftpenabled != "false"){
3741 if (isset($this->post['ftphostip'])) {
3742 $ftpiphost = $this->post['ftphostip'];
3743 update_option('bmi_pro_ftp_host', $ftpiphost);
3744 }
3745
3746 if (isset($this->post['ftphostusername'])) {
3747 $ftpHostUsername = $this->post['ftphostusername'];
3748 update_option('bmi_pro_ftp_username', $ftpHostUsername);
3749 }
3750
3751 if (isset($this->post['ftppassword'])) {
3752 $ftpHostPassword = $this->post['ftppassword'];
3753 if (!empty($ftpHostPassword) && is_string($ftpHostPassword) && strlen(trim($ftpHostPassword)) > 0)
3754 update_option('bmi_pro_ftp_password', $ftpHostPassword);
3755 }
3756
3757 if (isset($this->post['ftpport'])) {
3758 $ftpHostPort = $this->post['ftpport'];
3759 update_option('bmi_pro_ftp_port', $ftpHostPort);
3760 }
3761
3762 if (isset($this->post['ftpdir'])) {
3763 $ftpHostDir = $this->post['ftpdir'];
3764 update_option('bmi_pro_ftp_backup_dir', $ftpHostDir);
3765 }
3766 } else {
3767 delete_option('bmi_pro_ftp_host');
3768 delete_option('bmi_pro_ftp_username');
3769 delete_option('bmi_pro_ftp_password');
3770 }
3771
3772 } else {
3773 delete_option('bmi_pro_ftp_host');
3774 delete_option('bmi_pro_ftp_username');
3775 delete_option('bmi_pro_ftp_password');
3776 }
3777
3778 if (isset($this->post['aws'])) {
3779 $s3enabled = $this->post['aws'];
3780 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::AWS', $s3enabled)) {
3781 $errors++;
3782 }
3783 }
3784
3785 if (isset($this->post['wasabi'])) {
3786 $wasabienabled = $this->post['wasabi'];
3787 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::WASABI', $wasabienabled)) {
3788 $errors++;
3789 }
3790 }
3791
3792 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO === 1) {
3793
3794 if (isset($this->post['onedrive'])) {
3795 $onedriveenabled = $this->post['onedrive'];
3796 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::ONEDRIVE', $onedriveenabled)) {
3797 $errors++;
3798 }
3799 }
3800
3801 if (isset($this->post['sftp'])) {
3802 $sftpenabled = $this->post['sftp'];
3803 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::SFTP', $sftpenabled)) {
3804 $errors++;
3805 }
3806
3807 }
3808
3809 if (isset($this->post['pcloud'])) {
3810 $pcloudenabled = $this->post['pcloud'];
3811 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::PCLOUD', $pcloudenabled)) {
3812 $errors++;
3813 }
3814 }
3815
3816
3817 }
3818
3819 if (is_writable($dir_path)) {
3820 if (!Dashboard\bmi_set_config('STORAGE::DIRECT::URL', $accessible)) {
3821 Logger::error('Backup Storage Direct Url Error');
3822 $errors++;
3823 }
3824 if (!Dashboard\bmi_set_config('STORAGE::LOCAL::PATH', esc_attr($dir_path))) {
3825 Logger::error('Backup Storage Local Path Error');
3826 $errors++;
3827 } else {
3828 $cur_dir = BMP::fixSlashes($curr_path);
3829 $new_dir = BMP::fixSlashes($dir_path);
3830
3831 $backups_cur_dir = BMP::fixSlashes($curr_path) . DIRECTORY_SEPARATOR . 'backups';
3832 $backups_new_dir = BMP::fixSlashes($dir_path) . DIRECTORY_SEPARATOR . 'backups';
3833
3834 $staging_cur_dir = BMP::fixSlashes($curr_path) . DIRECTORY_SEPARATOR . 'staging';
3835 $staging_new_dir = BMP::fixSlashes($dir_path) . DIRECTORY_SEPARATOR . 'staging';
3836
3837 $tmp_cur_dir = BMP::fixSlashes($curr_path) . DIRECTORY_SEPARATOR . 'tmp';
3838 $tmp_new_dir = BMP::fixSlashes($dir_path) . DIRECTORY_SEPARATOR . 'tmp';
3839
3840 update_option('BMI::STORAGE::LOCAL::PATH', $new_dir);
3841
3842 if ($cur_dir != $new_dir) {
3843
3844 if (!file_exists($new_dir)) @mkdir($new_dir, 0755, true);
3845 if (!file_exists($backups_new_dir)) @mkdir($backups_new_dir, 0755, true);
3846 if (!file_exists($staging_new_dir)) @mkdir($staging_new_dir, 0755, true);
3847 if (!file_exists($tmp_new_dir)) @mkdir($tmp_new_dir, 0755, true);
3848
3849 $scanned_directory_staging = array_diff(scandir($staging_cur_dir), ['..', '.']);
3850 foreach ($scanned_directory_staging as $i => $file) {
3851 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($staging_cur_dir . DIRECTORY_SEPARATOR . $file)) {
3852 rename($staging_cur_dir . DIRECTORY_SEPARATOR . $file, $staging_new_dir . DIRECTORY_SEPARATOR . $file);
3853 }
3854 }
3855
3856 $scanned_directory_tmp = array_diff(scandir($tmp_cur_dir), ['..', '.']);
3857 foreach ($scanned_directory_tmp as $i => $file) {
3858 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($tmp_cur_dir . DIRECTORY_SEPARATOR . $file)) {
3859 rename($tmp_cur_dir . DIRECTORY_SEPARATOR . $file, $tmp_new_dir . DIRECTORY_SEPARATOR . $file);
3860 }
3861 }
3862
3863 $scanned_directory_backups = array_diff(scandir($backups_cur_dir), ['..', '.']);
3864 foreach ($scanned_directory_backups as $i => $file) {
3865 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($backups_cur_dir . DIRECTORY_SEPARATOR . $file)) {
3866 rename($backups_cur_dir . DIRECTORY_SEPARATOR . $file, $backups_new_dir . DIRECTORY_SEPARATOR . $file);
3867 }
3868 }
3869
3870 $scanned_directory = array_diff(scandir($cur_dir), ['..', '.']);
3871 foreach ($scanned_directory as $i => $file) {
3872 if (file_exists($cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($cur_dir . DIRECTORY_SEPARATOR . $file)) {
3873 rename($cur_dir . DIRECTORY_SEPARATOR . $file, $new_dir . DIRECTORY_SEPARATOR . $file);
3874 }
3875 }
3876
3877 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . '.htaccess')) @unlink($backups_cur_dir . DIRECTORY_SEPARATOR . '.htaccess');
3878 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.php')) @unlink($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.php');
3879 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.html')) @unlink($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.html');
3880 if (file_exists($backups_cur_dir)) @rmdir($backups_cur_dir);
3881
3882 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . '.htaccess')) @unlink($staging_cur_dir . DIRECTORY_SEPARATOR . '.htaccess');
3883 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.php')) @unlink($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.php');
3884 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.html')) @unlink($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.html');
3885 if (file_exists($staging_cur_dir)) @rmdir($staging_cur_dir);
3886
3887 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . '.htaccess')) @unlink($tmp_cur_dir . DIRECTORY_SEPARATOR . '.htaccess');
3888 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.php')) @unlink($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.php');
3889 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.html')) @unlink($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.html');
3890 if (file_exists($tmp_cur_dir)) @rmdir($tmp_cur_dir);
3891
3892 if (file_exists($cur_dir . DIRECTORY_SEPARATOR . 'complete_logs.' . BMI_LOGS_SUFFIX . '.log')) @unlink($cur_dir . DIRECTORY_SEPARATOR . 'complete_logs.' . BMI_LOGS_SUFFIX . '.log');
3893 if (file_exists($cur_dir)) @rmdir($cur_dir);
3894
3895 if (is_dir($cur_dir) && file_exists($cur_dir)) {
3896 $left_files = array_diff(scandir($cur_dir), ['..', '.']);
3897 if (sizeof($left_files) == 0) {
3898 if (file_exists($cur_dir)) {
3899 @rmdir($cur_dir);
3900 }
3901 }
3902 }
3903
3904 }
3905 }
3906 } else {
3907 if ($created === true) {
3908 if (file_exists($dir_path)) @unlink($dir_path);
3909 }
3910
3911 return ['status' => 'msg', 'why' => __('Entered path is not writable, cannot be used.', 'backup-backup'), 'level' => 'warning'];
3912 }
3913
3914 return ['status' => 'success', 'errors' => $errors];
3915 }
3916
3917 public function saveOtherOptions() {
3918
3919 // Errors
3920 $invalid_email = __('Provided email addess is not valid.', 'backup-backup');
3921 $title_long = __('Your email title is too long, please change the title (max 64 chars).', 'backup-backup');
3922 $title_short = __('Your email title is too short, please use longer one (at least 3 chars).', 'backup-backup');
3923 $title_empty = __('Title field is required, please fill it.', 'backup-backup');
3924 $email_empty = __('Email field cannot be empty, please fill it.', 'backup-backup');
3925 $cli_no_exist = __('Path to executable that you provided for PHP CLI does not exist.', 'backup-backup');
3926 $db_query_too_low = __('The value for query amount cannot be smaller than 15.', 'backup-backup');
3927 $db_query_too_much = __('The value for query amount cannot be larger than 15000.', 'backup-backup');
3928 $db_sr_max_too_low = __('The value for search replace max page cannot be smaller than 10.', 'backup-backup');
3929 $db_sr_max_too_much = __('The value for search replace max page cannot be larger than 30000.', 'backup-backup');
3930 $fl_ex_max_too_low = __('The value for extraction limit cannot be smaller than 50.', 'backup-backup');
3931 $fl_ex_max_too_much = __('The value for extraction limit cannot be larger than 20000.', 'backup-backup');
3932
3933 $email = sanitize_email(trim($this->post['email'])); // OTHER:EMAIL
3934 $email_title = sanitize_text_field(trim($this->post['email_title'])); // OTHER:EMAIL:TITLE
3935 $schedule_issues = $this->post['schedule_issues'] === 'true' ? true : false; // OTHER:EMAIL:NOTIS
3936 $experiment_timeout = $this->post['experiment_timeout'] === 'true' ? true : false; // OTHER:EXPERIMENT:TIMEOUT
3937 $experiment_timeout_hard = $this->post['experimental_hard_timeout'] === 'true' ? true : false; // OTHER:EXPERIMENT:TIMEOUT:HARD
3938 $php_cli_manual_path = isset($this->post['php_cli_manual_path']) ? trim($this->post['php_cli_manual_path']) : ''; // OTHER:CLI:PATH
3939 $php_cli_disable_others = $this->post['php_cli_disable_others'] === 'true' ? true : false; // OTHER:CLI:DISABLE
3940 $normal_timeout = $this->post['normal_timeout'] === 'true' ? true : false; // OTHER:USE:TIMEOUT:NORMAL
3941 $insecure_download = $this->post['download_technique'] === 'true' ? true : false; // OTHER:DOWNLOAD:DIRECT
3942 $db_query_size = isset($this->post['db_queries_amount']) ? trim($this->post['db_queries_amount']) : '2000'; // OTHER:DB:QUERIES
3943 $db_search_replace_max = isset($this->post['db_search_replace_max']) ? trim($this->post['db_search_replace_max']) : '300'; // OTHER:DB:SEARCHREPLACE:MAX
3944 $file_limit_extraction_max = isset($this->post['file_limit_extraction_max']) ? trim($this->post['file_limit_extraction_max']) : 'auto'; // OTHER:FILE:EXTRACT:MAX
3945 $db_restore_splitting = $this->post['bmi-restore-splitting'] === 'true' ? true : false; // OTHER:RESTORE:SPLITTING
3946 $db_restore_v3_engine = $this->post['bmi-db-v3-restore-engine'] === 'true' ? true : false; // OTHER:RESTORE:DB:V3
3947
3948 $no_assets_b4_restore = $this->post['remove-assets-before-restore'] === 'true' ? true : false; // OTHER:RESTORE:BEFORE:CLEANUP
3949 $single_file_db_force = $this->post['bmi-db-single-file-backup'] === 'true' ? true : false; // OTHER:BACKUP:DB:SINGLE:FILE
3950 $db_batching_backup = $this->post['bmi-db-batching-backup'] === 'true' ? true : false; // OTHER:BACKUP:DB:BATCHING
3951
3952 $bmi_disable_space_check = $this->post['bmi-disable-space-check-function'] === 'true' ? true : false; // OTHER:BACKUP:SPACE:CHECKING
3953
3954 $uninstall_config = $this->post['uninstall_config'] === 'true' ? true : false; // OTHER:UNINSTALL:CONFIGS
3955 $uninstall_backups = $this->post['uninstall_backups'] === 'true' ? true : false; // OTHER:UNINSTALL:BACKUPS
3956 $use_new_search_replace_engine = $this->post['use_new_search_replace_engine'] === 'true' ? true : false; // OTHER::NEW_SEARCH_REPLACE_ENGINE
3957 $use_new_database_export_engine = $this->post['use_new_database_export_engine'] === 'true' ? true : false; // OTHER::NEW_DATABASE_EXPORT_ENGINE
3958
3959 if ($experiment_timeout_hard === true) {
3960 $experiment_timeout = false;
3961 }
3962
3963 if ($normal_timeout === true) {
3964 $experiment_timeout = false;
3965 $experiment_timeout_hard = false;
3966 }
3967
3968 if (!is_numeric($db_query_size) || empty($db_query_size)) {
3969 $db_query_size = "2000";
3970 }
3971
3972 if (!is_numeric($file_limit_extraction_max) || empty($file_limit_extraction_max)) {
3973 $file_limit_extraction_max = "auto";
3974 }
3975
3976 if (!is_numeric($db_search_replace_max) || empty($db_search_replace_max)) {
3977 $db_search_replace_max = "300";
3978 }
3979
3980 if (strlen($email) <= 0) {
3981 return ['status' => 'msg', 'why' => $email_empty, 'level' => 'warning'];
3982 }
3983 if (strlen($email_title) <= 0) {
3984 return ['status' => 'msg', 'why' => $title_empty, 'level' => 'warning'];
3985 }
3986 if (strlen($email_title) > 64) {
3987 return ['status' => 'msg', 'why' => $title_long, 'level' => 'warning'];
3988 }
3989 if (strlen($email_title) < 3) {
3990 return ['status' => 'msg', 'why' => $title_short, 'level' => 'warning'];
3991 }
3992 if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
3993 return ['status' => 'msg', 'why' => $invalid_email, 'level' => 'warning'];
3994 }
3995 if ($php_cli_manual_path != '' && !file_exists($php_cli_manual_path)) {
3996 return ['status' => 'msg', 'why' => $cli_no_exist, 'level' => 'warning'];
3997 }
3998 if (intval($db_query_size) > 15000) {
3999 return ['status' => 'msg', 'why' => $db_query_too_much, 'level' => 'warning'];
4000 }
4001 if (intval($db_query_size) < 15) {
4002 return ['status' => 'msg', 'why' => $db_query_too_low, 'level' => 'warning'];
4003 }
4004 if (intval($db_search_replace_max) > 30000) {
4005 return ['status' => 'msg', 'why' => $db_sr_max_too_much, 'level' => 'warning'];
4006 }
4007 if (intval($db_search_replace_max) < 10) {
4008 return ['status' => 'msg', 'why' => $db_sr_max_too_low, 'level' => 'warning'];
4009 }
4010 if ($file_limit_extraction_max != 'auto' && intval($file_limit_extraction_max) > 20000) {
4011 return ['status' => 'msg', 'why' => $fl_ex_max_too_much, 'level' => 'warning'];
4012 }
4013 if ($file_limit_extraction_max != 'auto' && intval($file_limit_extraction_max) < 50) {
4014 return ['status' => 'msg', 'why' => $fl_ex_max_too_low, 'level' => 'warning'];
4015 }
4016
4017 $error = 0;
4018 if (!Dashboard\bmi_set_config('OTHER:EMAIL', $email)) {
4019 Logger::error('Backup Other Email Error');
4020 $error++;
4021 }
4022 if (!Dashboard\bmi_set_config('OTHER:EMAIL:TITLE', $email_title)) {
4023 Logger::error('Backup Other Email Title Error');
4024 $error++;
4025 }
4026 if (!Dashboard\bmi_set_config('OTHER:EMAIL:NOTIS', $schedule_issues)) {
4027 Logger::error('Backup Other Email Notis Error');
4028 $error++;
4029 }
4030 if (!Dashboard\bmi_set_config('OTHER:CLI:PATH', $php_cli_manual_path)) {
4031 Logger::error('Backup Other CLI Path Error');
4032 $error++;
4033 }
4034 if (!Dashboard\bmi_set_config('OTHER:CLI:DISABLE', $php_cli_disable_others)) {
4035 Logger::error('Backup Other CLI Disable Error');
4036 $error++;
4037 }
4038 if (!Dashboard\bmi_set_config('OTHER:EXPERIMENT:TIMEOUT', $experiment_timeout)) {
4039 Logger::error('Backup Other Experiment Timeout Error');
4040 $error++;
4041 }
4042 if (!Dashboard\bmi_set_config('OTHER:EXPERIMENT:TIMEOUT:HARD', $experiment_timeout_hard)) {
4043 Logger::error('Backup Other Experiment Timeout Hard Error');
4044 $error++;
4045 }
4046 if (!Dashboard\bmi_set_config('OTHER:USE:TIMEOUT:NORMAL', $normal_timeout)) {
4047 Logger::error('Backup Other Experiment Timeout Normal Error');
4048 $error++;
4049 }
4050 if (!Dashboard\bmi_set_config('OTHER:RESTORE:DB:V3', $db_restore_v3_engine)) {
4051 Logger::error('Backup Other Restore DB V3 Error');
4052 $error++;
4053 }
4054 if (!Dashboard\bmi_set_config('OTHER:DB:QUERIES', $db_query_size)) {
4055 Logger::error('Backup Other DB Queries Error');
4056 $error++;
4057 }
4058 if (!Dashboard\bmi_set_config('OTHER:DB:SEARCHREPLACE:MAX', $db_search_replace_max)) {
4059 Logger::error('Backup Other DB Queries Error');
4060 $error++;
4061 }
4062 if (!Dashboard\bmi_set_config('OTHER:FILE:EXTRACT:MAX', $file_limit_extraction_max)) {
4063 Logger::error('Backup Other File Extract Max Error');
4064 $error++;
4065 }
4066 if (!Dashboard\bmi_set_config('OTHER:DOWNLOAD:DIRECT', $insecure_download)) {
4067 Logger::error('Backup Other Download Direct Error');
4068 $error++;
4069 }
4070 if (!Dashboard\bmi_set_config('OTHER:UNINSTALL:CONFIGS', $uninstall_config)) {
4071 Logger::error('Backup Other Uninstall Configs Error');
4072 $error++;
4073 }
4074 if (!Dashboard\bmi_set_config('OTHER:UNINSTALL:BACKUPS', $uninstall_backups)) {
4075 Logger::error('Backup Other Uninstall Backups Error');
4076 $error++;
4077 }
4078 if (!Dashboard\bmi_set_config('OTHER:RESTORE:SPLITTING', $db_restore_splitting)) {
4079 Logger::error('Backup Other Restore Splitting Error');
4080 $error++;
4081 }
4082 if (!Dashboard\bmi_set_config('OTHER:BACKUP:DB:SINGLE:FILE', $single_file_db_force)) {
4083 Logger::error('Backup Other Backup DB Single File Error');
4084 $error++;
4085 }
4086 if (!Dashboard\bmi_set_config('OTHER:BACKUP:DB:BATCHING', $db_batching_backup)) {
4087 Logger::error('Backup Other Backup DB Batching Error');
4088 $error++;
4089 }
4090 if (!Dashboard\bmi_set_config('OTHER:BACKUP:SPACE:CHECKING', $bmi_disable_space_check)) {
4091 Logger::error('Backup Other Backup Space Checking Error');
4092 $error++;
4093 }
4094 if (!Dashboard\bmi_set_config('OTHER:RESTORE:BEFORE:CLEANUP', $no_assets_b4_restore)) {
4095 Logger::error('Backup Other Restore Before Cleanup Error');
4096 $error++;
4097 }
4098 if (!Dashboard\bmi_set_config('OTHER::NEW_SEARCH_REPLACE_ENGINE', $use_new_search_replace_engine)) {
4099 Logger::error('Backup Other DB Search Replace New Engine Error');
4100 $error++;
4101 }
4102 if (!Dashboard\bmi_set_config('OTHER::NEW_DATABASE_EXPORT_ENGINE', $use_new_database_export_engine)) {
4103 Logger::error('Backup Other DB New Export Engine Error');
4104 $error++;
4105 }
4106
4107 if (has_action('bmi_premium_other_options')) {
4108 do_action('bmi_premium_other_options', $this->post);
4109 }
4110
4111 return ['status' => 'success', 'errors' => $error];
4112 }
4113
4114 public function saveStorageTypeConfig() {
4115
4116 // Errors
4117 $name_empty = __('Name is required, please fill the input.', 'backup-backup');
4118 $name_long = __('Your name is too long, please change the name.', 'backup-backup');
4119 $name_short = __('Your name is too short, please create longer one.', 'backup-backup');
4120 $name_space = __('Please, do not use spaces in file name.', 'backup-backup');
4121 $name_forbidden = __('Your name contains character(s) that are not allowed in file names: ', 'backup-backup');
4122
4123 $forbidden_chars = ['/', '\\', '<', '>', ':', '"', "'", '|', '?', '*', '.', ';', '@', '!', '~', '`', ',', '#', '$', '&', '=', '+'];
4124 $name = trim($this->post['name']); // BACKUP:NAME
4125 $extensionType = trim($this->post['extension']); // BACKUP:EXTENSION:TYPE
4126
4127 if (strlen($name) == 0) {
4128 return ['status' => 'msg', 'why' => $name_empty, 'level' => 'warning'];
4129 }
4130 if (strlen($name) > 40) {
4131 return ['status' => 'msg', 'why' => $name_long, 'level' => 'warning'];
4132 }
4133 if (strlen($name) < 3) {
4134 return ['status' => 'msg', 'why' => $name_short, 'level' => 'warning'];
4135 }
4136 if (strpos($name, ' ') !== false) {
4137 return ['status' => 'msg', 'why' => $name_space, 'level' => 'warning'];
4138 }
4139
4140 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO == 1) {
4141 if (!in_array($extensionType, ['.zip', '.tar.gz', '.tar'])) {
4142 return ['status' => 'msg', 'why' => $name_space, 'level' => 'warning'];
4143 }
4144 }
4145
4146 for ($i = 0; $i < sizeof($forbidden_chars); ++$i) {
4147 $char = $forbidden_chars[$i];
4148 if (strpos($name, $char) !== false) {
4149 return ['status' => 'msg', 'why' => $name_forbidden . $char, 'level' => 'warning'];
4150 }
4151 }
4152
4153 $error = 0;
4154 if (!Dashboard\bmi_set_config('BACKUP:NAME', $name)) {
4155 Logger::error('Backup Name Error');
4156 $error++;
4157 }
4158
4159 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO == 1) {
4160 if (!Dashboard\bmi_set_config('BACKUP:EXTENSION:TYPE', $extensionType)) {
4161 Logger::error('Backup Extension Type Error');
4162 $error++;
4163 }
4164 }
4165
4166 return ['status' => 'success', 'errors' => $error];
4167 }
4168
4169 public function saveFilesConfig() {
4170 $db_group = $this->post['database_group']; // BACKUP:DATABASE
4171 $files_group = $this->post['files_group']; // BACKUP:FILES
4172
4173 $fgp = $this->post['files-group-plugins']; // BACKUP:FILES::PLUGINS
4174 $fgu = $this->post['files-group-uploads']; // BACKUP:FILES::UPLOADS
4175 $fgt = $this->post['files-group-themes']; // BACKUP:FILES::THEMES
4176 $fgoc = $this->post['files-group-other-contents']; // BACKUP:FILES::OTHERS
4177 $fgwp = $this->post['files-group-wp-install']; // BACKUP:FILES::WP
4178
4179 $file_filters = $this->post['files_by_filters']; // BACKUP:FILES::FILTER
4180 $ffs = $this->post['ex_b_fs']; // BACKUP:FILES::FILTER:SIZE
4181 $ffsizemax = $this->post['BFFSIN']; // BACKUP:FILES::FILTER:SIZE:IN
4182 $ffn = $this->post['ex_b_names']; // BACKUP:FILES::FILTER:NAMES
4183 $ffp = $this->post['ex_b_fpaths']; // BACKUP:FILES::FILTER:FPATHS
4184 $ffd = $this->post['ex_b_dpaths']; // BACKUP:FILES::FILTER:DPATHS
4185
4186 $dbeg = $this->post['db-exclude-tables-group']; // BACKUP:DATABASE:EXCLUDE
4187 $dbet = $this->post['db-excluded-tables']; // BACKUP:DATABASE:EXCLUDE:LIST
4188
4189 $existant = [];
4190 $parsed = [];
4191 $ffnames = $this->post['dynamic-names']; // BACKUP:FILES::FILTER:NAMES:IN
4192 $ffpnames = array_unique($this->post['dynamic-fpaths-names']); // BACKUP:FILES::FILTER:FPATHS:IN
4193 $ffdnames = array_unique($this->post['dynamic-dpaths-names']); // BACKUP:FILES::FILTER:DPATHS:IN
4194
4195 if (is_array($dbet) || is_object($dbet)) {
4196 if (sizeof($dbet) == 1 && $dbet[0] == 'empty') {
4197 $dbet = [];
4198 }
4199 }
4200
4201 if ($dbeg === 'true' || $dbeg === true) $dbeg = true;
4202 else $dbeg = false;
4203
4204 $max = sizeof($ffpnames);
4205 for ($i = 0; $i < $max; ++$i) {
4206 if (!is_string($ffpnames[$i]) || trim(strlen($ffpnames[$i])) <= 1) {
4207 array_splice($ffpnames, $i, 1);
4208 $i--;
4209 $max--;
4210 }
4211 }
4212
4213 $max = sizeof($ffdnames);
4214 for ($i = 0; $i < $max; ++$i) {
4215 if (!is_string($ffdnames[$i]) || trim(strlen($ffdnames[$i])) <= 1) {
4216 array_splice($ffdnames, $i, 1);
4217 $i--;
4218 $max--;
4219 }
4220 }
4221
4222 for ($i = 0; $i < sizeof($ffnames); ++$i) {
4223 $row = $ffnames[$i];
4224 $txt = array_key_exists('txt', $row) ? "" . $row['txt'] . "" : false;
4225 $pos = array_key_exists('pos', $row) ? $row['pos'] : false;
4226 $whr = array_key_exists('whr', $row) ? $row['whr'] : false;
4227
4228 if ($txt === false || $pos === false || $whr === false) {
4229 continue;
4230 }
4231 if (trim(strlen($txt)) <= 0) {
4232 continue;
4233 }
4234 if (!in_array($pos, ["1", "2", "3"])) {
4235 continue;
4236 }
4237 if (!in_array($whr, ["1", "2"])) {
4238 continue;
4239 }
4240 if (in_array($txt . $pos . $whr, $existant)) {
4241 continue;
4242 } else {
4243 $existant[] = $txt . $pos . $whr;
4244 }
4245
4246 $parsed[] = ['txt' => $txt, 'pos' => $pos, 'whr' => $whr];
4247 }
4248
4249 if ($ffs == 'true' && !is_numeric($ffsizemax)) {
4250 return ['status' => 'msg', 'why' => __('Entred file size limit, is not correct number.', 'backup-backup'), 'level' => 'warning'];
4251 }
4252
4253 $error = 0;
4254 if (!Dashboard\bmi_set_config('BACKUP:DATABASE', $db_group)) {
4255 Logger::error('Backup Database Error');
4256 $error++;
4257 }
4258 if (!Dashboard\bmi_set_config('BACKUP:FILES', $files_group)) {
4259 Logger::error('Backup Files Error');
4260 $error++;
4261 }
4262
4263 if (!Dashboard\bmi_set_config('BACKUP:FILES::PLUGINS', $fgp)) {
4264 Logger::error('Backup Files Plugins Error');
4265 $error++;
4266 }
4267 if (!Dashboard\bmi_set_config('BACKUP:FILES::UPLOADS', $fgu)) {
4268 Logger::error('Backup Files Uploads Error');
4269 $error++;
4270 }
4271 if (!Dashboard\bmi_set_config('BACKUP:FILES::THEMES', $fgt)) {
4272 Logger::error('Backup Files Themes Error');
4273 $error++;
4274 }
4275 if (!Dashboard\bmi_set_config('BACKUP:FILES::OTHERS', $fgoc)) {
4276 Logger::error('Backup Files Others Error');
4277 $error++;
4278 }
4279 if (!Dashboard\bmi_set_config('BACKUP:FILES::WP', $fgwp)) {
4280 Logger::error('Backup Files WP Error');
4281 $error++;
4282 }
4283
4284 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER', $file_filters)) {
4285 Logger::error('Backup Files Filter Error');
4286 $error++;
4287 }
4288 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:SIZE', $ffs)) {
4289 Logger::error('Backup Files Filter Size Error');
4290 $error++;
4291 }
4292 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:NAMES', $ffn)) {
4293 Logger::error('Backup Files Names Error');
4294 $error++;
4295 }
4296 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:FPATHS', $ffp)) {
4297 Logger::error('Backup Files Fpaths Error');
4298 $error++;
4299 }
4300 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:DPATHS', $ffd)) {
4301 Logger::error('Backup Files Dpaths Error');
4302 $error++;
4303 }
4304
4305 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:SIZE:IN', $ffsizemax)) {
4306 Logger::error('Backup Files Filter Size In Error');
4307 $error++;
4308 }
4309 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:NAMES:IN', $parsed)) {
4310 Logger::error('Backup Files Filter Names In Error');
4311 $error++;
4312 }
4313 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:FPATHS:IN', $ffpnames)) {
4314 Logger::error('Backup Files Filter Fpaths In Error');
4315 $error++;
4316 }
4317 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:DPATHS:IN', $ffdnames)) {
4318 Logger::error('Backup Files Filter Dpaths In Error');
4319 $error++;
4320 }
4321
4322 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO == 1) {
4323 if (!Dashboard\bmi_set_config('BACKUP:DATABASE:EXCLUDE', $dbeg)) {
4324 Logger::error('Backup Files Filter Database Exclude Error');
4325 $error++;
4326 }
4327 if (!Dashboard\bmi_set_config('BACKUP:DATABASE:EXCLUDE:LIST', $dbet)) {
4328 Logger::error('Backup Files Filter Database Exclude List Error');
4329 $error++;
4330 }
4331 }
4332
4333 if (has_action('bmip_smart_exclusion_options')){
4334 do_action('bmip_smart_exclusion_options', $this->post);
4335 }
4336
4337 // return array('status' => 'msg', 'why' => __('Entred path is not writable or does not exist.', 'backup-backup'), 'level' => 'warning');
4338
4339 return ['status' => 'success', 'errors' => $error];
4340 }
4341
4342 public function scanFilesForBackup(&$progress, $stgSites = [], $fileCalcType = false) {
4343 require_once BMI_INCLUDES . '/scanner/files.php';
4344 require_once BMI_INCLUDES . '/file-explorer.php';
4345 $stagingSites = [];
4346
4347 // Get all directory names of staging sites
4348 foreach ($stgSites as $index => $site) {
4349
4350 // Convert every directory to their location path
4351 $stagingSites[] = '***ABSPATH***/' . $site['name'];
4352
4353 }
4354
4355 // Use filters?
4356 $is = Dashboard\bmi_get_config('BACKUP:FILES::FILTER') === 'true' ? true : false;
4357
4358 // Get settings form config
4359 $fgp = Dashboard\bmi_get_config('BACKUP:FILES::PLUGINS');
4360 $fgt = Dashboard\bmi_get_config('BACKUP:FILES::THEMES');
4361 $fgu = Dashboard\bmi_get_config('BACKUP:FILES::UPLOADS');
4362 $fgoc = Dashboard\bmi_get_config('BACKUP:FILES::OTHERS');
4363 $fgwp = Dashboard\bmi_get_config('BACKUP:FILES::WP');
4364 $dpathsis = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:DPATHS') === 'true' ? true : false;
4365 $dpaths = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:DPATHS:IN');
4366 $dynamesis = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES') === 'true' ? true : false;
4367 $dynames = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES:IN');
4368 $dynparsed = [];
4369
4370 $isSmartExclusion =defined("BMI_BACKUP_PRO") && BMI_BACKUP_PRO && Dashboard\bmi_get_config('SMART:EXCLUSION:ENABLED') == 'true' ? true : false;
4371 $isCacheExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:CACHE') == 'true' ? true : false);
4372 $isDeactivePluginsExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:DPLUGINS') == 'true' ? true : false);
4373 $isNotUsedThemesExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:NUTHEMES') == 'true' ? true : false);
4374 $isDebugLogsExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:DLOGS') == 'true' ? true : false);
4375 $isPostRevisionsExcluded = $isSmartExclusion &&(Dashboard\bmi_get_config('SMART:EXCLUSION:PREVISIONS') == 'true' ? true : false);
4376
4377
4378 if ($fileCalcType != false) {
4379 $fgp = ($fileCalcType == 'plugins') ? true : false;
4380 $fgt = ($fileCalcType == 'themes') ? true : false;
4381 $fgu = ($fileCalcType == 'uploads') ? true : false;
4382 $fgoc = ($fileCalcType == 'contents_others') ? true : false;
4383 $fgwp = ($fileCalcType == 'wordpress') ? true : false;
4384 }
4385
4386 // Filter dynames to for smaller size
4387 if ($is && $dynamesis) {
4388 for ($i = 0; $i < sizeof($dynames); ++$i) {
4389 $s = $dynames[$i];
4390 if ($s->whr == '2') {
4391 $dynparsed[] = ['s' => $s->txt, 'w' => $s->pos, 'z' => strlen($s->txt)];
4392 }
4393 }
4394 }
4395
4396 // Set exclusion rules
4397 $ignored_folders_default = [];
4398 if ($is && $dynamesis) {
4399 BMP::merge_arrays($ignored_folders_default, $dynparsed);
4400 }
4401 $ignored_folders = $ignored_folders_default;
4402 $ignored_paths_default = [BMI_CONFIG_DIR, BMI_ROOT_DIR];
4403 $ignored_paths_default[] = "***ABSPATH***/wp-content/ai1wm-backups";
4404 $ignored_paths_default[] = "***ABSPATH***/wp-content/ai1wm-backups-old";
4405 $ignored_paths_default[] = "***ABSPATH***/wp-content/mwp-download";
4406 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-clone";
4407 $ignored_paths_default[] = "***ABSPATH***/wp-content/updraft";
4408 $ignored_paths_default[] = "***ABSPATH***/wp-content/ebwp-backups";
4409 $ignored_paths_default[] = "***ABSPATH***/wp-content/cache/seraphinite-accelerator";
4410 $ignored_paths_default[] = "***ABSPATH***/wp-content/backups-dup-pro";
4411 $ignored_paths_default[] = "***ABSPATH***/wp-content/wpvividbackups";
4412 $ignored_paths_default[] = "***ABSPATH***/wp-content/backup-guard";
4413 $ignored_paths_default[] = "***ABSPATH***/wp-content/backuply";
4414 $ignored_paths_default[] = "***ABSPATH***/wp-content/backups-dup-lite";
4415 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/backupbuddy_backups";
4416 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-file-manager-pro";
4417 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-file-manager";
4418 $ignored_paths_default[] = "***ABSPATH***/wp-content/plugins/akeebabackupwp";
4419 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/jetbackup";
4420 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/backup-guard";
4421 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-migrate-db";
4422
4423 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-staging";
4424
4425 if ($isSmartExclusion && ($fileCalcType == false || $fileCalcType == 'database')) {
4426 if ($isCacheExcluded) {
4427 $ignored_paths_default = apply_filters('bmip_smart_exclusion_cache', $ignored_paths_default);
4428 }
4429 if ($isDeactivePluginsExcluded) {
4430 $ignored_paths_default = apply_filters('bmip_smart_exclusion_deactive_plugins', $ignored_paths_default);
4431 }
4432 if ($isNotUsedThemesExcluded) {
4433 $ignored_paths_default = apply_filters('bmip_smart_exclusion_not_used_themes', $ignored_paths_default);
4434 }
4435 }
4436
4437 // Exclude cache directory permanently as it's just cache
4438 // $ignored_paths_default[] = "***ABSPATH***/wp-content/cache";
4439 // $ignored_paths_default[] = "***ABSPATH***/wp-content/cache_bak";
4440 // $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/cache";
4441
4442 // Add staging sites to permanent exclusion rules
4443 for ($i = 0; $i < sizeof($stagingSites); ++$i) {
4444 $ignored_paths_default[] = $stagingSites[$i];
4445 }
4446
4447 if (defined('BMI_PRO_ROOT_DIR')) $ignored_paths_default[] = BMI_PRO_ROOT_DIR;
4448 if ($is && $dpathsis) {
4449 foreach($dpaths as $dpath) {
4450 $dpath = str_replace('***ABSPATH***', untrailingslashit(ABSPATH), $dpath);
4451 $dpath = BMP::fixSlashes($dpath);
4452 if (is_dir($dpath)) {
4453 if (!$fileCalcType) $progress->log(__('Removing directory from backup (due to exclude rules): ', 'backup-backup') . $dpath, 'WARN');
4454 $ignored_folders_default[] = $dpath;
4455 }
4456 $ignored_paths_default[] = $dpath;
4457 }
4458 }
4459 $ignored_paths = $ignored_paths_default;
4460
4461 // Fix slashes for current system (directories)
4462 for ($i = 0; $i < sizeof($ignored_paths); ++$i) {
4463 $ignored_paths[$i] = str_replace('***ABSPATH***', untrailingslashit(ABSPATH), $ignored_paths[$i]);
4464 $ignored_paths[$i] = BMP::fixSlashes($ignored_paths[$i]);
4465 }
4466
4467 // WordPress Paths
4468 $plugins_path = BMP::fixSlashes(WP_PLUGIN_DIR);
4469 $themes_path = BMP::fixSlashes(dirname(get_template_directory()));
4470 $uploads_path = BMP::fixSlashes(wp_upload_dir()['basedir']);
4471 $wp_contents = BMP::fixSlashes(WP_CONTENT_DIR);
4472 $wp_install = BMP::fixSlashes(ABSPATH);
4473
4474 // Getting plugins
4475 $sfgp = Scanner::equalFolderByPath($wp_install, $plugins_path, $ignored_folders);
4476 if ($fgp == 'true' && !$sfgp) {
4477 $plugins_path_files = Scanner::scanFilesGetNamesWithIgnoreFBC($plugins_path, $ignored_folders, $ignored_paths);
4478 foreach($ignored_paths as $dpath) {
4479 $isSub = File_Explorer::isSub($dpath, $plugins_path);
4480 if ($isSub != -1) {
4481 $this->ignoredDirectoriesSize += File_Explorer::getDirSize($dpath);
4482 }
4483 }
4484 }
4485
4486 // Getting themes
4487 $sfgt = Scanner::equalFolderByPath($wp_install, $themes_path, $ignored_folders);
4488 if ($fgt == 'true' && !$sfgt) {
4489 $themes_path_files = Scanner::scanFilesGetNamesWithIgnoreFBC($themes_path, $ignored_folders, $ignored_paths);
4490 foreach($ignored_paths as $dpath) {
4491 $isSub = File_Explorer::isSub($dpath, $themes_path);
4492 if ($isSub != -1) {
4493 $this->ignoredDirectoriesSize += File_Explorer::getDirSize($dpath);
4494 }
4495 }
4496 }
4497
4498 // Getting uploads
4499 $sfgu = Scanner::equalFolderByPath($wp_install, $uploads_path, $ignored_folders);
4500 if ($fgu == 'true' && !$sfgu) {
4501 $uploads_path_files = Scanner::scanFilesGetNamesWithIgnoreFBC($uploads_path, $ignored_folders, $ignored_paths);
4502 foreach($ignored_paths as $dpath) {
4503 $isSub = File_Explorer::isSub($dpath, $uploads_path);
4504 if ($isSub != -1) {
4505 $this->ignoredDirectoriesSize += File_Explorer::getDirSize($dpath);
4506 }
4507 }
4508 }
4509
4510 // Ignore above paths
4511 $sfgoc = Scanner::equalFolderByPath($wp_install, $wp_contents, $ignored_folders);
4512 if ($fgoc == 'true' && !$sfgoc) {
4513
4514 // Ignore common folders (already scanned)
4515 $content_folders = [$plugins_path, $themes_path, $uploads_path];
4516 BMP::merge_arrays($content_folders, $ignored_paths);
4517
4518 // Getting other contents
4519 $wp_contents_files = Scanner::scanFilesGetNamesWithIgnoreFBC($wp_contents, $ignored_folders, $content_folders);
4520
4521 foreach($ignored_paths as $dpath) {
4522 $isSub = File_Explorer::isSub($dpath, $wp_contents) != -1 &&
4523 File_Explorer::isSub($dpath, $plugins_path) == -1 &&
4524 File_Explorer::isSub($dpath, $themes_path) == -1 &&
4525 File_Explorer::isSub($dpath, $uploads_path) == -1;
4526 if ($isSub) {
4527 $this->ignoredDirectoriesSize += File_Explorer::getDirSize($dpath);
4528 }
4529 }
4530 }
4531
4532 // Ignore contents path
4533 if ($fgwp == 'true') {
4534
4535 // Ignore contents file
4536 $ignored_paths[] = $wp_contents;
4537
4538 // Getting WP Installation
4539 $wp_install_files = Scanner::scanFilesGetNamesWithIgnoreFBC($wp_install, $ignored_folders, $ignored_paths);
4540
4541 foreach($ignored_paths as $dpath) {
4542 $isSub = File_Explorer::isSub($dpath, $wp_install) != -1 &&
4543 File_Explorer::isSub($dpath, $wp_contents) == -1;
4544 if ($isSub) {
4545 $this->ignoredDirectoriesSize += File_Explorer::getDirSize($dpath);
4546 }
4547 }
4548 }
4549
4550 // Concat all file paths
4551 $all_files = [];
4552 if ($fgp == 'true' && !$sfgp) {
4553 BMP::merge_arrays($all_files, $plugins_path_files);
4554 unset($plugins_path_files);
4555 }
4556
4557 if ($fgt == 'true' && !$sfgt) {
4558 BMP::merge_arrays($all_files, $themes_path_files);
4559 unset($themes_path_files);
4560 }
4561
4562 if ($fgu == 'true' && !$sfgu) {
4563 BMP::merge_arrays($all_files, $uploads_path_files);
4564 unset($uploads_path_files);
4565 }
4566
4567 if ($fgoc == 'true' && !$sfgoc) {
4568 BMP::merge_arrays($all_files, $wp_contents_files);
4569 unset($wp_contents_files);
4570 }
4571
4572 if ($fgwp == 'true') {
4573 BMP::merge_arrays($all_files, $wp_install_files);
4574 unset($wp_install_files);
4575 }
4576
4577 return $all_files;
4578 }
4579
4580 public function parseFilesForBackup(&$files, &$progress, $cron = false, $dirCalc = false) {
4581
4582 $is = Dashboard\bmi_get_config('BACKUP:FILES::FILTER') === 'true' ? true : false;
4583 $acis = (Dashboard\bmi_get_config('BACKUP:FILES::FILTER:FPATHS') === 'true' && $is) ? true : false;
4584 $ac = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:FPATHS:IN');
4585
4586 $abis = (Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES') === 'true' && $is) ? true : false;
4587 $ab = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES:IN');
4588 $abres = [];
4589 $acres = new \stdClass();
4590
4591 $isSmartExclusion = defined("BMI_BACKUP_PRO") && BMI_BACKUP_PRO && Dashboard\bmi_get_config('SMART:EXCLUSION:ENABLED') == 'true' ? true : false;
4592 $isDebugLogsExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:DLOGS') == 'true' ? true : false);
4593
4594 // Local list of permanently blocked files
4595 if ($acis == false) {
4596 $acis = true;
4597 $ac = [
4598 '***ABSPATH***/wp-content/uploads/wpforms/.htaccess.cpmh3129', // Binary broken file of wpforms
4599 '***ABSPATH***/wp-content/uploads/gravity_forms/.htaccess.cpmh3129', // Binary broken file of wpforms
4600 '***ABSPATH***/.htaccess.cpmh3129', // Binary broken file of wpforms
4601 '***ABSPATH***/logs/traffic.html/.md5sums', // Binary broken file of wpforms
4602 '***ABSPATH***/wp-config.php', // Exclude wp-config.php permanently
4603 '***ABSPATH***/wp-content/mu-plugins/bmi-autologin.php',
4604 '***ABSPATH***/wp-content/backup-migration-config.php' // Exclude BMI CONFIG hardly
4605 ];
4606 } else {
4607 foreach ($ac as $key => $value) {
4608 $value = str_replace('***ABSPATH***', untrailingslashit(ABSPATH), $value);
4609 $value = BMP::fixSlashes($value);
4610 if (file_exists($value)) {
4611 if (!$dirCalc) $progress->log(__('Removing file from backup (due to exclude rules): ', 'backup-backup') . $value, 'WARN');
4612 $ac[$key] = $value;
4613 }
4614 }
4615 $ac[] = '***ABSPATH***/wp-content/uploads/wpforms/.htaccess.cpmh3129'; // Binary broken file of wpforms
4616 $ac[] = '***ABSPATH***/wp-content/uploads/gravity_forms/.htaccess.cpmh3129'; // Binary broken file of wpforms
4617 $ac[] = '***ABSPATH***/.htaccess.cpmh3129'; // Binary broken file of wpforms
4618 $ac[] = '***ABSPATH***/logs/traffic.html/.md5sums'; // Binary broken file of wpforms
4619 $ac[] = '***ABSPATH***/wp-config.php'; // Exclude wp-config.php permanently
4620 $ac[] = '***ABSPATH***/wp-content/backup-migration-config.php'; // Exclude BMI CONFIG hardly
4621 }
4622
4623 if ($isDebugLogsExcluded) {
4624 $ac = apply_filters('bmip_smart_exclusion_debug_logs', $ac);
4625 }
4626
4627 $temp_is = false;
4628 if ($is == false) {
4629 $temp_is = true;
4630 }
4631
4632 if (($is && $acis) || $temp_is) {
4633 foreach ($ac as $key => $value) {
4634 $value = str_replace('***ABSPATH***', untrailingslashit(ABSPATH), $value);
4635 $value = BMP::fixSlashes($value);
4636 $acres->{$value} = 1;
4637 }
4638 }
4639
4640 if ($is && $abis) {
4641 for ($i = 0; $i < sizeof($ab); ++$i) {
4642 $s = $ab[$i];
4643 if ($s->whr == '1') {
4644 $abres[] = ['s' => $s->txt, 'w' => $s->pos, 'z' => strlen($s->txt)];
4645 }
4646 }
4647 }
4648
4649 $limitcrl = 64;
4650 $cliEnabled = false;
4651 if (defined('BMI_CLI_ENABLED')) $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
4652 if ($dirCalc && $cliEnabled && !defined('BMI_CLI_FAILED')) $limitcrl = 128;
4653 $first_big = false;
4654 $sizemax = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:SIZE:IN');
4655 $usesize = (Dashboard\bmi_get_config('BACKUP:FILES::FILTER:SIZE') === 'true' && $is) ? true : false;
4656 if (!is_numeric($sizemax)) {
4657 $usesize = false;
4658 $sizemax = 99999;
4659 } else {
4660 $sizemax = intval($sizemax);
4661 }
4662
4663 // If legacy === false it will use background process to bypass the timeout
4664 if ($dirCalc) {
4665 $legacy = true;
4666 } else {
4667 $legacyVersion = apply_filters('bmi_legacy_version', BMI_LEGACY_VERSION);
4668 $legacyHardVersion = apply_filters('bmi_legacy_hard_version', BMI_LEGACY_HARD_VERSION);
4669 $functionNormal = apply_filters('bmi_function_normal', BMI_FUNCTION_NORMAL);
4670 if (!defined('BMI_LEGACY_VERSION')) $legacy = true;
4671 else $legacy = $legacyVersion;
4672 if ($legacy && defined('BMI_LEGACY_HARD_VERSION') && !$legacyHardVersion) $legacy = $legacyHardVersion;
4673 $cliEnabled = false;
4674 if (defined('BMI_CLI_ENABLED')) $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
4675 if (defined('BMI_FUNCTION_NORMAL') && $cliEnabled === true && $functionNormal === true && !defined('BMI_CLI_FAILED')) $legacy = false;
4676 }
4677
4678 $total_size = 0;
4679 $excludedBytes = 0;
4680 $max = $sizemax * (1024 * 1024);
4681 $maxfor = sizeof($files);
4682
4683 // Non-legacy variables
4684 if ($legacy === false) {
4685 $Hx = trailingslashit(WP_CONTENT_DIR);
4686 $Hz = trailingslashit(ABSPATH);
4687 $Hxs = strlen($Hx);
4688 $Hzs = strlen($Hz);
4689 }
4690
4691 // Sort it by size
4692 if ($legacy === false) {
4693 usort($files, function ($a, $b) {
4694 $a = explode(',', $a);
4695 $last = sizeof($a) - 1;
4696 $sizea = intval($a[$last]);
4697
4698 $b = explode(',', $b);
4699 $last = sizeof($b) - 1;
4700 $sizeb = intval($b[$last]);
4701
4702 if ($sizea == $sizeb) return 0;
4703 if ($sizea < $sizeb) return -1;
4704 else return 1;
4705 });
4706 }
4707
4708 // Process due to rules
4709 for ($i = 0; $i < $maxfor; ++$i) {
4710
4711 // Remove size from path and get the size
4712 $files[$i] = explode(',', $files[$i]);
4713 $last = sizeof($files[$i]) - 1;
4714 $size = intval($files[$i][$last]);
4715 unset($files[$i][$last]);
4716 $files[$i] = implode(',', $files[$i]);
4717
4718 if ($usesize && Scanner::fileTooLarge($size, $max)) {
4719 if (!$dirCalc) $progress->log(__("Removing file from backup (too large) ", 'backup-backup') . $files[$i] . ' (' . number_format(($size / 1024 / 1024), 2) . ' MB)', 'WARN');
4720 array_splice($files, $i, 1);
4721 $maxfor--;
4722 $i--;
4723
4724 $excludedBytes += $size;
4725 continue;
4726 }
4727
4728 if ($abis && Scanner::equalFolder(basename($files[$i]), $abres)) {
4729 if (!$dirCalc) $progress->log(__("Removing file from backup (due to exclude rules): ", 'backup-backup') . $files[$i], 'WARN');
4730 array_splice($files, $i, 1);
4731 $maxfor--;
4732 $i--;
4733
4734 $excludedBytes += $size;
4735 continue;
4736 }
4737
4738 if ($acis && property_exists($acres, $files[$i])) {
4739 if (!$dirCalc) $progress->log(__("Removing file from backup (due to path rules): ", 'backup-backup') . $files[$i], 'WARN');
4740 array_splice($files, $i, 1);
4741 $maxfor--;
4742 $i--;
4743
4744 $excludedBytes += $size;
4745 continue;
4746 }
4747
4748 // if ($size === 0) {
4749 // array_splice($files, $i, 1);
4750 // $maxfor--;
4751 // $i--;
4752
4753 // $excludedBytes += $size;
4754 // continue;
4755 // }
4756
4757 if (strpos($files[$i], 'bmi-pclzip-') !== false || strpos($files[$i], 'backup-migration') !== false) {
4758 array_splice($files, $i, 1);
4759 $maxfor--;
4760 $i--;
4761
4762 $excludedBytes += $size;
4763 continue;
4764 }
4765
4766 if ($size > ($limitcrl * (1024 * 1024))) {
4767 if ($first_big === false) $first_big = $i;
4768 if (!$dirCalc) $progress->log(__("This file is quite big consider to exclude it, if backup fails: ", 'backup-backup') . $files[$i] . ' (' . BMP::humanSize($size) . ')', 'WARN');
4769 }
4770
4771 $functionNormal = apply_filters('bmi_function_normal', BMI_FUNCTION_NORMAL);
4772 $cliEnabled = apply_filters('bmi_cli_enabled', defined('BMI_CLI_ENABLED') ? BMI_CLI_ENABLED : false);
4773 if (($legacy === false && ($functionNormal === false || ($functionNormal === true && $cliEnabled === true))) && (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false)) {
4774 $fx = strpos($files[$i], $Hx);
4775 $fz = strpos($files[$i], $Hz);
4776
4777 if ($fx !== false) $files[$i] = substr_replace($files[$i], '@1@', $fx, $Hxs);
4778 else if ($fz !== false) $files[$i] = substr_replace($files[$i], '@2@', $fz, $Hzs);
4779
4780 $files[$i] .= ',' . $size;
4781 }
4782 $total_size += $size;
4783 }
4784
4785 if ($legacy === false && (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false)) {
4786 $list_file = BMI_TMP . DIRECTORY_SEPARATOR . 'files_latest.list';
4787 if (file_exists($list_file)) @unlink($list_file);
4788 $files_list = fopen($list_file, 'a');
4789 if ($first_big === false) fwrite($files_list, sizeof($files) . "_-1\r\n");
4790 else fwrite($files_list, sizeof($files) . '_' . $first_big . "\r\n");
4791 for ($i = 0; $i < sizeof($files); ++$i) {
4792 fwrite($files_list, $files[$i] . "\r\n");
4793 }
4794 fclose($files_list);
4795 $this->first_big = $first_big;
4796 }
4797
4798 $this->total_excluded_size_for_backup = $excludedBytes + $this->ignoredDirectoriesSize;
4799 $this->total_size_for_backup = $total_size;
4800 $this->total_size_for_backup_in_mb = ($total_size / 1024 / 1024);
4801
4802 return $files;
4803 }
4804
4805 public function toggleBackupLock($unlock = false) {
4806
4807 // Require lib
4808 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'zipper' . DIRECTORY_SEPARATOR . 'zipping.php';
4809
4810 // Backup name
4811 $filename = $this->post['filename'];
4812
4813 // Init Zipper
4814 $zipper = new Zipper();
4815
4816 // Path to Backup
4817 $path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $filename;
4818 $path_dir = BMP::fixSlashes(dirname($path));
4819
4820 // Check if file exists
4821 if (!file_exists($path)) {
4822 return ['status' => 'fail'];
4823 }
4824
4825 // Check if directory is correct
4826 if ($path_dir != BMP::fixSlashes(BMI_BACKUPS)) {
4827 return ['status' => 'fail'];
4828 }
4829
4830 // Toggle the lock
4831 $status = $zipper->lock_zip($path, $unlock);
4832
4833 // Return the status
4834 return ['status' => ($status ? 'success' : 'fail')];
4835 }
4836
4837 public function getDynamicNames() {
4838 $data = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES:IN');
4839 $fpdata = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:FPATHS:IN');
4840 $fddata = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:DPATHS:IN');
4841
4842 for ($i = 0; $i < sizeof($fpdata); ++$i) {
4843 $fpdata[$i] = BMP::fixSlashes($fpdata[$i]);
4844 }
4845
4846 for ($i = 0; $i < sizeof($fddata); ++$i) {
4847 $fddata[$i] = BMP::fixSlashes($fddata[$i]);
4848 }
4849
4850 return [
4851 'status' => 'success',
4852 'dynamic-fpaths-names' => $fpdata,
4853 'dynamic-dpaths-names' => $fddata,
4854 'data' => $data
4855 ];
4856 }
4857
4858 public function resetConfiguration() {
4859
4860 if (file_exists(BMI_CONFIG_PATH)) {
4861 @unlink(BMI_CONFIG_PATH);
4862 }
4863
4864 delete_option('bmi_hotfixes');
4865 delete_option('bmip_to_be_uploaded');
4866 delete_option('bmi_pro_gd_client_id');
4867 delete_option('bmi_pro_gd_token');
4868 delete_option('bmi_pro_cron_domain_done');
4869 delete_option('BMI::STORAGE::LOCAL::PATH');
4870
4871 // update_option('BMI_LOGS_SHARING_IS_ALLOWED', 'unknown');
4872
4873 return ['status' => 'success'];
4874
4875 }
4876
4877 public function getSiteData() {
4878 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'check' . DIRECTORY_SEPARATOR . 'system_info.php';
4879 $bmi = new SI();
4880 $bmi = $bmi->to_array();
4881
4882 return ['status' => 'success', 'data' => $bmi];
4883 }
4884
4885 public function calculateCron() {
4886 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'cron' . DIRECTORY_SEPARATOR . 'handler.php';
4887
4888 $minutes = [];
4889 $keeps = [];
4890 $days = [];
4891 $weeks = [];
4892 $hours = [];
4893
4894 for ($i = 1; $i <= 28; ++$i) {
4895 $days[] = substr('0' . $i, -2);
4896 }
4897 for ($i = 1; $i <= 7; ++$i) {
4898 $weeks[] = $i . '';
4899 }
4900 for ($i = 0; $i <= 23; ++$i) {
4901 $hours[] = substr('0' . $i, -2);
4902 }
4903 for ($i = 0; $i <= 55; $i += 5) {
4904 $minutes[] = substr('0' . $i, -2);
4905 }
4906 for ($i = 1; $i <= 20; ++$i) {
4907 $keeps[] = $i . '';
4908 }
4909
4910 $errors = 0;
4911 if (in_array($this->post['type'], ['month', 'week', 'day'])) {
4912 if (!Dashboard\bmi_set_config('CRON:TYPE', $this->post['type'])) {
4913 $errors++;
4914 }
4915 }
4916 if (in_array($this->post['day'], $days)) {
4917 if (!Dashboard\bmi_set_config('CRON:DAY', $this->post['day'])) {
4918 $errors++;
4919 }
4920 }
4921 if (in_array($this->post['week'], $weeks)) {
4922 if (!Dashboard\bmi_set_config('CRON:WEEK', $this->post['week'])) {
4923 $errors++;
4924 }
4925 }
4926 if (in_array($this->post['hour'], $hours)) {
4927 if (!Dashboard\bmi_set_config('CRON:HOUR', $this->post['hour'])) {
4928 $errors++;
4929 }
4930 }
4931 if (in_array($this->post['minute'], $minutes)) {
4932 if (!Dashboard\bmi_set_config('CRON:MINUTE', $this->post['minute'])) {
4933 $errors++;
4934 }
4935 }
4936 if (in_array($this->post['keep'], $keeps)) {
4937 if (!Dashboard\bmi_set_config('CRON:KEEP', $this->post['keep'])) {
4938 $errors++;
4939 }
4940 }
4941
4942 if ($this->post['enabled'] === 'true') {
4943 $this->post['enabled'] = true;
4944 } else {
4945 $this->post['enabled'] = false;
4946 }
4947
4948 if (!Dashboard\bmi_set_config('CRON:ENABLED', $this->post['enabled'])) {
4949 $errors++;
4950 }
4951
4952 if ($errors === 0) {
4953 $time = Crons::calculate_date([
4954 'type' => $this->post['type'],
4955 'week' => $this->post['week'],
4956 'day' => $this->post['day'],
4957 'hour' => $this->post['hour'],
4958 'minute' => $this->post['minute']
4959 ], time());
4960
4961 $file = BMI_TMP . DIRECTORY_SEPARATOR . '.plan';
4962 if (file_exists($file)) {
4963 $earlier = intval(file_get_contents($file));
4964 } else {
4965 $earlier = 0;
4966 }
4967
4968 if (!wp_next_scheduled('bmi_do_backup_right_now') || $earlier === 0 || (abs($time - $earlier) >= 15)) {
4969 wp_clear_scheduled_hook('bmi_do_backup_right_now');
4970 if ($this->post['enabled'] === true) {
4971 wp_schedule_single_event($time, 'bmi_do_backup_right_now');
4972 file_put_contents($file, $time);
4973 }
4974 }
4975
4976 return [
4977 'status' => 'success',
4978 'data' => date('Y-m-d H:i:s', $time),
4979 'currdata' => date('Y-m-d H:i:s')
4980 ];
4981 } else {
4982 return ['status' => 'error'];
4983 }
4984 }
4985
4986 public function dismissErrorNotice() {
4987 $optionId = isset($this->post['option_id']) ? $this->post['option_id'] : '';
4988 if (in_array($optionId, ['backupbliss-issues', 'backupbliss-dismiss-upload-issue']))
4989 {
4990 require_once BMI_INCLUDES . '/external/backupbliss.php';
4991 $backupbliss = new BackupBliss();
4992 }
4993
4994 switch ($optionId) {
4995 case 'email-issues':
4996 delete_option('bmi_display_email_issues');
4997 break;
4998 case 'before-update-issues':
4999 delete_option('bmi_display_before_update_backup_issues');
5000 break;
5001 case 'aws-issues':
5002 update_option('bmip_aws_dismiss_issue', true);
5003 break;
5004 case 'wasabi-issues':
5005 update_option('bmip_wasabi_dismiss_issue', true);
5006 break;
5007 case 'sftp-issues':
5008 update_option('bmip_sftp_dismiss_issue', true);
5009 break;
5010 case 'gdrive-issues':
5011 delete_transient('bmip_gd_issue');
5012 break;
5013 case 'pcloud-issues':
5014 update_option('bmip_pcloud_dismiss_issue', true);
5015 break;
5016 case 'backupbliss-issues':
5017 $backupbliss->removeNotice("invalid_key");
5018 $backupbliss->removeNotice("invalid_permission");
5019 if ($backupbliss->getNotice("storage_warn"))
5020 $backupbliss->hideNotice("storage_warn", 60 * 60);
5021 if ($backupbliss->getNotice("upload_issue"))
5022 $backupbliss->hideNotice("upload_issue", 60); //Hide only for a minute
5023 break;
5024 case 'backupbliss-dismiss-upload-issue':
5025 $backupbliss->hideFailureWarnNotice(14 * 24 * 60 * 60); //14 days
5026 break;
5027 case 'security-plugin-warning':
5028 update_option('bmi_security_warning_dismiss', true);
5029 default:
5030 break;
5031 }
5032 }
5033
5034 // recursive removal
5035 private function rrmdir($dir) {
5036
5037 if (is_dir($dir)) {
5038
5039 $objects = scandir($dir);
5040 foreach ($objects as $object) {
5041
5042 if ($object != "." && $object != "..") {
5043
5044 if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . DIRECTORY_SEPARATOR . $object)) {
5045
5046 $this->rrmdir($dir . DIRECTORY_SEPARATOR . $object);
5047
5048 } else {
5049
5050 @unlink($dir . DIRECTORY_SEPARATOR . $object);
5051
5052 }
5053
5054 }
5055
5056 }
5057
5058 @rmdir($dir);
5059
5060 } else {
5061
5062 if (file_exists($dir) && is_file($dir)) {
5063
5064 @unlink($dir);
5065
5066 }
5067
5068 }
5069
5070 }
5071
5072 public function forceBackupToStop() {
5073
5074 $filesToBeRemoved = [];
5075
5076 $tmp_dir = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp';
5077 if (!is_dir($tmp_dir)) @mkdir($tmp_dir, 0755, true);
5078
5079 foreach (scandir($tmp_dir) as $filename) {
5080
5081 if (in_array($filename, ['.', '..'])) continue;
5082 $path = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . $filename;
5083 $filesToBeRemoved[] = $path;
5084
5085 }
5086
5087 $allowedFiles = ['wp-config.php', '.htaccess', '.litespeed', '.default.json', 'driveKeys.php', 'dropboxKeys.php', '.autologin.php', '.migrationFinished', 'onedriveKeys.php', 'awsKeys.php', 'wasabiKeys.php', 'backupblissKeys.php', 'sftpKeys.php', 'pcloudKeys.php'];
5088 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . '.*') as $filename) {
5089
5090 $basename = basename($filename);
5091
5092 if (in_array($basename, ['.', '..'])) continue;
5093 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
5094 $filesToBeRemoved[] = $filename;
5095 }
5096
5097 }
5098
5099 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'BMI-*', GLOB_ONLYDIR) as $filename) {
5100
5101 $basename = basename($filename);
5102
5103 if (in_array($basename, ['.', '..'])) continue;
5104 if (is_dir($filename) && !in_array($filename, $allowedFiles)) {
5105 $filesToBeRemoved[] = $filename;
5106 }
5107
5108 }
5109
5110 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'bg-BMI-*', GLOB_ONLYDIR) as $filename) {
5111
5112 $basename = basename($filename);
5113
5114 if (in_array($basename, ['.', '..'])) continue;
5115 if (is_dir($filename) && !in_array($filename, $allowedFiles)) {
5116 $filesToBeRemoved[] = $filename;
5117 }
5118
5119 }
5120
5121 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.backup_cli_lock';
5122 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.backup_cli_lock_ended';
5123 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.backup_cli_lock_end';
5124 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.last_triggered';
5125 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running';
5126 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.space_check';
5127 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'db_tables';
5128 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'bmi_backup_manifest.json';
5129 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'files_latest.list';
5130 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'currentBackupConfig.php';
5131
5132 if (is_array($filesToBeRemoved) || is_object($filesToBeRemoved)) {
5133 foreach ((array) $filesToBeRemoved as $file) {
5134 $this->rrmdir($file);
5135 }
5136 }
5137
5138 return ['status' => 'success'];
5139
5140 }
5141
5142 public function forceRestoreToStop() {
5143
5144 $filesToBeRemoved = [];
5145
5146 $themedir = get_theme_root();
5147 $tempTheme = $themedir . DIRECTORY_SEPARATOR . 'backup_migration_restoration_in_progress';
5148 $filesToBeRemoved[] = $tempTheme;
5149
5150 $tmpDirectory = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp';
5151 if (!is_dir($tmpDirectory)) @mkdir($tmpDirectory, 0755, true);
5152
5153 foreach (scandir($tmpDirectory) as $filename) {
5154
5155 if (in_array($filename, ['.', '..'])) continue;
5156 $path = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . $filename;
5157 $filesToBeRemoved[] = $path;
5158
5159 }
5160
5161 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'backup-migration_??????????') as $filename) {
5162
5163 $basename = basename($filename);
5164
5165 if (is_dir($filename) && !in_array($basename, ['.', '..'])) {
5166 $filesToBeRemoved[] = $filename;
5167 }
5168
5169 }
5170
5171 $allowedFiles = ['wp-config.php', '.htaccess', '.litespeed', '.default.json', 'driveKeys.php', 'dropboxKeys.php', '.autologin.php', '.migrationFinished', 'onedriveKeys.php','awsKeys.php', 'wasabiKeys.php', 'backupblissKeys.php', 'sftpKeys.php', 'pcloudKeys.php'];
5172 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . '.*') as $filename) {
5173
5174 $basename = basename($filename);
5175
5176 if (in_array($basename, ['.', '..'])) continue;
5177 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
5178 $filesToBeRemoved[] = $filename;
5179 }
5180
5181 }
5182
5183 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_scan_*') as $filename) {
5184
5185 $basename = basename($filename);
5186
5187 if (in_array($basename, ['.', '..'])) continue;
5188 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
5189 $filesToBeRemoved[] = $filename;
5190 }
5191
5192 }
5193
5194 foreach (glob(untrailingslashit(ABSPATH) . DIRECTORY_SEPARATOR . 'wp-config.??????????.php') as $filename) {
5195
5196 $basename = basename($filename);
5197
5198 if (in_array($basename, ['.', '..'])) continue;
5199 if (is_file($filename) && !in_array($filename, $allowedFiles)) {
5200 $filesToBeRemoved[] = $filename;
5201 }
5202
5203 }
5204
5205 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock';
5206 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock_cli';
5207 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock_cli_end';
5208 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock_ended';
5209 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.cli_download_last';
5210 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running';
5211 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.space_check';
5212 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . '.restore_secret';
5213 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . '.table_map';
5214
5215 if (is_array($filesToBeRemoved) || is_object($filesToBeRemoved)) {
5216 foreach ((array) $filesToBeRemoved as $file) {
5217 $this->rrmdir($file);
5218 }
5219 }
5220
5221 return ['status' => 'success'];
5222
5223 }
5224
5225 public function sendTroubleshootingDetails($send_type = 'manual', $triggeredBy = false, $blocking = true) {
5226
5227 global $table_prefix;
5228
5229 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'check' . DIRECTORY_SEPARATOR . 'system_info.php';
5230 $bmiSiteData = new SI();
5231 $bmiSiteData = $bmiSiteData->to_array();
5232 $bmiSiteData['database_size'] = $this->getDatabaseSize();
5233 $bmiSiteData['database_size_mb'] = BMP::humanSize($bmiSiteData['database_size']);
5234 $bmiSiteData['xhria'] = get_option('z__bmi_xhria', 'none');
5235 $bmiSiteData['current_table_prefix'] = $table_prefix;
5236
5237 $wpconfigPath = ABSPATH . DIRECTORY_SEPARATOR . 'wp-config.php';
5238 if (file_exists($wpconfigPath)) {
5239 $bmiSiteData['is_wp_config_writable'] = is_writable($wpconfigPath) ? "yes" : "no";
5240 } else {
5241 $bmiSiteData['is_wp_config_writable'] = "file_does_not_exist?";
5242 }
5243
5244 $latestBackupLogs = 'does_not_exist';
5245 $latestBackupProgress = 'does_not_exist';
5246 $latestRestorationLogs = 'does_not_exist';
5247 $latestRestorationProgress = 'does_not_exist';
5248 $latestStagingLogs = 'does_not_exist';
5249 $latestStagingProgress = 'does_not_exist';
5250 $currentPluginConfig = 'does_not_exist';
5251 $pluginGlobalLogs = 'does_not_exist';
5252 $backgroundErrors = 'does_not_exist';
5253
5254 if (file_exists(BMI_BACKUPS . '/latest.' . BMI_LOGS_SUFFIX . '.log')) {
5255 $latestBackupLogs = file_get_contents(BMI_BACKUPS . '/latest.' . BMI_LOGS_SUFFIX . '.log');
5256 }
5257
5258 if (file_exists(BMI_BACKUPS . '/latest_progress.' . BMI_LOGS_SUFFIX . '.log')) {
5259 $latestBackupProgress = file_get_contents(BMI_BACKUPS . '/latest_progress.' . BMI_LOGS_SUFFIX . '.log');
5260 }
5261
5262 if (file_exists(BMI_BACKUPS . '/latest_migration.' . BMI_LOGS_SUFFIX . '.log')) {
5263 $latestRestorationLogs = file_get_contents(BMI_BACKUPS . '/latest_migration.' . BMI_LOGS_SUFFIX . '.log');
5264 }
5265
5266 if (file_exists(BMI_BACKUPS . '/latest_migration_progress.' . BMI_LOGS_SUFFIX . '.log')) {
5267 $latestRestorationProgress = file_get_contents(BMI_BACKUPS . '/latest_migration_progress.' . BMI_LOGS_SUFFIX . '.log');
5268 }
5269
5270 if (file_exists(BMI_STAGING . '/latest_staging.' . BMI_LOGS_SUFFIX . '.log')) {
5271 $latestStagingLogs = file_get_contents(BMI_STAGING . '/latest_staging.' . BMI_LOGS_SUFFIX . '.log');
5272 }
5273
5274 if (file_exists(BMI_STAGING . '/latest_staging_progress.' . BMI_LOGS_SUFFIX . '.log')) {
5275 $latestStagingProgress = file_get_contents(BMI_STAGING . '/latest_staging_progress.' . BMI_LOGS_SUFFIX . '.log');
5276 }
5277
5278 if (file_exists(BMI_CONFIG_PATH)) {
5279 $currentPluginConfig = substr(file_get_contents(BMI_CONFIG_PATH), 8);
5280 }
5281
5282 $completeLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.' . BMI_LOGS_SUFFIX . '.log';
5283 if (file_exists($completeLogsPath)) {
5284 $fileSize = filesize($completeLogsPath);
5285 if ($fileSize <= 65535) {
5286 $pluginGlobalLogs = file_get_contents($completeLogsPath);
5287 } else {
5288 $fp = fopen($completeLogsPath, 'rb');
5289 if ($fp) {
5290 $seekPos = max(0, $fileSize - 65509 ); // Read last 64KB
5291 fseek($fp, $seekPos, SEEK_SET);
5292 $lastBytes = fread($fp, 65509);
5293 fclose($fp);
5294
5295 $pluginGlobalLogs = 'file_too_large, last 64KB:' . "\n" . $lastBytes;
5296
5297 file_put_contents($completeLogsPath, $lastBytes);
5298 } else {
5299 $pluginGlobalLogs = 'could_not_open_file';
5300 }
5301 }
5302 }
5303
5304 $backgroundLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'background-errors.' . BMI_LOGS_SUFFIX . '.log';
5305 if (file_exists($backgroundLogsPath)) {
5306 if ((filesize($backgroundLogsPath) / 1024 / 1024) <= 4) {
5307 $backgroundErrors = file_get_contents($backgroundLogsPath);
5308 } else {
5309 @unlink($backgroundLogsPath);
5310 @touch($backgroundLogsPath);
5311 $backgroundErrors = 'file_too_large';
5312 }
5313 }
5314
5315 $ifCLI = false;
5316 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
5317 $ifCLI = true;
5318 }
5319
5320 $logsSourceFrontEnd = 'manual';
5321 if ($triggeredBy != false) {
5322 $logsSourceFrontEnd = $triggeredBy;
5323 }
5324 if (isset($this->post['source']) && in_array($this->post['source'], ['backup', 'migration', 'staging'])) {
5325 $logsSourceFrontEnd = $this->post['source'];
5326 }
5327
5328 $latestBackupLogs = preg_replace('/\:\ ((.*)\.zip)/', ': *****.zip', $latestBackupLogs);
5329 $latestRestorationLogs = preg_replace('/bmi\-id\=(.*)\.zip/', 'bmi-id=[***redacted***].zip', $latestRestorationLogs);
5330 $latestStagingLogs = preg_replace('/\:\ ((.*)\.zip)/', ': *****.zip', $latestStagingLogs);
5331
5332 $currentPluginConfig = json_decode($currentPluginConfig);
5333 unset($currentPluginConfig->{"OTHER:EMAIL"});
5334 $currentPluginConfig = json_encode($currentPluginConfig);
5335
5336 $url = 'https://' . BMI_API_BACKUPBLISS_PUSH . '/v1' . '/push';
5337 $data = array(
5338 'method' => 'POST',
5339 'timeout' => 15,
5340 'blocking' => $blocking,
5341 'sslverify' => false,
5342 'send_type' => $send_type,
5343 'body' => array(
5344 'admin_url' => admin_url(),
5345 'home_url' => home_url(),
5346 'site_url' => get_site_url(),
5347 'is_multisite' => is_multisite() ? "yes" : "no",
5348 'is_abspath_writable' => is_writable(ABSPATH) ? "yes" : "no",
5349 'site_information' => $bmiSiteData,
5350 'latest_backup_logs' => $latestBackupLogs,
5351 'latest_backup_progress' => $latestBackupProgress,
5352 'latest_restoration_logs' => $latestRestorationLogs,
5353 'latest_restoration_progress' => $latestRestorationProgress,
5354 'latest_staging_logs' => $latestStagingLogs,
5355 'latest_staging_progress' => $latestStagingProgress,
5356 'current_plugin_config' => $currentPluginConfig,
5357 'plugin_global_logs' => $pluginGlobalLogs,
5358 'background_errors' => $backgroundErrors,
5359 'triggered_by' => $logsSourceFrontEnd,
5360 'is_defined' => defined('BMI_BACKUP_PRO') ? 'yes' : 'no',
5361 'is_cli' => $ifCLI
5362 )
5363 );
5364
5365 $disabled_functions = explode(',', ini_get('disable_functions'));
5366 $vA = !in_array('curl_exec', $disabled_functions);
5367 $vB = !in_array('curl_init', $disabled_functions);
5368 $vC = !in_array('http_build_query', $disabled_functions);
5369 $vD = !in_array('stream_context_create', $disabled_functions);
5370 $vE = !in_array('file_get_contents', $disabled_functions);
5371 $vF = false;
5372 $response = false;
5373
5374 if (function_exists('curl_version') && function_exists('curl_exec') && function_exists('curl_init') && $vA && $vB) {
5375
5376 $response = wp_remote_post($url, $data);
5377
5378 } else {
5379
5380 if (ini_get('allow_url_fopen') == true && $vC && $vD && $vE) {
5381
5382 $vF = true;
5383 $postdata = http_build_query($data['body']);
5384
5385 $opts = [
5386 'ssl' => [ 'verify_peer_name' => false, 'verify_peer' => false ],
5387 'http' => [
5388 'method' => 'POST',
5389 'header' => 'Content-type: application/x-www-form-urlencoded',
5390 'content' => $postdata
5391 ]
5392 ];
5393
5394 $context = stream_context_create($opts);
5395 $result = file_get_contents($url, false, $context);
5396
5397 $response = [ 'body' => $result ];
5398
5399 }
5400
5401 }
5402
5403 if ($response === false || is_wp_error($response)) {
5404 $error_message = $response->get_error_message();
5405 Logger::error($error_message, 'backup-backup');
5406 return ['status' => 'fail'];
5407 } else {
5408 try {
5409 $body = json_decode($response['body']);
5410 if (isset($body->code)) {
5411 return ['status' => 'success', 'code' => sanitize_text_field($body->code)];
5412 } else {
5413 return ['status' => 'fail'];
5414 }
5415 } catch (\Exception $e) {
5416 Logger::error(print_r($e, true), 'backup-backup');
5417 return ['status' => 'fail'];
5418 } catch (\Throwable $t) {
5419 Logger::error(print_r($t, true), 'backup-backup');
5420 return ['status' => 'fail'];
5421 }
5422 }
5423
5424 }
5425
5426 public function actionsAfterProcess($success = false, $triggeredBy = 'backup', $isCron = false) {
5427
5428 $afterMigrationLock = BMI_TMP . DIRECTORY_SEPARATOR . '.migrationFinished';
5429 if ($success) {
5430
5431 file_put_contents($afterMigrationLock, '');
5432 Logger::log("Process (" . $triggeredBy . ") finished successfully via ajax.php");
5433
5434 } else {
5435
5436 Logger::log("Process (" . $triggeredBy . ") finished with errors via ajax.php");
5437 if (file_exists($afterMigrationLock)) @unlink($afterMigrationLock);
5438
5439 }
5440
5441 if ($triggeredBy === 'backup' && $isCron) BMP::handle_after_cron();
5442
5443 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json')) @unlink(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json');
5444
5445
5446 if (has_action('bmi_premium_after_process') || (defined('BACKUP_TRIGGERED_BY_URL') && BACKUP_TRIGGERED_BY_URL === true)){
5447 do_action('bmi_premium_after_process', $success, $triggeredBy, defined('BACKUP_TRIGGERED_BY_URL') && BACKUP_TRIGGERED_BY_URL === true);
5448 }
5449
5450
5451 return null;
5452
5453 // REMOVED CODE:
5454 // $canShare = BMP::canShareLogsOrShouldAsk();
5455 // if ($canShare === 'allowed') {
5456 //
5457 // $send_type = 'error';
5458 // if ($success) $send_type = 'success';
5459 // $this->sendTroubleshootingDetails($send_type, $triggeredBy, false);
5460 //
5461 // }
5462
5463 }
5464
5465 public function logSharing() {
5466
5467 $type = $this->post['question'];
5468
5469 if ($type == 'set_yes') {
5470
5471 // $isOk = Dashboard\bmi_set_config('LOGS::SHARING', 'yes');
5472 // update_option('BMI_LOGS_SHARING_IS_ALLOWED', 'yes');
5473 return ['status' => 'success'];
5474
5475 } else if ($type == 'set_no') {
5476
5477 // $isOk = Dashboard\bmi_set_config('LOGS::SHARING', 'no');
5478 // update_option('BMI_LOGS_SHARING_IS_ALLOWED', 'no');
5479 return ['status' => 'success'];
5480
5481 } else if ($type == 'is_allowed') {
5482
5483 // $canShare = BMP::canShareLogsOrShouldAsk();
5484 // return ['status' => 'success', 'result' => $canShare];
5485 return ['status' => 'success', 'result' => 'not-allowed'];
5486
5487 } else {
5488
5489 return ['status' => 'fail'];
5490
5491 }
5492
5493 }
5494
5495 public function getLatestBackupFile() {
5496
5497 $dir = BMI_BACKUPS;
5498 $backupdir = array_diff(scandir($dir), ['..', '.']);
5499 $backups = [];
5500 foreach ($backupdir as $index => $name) {
5501
5502 $ext = pathinfo($dir . DIRECTORY_SEPARATOR . $name, PATHINFO_EXTENSION);
5503
5504 if (in_array($ext, ['zip', 'tar', 'gz'])) {
5505 $backups[] = [
5506 'cdate' => filemtime($dir . DIRECTORY_SEPARATOR . $name),
5507 'name' => $name
5508 ];
5509 }
5510
5511 }
5512
5513 usort($backups, function ($a, $b) {
5514 if (intval($a['cdate']) < intval($b['cdate'])) return 1;
5515 else return -1;
5516 });
5517
5518 $backups = array_values($backups);
5519
5520 if (sizeof($backups) > 0) {
5521 return $backups[0]['name'];
5522 } else {
5523 return '---';
5524 }
5525
5526 }
5527
5528 /**
5529 * isStagingSiteCreationOngoing - Checks if the process is ongoing or not
5530 *
5531 * @return {bool} true if the process is running false if its not
5532 */
5533 public function isStagingSiteCreationOngoing() {
5534
5535 $staging_lock = BMI_STAGING . '/.staging_lock';
5536 if (file_exists($staging_lock) && (time() - filemtime($staging_lock)) <= 15) {
5537 return true;
5538 } else {
5539 return false;
5540 }
5541
5542 }
5543
5544 /**
5545 * checkStagingLocalName - Verifies name of staging site and checks if it's not currently running
5546 * Can be called for verification pre start or during start on initial request
5547 *
5548 * @param {string} $name = false name of staging site if called without ajax
5549 * @return {array} with status/fail/progress data
5550 */
5551 public function checkStagingLocalName($name = false) {
5552
5553 if ($name == false && isset($this->post['name'])) {
5554 $name = $this->post['name'];
5555 }
5556
5557 $ongoing = __('Staging site creation is already ongoing, please wait and try again.', 'backup-backup');
5558 $empty = __('You have to provide some staging site name before process.', 'backup-backup');
5559 $toolong = __('Staging site name cannot be longer than 24 characters.', 'backup-backup');
5560 $invalid = __('Provided name contains prohibited characters.', 'backup-backup');
5561 $blacklisted = __('This name is not allowed to be used, please pick different one.', 'backup-backup');
5562 $exist = __('Seems like directory or staging site with that name already exist, pick different one.', 'backup-backup');
5563 $dashes = __('Name cannot start or end with dash or underscore.', 'backup-backup');
5564
5565 if ($this->isStagingSiteCreationOngoing()) {
5566 return ['status' => 'fail', 'message' => $ongoing];
5567 }
5568
5569 if (strlen($name) <= 0) {
5570 return ['status' => 'fail', 'message' => $empty];
5571 }
5572
5573 if (!preg_match('/^[a-zA-Z0-9-_]+$/', $name)) {
5574 return ['status' => 'fail', 'message' => $invalid];
5575 }
5576
5577 if (strlen($name) >= 24) {
5578 return ['status' => 'fail', 'message' => $toolong];
5579 }
5580
5581 if (in_array($name[0], ['_', '-']) || in_array($name[strlen($name) - 1], ['_', '-'])) {
5582 return ['status' => 'fail', 'message' => $dashes];
5583 }
5584
5585 $bannedNames = [
5586 'wp-content',
5587 'wp-admin',
5588 'wp-includes',
5589 'content',
5590 'admin',
5591 'includes',
5592 'tmp',
5593 '.well-known',
5594 'download',
5595 'downloads',
5596 'google',
5597 'temporary'
5598 ];
5599
5600 if (strpos($name, '.') !== false) {
5601 return ['status' => 'fail', 'message' => $blacklisted];
5602 }
5603
5604 if (in_array($name, $bannedNames)) {
5605 return ['status' => 'fail', 'message' => $blacklisted];
5606 }
5607
5608 $path = trailingslashit(ABSPATH) . $name;
5609 if (file_exists($path) || is_dir($path)) {
5610 return ['status' => 'fail', 'message' => $exist];
5611 }
5612
5613 return ['status' => 'success'];
5614
5615 }
5616
5617 /**
5618 * startLocalStagingCreation - Initials creation of staging site process
5619 *
5620 * @return {array} with status/fail/progress data
5621 */
5622 public function startLocalStagingCreation() {
5623
5624 // Verification of state
5625 $name = $this->post['name'];
5626 $verification = $this->checkStagingLocalName($name);
5627 $staging_lock = BMI_STAGING . '/.staging_lock';
5628
5629 // Fail in case of wrong data or state
5630 if (isset($verification['status']) && $verification['status'] != 'success') {
5631 return $verification;
5632 }
5633
5634 // Update lock file to prevent double processes
5635 touch($staging_lock);
5636
5637 // Include local staging site controller
5638 require_once BMI_INCLUDES . '/staging/local.php';
5639 $staging = new StagingLocal($name, true);
5640
5641 // Append the return if staging process requires more batches
5642 if ($staging->continue == true) return $staging->continuationData;
5643
5644 return [ 'status' => 'continue', 'data' => [ 'name' => $name ] ];
5645
5646 }
5647
5648 /**
5649 * stagingSitesGetList - Returns staging sites list
5650 *
5651 * @return {array} with staging sites data
5652 */
5653 public function stagingSitesGetList() {
5654
5655 // Include local staging site controller
5656 require_once BMI_INCLUDES . '/staging/controller.php';
5657 $staging = new Staging('..ajax..');
5658 $sites = $staging->getStagingSites();
5659
5660 return [ 'status' => 'success', 'sites' => $sites ];
5661
5662 }
5663
5664 /**
5665 * stagingRename - Renames display name
5666 *
5667 * @return {array} status
5668 */
5669 public function stagingRename() {
5670
5671 $name = $this->post['name'];
5672 $newName = $this->post['new'];
5673
5674 // Include local staging site controller
5675 require_once BMI_INCLUDES . '/staging/controller.php';
5676 $staging = new Staging('..ajax..');
5677 return $staging->rename($name, $newName);
5678
5679 }
5680
5681 /**
5682 * stagingPrepareLogin - Prepares login script
5683 *
5684 * @return {array} login credentials
5685 */
5686 public function stagingPrepareLogin() {
5687
5688 $name = $this->post['name'];
5689
5690 // Include local staging site controller
5691 require_once BMI_INCLUDES . '/staging/controller.php';
5692 $staging = new Staging('..ajax..');
5693 return $staging->prepareLogin($name);
5694
5695 }
5696
5697 /**
5698 * Handles secure backup via browser method
5699 */
5700 public function backupBrowserMethodHandler() {
5701
5702 try {
5703
5704 // Load bypasser
5705 require_once BMI_INCLUDES . '/backup-process.php';
5706 $request = new Bypasser(false, BMI_CONFIG_DIR, trailingslashit(WP_CONTENT_DIR), BMI_BACKUPS, trailingslashit(ABSPATH), plugin_dir_path(BMI_ROOT_FILE));
5707
5708 // Handle request
5709 $request->handle_batch();
5710 $request->shutdown();
5711 return;
5712
5713 } catch (\Exception $e) {
5714
5715 error_log('There was an error with Backup Migration plugin: ' . $e->getMessage());
5716 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $e->getMessage());
5717 error_log(strval($e));
5718
5719 } catch (\Throwable $t) {
5720
5721 error_log('There was an error with Backup Migration plugin: ' . $t->getMessage());
5722 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $t->getMessage());
5723 error_log(strval($t));
5724
5725 }
5726
5727 return [ 'status' => 'error' ];
5728
5729 }
5730
5731 /**
5732 * Handles ajax error on browser side, keep alive timeout etc.
5733 *
5734 * @return array static success
5735 */
5736 public function frontEndAjaxError() {
5737
5738 if ($this->post['call'] == 'create-backup') {
5739 require_once BMI_INCLUDES . '/progress/zip.php';
5740 $logger = new Progress('', 0, 0, false, false);
5741 } else if (in_array($this->post['call'], ['restore-backup', 'download-backup', 'continue_restore_process'])) {
5742 require_once BMI_INCLUDES . '/progress/migration.php';
5743 $logger = new MigrationProgress(true);
5744 } else if (in_array($this->post['call'], ['staging-start-local-creation', 'staging-local-creation-process', 'staging-tastewp-creation-process'])) {
5745 require_once BMI_INCLUDES . '/progress/staging.php';
5746 $logger = new StagingProgress(true);
5747 }
5748
5749 if (isset($this->post['error'])) {
5750
5751 Logger::error('Front End Ajax Error START');
5752 if (isset($logger)) $logger->log('Front End Ajax Error START', 'verbose');
5753
5754 if (is_array($this->post['error'])) {
5755
5756 $errors = $this->post['error'];
5757 foreach ($errors as $k => $val) {
5758 $error = sanitize_text_field(print_r($val, true));
5759 Logger::error($k . ' = ' . $error);
5760 if (isset($logger)) $logger->log($k . ' = ' . $error, 'verbose');
5761 }
5762
5763 } else {
5764
5765 $theError = sanitize_text_field(print_r($this->post->error, true));
5766 Logger::error('Front End Ajax Error: ' . $theError);
5767 if (isset($logger)) $logger->log($theError, 'verbose');
5768
5769 }
5770
5771 Logger::error('Front End Ajax Error END');
5772 if (isset($logger)) $logger->log('Front End Ajax Error END', 'verbose');
5773
5774 } else {
5775
5776 Logger::error('Front End Ajax Error was called, but no error included.');
5777
5778 }
5779
5780 if (isset($logger)) {
5781 $logger->log(__('Browser-side error detected, the process will try to restart with alternative methods, otherwise it will throw error window.', 'backup-backup'), 'error');
5782 $logger->log('Browser-side error detected, the process will try to restart with alternative methods, otherwise it will throw error window.', 'verbose');
5783 }
5784
5785 return [ 'status' => 'success' ];
5786
5787 }
5788
5789 /**
5790 * stagingDelete - Removes the staging site
5791 *
5792 * @return {array} status
5793 */
5794 public function stagingDelete() {
5795
5796 $name = $this->post['name'];
5797
5798 // Include local staging site controller
5799 require_once BMI_INCLUDES . '/staging/controller.php';
5800 $staging = new Staging('..ajax..');
5801 return $staging->delete($name);
5802
5803 }
5804
5805 /**
5806 * localStagingCreationProcess - Method that can continue batching of Staging process
5807 *
5808 * @return {array} data that should be send back to this function as POST
5809 */
5810 public function localStagingCreationProcess() {
5811
5812 // Get $name and declare lock file
5813 $name = $this->post['name'];
5814 $staging_lock = BMI_STAGING . '/.staging_lock';
5815
5816 // Update lock file to prevent double processes
5817 touch($staging_lock);
5818
5819 // Include local staging site controller
5820 require_once BMI_INCLUDES . '/staging/local.php';
5821 $staging = new StagingLocal($name);
5822
5823 // Process handler
5824 if (isset($this->post['delete'])) {
5825 $staging->requestDelete();
5826 } else $staging->continueProcess();
5827
5828 // Append the return if staging process requires more batches
5829 if ($staging->continue == true) return $staging->continuationData;
5830
5831 // Send success if nothing went wrong which finishes the process
5832 if (file_exists($staging_lock)) @unlink($staging_lock);
5833 return ['status' => 'error'];
5834
5835 }
5836
5837 /**
5838 * tastewpStagingCreation - Initializes and declares staging site will
5839 *
5840 * @return {array} batching status
5841 */
5842 public function tastewpStagingCreation() {
5843
5844 // Get $name and declare lock file
5845 $name = $this->post['name'];
5846 $backupName = isset($this->post['backupName']) ? $this->post['backupName'] : false;
5847 $initialize = isset($this->post['initialize']) ? $this->post['initialize'] : false;
5848 $staging_lock = BMI_STAGING . '/.staging_lock';
5849
5850 // Fix var type
5851 if ($initialize === true || $initialize == 'true') $initialize = true;
5852 else $initialize = false;
5853
5854 // Update lock file to prevent double processes
5855 touch($staging_lock);
5856
5857 // Include TasteWP staging site controller
5858 require_once BMI_INCLUDES . '/staging/tastewp.php';
5859
5860 // Process handler
5861 if (isset($this->post['delete'])) {
5862 $delete = true;
5863 } else $delete = false;
5864
5865 // Make first handshake with TasteWP
5866 $staging = new StagingTasteWP($name, $initialize, $backupName, $delete);
5867
5868 // Append the return if staging process requires more batches
5869 if ($staging->continue == true) return $staging->continuationData;
5870
5871 // Send success if nothing went wrong which finishes the process
5872 if (file_exists($staging_lock)) @unlink($staging_lock);
5873 return ['status' => 'error'];
5874
5875 }
5876
5877 public function debugging() {
5878
5879 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'scanner' . DIRECTORY_SEPARATOR . 'backups.php';
5880 $backups = new Backups();
5881 $availableBackups = $backups->getAvailableBackups();
5882 $list = $availableBackups['local'];
5883
5884 // $cron_list = [];
5885 // $cron_dates = [];
5886 // foreach ($list as $key => $value) {
5887 // if ($list[$key][6] == true) {
5888 // if ($list[$key][5] == 'unlocked') {
5889 // $cron_list[$list[$key][1]] = $list[$key][0];
5890 // $cron_dates[] = $list[$key][1];
5891 // }
5892 // }
5893 // }
5894
5895 // usort($cron_dates, function ($a, $b) {
5896 // return (strtotime($a) < strtotime($b)) ? -1 : 1;
5897 // });
5898
5899 // $cron_dates = array_slice($cron_dates, 0, -(intval(Dashboard\bmi_get_config('CRON:KEEP'))));
5900 // foreach ($cron_dates as $key => $value) {
5901 // $name = $cron_list[$cron_dates[$key]];
5902 // $name = explode('#%&', $name)[1];
5903 // Logger::log(__("Removing backup due to keep rules: ", 'backup-backup') . $name);
5904 // @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . $name);
5905 // }
5906
5907 if (isset($availableBackups['external']['gdrive'])) {
5908 $sortedMD5s = [];
5909 $gdrive = $availableBackups['external']['gdrive'];
5910 foreach ($gdrive as $md5 => $data) {
5911 if ($gdrive[$md5][6] == true && $gdrive[$md5][5] == 'unlocked') {
5912 $sortedMD5s[] = [$gdrive[$md5][1], $md5];
5913 }
5914 }
5915
5916 usort($sortedMD5s, function ($a, $b) {
5917 return (strtotime($a[0]) < strtotime($b[0])) ? -1 : 1;
5918 });
5919
5920 $gdrive_md5s = array_slice($sortedMD5s, 0, -(intval(Dashboard\bmi_get_config('CRON:KEEP'))));
5921 foreach ($sortedMD5s as $index => $data) {
5922 $md5 = $data[1];
5923
5924 }
5925 }
5926
5927 return ['availableBackups' => $availableBackups, '$gdrive' => $sortedMD5s];
5928
5929 }
5930
5931 public function checkCompatibility() {
5932
5933 $for = isset($this->post['for']) ? $this->post['for'] : 'backup';
5934
5935 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'check' . DIRECTORY_SEPARATOR . 'compatibility.php';
5936 $compatibility = new Compatibility($for);
5937 $errors = $compatibility->check();
5938 return ['status' => 'success', 'data' => $errors, 'mainReasonFound' => $compatibility->mainReasonFound()];
5939 }
5940
5941 public function clickedOnPluginReview() {
5942 update_option('bmi_review_clicked', time());
5943 }
5944
5945
5946 public function checkDiskSpace(){
5947 $file = BMI_BACKUPS . '/' . '.space_check';
5948
5949 $backupSize = BMP::getRecentSize() * 1.4;
5950
5951 try {
5952 $size = $backupSize;
5953 $fh = fopen($file, 'w');
5954 while($size > 0){
5955 $chunk = 1024;
5956 fputs($fh, str_pad('', min($chunk, $size)));
5957 $size -= $chunk;
5958 }
5959 fclose($fh);
5960
5961 $fs = filesize($file);
5962 @unlink($file);
5963
5964 return ['status' => 'enough-space'];
5965
5966
5967 } catch (\Exception $e) {
5968 if (file_exists($file)){
5969 $fileSize = filesize($file);
5970 unlink($file);
5971
5972 return ['status' => 'not-enough-space', 'data' => ['available' => BMP::humanSize(intval($fileSize)), 'required' => BMP::humanSize(intval($backupSize))]];
5973 }
5974
5975 } catch (\Throwable $e) {
5976 if (file_exists($file)){
5977 $fileSize = filesize($file);
5978 unlink($file);
5979 return ['status' => 'not-enough-space', 'data' => ['available' => BMP::humanSize(intval($fileSize)), 'required' => BMP::humanSize(intval($backupSize))]];
5980 }
5981
5982 }
5983 }
5984
5985 public function cleanUpAfterError() {
5986 $runningFile = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running';
5987 $spaceCheckFile = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.space_check';
5988
5989 if (file_exists($runningFile)){
5990 $backupName = file_get_contents($runningFile);
5991 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName)){
5992 $partialBackup = glob(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName . '.??????');
5993 if (is_array($partialBackup) && !empty($partialBackup)){
5994 foreach ($partialBackup as $file){
5995 @unlink($file);
5996 }
5997 }
5998 @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName);
5999 }
6000 @unlink($runningFile);
6001 }
6002
6003 if (file_exists($spaceCheckFile)){
6004 @unlink($spaceCheckFile);
6005 }
6006 }
6007
6008 function manuallyEnqueueUpload(){
6009 $type = isset($this->post['type']) ? $this->post['type'] : '';
6010 $md5 = isset($this->post['md5']) ? $this->post['md5'] : '';
6011 if (empty($type)) {
6012 return ['status' => 'error', 'msg' => __('Missing backup type.', 'backup-backup')];
6013 }
6014
6015 $uploadedBackupStatus = get_option('bmi_uploaded_backups_status', []);
6016
6017 if (!isset($uploadedBackupStatus[$md5]) || !isset($uploadedBackupStatus[$md5][$type])) {
6018 Logger::error("Failed to enqueue backup for upload. Details: " . print_r([$md5, $type, $uploadedBackupStatus], true));
6019 return [
6020 'status' => 'error',
6021 'msg' => __('Something went wrong', 'backup-backup')
6022 ];
6023 }
6024
6025 unset($uploadedBackupStatus[$md5][$type]);
6026 update_option('bmi_uploaded_backups_status', $uploadedBackupStatus);
6027
6028 return ['status' => 'success', 'msg' => __('Backup will be enqueued for upload shortly.', 'backup-backup'), 'data' => ['type' => $type]];
6029 }
6030
6031 /**
6032 *
6033 * @return mixed Response data from the ping server synchronization.
6034 */
6035 public function resyncWithPingServer() {
6036 $response = $this->shareDomainForAutoCron(true);
6037 return $response;
6038 }
6039
6040 }
6041