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