PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.4.9
Backup Migration v1.4.9
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 11 months ago bodies 11 months ago check 11 months ago cli 11 months ago cron 11 months ago dashboard 11 months ago database 11 months ago external 11 months ago extracter 11 months ago htaccess 11 months ago notices 11 months ago progress 11 months ago scanner 11 months ago staging 11 months ago traits 11 months ago uploader 11 months ago zipper 11 months ago .htaccess 11 months ago activation.php 11 months ago ajax.php 11 months ago ajax_offline.php 11 months ago analyst.php 11 months ago backup-process.php 11 months ago class-backup-method-mananger.php 11 months ago cli-handler.php 11 months ago compatibility.php 11 months ago config.php 11 months ago constants.php 11 months ago initializer.php 11 months ago logger.php 11 months ago offline.php 11 months ago
ajax.php
4440 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\External\BMI_External_SFTP as SFTP;
33
34 /**
35 * Ajax Handler for BMI
36 */
37 class BMI_Ajax {
38
39 public $post;
40 public $zip_progress;
41 public $migration_progress;
42 public $lock_cli;
43 public $lastCurlCode;
44
45 public $total_size_for_backup = 0;
46 public $total_size_for_backup_in_mb = 0;
47 public $total_excluded_size_for_backup = 0;
48
49 public function __construct($initializedWithCLI = false) {
50
51 // Initialize CRON if wasn't done earlier
52 $this->shareDomainForAutoCron();
53
54 // Return if it's not post
55 if (empty($_POST)) {
56 $this->post = ['f' => 'unknown_method'];
57 return;
58 }
59
60 // Sanitize User Input
61 $this->post = BMP::sanitize($_POST);
62
63 if (!isset($this->post['f'])) {
64 if (is_object($this->post) || is_array($this->post)) $this->post['f'] = 'unknown_method';
65 else $this->post = ['f' => 'unknown_method'];
66 }
67
68 // Check nonce for non PHP CLI usage (ignore while self requested via previously verified nonce to PHP CLI)
69 if (check_ajax_referer('backup-migration-ajax', 'nonce', false) === false && $initializedWithCLI === false) {
70 return wp_send_json_error(['reason' => 'not authorized request']);
71 }
72
73 // Log Handler Call (Verbose)
74 Logger::debug(__("Running POST Function: ", 'backup-backup') . $this->post['f']);
75
76 // Create backup folder
77 if (!file_exists(BMI_BACKUPS)) {
78 mkdir(BMI_BACKUPS, 0755, true);
79 }
80
81 // Create background logs file
82 $backgroundLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'background-errors.log';
83 if (!file_exists($backgroundLogsPath)) {
84 @touch($backgroundLogsPath);
85 }
86
87 if (!isset($this->post['f'])) {
88 return;
89 }
90
91 // Handle User Request If Known And Sanitize Response
92 if ($this->post['f'] == 'scan-directory') {
93 BMP::res($this->dirSize());
94 } elseif ($this->post['f'] == 'create-backup') {
95 BMP::res($this->prepareAndMakeBackup());
96 } elseif ($this->post['f'] == 'reset-latest') {
97 BMP::res($this->resetLatestLogs());
98 } elseif ($this->post['f'] == 'get-current-backups') {
99 BMP::res($this->getBackupsList());
100 } elseif ($this->post['f'] == 'restore-backup') {
101 BMP::res($this->restoreBackup());
102 } elseif ($this->post['f'] == 'is-running-backup') {
103 BMP::res($this->isRunningBackup());
104 } elseif ($this->post['f'] == 'stop-backup') {
105 BMP::res($this->stopBackup());
106 } elseif ($this->post['f'] == 'download-backup') {
107 BMP::res($this->handleQuickMigration());
108 } elseif ($this->post['f'] == 'migration-locked') {
109 BMP::res($this->isMigrationLocked());
110 } elseif ($this->post['f'] == 'upload-backup') {
111 BMP::res($this->handleChunkUpload());
112 } elseif ($this->post['f'] == 'delete-backup') {
113 BMP::res($this->removeBackupFile());
114 } elseif ($this->post['f'] == 'save-storage') {
115 BMP::res($this->saveStorageConfig());
116 } elseif ($this->post['f'] == 'save-file-config') {
117 BMP::res($this->saveFilesConfig());
118 } elseif ($this->post['f'] == 'save-other-options') {
119 BMP::res($this->saveOtherOptions());
120 } elseif ($this->post['f'] == 'store-config') {
121 BMP::res($this->saveStorageTypeConfig());
122 } elseif ($this->post['f'] == 'unlock-backup') {
123 BMP::res($this->toggleBackupLock(true));
124 } elseif ($this->post['f'] == 'lock-backup') {
125 BMP::res($this->toggleBackupLock(false));
126 } elseif ($this->post['f'] == 'get-dynamic-names') {
127 BMP::res($this->getDynamicNames());
128 } elseif ($this->post['f'] == 'reset-configuration') {
129 BMP::res($this->resetConfiguration());
130 } elseif ($this->post['f'] == 'get-site-data') {
131 BMP::res($this->getSiteData());
132 } elseif ($this->post['f'] == 'send-test-mail') {
133 BMP::res($this->sendTestMail());
134 } elseif ($this->post['f'] == 'calculate-cron') {
135 BMP::res($this->calculateCron());
136 } elseif ($this->post['f'] == 'dismiss-error-notice') {
137 BMP::res($this->dismissErrorNotice());
138 } elseif ($this->post['f'] == 'fix_uname_issues') {
139 BMP::res($this->fixUnameFunction());
140 } elseif ($this->post['f'] == 'revert_uname_issues') {
141 BMP::res($this->revertUnameProcess());
142 } elseif ($this->post['f'] == 'continue_restore_process') {
143 BMP::res($this->continueRestoreProcess());
144 } elseif ($this->post['f'] == 'htaccess-litespeed') {
145 BMP::res($this->fixLitespeed());
146 } elseif ($this->post['f'] == 'force-backup-to-stop') {
147 BMP::res($this->forceBackupToStop());
148 } elseif ($this->post['f'] == 'force-restore-to-stop') {
149 BMP::res($this->forceRestoreToStop());
150 } elseif ($this->post['f'] == 'staging-local-name') {
151 BMP::res($this->checkStagingLocalName());
152 } elseif ($this->post['f'] == 'staging-start-local-creation') {
153 BMP::res($this->startLocalStagingCreation());
154 } elseif ($this->post['f'] == 'staging-local-creation-process') {
155 BMP::res($this->localStagingCreationProcess());
156 } elseif ($this->post['f'] == 'staging-tastewp-creation-process') {
157 BMP::res($this->tastewpStagingCreation());
158 } elseif ($this->post['f'] == 'staging-rename-display') {
159 BMP::res($this->stagingRename());
160 } elseif ($this->post['f'] == 'staging-prepare-login') {
161 BMP::res($this->stagingPrepareLogin());
162 } elseif ($this->post['f'] == 'staging-delete-permanently') {
163 BMP::res($this->stagingDelete());
164 } elseif ($this->post['f'] == 'staging-get-updated-list') {
165 BMP::res($this->stagingSitesGetList());
166 } elseif ($this->post['f'] == 'send-troubleshooting-logs') {
167 BMP::res($this->sendTroubleshootingDetails());
168 } elseif ($this->post['f'] == 'log-sharing-details') {
169 BMP::res($this->logSharing());
170 } elseif ($this->post['f'] == 'get-latest-backup') {
171 BMP::res($this->getLatestBackupFile());
172 } elseif ($this->post['f'] == 'front-end-ajax-error') {
173 BMP::res($this->frontEndAjaxError());
174 } elseif ($this->post['f'] == 'backup-browser-method') {
175 BMP::res($this->backupBrowserMethodHandler());
176 } elseif ($this->post['f'] == 'debugging') {
177 BMP::res($this->debugging());
178 } elseif ($this->post['f'] == 'check-disk-space') {
179 BMP::res($this->checkDiskSpace());
180 } elseif ($this->post['f'] == 'check-comptability') {
181 BMP::res($this->checkCompatibility());
182 } elseif ($this->post['f'] == 'clean-up-after-error'){
183 BMP::res($this->cleanUpAfterError());
184 } elseif (substr($this->post['f'], 0, 3) === "bb-") {
185 require_once BMI_INCLUDES . '/external/backupbliss.php';
186 $backupBliss = new BackupBliss();
187 BMP::res($backupBliss->process(substr($this->post['f'], 3), $this->post));
188 } elseif ($this->post['f'] == 'check-not-uploaded-backups') {
189 do_action('bmi_ajax_offline', $this->post);
190 } elseif($this->post['f'] == 'download-cloud-backup') {
191 if (isset($this->post['storage']) && $this->post['storage'] == 'backupbliss')
192 BMP::res($this->downloadCloudBackup());
193 //Forward it to premium plugin for other cloud downloads
194 elseif (has_action('bmi_premium_ajax')) {
195 do_action('bmi_premium_ajax', $this->post);
196 }
197 }
198
199
200 //If none of the action matches it executes premium ajax if it exists
201 elseif (has_action('bmi_premium_ajax')) {
202 do_action('bmi_premium_ajax', $this->post);
203 }
204
205 }
206
207 /**
208 * shareDomainForAutoCron - Allows our API to keep scheduled backups on time
209 *
210 * @return json rtoken
211 */
212 private function shareDomainForAutoCron()
213 {
214
215 $cron_shared = get_option('bmi_cron_new_domain_done', false);
216 if ($cron_shared) return 0;
217
218 $baseurl = home_url();
219 if (substr($baseurl, 0, 4) != 'http') {
220 if (is_ssl()) $baseurl = 'https://' . home_url();
221 else $baseurl = 'http://' . home_url();
222 }
223
224 $url = 'https://authentication.backupbliss.com/v1/crons/connect';
225 $response = wp_remote_post($url, array(
226 'method' => 'POST',
227 'timeout' => 15,
228 'redirection' => 2,
229 'httpversion' => '1.0',
230 'blocking' => true,
231 'body' => array('site' => $baseurl)
232 ));
233
234 if (!is_wp_error($response)) {
235 $response = json_decode($response['body'], true);
236 if (isset($response['status']) && $response['status'] === 'success') {
237 update_option('bmi_cron_new_domain_done', true);
238 }
239
240 return 0;
241 }
242
243 return 0;
244 }
245
246 /**
247 * randomString - Generates "random" string
248 *
249 * @return string "random"
250 */
251 private function randomString($length = 64)
252 {
253
254 $chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
255 $str = "";
256
257 for ($i = 0; $i < $length; ++$i) {
258
259 $str .= $chars[mt_rand(0, strlen($chars) - 1)];
260 }
261
262 return $str;
263 }
264
265 /**
266 * downloadCloudBackup - Downloads Cloud Backup to Local Storage
267 *
268 * @return json status
269 */
270 private function downloadCloudBackup()
271 {
272
273 $secret = false;
274 if (isset($this->post['secret'])) $secret = $this->post['secret'];
275
276 $lock = BMI_BACKUPS . '/.migration_lock';
277 if (file_exists($lock) && (time() - filemtime($lock)) < 1) {
278 $lockContent = file_get_contents($lock);
279 if ($lockContent !== $secret) {
280 return ['status' => 'msg', 'why' => __('Download process is currently running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
281 }
282 }
283
284 require_once BMI_INCLUDES . '/progress/migration.php';
285
286 $step = intval($this->post['step']);
287 $storage = $this->post['storage'];
288 $startRestoreProcess = isset($this->post['startRestoreProcess']) ? $this->post['startRestoreProcess'] : 'true';
289
290 $clearFile = ($step === 0) ? false : true;
291 $migration = new MigrationProgress($clearFile);
292 $migration->start();
293
294 if ($storage == 'backupbliss') {
295
296 require_once BMI_INCLUDES . '/external/backupbliss.php';
297 $backupbliss = new BackupBliss();
298
299 $backupDetails = false;
300 $fileId = $this->post['fileId'];
301
302 if ($step === 0 || (!isset($this->post['size']) || $this->post['size'] == false || !is_numeric($this->post['size']))) {
303
304 $migration->log((__('Backup & Migration version: ', 'backup-backup') . BMI_VERSION));
305 $migration->log(__('Creating lock file', 'backup-backup'));
306 $secret = $this->randomString();
307 file_put_contents($lock, $secret);
308
309 $migration->log('Download intialized', 'INFO');
310 $migration->log('Getting backup details from BackupBliss...', 'STEP');
311 $backupDetails = $backupbliss->getFileDetailByName($fileId);
312
313 if (!$backupDetails) {
314
315 $migration->log("Couldn't fetch backup details from cloud.", 'ERROR');
316 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
317 if (file_exists($lock)) @unlink($lock);
318
319 $migration->log('#002', 'END-CODE');
320 $migration->end();
321
322 return ['status' => 'error'];
323 }
324
325 $size = intval($backupDetails['size']);
326 $originalFilename = $backupDetails['name'];
327
328 $migration->log('Backup details received!', 'SUCCESS');
329 $migration->log('Backup original name: ' . $originalFilename, 'INFO');
330 $migration->log('Starting download process...', 'STEP');
331
332 $availableMemory = BMP::getAvailableMemoryInBytes();
333 $bytesPerRequest = intval($availableMemory / 4);
334
335 $migration->log('Single batch will use up to: ' . $bytesPerRequest . ' bytes (~' . intval($bytesPerRequest / 1024 / 1024 / 2) . ' MBs)', 'INFO');
336
337 $fileIterator = 2;
338 $originalFilenameInfo = pathinfo($originalFilename);
339 $extension = $originalFilenameInfo['extension'];
340 $originalFilename = $originalFilenameInfo['filename'];
341 if ($originalFilenameInfo['extension'] == 'gz') {
342 $originalFilename = pathinfo($originalFilename, PATHINFO_FILENAME);
343 $extension = 'tar.gz';
344 }
345
346 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '.' . $extension;
347 $finalName = $originalFilename . '.' . $extension;
348
349 while (file_exists($backupDestinationPath)) {
350 $backupDestinationPath = BMI_BACKUPS . DIRECTORY_SEPARATOR . $originalFilename . '-' . $fileIterator . '.' . $extension;
351 $finalName = $originalFilename . '-' . $fileIterator . '.' . $extension;
352 $fileIterator++;
353 }
354
355 $originalFilename = $finalName;
356
357 $backupDestinationPath .= '.crdownload';
358
359 } else {
360
361 $size = intval($this->post['size']);
362 $originalFilename = $this->post['filename'];
363 $backupDestinationPath = $this->post['writepath'];
364 $bytesPerRequest = intval($this->post['chunksize']);
365 }
366
367 $md5 = $this->post['md5'];
368
369 $totalBatches = ceil($size / (256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2)));
370
371 if ($totalBatches <= $step) {
372
373 $migration->log('Download process finished!', 'SUCCESS');
374 $migration->log('Verifying MD5 checksum of downloaded file...', 'STEP');
375
376 rename($backupDestinationPath, str_replace('.crdownload', '', $backupDestinationPath));
377 $backupDestinationPath = str_replace('.crdownload', '', $backupDestinationPath);
378
379
380 $local_md5 = hash_file('md5', $backupDestinationPath);
381 if (file_exists($backupDestinationPath) && $local_md5 == $md5) {
382
383 $migration->log('Downloaded MD5: ' . $local_md5, 'INFO');
384 $migration->log('Expected MD5: ' . $md5, 'INFO');
385 $migration->log('File MD5 checksum is correct!', 'SUCCESS');
386 } else {
387
388 $migration->log('File MD5 checksum is NOT correct!', 'ERROR');
389 $migration->log('Downloaded MD5: ' . $local_md5, 'ERROR');
390 $migration->log('Expected MD5: ' . $md5, 'ERROR');
391 $migration->log('Downloaded file path: ' . $backupDestinationPath, 'ERROR');
392 $migration->log('File exist?: ' . (file_exists($backupDestinationPath) ? "Yes" : "No?"), 'ERROR');
393 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
394 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
395 if (file_exists($lock)) @unlink($lock);
396
397 $migration->log('#002', 'END-CODE');
398 $migration->end();
399
400 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
401 return ['status' => 'error'];
402 }
403
404 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
405 if (file_exists($lock)) @unlink($lock);
406 if ($startRestoreProcess == 'true') {
407 $migration->log('Requesting restoration process...', 'STEP');
408
409 $migration->log('#205', 'END-CODE');
410 } else {
411 $migration->log('Download process finished!', 'SUCCESS');
412 $migration->log('#206', 'END-CODE');
413 }
414 $migration->progress(100);
415 $migration->end();
416
417 return ['status' => 'success', 'finished' => 'true', 'filename' => $originalFilename];
418 } else {
419
420 $chunkSize = 256 * 1024 * 4 * intval($bytesPerRequest / 1024 / 1024 / 2);
421 $startRange = ($step * $chunkSize);
422 if ($step !== 0) $startRange = $startRange + 1;
423 $endRange = (($step + 1) * $chunkSize);
424 if ($endRange > $size) $endRange = $size;
425 $percentage = intval(($endRange / $size) * 100);
426
427 $data = $backupbliss->getFile($fileId, $startRange, $endRange);
428
429 if (!$data["file_detail"] || !$data["file_data"]) {
430
431 $migration->log("Couldn't fetch backup file from cloud.", 'ERROR');
432 $migration->log('For security reasons, I will remove the file (if exist) and stop the process...', 'ERROR');
433 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
434 if (file_exists($lock)) @unlink($lock);
435
436 $migration->log('#002', 'END-CODE');
437 $migration->end();
438
439 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
440 return ['status' => 'error'];
441 }
442
443 if ((is_dir(dirname($backupDestinationPath)) && file_exists($backupDestinationPath)) || $step === 0) {
444
445 $backupFile = fopen($backupDestinationPath, 'ab');
446 fwrite($backupFile, $data['file_data']);
447 fclose($backupFile);
448 } else {
449
450 $migration->log('File is not writable or directory does not exist.', 'ERROR');
451 $migration->log('File: ' . basename($backupDestinationPath), 'ERROR');
452 $migration->log('Dirname: ' . dirname($backupDestinationPath), 'ERROR');
453 $migration->log('For security reasons, I will remove the file and stop the process...', 'ERROR');
454 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
455 if (file_exists($lock)) @unlink($lock);
456
457 $migration->log('#002', 'END-CODE');
458 $migration->end();
459
460 if (file_exists($backupDestinationPath)) @unlink($backupDestinationPath);
461 return ['status' => 'error'];
462 }
463
464 $migration->log('Download progress (' . ($step + 1) . '/' . $totalBatches . '): ' . $endRange . '/' . $size . ' (' . $percentage . '%)', 'INFO');
465 $migration->progress($percentage);
466 $migration->end();
467
468 return [
469 'status' => 'success',
470 'size' => $size,
471 'md5' => $md5,
472 'finished' => 'false',
473 'originalFilename' => $originalFilename,
474 'writepath' => $backupDestinationPath,
475 'chunksize' => $bytesPerRequest,
476 'secret' => $secret
477 ];
478 }
479 }
480
481 if (file_exists($lock)) @unlink($lock);
482 return ['status' => 'error'];
483 }
484
485 public function siteURL() {
486 $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
487 $domainName = $_SERVER['HTTP_HOST'];
488
489 return $protocol . $domainName;
490 }
491
492 public function checkIfPHPCliExist(&$logger) {
493
494 $shouldContinue = apply_filters('bmi_cli_enabled', true);
495 if ($shouldContinue === false) {
496 $logger->log(__('PHP CLI is disabled manually, plugin will omit all PHP CLI steps.', 'backup-backup'), 'warn');
497 return false;
498 }
499
500
501 if (defined('BMI_CLI_ENABLED')) {
502 $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
503 if ($cliEnabled === false) {
504 $logger->log(__('PHP CLI is disabled manually, plugin will omit all PHP CLI steps.', 'backup-backup'), 'warn');
505 return false;
506 }
507 }
508
509 $logger->log(__('Looking for PHP CLI executable file.', 'backup-backup'), 'step');
510 require_once BMI_INCLUDES . '/cli/php_cli_finder.php';
511 $checker = new PHPCLICheck();
512 $result = $checker->findPHP();
513
514 if ($result === false) {
515
516 if (!defined('BMI_CLI_ENABLED')) define('BMI_CLI_ENABLED', false);
517 if (!defined('BMI_CLI_EXECUTABLE')) define('BMI_CLI_EXECUTABLE', false);
518 if ($checker->ini_disabled === true) {
519 $logger->log(__('PHP CLI is disabled in your php.ini file, the process may be unstable.', 'backup-backup'), 'warn');
520 } else {
521 $logger->log(__('Could not find proper PHP CLI executable, this process may be unstable.', 'backup-backup'), 'warn');
522 }
523
524 return false;
525
526 } else {
527
528 if (!defined('BMI_CLI_ENABLED')) define('BMI_CLI_ENABLED', apply_filters('bmi_cli_enabled', true));
529 if (!defined('BMI_CLI_EXECUTABLE')) define('BMI_CLI_EXECUTABLE', $result['executable']);
530
531 $logger->log(__('PHP CLI Filename: ', 'backup-backup') . basename($result['executable']), 'info');
532 $logger->log(__('PHP CLI Version: ', 'backup-backup') . $result['version'] . ' ' . $result['brand'], 'info');
533 $logger->log(__('PHP CLI Memory limit: ', 'backup-backup') . $result['memory'], 'info');
534 $logger->log(__('PHP CLI Execution limit: ', 'backup-backup') . $result['max_exec'], 'info');
535 $logger->log(__('We properly detected PHP CLI executable file.', 'backup-backup'), 'success');
536
537 return $result;
538
539 }
540
541 }
542
543 public function getDatabaseSize() {
544
545 global $wpdb;
546 $prefix = $wpdb->prefix;
547
548 $sql = "SELECT SUM(DATA_LENGTH + INDEX_LENGTH) AS `bytes` FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s;";
549 $sql = $wpdb->prepare($sql, array(DB_NAME));
550
551 $result = $wpdb->get_results($sql);
552 return intval($result[0]->bytes);
553
554 }
555
556 public function dirSize() {
557
558 // Folder
559 $f = $this->post['folder'];
560
561 // Bytes
562 $bytes = 0;
563 $excludedBytes = 0;
564
565 $emptyVar = [ 'this_is_empty_array' ];
566 $allowed = [ 'plugins', 'uploads', 'themes', 'contents_others', 'wordpress' ];
567
568 if (in_array($f, $allowed)) {
569
570 // Get list of staging sites for exclusion rules
571 require_once BMI_INCLUDES . '/staging/controller.php';
572 $staging = new Staging('..ajax..');
573 $stagingSites = $staging->getStagingSites(true);
574
575 $files = $this->scanFilesForBackup($emptyVar, $stagingSites, $f);
576 $files = $this->parseFilesForBackup($files, $emptyVar, false, true);
577
578 $bytes = $this->total_size_for_backup;
579 $excludedBytes = $this->total_excluded_size_for_backup;
580 set_transient('bmi_latest_size_' . $f, $bytes);
581 } elseif ($f == 'database') {
582
583 $bytes = $this->getDatabaseSize();
584 set_transient('bmi_latest_size_' . $f, $bytes);
585 }
586
587 return [ 'bytes' => $bytes, 'excluded' => $excludedBytes, 'readable' => BMP::humanSize($bytes) ];
588
589 }
590
591 public function backupErrorHandler() {
592 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
593
594 if (BMI_DEBUG) {
595 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (ERROR HANDLER #1):');
596 error_log(print_r($errno, true));
597 error_log(print_r($errstr, true));
598 error_log(print_r($errfile, true));
599 error_log(print_r($errline, true));
600 }
601
602 if (strpos($errstr, 'deprecated') !== false) return;
603 if (strpos($errstr, 'php_uname') !== false) return;
604 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false && $errno != E_ERROR) return;
605
606 if ($errno != E_ERROR && $errno != E_CORE_ERROR && $errno != E_COMPILE_ERROR && $errno != E_USER_ERROR && $errno != E_RECOVERABLE_ERROR) {
607
608 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false) return;
609 Logger::error(__('There was an error before request shutdown (but it was not logged to restore log)', 'backup-backup'));
610 Logger::error(__('Error message: ', 'backup-backup') . $errstr);
611 Logger::error(__('Error file/line: ', 'backup-backup') . $errfile . '|' . $errline);
612 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $errno);
613 return;
614
615 }
616 if (strpos($errfile, 'backup-backup') === false) {
617 Logger::error(__("Restore process was not aborted because this error is not related to Backup Migration.", 'backup-backup'));
618 $this->zip_progress->log(__("There was an error not related to Backup Migration Plugin.", 'backup-backup'), 'warn');
619 $this->zip_progress->log(__("Message: ", 'backup-backup') . $errstr, 'warn');
620 $this->zip_progress->log(__("Backup will not be aborted because of this.", 'backup-backup'), 'warn');
621 return;
622 }
623 if (strpos($errstr, 'unlink(') !== false) {
624 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
625 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#02' . '|' . $errno);
626 Logger::error($errstr);
627 return;
628 }
629 if (strpos($errfile, 'pclzip') !== false) {
630 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
631 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#03' . '|' . $errno);
632 Logger::error($errstr);
633 return;
634 }
635 if (strpos($errstr, 'rename(') !== false) {
636 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
637 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#04' . '|' . $errno);
638 Logger::error($errstr);
639 $this->zip_progress->log(__("Cannot move: ", 'backup-backup') . $errstr, 'warn');
640 return;
641 }
642
643 $this->zip_progress->log(__("There was an error during backup:", 'backup-backup'), 'error');
644 $this->zip_progress->log(__("Message: ", 'backup-backup') . $errstr, 'error');
645 $this->zip_progress->log(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline, 'error');
646 $this->zip_progress->log(__('Unfortunately we had to remove the backup (if partly created).', 'backup-backup'), 'error');
647
648 $backup = $GLOBALS['bmi_current_backup_name'];
649 $backup_path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $backup;
650 if (file_exists($backup_path)) @unlink($backup_path);
651 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running');
652 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort');
653
654 $this->zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
655 $this->zip_progress->log(__("#002", 'backup-backup'), 'end-code');
656 $this->zip_progress->end();
657
658 $GLOBALS['bmi_error_handled'] = true;
659 BMP::res(['status' => 'error', 'error' => $errstr]);
660 exit;
661
662 }, E_ALL);
663 }
664
665 public function migrationErrorHandler() {
666 set_exception_handler(function ($exception) {
667 if (BMI_DEBUG) {
668 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (EXCEPTION HANDLER #1):');
669 error_log(print_r($exception, true));
670 }
671
672 $this->migration_progress->log(__("Restore exception: ", 'backup-backup') . $exception->getMessage(), 'warn');
673 Logger::log(__("Restore exception: ", 'backup-backup') . $exception->getMessage());
674 });
675 }
676
677 public function migrationExceptionHandler() {
678 set_error_handler(function ($errno, $errstr, $errfile, $errline) {
679
680 if (BMI_DEBUG) {
681 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (ERROR HANDLER #2):');
682 error_log(print_r($errno, true));
683 error_log(print_r($errstr, true));
684 error_log(print_r($errfile, true));
685 error_log(print_r($errline, true));
686 }
687
688 if (strpos($errstr, 'deprecated') !== false) return;
689 if (strpos($errstr, 'php_uname') !== false) return;
690 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration' && $errno != E_ERROR) === false) return;
691
692 if ($errno == E_NOTICE) return;
693 if ($errno != E_ERROR && $errno != E_CORE_ERROR && $errno != E_COMPILE_ERROR && $errno != E_USER_ERROR && $errno != E_RECOVERABLE_ERROR) {
694 if (strpos($errfile, 'backup-backup') === false && strpos($errfile, 'backup-migration') === false) return;
695 Logger::error(__('There was an error before request shutdown (but it was not logged to restore log)', 'backup-backup'));
696 Logger::error(__('Error message: ', 'backup-backup') . $errstr);
697 Logger::error(__('Error file/line: ', 'backup-backup') . $errfile . '|' . $errline);
698 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#05' . '|' . $errno);
699 return;
700 }
701
702 Logger::error(__("There was an error/warning during restore process:", 'backup-backup'));
703 Logger::error(__("Message: ", 'backup-backup') . $errstr);
704 Logger::error(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline);
705 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#06' . '|' . $errno);
706
707 if (strpos($errfile, 'backup-backup') === false) {
708 Logger::error(__("Restore process was not aborted because this error is not related to Backup Migration.", 'backup-backup'));
709 $this->migration_progress->log(__("There was an error not related to Backup Migration Plugin.", 'backup-backup'), 'warn');
710 $this->migration_progress->log(__("Message: ", 'backup-backup') . $errstr, 'warn');
711 $this->migration_progress->log(__("Backup will not be aborted because of this.", 'backup-backup'), 'warn');
712 return;
713 }
714 if (strpos($errstr, 'unlink(') !== false) {
715 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
716 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#07' . '|' . $errno);
717 Logger::error($errstr);
718 return;
719 }
720 if (strpos($errfile, 'pclzip') !== false) {
721 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
722 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#08' . '|' . $errno);
723 Logger::error($errstr);
724 return;
725 }
726 if (strpos($errstr, 'rename(') !== false) {
727 Logger::error(__("Restore process was not aborted due to this error.", 'backup-backup'));
728 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#09' . '|' . $errno);
729 Logger::error($errstr);
730 $this->migration_progress->log(__("Cannot move: ", 'backup-backup') . $errstr, 'warn');
731 return;
732 }
733
734 $this->migration_progress->log(__("There was an error during restore process:", 'backup-backup'), 'error');
735 $this->migration_progress->log(__("Message: ", 'backup-backup') . $errstr, 'error');
736 $this->migration_progress->log(__("File/line: ", 'backup-backup') . $errfile . '|' . $errline, 'error');
737
738 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock');
739
740 $this->migration_progress->log(__("Aborting restore process...", 'backup-backup'), 'step');
741
742 if (isset($GLOBALS['bmi_current_tmp_restore']) && !empty($GLOBALS['bmi_current_tmp_restore'])) {
743
744 $this->migration_progress->log(__("Cleaning up exported files...", 'backup-backup'), 'step');
745
746 $tmp_unique = $GLOBALS['bmi_current_tmp_restore_unique'];
747 $dir = $GLOBALS['bmi_current_tmp_restore'];
748 $it = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
749 $files = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
750
751 $this->migration_progress->log(__('Removing ', 'backup-backup') . iterator_count($files) . __(' files', 'backup-backup'), 'INFO');
752 foreach ($files as $file) {
753 if ($file->isDir()) {
754 @rmdir($file->getRealPath());
755 } else {
756 @unlink($file->getRealPath());
757 }
758 }
759
760 @rmdir($dir);
761
762 $config_file = untrailingslashit(ABSPATH) . DIRECTORY_SEPARATOR . 'wp-config.' . $tmp_unique . '.php';
763 if (file_exists($config_file)) @unlink($config_file);
764
765 }
766
767 $this->migration_progress->log(__("#002", 'backup-backup'), 'end-code');
768 $this->migration_progress->end();
769
770 $GLOBALS['bmi_error_handled'] = true;
771 BMP::res(['status' => 'error', 'error' => $errstr]);
772 exit;
773
774 }, E_ALL);
775 }
776
777 public function backupExceptionHandler() {
778 set_exception_handler(function ($exception) {
779 if (BMI_DEBUG) {
780 error_log('BMI DEBUG ENABLED, HERE IS THE COMPLETE REPORT (EXCEPTION HANDLER #2):');
781 error_log(print_r($exception, true));
782 }
783
784 $this->zip_progress->log(__("Exception: ", 'backup-backup') . $exception->getMessage(), 'warn');
785 Logger::log(__("Exception: ", 'backup-backup') . $exception->getMessage());
786 });
787 }
788
789 public function resetLatestLogs() {
790
791 // Restore htaccess
792 BMP::revertLitespeed();
793 BMP::fixLitespeed();
794
795 // Check time if not bugged
796 if (file_exists(BMI_BACKUPS . '/.running') && (time() - filemtime(BMI_BACKUPS . '/.running')) > 65) {
797 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
798 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
799 }
800
801 // Check if backup is not in progress
802 if (file_exists(BMI_BACKUPS . '/.running')) {
803 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
804 }
805
806 // Remove too large logs
807 $completeLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.log';
808 if (file_exists($completeLogsPath) && (filesize($completeLogsPath) / 1024 / 1024) >= 3) {
809 @unlink($completeLogsPath);
810 }
811
812 $backgroundLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'background-errors.log';
813 if (file_exists($backgroundLogsPath) && (filesize($backgroundLogsPath) / 1024 / 1024) >= 3) {
814 @unlink($backgroundLogsPath);
815 }
816
817 @touch($completeLogsPath);
818 @touch($backgroundLogsPath);
819
820 // Require logs
821 require_once BMI_INCLUDES . '/progress/zip.php';
822 require_once BMI_INCLUDES . '/progress/migration.php';
823 require_once BMI_INCLUDES . '/progress/staging.php';
824
825 // Write initial
826 $zip_progress = new Progress('', 0);
827 $zip_progress->start();
828 $zip_progress->log(__("Initializing backup...", 'backup-backup'), 'step');
829 $zip_progress->progress('0/100');
830 $zip_progress->end();
831
832 // Write initial
833 $migration = new MigrationProgress(false);
834 $migration->start();
835 $migration->log(__('Initializing restore process', 'backup-backup'), 'STEP');
836 $migration->progress('0');
837 $migration->end();
838
839 // Write initial
840 $staging = new StagingProgress(false);
841 $staging->start();
842 $staging->log(__('Preparing creation of staging site...', 'backup-backup'), 'STEP');
843 $staging->progress('0');
844 $staging->end();
845
846 // Return done
847 return ['status' => 'success'];
848 }
849
850 public function makeBackupName() {
851 $name = Dashboard\bmi_get_config('BACKUP:NAME');
852
853 $urlparts = parse_url(home_url());
854 $domain = str_replace('.', '-', sanitize_text_field($urlparts['host']));
855
856 $hash = BMP::randomString(16);
857 $name = str_replace('%domain', $domain, $name);
858 $name = str_replace('%hash', $hash, $name);
859 $name = str_replace('%Y', date('Y'), $name);
860 $name = str_replace('%M', date('M'), $name);
861 $name = str_replace('%D', date('D'), $name);
862 $name = str_replace('%d', date('d'), $name);
863 $name = str_replace('%j', date('j'), $name);
864 $name = str_replace('%m', date('m'), $name);
865 $name = str_replace('%n', date('n'), $name);
866 $name = str_replace('%Y', date('Y'), $name);
867 $name = str_replace('%y', date('y'), $name);
868 $name = str_replace('%a', date('a'), $name);
869 $name = str_replace('%A', date('A'), $name);
870 $name = str_replace('%B', date('B'), $name);
871 $name = str_replace('%g', date('g'), $name);
872 $name = str_replace('%G', date('G'), $name);
873 $name = str_replace('%h', date('h'), $name);
874 $name = str_replace('%H', date('H'), $name);
875 $name = str_replace('%i', date('i'), $name);
876 $name = str_replace('%s', date('s'), $name);
877 $name = str_replace('%s', date('s'), $name);
878
879 $i = 2;
880 $tmpname = $name;
881
882 while (file_exists($tmpname . '.zip')) {
883 $tmpname = $name . '_' . $i;
884 $i++;
885 }
886
887 $name = $tmpname . '.zip';
888
889 if (has_filter('bmip_backup_name')) {
890 $name = apply_filters('bmip_backup_name', $name);
891 }
892
893 $GLOBALS['bmi_current_backup_name'] = $name;
894 return $name;
895 }
896
897 public function fixUnameFunction() {
898 $file = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
899 $backup = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip-backup.php';
900
901 // Make backup
902 if (!file_exists($backup)) {
903 @copy($file, $backup);
904 }
905
906 // Replace deprecated php_uname function which is mostly disabled and cause errors
907 $replace = file_get_contents($file);
908 $replace = str_replace('php_uname()', '(DIRECTORY_SEPARATOR === "/" ? "linux" : "windows")', $replace);
909 file_put_contents($file, $replace);
910 return ['status' => 'success'];
911 }
912
913 public function revertUnameProcess() {
914 $file = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip.php';
915 $backup = trailingslashit(ABSPATH) . 'wp-admin/includes/class-pclzip-backup.php';
916 if (file_exists($backup)) {
917 if (file_exists($file)) @unlink($file);
918 @copy($backup, $file);
919 }
920 return ['status' => 'success'];
921 }
922
923 public function isFunctionEnabled($func) {
924 $disabled = explode(',', ini_get('disable_functions'));
925 $isDisabled = in_array($func, $disabled);
926 if (!$isDisabled && function_exists($func)) return true;
927 else return false;
928 }
929
930 public function prepareAndMakeBackup($cron = false) {
931
932 global $wp_version;
933
934 $triggerLock = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.last_triggered';
935
936 if ($this->isFunctionEnabled('ini_set')) {
937 ini_set('display_errors', 1);
938 ini_set('error_reporting', E_ALL);
939 ini_set('log_errors', 1);
940 ini_set('error_log', BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.log');
941 }
942
943 // Double check for .space_check file
944 if (file_exists(BMI_BACKUPS . '/.space_check')) @unlink(BMI_BACKUPS . '/.space_check');
945
946 // Require File Scanner
947 require_once BMI_INCLUDES . '/progress/zip.php';
948 require_once BMI_INCLUDES . '/check/checker.php';
949
950 // CLI Handler
951 $cliHandler = trailingslashit(sanitize_text_field(BMI_INCLUDES)) . 'cli-handler.php';
952
953 // Backup name
954 if (defined('BMI_CLI_ARGUMENT') && !empty(BMI_CLI_ARGUMENT)) {
955 $name = BMI_CLI_ARGUMENT;
956 } else {
957 $name = $this->makeBackupName();
958 }
959
960 // Progress & Logs
961 $cliRunning = (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) ? true : false;
962 $shouldResetLogs = !$cliRunning;
963 if (defined('BMI_DOING_SCHEDULED_BACKUP_VIA_CLI')) {
964 $cron = true;
965 $shouldResetLogs = true;
966 }
967
968 $clearEndCodes = false;
969 if (isset($this->post['preserveLogs']) && ($this->post['preserveLogs'] == 'true' || $this->post['preserveLogs'] === true)) {
970 $shouldResetLogs = false;
971 $clearEndCodes = true;
972 }
973
974 $zip_progress = new Progress($name, 100, 0, $cron, $shouldResetLogs, $clearEndCodes);
975 $zip_progress->start();
976
977 // PHP CLI Check
978 $isCLI = false;
979 $cli_lock = BMI_BACKUPS . '/.backup_lock_cli';
980 $cli_lock_end = BMI_BACKUPS . '/.backup_lock_cli_end';
981 $cli_failed_lock = BMI_BACKUPS . '/.backup_lock_cli_failed';
982
983 if (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) {
984
985 $cli_result = $this->checkIfPHPCliExist($zip_progress);
986 $functionNormal = apply_filters('bmi_function_normal', BMI_FUNCTION_NORMAL);
987 if ($cli_result !== false && $functionNormal === true) {
988
989 $res = null;
990 if (defined('BMI_DOING_SCHEDULED_BACKUP')) {
991 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_backup_cron ' . $name . ' > /dev/null &', $res);
992 } else {
993 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_backup ' . $name . ' > /dev/null &', $res);
994 }
995 $res = implode("\n", $res);
996
997 sleep(3);
998
999 if (file_exists($cli_lock_end) && (time() - filemtime($cli_lock_end)) < 10) {
1000
1001 if (file_exists($cli_lock_end)) @unlink($cli_lock_end);
1002 if (file_exists($triggerLock)) @unlink($triggerLock);
1003 return ['status' => 'success', 'filename' => $name];
1004 exit;
1005
1006 }
1007
1008 if (!file_exists($cli_lock) || (time() - filemtime($cli_lock)) > 10) {
1009
1010 if (!file_exists(BMI_BACKUPS . '/.abort') || (time() - filemtime(BMI_BACKUPS . '/.abort')) > 10) {
1011
1012 $zip_progress->log(__("Something went wrong in PHP CLI process, backup will be continued with legacy methods.", 'backup-backup'), 'warn');
1013 if (file_exists($cli_lock)) @unlink($cli_lock);
1014 define('BMI_CLI_FAILED', true);
1015 touch($cli_failed_lock);
1016
1017 } else {
1018
1019 $zip_progress->log(__("Backup will not be continued due to manual abort by user.", 'backup-backup'), 'warn');
1020 if (file_exists($cli_lock)) @unlink($cli_lock);
1021 if (file_exists($triggerLock)) @unlink($triggerLock);
1022 return ['status' => 'msg', 'why' => __('Backup process aborted.', 'backup-backup'), 'level' => 'info'];
1023
1024 }
1025
1026 } else {
1027
1028 return ['status' => 'background', 'filename' => $name];
1029
1030 }
1031
1032 } else {
1033
1034 if ($functionNormal !== true) {
1035 $zip_progress->log(__("PHP CLI will not run due to user settings in plugin other options.", 'backup-backup'), 'warn');
1036 } else {
1037 $zip_progress->log(__("PHP CLI file cannot be executed due to unknown reason.", 'backup-backup'), 'warn');
1038 }
1039
1040 }
1041
1042 } else {
1043
1044 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
1045
1046 if (file_exists($cli_failed_lock) && (time() - filemtime($cli_failed_lock)) < 10) {
1047 exit;
1048 }
1049
1050 $isCLI = true;
1051 $zip_progress->log(__("Backup via PHP CLI initialized successfully.", 'backup-backup'), 'success');
1052 touch($cli_lock);
1053
1054 }
1055
1056 }
1057
1058 // Just in case (e.g. syntax error, we can close the file correctly)
1059 $GLOBALS['bmi_backup_progress'] = $zip_progress;
1060
1061 // Logs
1062 $zip_progress->log(__("Initializing backup...", 'backup-backup'), 'step');
1063 $zip_progress->log((__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION), 'info');
1064 $zip_progress->log(__("Site which will be backed up: ", 'backup-backup') . site_url(), 'info');
1065 $zip_progress->log(__("PHP Version: ", 'backup-backup') . PHP_VERSION, 'info');
1066 $zip_progress->log(__("WP Version: ", 'backup-backup') . $wp_version, 'info');
1067 $zip_progress->log(__("MySQL Version: ", 'backup-backup') . $GLOBALS['wpdb']->db_version(), 'info');
1068 $maxAllowedPackets = $GLOBALS['wpdb']->get_results("SHOW VARIABLES LIKE 'max_allowed_packet';");
1069 if (sizeof($maxAllowedPackets) > 0) {
1070 $zip_progress->log(__("MySQL Max Length: ", 'backup-backup') . $maxAllowedPackets[0]->Value, 'info');
1071 } else {
1072 $zip_progress->log(__("MySQL Max Length: ", 'backup-backup') . 'Unknown', 'info');
1073 }
1074 if (isset($_SERVER['SERVER_SOFTWARE']) && !empty($_SERVER['SERVER_SOFTWARE'])) {
1075 $zip_progress->log(__("Web server: ", 'backup-backup') . $_SERVER['SERVER_SOFTWARE'], 'info');
1076 } else {
1077 $zip_progress->log(__("Web server: Not available", 'backup-backup'), 'info');
1078 }
1079 $zip_progress->log(__("Max execution time (in seconds): ", 'backup-backup') . @ini_get('max_execution_time'), 'info');
1080
1081 $zip_progress->log(__("Memory limit (server): ", 'backup-backup') . @ini_get('memory_limit'), 'info');
1082 if (defined('WP_MEMORY_LIMIT')) {
1083 $zip_progress->log(__("Memory limit (wp-config): ", 'backup-backup') . WP_MEMORY_LIMIT, 'info');
1084 }
1085 if (defined('WP_MAX_MEMORY_LIMIT')) {
1086 $zip_progress->log(__("Memory limit (wp-config admin): ", 'backup-backup') . WP_MAX_MEMORY_LIMIT, 'info');
1087 }
1088
1089 if (defined('BMI_DB_MAX_ROWS_PER_QUERY')) {
1090 $zip_progress->log(__('Max rows per query (this site): ', 'backup-backup') . BMI_DB_MAX_ROWS_PER_QUERY, 'info');
1091 }
1092
1093 $zip_progress->log(__("Checking if backup dir is writable...", 'backup-backup'), 'info');
1094
1095 if (defined('BMI_DOING_SCHEDULED_BACKUP')) {
1096 $zip_progress->log(__("This process was initialized due to scheduled backup configuration...", 'backup-backup'), 'info');
1097 $zip_progress->log(__("Backup will be unlocked by default as it is not manual backup...", 'backup-backup'), 'info');
1098 $zip_progress->log('This log is triggered by SCHEDULED BACKUP and its part of automatic backup creation', 'verbose');
1099 }
1100
1101 if (defined('BMI_BACKUP_PRO')) {
1102 if (BMI_BACKUP_PRO == 1) {
1103 $zip_progress->log(__("Premium plugin is enabled and activated", 'backup-backup'), 'info');
1104 } else {
1105 $zip_progress->log(__("Premium version is enabled but not active, using free plugin.", 'backup-backup'), 'warn');
1106 }
1107 }
1108
1109 // Error handler
1110 $zip_progress->log(__("Initializing custom error handler", 'backup-backup'), 'info');
1111 $this->zip_progress = &$zip_progress;
1112 $this->backupErrorHandler();
1113 $this->backupExceptionHandler();
1114
1115 // Checker
1116 $checker = new Checker($zip_progress);
1117
1118 if (!is_writable(dirname(BMI_BACKUPS))) {
1119
1120 // Abort backup
1121 $zip_progress->log(__("Backup directory is not writable...", 'backup-backup'), 'error');
1122 $zip_progress->log(__("Path: ", 'backup-backup') . BMI_BACKUPS, 'error');
1123
1124 // Close backup
1125 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1126 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1127 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1128
1129 // Log and close log
1130 $zip_progress->log('#002', 'END-CODE');
1131 $zip_progress->end();
1132
1133 if ($isCLI === true) touch($cli_lock_end);
1134 $this->actionsAfterProcess();
1135
1136 // Return error
1137 if (file_exists($triggerLock)) @unlink($triggerLock);
1138 if ($cron == true) return ['status' => 'success'];
1139 else return ['status' => 'error'];
1140 } else {
1141 $zip_progress->log(__("Yup it is writable...", 'backup-backup'), 'success');
1142 }
1143
1144 if (!file_exists(BMI_BACKUPS)) @mkdir(BMI_BACKUPS, true);
1145
1146 // Get list of staging sites for exclusion rules
1147 require_once BMI_INCLUDES . '/staging/controller.php';
1148 $staging = new Staging('..ajax..');
1149 $stagingSites = $staging->getStagingSites(true);
1150
1151 // Get file names (huge list mostly)
1152 if (has_filter('bmip_backup_files')) {
1153 $files = apply_filters('bmip_backup_files', []);
1154 } else if ($fgwp = Dashboard\bmi_get_config('BACKUP:FILES') == 'true') {
1155 $zip_progress->log(__("Scanning files...", 'backup-backup'), 'step');
1156 $files = $this->scanFilesForBackup($zip_progress, $stagingSites);
1157 $files = $this->parseFilesForBackup($files, $zip_progress, $cron);
1158 } else {
1159 $zip_progress->log(__("Omitting files (due to settings)...", 'backup-backup'), 'warn');
1160 $files = [];
1161 }
1162
1163 $zip_progress->log(str_replace('%s', $this->total_excluded_size_for_backup, __("Total size of excluded files: %s bytes", 'backup-backup')), 'info');
1164 $zip_progress->log("Total size of excluded files (bytes): " . $this->total_excluded_size_for_backup, 'verbose');
1165
1166 // Check if there is enough space
1167 $bytes = intval($this->total_size_for_backup * 1.4);
1168 update_option('bmi_required_space', $bytes);
1169 $zip_progress->log(__("Checking free space, reserving...", 'backup-backup'), 'step');
1170 if ($this->total_size_for_backup_in_mb >= BMI_REV * 1000 && get_option('bmip_last', false) != '1') {
1171
1172 // Abort backup
1173 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
1174 $zip_progress->log(str_replace('%s', BMI_REV, __("Site weights more than %s GB.", 'backup-backup')), 'error');
1175 if (isset($this->post['f'])) {
1176 $zip_progress->log('Function: ' . print_r($this->post['f'], true), 'verbose');
1177 }
1178
1179 if (isset($_SERVER)) {
1180 $zip_progress->log('REQUEST_URI: ' . $_SERVER['REQUEST_URI'], 'verbose');
1181 $zip_progress->log('REQUEST_METHOD: ' . $_SERVER['REQUEST_METHOD'], 'verbose');
1182 }
1183
1184 if (!empty($this->post)) {
1185 $zip_progress->log(print_r($this->post, true), 'verbose');
1186 }
1187
1188 // Close backup
1189 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1190 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1191 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1192
1193 // Log and close log
1194 $zip_progress->log('#100', 'END-CODE');
1195 $zip_progress->end();
1196
1197 if ($isCLI === true) touch($cli_lock_end);
1198 $this->actionsAfterProcess();
1199
1200 // Return error
1201 if (file_exists($triggerLock)) @unlink($triggerLock);
1202 return ['status' => 'error', 'bfs' => true];
1203 }
1204
1205 $isSpaceCheckDisabled = Dashboard\bmi_get_config('OTHER:BACKUP:SPACE:CHECKING');
1206
1207 if ($isSpaceCheckDisabled) {
1208
1209 $zip_progress->log(__("Free space checking is disabled by user in settings...", 'backup-backup'), 'warn');
1210 $zip_progress->log(__("Backup will continue, trusting there is enough space...", 'backup-backup'), 'warn');
1211
1212 } else {
1213
1214 if (!$checker->check_free_space($bytes)) {
1215
1216 // Abort backup
1217 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
1218 $zip_progress->log(__("There is no space for that backup, checked: ", 'backup-backup') . ($bytes) . __(" bytes", 'backup-backup'), 'error');
1219 $zip_progress->log('not_enough_space', 'verbose');
1220
1221 // Close backup
1222 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1223 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1224 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1225
1226 // Log and close log
1227 $zip_progress->log('#002', 'END-CODE');
1228 $zip_progress->end();
1229
1230 if ($isCLI === true) touch($cli_lock_end);
1231 $this->actionsAfterProcess();
1232
1233 // Return error
1234 if (file_exists($triggerLock)) @unlink($triggerLock);
1235 if ($cron == true) return ['status' => 'msg', 'why' => __('There is not enough space for backup, please free up ' . $bytes / 1024 / 1024 . ' MB of space.', 'backup-backup')];
1236 else return ['status' => 'error'];
1237 } else {
1238 $zip_progress->log(__("Confirmed, there is more than enough space, checked: ", 'backup-backup') . ($bytes) . __(" bytes", 'backup-backup'), 'success');
1239 $zip_progress->bytes = $this->total_size_for_backup;
1240 }
1241
1242 }
1243
1244 if (Dashboard\bmi_get_config('BACKUP:DATABASE') != 'true') {
1245
1246 // $zip_progress->log(__("Database won't be backed-up due to user settings, omitting...", 'backup-backup'), 'info');
1247 // Commented as message will be shown in database backup module
1248
1249 }
1250
1251 // Log and set files length
1252 $zip_progress->log(__("Scanning done - found ", 'backup-backup') . sizeof($files) . __(" files...", 'backup-backup'), 'info');
1253 $zip_progress->files = sizeof($files);
1254
1255 // Make Backup
1256 $zip_progress->log(__("Backup initialized...", 'backup-backup'), 'success');
1257 $zip_progress->log(__("Initializing archiving system...", 'backup-backup'), 'step');
1258
1259 $resultCreateBackup = $this->createBackup($files, ABSPATH, $name, $zip_progress, $cron, $isCLI);
1260 do_action('bmp_created_backup',$resultCreateBackup);
1261 return $resultCreateBackup;
1262
1263 $bckpres = $this->createBackup($files, ABSPATH, $name, $zip_progress, $cron, $isCLI);
1264 if (file_exists($triggerLock)) @unlink($triggerLock);
1265 if ($cron == true) return ['status' => 'success'];
1266 else return $bckpres;
1267 }
1268
1269 public function fixLitespeed() {
1270 BMP::fixLitespeed();
1271
1272 return ['status' => 'success'];
1273 }
1274
1275 public function revertLitespeed() {
1276 BMP::revertLitespeed();
1277
1278 return ['status' => 'success'];
1279 }
1280
1281 public function createBackup($files, $base, $name, &$zip_progress, $cron = false, $isCLI = false) {
1282
1283 // Require File Zipper
1284 require_once BMI_INCLUDES . '/zipper/zipping.php';
1285
1286 // CLI locks
1287 $cli_lock = BMI_BACKUPS . '/.backup_lock_cli';
1288 $cli_lock_end = BMI_BACKUPS . '/.backup_lock_cli_end';
1289 $cli_failed_lock = BMI_BACKUPS . '/.backup_lock_cli_failed';
1290
1291 // Backup name
1292 $backup_path = BMI_BACKUPS . '/' . $name;
1293
1294 // Check time if not bugged
1295 if (file_exists(BMI_BACKUPS . '/.running') && (time() - filemtime(BMI_BACKUPS . '/.running')) > 65) {
1296 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1297 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1298 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1299 if ($isCLI === true && file_exists($cli_lock_end)) @unlink($cli_lock_end);
1300 }
1301
1302 if ($isCLI === true) {
1303 if (file_exists($cli_failed_lock) && (time() - filemtime($cli_failed_lock)) < 10) {
1304 exit;
1305 }
1306 }
1307
1308 // Mark as in progress
1309 if (!file_exists(BMI_BACKUPS . '/.running')) {
1310 touch(BMI_BACKUPS . '/.running');
1311 file_put_contents(BMI_BACKUPS . '/.running', $name);
1312 if ($isCLI === true) touch($cli_lock);
1313 } else {
1314 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
1315 }
1316
1317 // Initialized
1318 $zip_progress->log(__("Archive system initialized...", 'backup-backup'), 'success');
1319
1320 // Make ZIP
1321 $zipper = new Zipper();
1322 $zippy = $zipper->makeZIP($files, $backup_path, $name, $zip_progress, $cron);
1323 if (!$zippy) {
1324
1325 // Make sure it's open
1326 $zip_progress->start();
1327
1328 // Abort backup
1329 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
1330
1331 // Close backup
1332 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1333 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1334 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1335
1336 // Log and close log
1337 $zip_progress->log('#002', 'END-CODE');
1338 $zip_progress->end();
1339
1340 if ($isCLI === true) touch($cli_lock_end);
1341
1342 // Return error
1343 if (file_exists($backup_path)) @unlink($backup_path);
1344
1345 $this->actionsAfterProcess();
1346 return ['status' => 'error'];
1347 }
1348
1349 if (isset($zippy['status']) && $zippy['status'] == 'background') {
1350 return;
1351 }
1352
1353 // Backup aborted
1354 if (file_exists(BMI_BACKUPS . '/.abort')) {
1355
1356 // Make sure it's open
1357 $zip_progress->start();
1358
1359 if (file_exists($backup_path)) @unlink($backup_path);
1360 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1361 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1362 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1363
1364 // Log and close log
1365 $zip_progress->log(__("Backup process aborted.", 'backup-backup'), 'warn');
1366 $zip_progress->log('#002', 'END-CODE');
1367 $zip_progress->end();
1368
1369 if ($isCLI === true) touch($cli_lock_end);
1370 Logger::log(__("Backup process aborted.", 'backup-backup'));
1371
1372 $this->actionsAfterProcess();
1373 return ['status' => 'msg', 'why' => __('Backup process aborted.', 'backup-backup'), 'level' => 'info'];
1374 }
1375
1376 if (!file_exists($backup_path) && !$cron) {
1377
1378 // Make sure it's open
1379 $zip_progress->start();
1380
1381 // Abort backup
1382 $zip_progress->log(__("Aborting backup...", 'backup-backup'), 'step');
1383 $zip_progress->log(__("There is no backup file...", 'backup-backup'), 'error');
1384 $zip_progress->log(__("We could not find backup file when it already should be here.", 'backup-backup'), 'error');
1385 $zip_progress->log(__("This error may be related to missing space. (filled during backup)", 'backup-backup'), 'error');
1386 $zip_progress->log(__("Path: ", 'backup-backup') . $backup_path, 'error');
1387
1388 // Close backup
1389 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1390 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1391 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1392
1393 // Log and close log
1394 $zip_progress->log('#002', 'END-CODE');
1395 $zip_progress->end();
1396
1397 if ($isCLI === true) touch($cli_lock_end);
1398 $this->actionsAfterProcess();
1399
1400 // Return error
1401 if ($cron == true) return ['status' => 'success'];
1402 else return ['status' => 'error'];
1403 }
1404
1405 // End zip log
1406 $zip_progress->log(__("New backup created and its name is: ", 'backup-backup') . $name, 'success');
1407 $zip_progress->log('#001', 'END-CODE');
1408 $zip_progress->end();
1409
1410 if ($isCLI === true) touch($cli_lock_end);
1411
1412 // Unlink progress
1413 if (file_exists(BMI_BACKUPS . '/.running')) @unlink(BMI_BACKUPS . '/.running');
1414 if (file_exists(BMI_BACKUPS . '/.abort')) @unlink(BMI_BACKUPS . '/.abort');
1415 if ($isCLI === true && file_exists($cli_lock)) @unlink($cli_lock);
1416
1417 // Return
1418 Logger::log(__("New backup created and its name is: ", 'backup-backup') . $name);
1419
1420 $GLOBALS['bmi_error_handled'] = true;
1421
1422 $this->actionsAfterProcess(true);
1423 return ['status' => 'success', 'filename' => $name, 'root' => plugin_dir_url(BMI_ROOT_FILE)];
1424
1425 }
1426
1427 public function continueRestoreProcess() {
1428
1429 // BMI_RESTORE_SECRET
1430
1431 }
1432
1433 public function getBackupsList() {
1434
1435 // Require File Scanner
1436 require_once BMI_INCLUDES . '/scanner/backups.php';
1437
1438 // Get backups
1439 $backups = new Backups();
1440 $manifests = $backups->getAvailableBackups();
1441
1442 // Return files
1443 return ['status' => 'success', 'backups' => $manifests];
1444 }
1445
1446 public function sendTestMail() {
1447
1448 $email = Dashboard\bmi_get_config('OTHER:EMAIL') != false ? Dashboard\bmi_get_config('OTHER:EMAIL') : get_bloginfo('admin_email');
1449 $subject = __('Backup Migration – Example email', 'backup-backup');
1450 $message = __('This is a test email sent by the Backup Migration plugin via Troubleshooting options!', 'backup-backup');
1451
1452 try {
1453
1454 if (wp_mail($email, $subject, $message)) return [ 'status' => 'success' ];
1455 else return ['status' => 'error'];
1456
1457 } catch (\Exception $e) {
1458
1459 return ['status' => 'error'];
1460
1461 } catch (\Throwable $e) {
1462
1463 return ['status' => 'error'];
1464
1465 }
1466
1467 }
1468
1469 public function restoreBackup() {
1470
1471 global $wp_version;
1472
1473 if ($this->isFunctionEnabled('ini_set')) {
1474 ini_set('display_errors', 1);
1475 ini_set('error_reporting', E_ALL);
1476 ini_set('log_errors', 1);
1477 ini_set('error_log', BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.log');
1478 }
1479
1480
1481 // Double check for .space_check file
1482 if (file_exists(BMI_BACKUPS . '/.space_check')) @unlink(BMI_BACKUPS . '/.space_check');
1483
1484 // Require File Scanner
1485 require_once BMI_INCLUDES . '/zipper/zipping.php';
1486 require_once BMI_INCLUDES . '/extracter/extract.php';
1487 require_once BMI_INCLUDES . '/progress/migration.php';
1488 require_once BMI_INCLUDES . '/check/checker.php';
1489
1490 // Make AutoLogin possible
1491 $ip = '127.0.0.1';
1492 if (isset($_SERVER['HTTP_CLIENT_IP'])) {
1493 $ip = $_SERVER['HTTP_CLIENT_IP'];
1494 } else {
1495 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
1496 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
1497 }
1498 if ($ip === false) {
1499 if (isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
1500 }
1501 }
1502 $autoLoginMD = time() . '_' . $ip . '_' . '4u70L051n';
1503
1504 // Progress & lock file
1505 $lock = BMI_BACKUPS . '/.migration_lock';
1506 $lock_cli = BMI_BACKUPS . '/.migration_lock_cli';
1507 $autologin_file = BMI_BACKUPS . '/.autologin';
1508 $lock_cli_end = BMI_BACKUPS . '/.migration_lock_ended';
1509 $progress = BMI_BACKUPS . '/latest_migration_progress.log';
1510 $cli_last_download = BMI_BACKUPS . '/.cli_download_last';
1511
1512 $ignoreRunCheck = ((isset($this->post['ignoreRunning']) && $this->post['ignoreRunning'] == 'true') ? true : false);
1513 $isCLIRunning = (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) ? true : false;
1514 if ($isCLIRunning) $ignoreRunCheck = false;
1515
1516 if (file_exists($lock) && (time() - filemtime($lock)) < 65 && !$ignoreRunCheck) {
1517 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'];
1518 }
1519
1520 // Check if download was via CLI
1521 if ($this->post['file'] == '.cli_download' && file_exists($cli_last_download)) {
1522 $this->post['file'] = file_get_contents($cli_last_download);
1523 if (file_exists($cli_last_download)) @unlink($cli_last_download);
1524 }
1525
1526 // Logs
1527 $migration = new MigrationProgress($this->post['remote']);
1528 $migration->start();
1529
1530 if ($ignoreRunCheck) {
1531
1532 $migration->mute();
1533
1534 }
1535
1536 // Check PHP CLI
1537 if ((!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) && (!defined('BMI_CLI_REQUEST') || BMI_CLI_REQUEST === false)) {
1538
1539 $cli_result = $this->checkIfPHPCliExist($migration);
1540
1541 if ($cli_result !== false) {
1542
1543 $cliHandler = trailingslashit(sanitize_text_field(BMI_INCLUDES)) . 'cli-handler.php';
1544 $backupName = esc_attr($this->post['file']);
1545 $remoteType = 'false';
1546 if ($this->post['remote'] == 'true' || $this->post['remote'] === true) $remoteType = 'true';
1547 if (file_exists($lock_cli_end)) @unlink($lock_cli_end);
1548
1549 $res = null;
1550 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_restore ' . $backupName . ' ' . $remoteType . ' > /dev/null &', $res);
1551 $res = implode("\n", $res);
1552
1553 sleep(3);
1554
1555 if (file_exists($lock_cli_end) && (time() - filemtime($lock_cli_end)) < 10) {
1556
1557 // Put autologin
1558 file_put_contents($autologin_file, $autoLoginMD);
1559 touch($autologin_file);
1560
1561 return ['status' => 'cli', 'login' => explode('_', $autoLoginMD)[0], 'url' => site_url()];
1562 exit;
1563
1564 }
1565
1566 if (!file_exists($lock_cli) || (time() - filemtime($lock_cli)) > 10) {
1567
1568 $progressFile = null;
1569 $migration->log(__('No response from PHP CLI - plugin will try to recover the migration with traditional restore.', 'backup-backup'), 'warn');
1570 if (file_exists($lock_cli)) @unlink($lock_cli);
1571
1572 } else {
1573
1574 $progressFile = null;
1575
1576 // $migration->log(__('PHP CLI responded with correct code - we will continue via PHP CLI.', 'backup-backup'), 'info');
1577 // $migration->end();
1578
1579 // Put autologin
1580 file_put_contents($autologin_file, $autoLoginMD);
1581 touch($autologin_file);
1582
1583 return ['status' => 'cli', 'login' => explode('_', $autoLoginMD)[0], 'url' => site_url()];
1584 exit;
1585
1586 }
1587
1588 } else {
1589
1590 if (file_exists($lock_cli)) @unlink($lock_cli);
1591
1592 }
1593
1594 } else {
1595
1596 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
1597 $migration->log(__('PHP CLI: Restore process initialized, restoring...', 'backup-backup'), 'success');
1598 touch($lock_cli);
1599 } else {
1600 $migration->log(__('Restore process initialized, restoring (non-cli mode)...', 'backup-backup'), 'success');
1601 }
1602
1603 }
1604
1605 // Just in case (e.g. syntax error, we can close the file correctly)
1606 $GLOBALS['bmi_migration_progress'] = $migration;
1607
1608 // Checker
1609 $checker = new Checker($migration);
1610 $zipper = new Zipper();
1611
1612 // Handle remote
1613 if ($this->post['file']) {
1614 $migration->log(__('Restore process responded', 'backup-backup'), 'SUCCESS');
1615 }
1616
1617 // Make lock file
1618 $migration->log(__('Locking migration process', 'backup-backup'), 'SUCCESS');
1619 touch($lock);
1620
1621 // Initializing
1622 $migration->log(__('Initializing restore process', 'backup-backup'), 'STEP');
1623 $migration->log((__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION), 'info');
1624
1625 // Error handler
1626 $migration->log(__("Initializing custom error handler", 'backup-backup'), 'info');
1627
1628 // Error handler
1629 $this->migration_progress = &$migration;
1630 $this->migrationErrorHandler();
1631 $this->migrationExceptionHandler();
1632
1633 $homeURL = site_url();
1634 if (strlen($homeURL) <= 8) $homeURL = home_url();
1635 if (defined('WP_SITEURL') && strlen(WP_SITEURL) > 8) $homeURL = WP_SITEURL;
1636
1637 $migration->log(__("Site which will be restored: ", 'backup-backup') . $homeURL, 'info');
1638 $migration->log(__("PHP Version: ", 'backup-backup') . PHP_VERSION, 'info');
1639 $migration->log(__("WP Version: ", 'backup-backup') . $wp_version, 'info');
1640 $migration->log(__("MySQL Version: ", 'backup-backup') . $GLOBALS['wpdb']->db_version(), 'info');
1641 $maxAllowedPackets = $GLOBALS['wpdb']->get_results("SHOW VARIABLES LIKE 'max_allowed_packet';");
1642 if (sizeof($maxAllowedPackets) > 0) {
1643 $migration->log(__("MySQL Max Length: ", 'backup-backup') . $maxAllowedPackets[0]->Value, 'info');
1644 } else {
1645 $migration->log(__("MySQL Max Length: ", 'backup-backup') . 'Unknown', 'info');
1646 }
1647 if (isset($_SERVER['SERVER_SOFTWARE']) && !defined('BMI_USING_CLI_FUNCTIONALITY')) {
1648 $migration->log(__("Web server: ", 'backup-backup') . $_SERVER['SERVER_SOFTWARE'], 'info');
1649 } else {
1650 $migration->log(__("Web server: Not available", 'backup-backup'), 'info');
1651 }
1652 $migration->log(__("Max execution time (in seconds): ", 'backup-backup') . @ini_get('max_execution_time'), 'info');
1653
1654 $migration->log(__("Memory limit (server): ", 'backup-backup') . @ini_get('memory_limit'), 'info');
1655 if (defined('WP_MEMORY_LIMIT')) {
1656 $migration->log(__("Memory limit (wp-config): ", 'backup-backup') . WP_MEMORY_LIMIT, 'info');
1657 }
1658 if (defined('WP_MAX_MEMORY_LIMIT')) {
1659 $migration->log(__("Memory limit (wp-config admin): ", 'backup-backup') . WP_MAX_MEMORY_LIMIT, 'info');
1660 }
1661
1662 if (defined('BMI_BACKUP_PRO')) {
1663 if (BMI_BACKUP_PRO == 1) {
1664 $migration->log(__("Premium plugin is enabled and activated", 'backup-backup'), 'info');
1665 } else {
1666 $migration->log(__("Premium version is enabled but not active, using free plugin.", 'backup-backup'), 'warn');
1667 }
1668 }
1669
1670 $migration->log(__("Restore process initialized successfully.", 'backup-backup'), 'success');
1671
1672 // Check file size
1673 $zippath = BMP::fixSlashes(BMI_BACKUPS) . DIRECTORY_SEPARATOR . $this->post['file'];
1674 if (!$ignoreRunCheck) {
1675
1676 $manifest = $zipper->getZipFileContent($zippath, 'bmi_backup_manifest.json');
1677 $migration->log(__('Free space checking...', 'backup-backup'), 'STEP');
1678 $migration->log(__('Checking if there is enough amount of free space', 'backup-backup'), 'INFO');
1679
1680 $isSpaceCheckDisabled = Dashboard\bmi_get_config('OTHER:BACKUP:SPACE:CHECKING');
1681
1682 if ($isSpaceCheckDisabled) {
1683 $migration->log(__("Free space checking is disabled by user in settings...", 'backup-backup'), 'warn');
1684 $migration->log(__("Restore will continue, trusting there is enough space...", 'backup-backup'), 'warn');
1685 } else {
1686 if ($manifest) {
1687 if (isset($manifest->bytes) && $manifest->bytes) {
1688 $bytes = intval($manifest->bytes * 1.4);
1689 update_option('bmi_required_space', $bytes);
1690 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json')) {
1691 $restoreParts = json_decode(file_get_contents(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json'));
1692 if (isset($restoreParts->size) && $restoreParts->size && $restoreParts->backupName == $this->post['file']) {
1693 $bytes = intval($restoreParts->size * 1.4);
1694 }
1695 }
1696 if (!$checker->check_free_space($bytes)) {
1697 $migration->log(__('Cannot start migration process', 'backup-backup'), 'ERROR');
1698 $migration->log(__('Error: There is not enough space on the server, checked: ' . ($bytes) . ' bytes.', 'backup-backup'), 'ERROR');
1699 $migration->log("not_enough_space", 'verbose');
1700 $migration->log(__('Aborting...', 'backup-backup'), 'ERROR');
1701 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1702
1703 if (file_exists($lock)) @unlink($lock);
1704 $migration->log('#004', 'END-CODE');
1705 $migration->end();
1706
1707 if ($isCLIRunning == true) touch($lock_cli_end);
1708 $this->actionsAfterProcess(false, 'migration');
1709
1710 return ['status' => 'error'];
1711 } else {
1712 $migration->log(__('Confirmed, there is enough space on the device, checked: ' . ($bytes) . ' bytes.', 'backup-backup'), 'SUCCESS');
1713 }
1714 }
1715 } else {
1716 $migration->log(__('Cannot start migration process', 'backup-backup'), 'ERROR');
1717 $migration->log(__('Error: File may not exist, check file name and if it still exist', 'backup-backup'), 'ERROR');
1718 $migration->log(__('Error: Could not find manifest in backup, file may be broken', 'backup-backup'), 'ERROR');
1719 $migration->log(__('Error: Btw. because of this I also cannot check free space', 'backup-backup'), 'ERROR');
1720 $migration->log(__('Used path: ', 'backup-backup') . $zippath, 'ERROR');
1721 $migration->log(__('Aborting...', 'backup-backup'), 'ERROR');
1722 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1723
1724 if (file_exists($lock)) @unlink($lock);
1725 $migration->log('#003', 'END-CODE');
1726 $migration->end();
1727
1728 if ($isCLIRunning == true) touch($lock_cli_end);
1729 $this->actionsAfterProcess(false, 'migration');
1730
1731 return ['status' => 'error'];
1732 }
1733 }
1734
1735 }
1736
1737 if ($ignoreRunCheck) {
1738
1739 $migration->unmute();
1740
1741 }
1742
1743 // New extracter
1744 $theTmpName = ((isset($this->post['tmpname'])) ? $this->post['tmpname'] : false);
1745 $options = ((isset($this->post['options'])) ? $this->post['options'] : []);
1746 $extracter = new Extracter($this->post['file'], $migration, $theTmpName, $isCLIRunning, $options);
1747
1748 // Extract
1749 $theSecret = ((isset($this->post['secret'])) ? $this->post['secret'] : null);
1750 $isFine = $extracter->extractTo($theSecret);
1751 if (!$isFine) {
1752 $migration->log(__('Aborting...', 'backup-backup'), 'ERROR');
1753 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1754
1755 if (file_exists($lock)) @unlink($lock);
1756 $migration->log('#002', 'END-CODE');
1757 $migration->end();
1758
1759 if ($isCLIRunning == true) touch($lock_cli_end);
1760 $this->actionsAfterProcess(false, 'migration');
1761
1762 return ['status' => 'error'];
1763 }
1764
1765 $migration->progress('100');
1766 $migration->log(__('Restore process completed', 'backup-backup'), 'SUCCESS');
1767 $migration->log(__('Finalizing restored files', 'backup-backup'), 'STEP');
1768 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1769 if (file_exists($lock)) @unlink($lock);
1770
1771 $migration->log('#001', 'END-CODE');
1772 $migration->end();
1773
1774 if ($isCLIRunning == true) touch($lock_cli_end);
1775
1776 // Put autologin
1777 file_put_contents($autologin_file, $autoLoginMD);
1778 touch($autologin_file);
1779
1780 $this->actionsAfterProcess(true, 'migration');
1781 return ['status' => 'success', 'login' => explode('_', $autoLoginMD)[0], 'url' => site_url()];
1782 }
1783
1784 public function isRunningBackup() {
1785 $this->lock_cli = BMI_BACKUPS . '/.backup_cli_lock';
1786
1787 // Ongoing processes
1788 $ongoing = get_option('bmip_to_be_uploaded', [
1789 'current_upload' => [],
1790 'queue' => [],
1791 'failed' => []
1792 ]);
1793
1794 // Backup CLI running
1795 if (file_exists($this->lock_cli) && (time() - filemtime($this->lock_cli)) <= 3600) {
1796 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning', 'ongoing' => $ongoing];
1797 }
1798
1799 if (file_exists(BMI_BACKUPS . '/.running') && (time() - filemtime(BMI_BACKUPS . '/.running')) <= 65) {
1800 return ['status' => 'msg', 'why' => __('Backup process already running, please wait till it complete.', 'backup-backup'), 'level' => 'warning', 'ongoing' => $ongoing];
1801 } else {
1802 return ['status' => 'success', 'ongoing' => $ongoing];
1803 }
1804 }
1805
1806 public function stopBackup() {
1807 if (!file_exists(BMI_BACKUPS . '/.running')) {
1808 return ['status' => 'msg', 'why' => __('Backup process completed or is not running.', 'backup-backup'), 'level' => 'info'];
1809 } else {
1810 if (!file_exists(BMI_BACKUPS . '/.abort')) {
1811 touch(BMI_BACKUPS . '/.abort');
1812 }
1813
1814 return ['status' => 'success'];
1815 }
1816 }
1817
1818 public function isMigrationLocked() {
1819 $lock = BMI_BACKUPS . '/.migration_lock';
1820 $lock_cli = BMI_BACKUPS . '/.migration_lock_cli';
1821 $lock_cli_end = BMI_BACKUPS . '/.migration_lock_ended';
1822
1823 if ((file_exists($lock) && (time() - filemtime($lock)) < 65) || (file_exists($lock_cli) && (time() - filemtime($lock_cli)) < 7200)) {
1824
1825 return ['status' => 'msg', 'why' => __('Restore process is currently running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
1826
1827 } else {
1828
1829 require_once BMI_INCLUDES . '/progress/migration.php';
1830 $progress = BMI_BACKUPS . '/latest_migration_progress.log';
1831 $shouldClearLogs = true;
1832
1833 if (isset($this->post['clearLogs']) && $this->post['clearLogs'] == 'false') {
1834 $shouldClearLogs = false;
1835 }
1836
1837 if ($shouldClearLogs === true) {
1838 if (file_exists($lock_cli_end) && (time() - filemtime($lock_cli_end)) > 10) {
1839
1840 $migration = new MigrationProgress();
1841 $migration->start();
1842 $migration->log(__('Initializing restore process...', 'backup-backup'), 'STEP');
1843 $migration->end();
1844
1845 file_put_contents($progress, '0');
1846
1847 }
1848 }
1849
1850 return ['status' => 'success'];
1851
1852 }
1853 }
1854
1855 public function downloadFile($url, $dest, $progress, $lock, &$logger) {
1856 $current_percentage = 0;
1857 $previous_logged = 0;
1858 $fp = fopen($dest, 'w+');
1859
1860 $progressfile = $progress;
1861 $lockfile = $lock;
1862
1863 $ch = curl_init(rawurldecode($url));
1864 curl_setopt($ch, CURLOPT_TIMEOUT, 0);
1865
1866 curl_setopt($ch, CURLOPT_FILE, $fp);
1867 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1868 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
1869 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
1870
1871 curl_setopt($ch, CURLOPT_NOPROGRESS, false);
1872 curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function ($resource, $download_size, $downloaded) use (&$current_percentage, &$lockfile, &$progressfile, &$logger, &$previous_logged) {
1873 if ($download_size > 0) {
1874 $new_percentage = intval(($downloaded / $download_size) * 100);
1875
1876 if (intval($current_percentage) != intval($new_percentage)) {
1877 $logger->progress($new_percentage);
1878
1879 if ($current_percentage == 0 || ($new_percentage % 5 == 0) || $new_percentage > 99) {
1880 $logger->log(sprintf(__('Download progress: %s/%s MB (%s%%)', 'backup-backup'), round($downloaded / 1024 / 1024), round($download_size / 1024 / 1024), $new_percentage), 'INFO');
1881 $previous_logged = $new_percentage;
1882 }
1883
1884 $current_percentage = $new_percentage;
1885 }
1886 }
1887 });
1888
1889 curl_exec($ch);
1890 $this->lastCurlCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1891
1892 $error_msg = false;
1893 if (curl_errno($ch)) {
1894 $error_msg = curl_error($ch);
1895 $curl_errno = curl_errno($ch);
1896 $fileSize = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
1897
1898 if ($curl_errno == CURLE_WRITE_ERROR || $curl_errno == CURLE_ABORTED_BY_CALLBACK) {
1899 $requiredSpace = $fileSize * 1.1; // Add 10% buffer
1900 update_option('bmi_required_space', $requiredSpace);
1901 $logger->log('not_enough_space', 'verbose');
1902 }
1903 }
1904
1905 curl_close($ch);
1906 fclose($fp);
1907
1908 if ($error_msg) {
1909 return $error_msg;
1910 } else {
1911 return false;
1912 }
1913 }
1914
1915 public function handleQuickMigration() {
1916 $lock = BMI_BACKUPS . '/.migration_lock';
1917 if (file_exists($lock) && (time() - filemtime($lock)) < 65) {
1918 return ['status' => 'msg', 'why' => __('Download process is currently running, please wait till it complete.', 'backup-backup'), 'level' => 'warning'];
1919 }
1920
1921 require_once BMI_INCLUDES . '/progress/migration.php';
1922 require_once BMI_INCLUDES . '/zipper/zipping.php';
1923
1924 $migration = new MigrationProgress(true);
1925 $migration->start();
1926
1927 $tmp_name = 'backup_' . time() . '.zip.part';
1928
1929 // Missing URL parameter
1930 if (!isset($this->post['url'])) {
1931 wp_send_json_error();
1932 }
1933
1934 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true && defined('BMI_CLI_ARGUMENT')) {
1935
1936 $url = BMI_CLI_ARGUMENT;
1937
1938 } else {
1939
1940 $url = $this->post['url'];
1941 $startRestoreProcess = isset($this->post['startRestoreProcess']) ? $this->post['startRestoreProcess'] : 'true';
1942
1943 $url = trim(rawurlencode(sanitize_url($url, ['http', 'https']))); // or esc_attr but rawurlencode should be fine
1944
1945 // Just why not {
1946 $url = str_replace(' ', '', $url);
1947 $url = str_replace('$', '%24', $url);
1948 $url = str_replace('`', '%60', $url);
1949 $url = str_replace('"', '%22', $url);
1950 $url = str_replace('\\', '%5C', $url);
1951 $url = str_replace('&amp;', '&', $url);
1952 // }
1953
1954 }
1955
1956 $dest = BMI_BACKUPS . '/' . $tmp_name;
1957 $progress = BMI_BACKUPS . '/latest_migration_progress.log';
1958 $cli_lock = BMI_BACKUPS . '/.cli_download_lock';
1959
1960 if (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false) {
1961
1962 $cli_result = $this->checkIfPHPCliExist($migration);
1963 if ($cli_result !== false) {
1964
1965 $cliHandler = trailingslashit(sanitize_text_field(BMI_INCLUDES)) . 'cli-handler.php';
1966
1967 $res = null;
1968 @exec(BMI_CLI_EXECUTABLE . ' -f "' . $cliHandler . '" bmi_quick_migration "' . $url . '" > /dev/null &', $res);
1969 $res = implode("\n", $res);
1970
1971 sleep(2);
1972 if (file_exists($cli_lock) && (time() - filemtime($cli_lock)) < 10) {
1973
1974 if (file_exists($cli_lock)) @unlink($cli_lock);
1975 return [ 'status' => 'cli_download' ];
1976 exit;
1977
1978 }
1979
1980 }
1981
1982 } else {
1983
1984 $migration->log(__('Downloading via PHP CLI', 'backup-backup'));
1985 touch($cli_lock);
1986
1987 }
1988
1989 $migration->log((__("Backup & Migration version: ", 'backup-backup') . BMI_VERSION));
1990 $migration->log(__('Creating lock file', 'backup-backup'));
1991 file_put_contents($lock, '');
1992 $migration->log(__('Initializing download process', 'backup-backup'), 'STEP');
1993 $downstart = microtime(true);
1994 $migration->log(__('Downloading initialized', 'backup-backup'), 'SUCCESS');
1995 $migration->log(__('Downloading remote file...', 'backup-backup'), 'STEP');
1996 $migration->log(__('Used URL: ', 'backup-backup') . rawurldecode($url), 'INFO');
1997 $fileError = $this->downloadFile($url, $dest, $progress, $lock, $migration);
1998 $migration->log(__('Unlocking migration', 'backup-backup'), 'INFO');
1999 if (file_exists($lock)) @unlink($lock);
2000
2001 if ($fileError) {
2002 $migration->log(__('Removing downloaded file', 'backup-backup'), 'INFO');
2003 if (file_exists($dest)) @unlink($dest);
2004 $migration->log(__('Download error', 'backup-backup'), 'ERROR');
2005
2006 if (strpos($fileError, 'Failed writing body') !== false) {
2007 $migration->log(__('Error: There is not enough space on the server', 'backup-backup'), 'ERROR');
2008 $migration->log("not_enough_space", 'verbose');
2009 } else {
2010 $migration->log(__('Error', 'backup-backup') . ': ' . $fileError, 'ERROR');
2011 }
2012
2013 $migration->log('#002', 'END-CODE');
2014 return ['status' => 'error'];
2015 } else {
2016 $migration->log(__('Download completed (took: ', 'backup-backup') . (microtime(true) - $downstart) . 's)', 'SUCCESS');
2017 $migration->log(__('Looking for backup manifest', 'backup-backup'), 'STEP');
2018 $zipper = new Zipper();
2019 $content = $zipper->getZipFileContent($dest, 'bmi_backup_manifest.json');
2020 if ($content) {
2021 try {
2022 $i = 1;
2023 $name = $content->name;
2024 $prepared_name = $name;
2025 $migration->log(__('Manifest found remote name: ', 'backup-backup') . $name, 'SUCCESS');
2026
2027 while (file_exists(BMI_BACKUPS . '/' . $prepared_name)) {
2028 $prepared_name = substr($name, 0, -4) . '_' . $i . '.zip';
2029 $i++;
2030 }
2031
2032 rename($dest, BMI_BACKUPS . '/' . $prepared_name);
2033 $migration->log(__('Requesting restore process', 'backup-backup'), 'STEP');
2034 $migration->progress(0);
2035 file_put_contents(BMI_BACKUPS . '/' . '.cli_download_last', $prepared_name);
2036 if ($startRestoreProcess == 'true'){
2037 $migration->log('#205', 'END-CODE');
2038 } else {
2039 $migration->log('#206', 'END-CODE');
2040 }
2041
2042 if (defined('BMI_USING_CLI_FUNCTIONALITY')) {
2043 $this->post['file'] = '.cli_download';
2044 $this->post['remote'] = true;
2045 return $this->restoreBackup();
2046 } else {
2047 return ['status' => 'success', 'name' => $prepared_name];
2048 }
2049 } catch (\Exception $e) {
2050 $migration->log(__('Error: ', 'backup-backup') . $e, 'ERROR');
2051 $migration->log(__('Removing downloaded file', 'backup-backup'), 'ERROR');
2052 if (file_exists($dest)) @unlink($dest);
2053
2054 $migration->log('#002', 'END-CODE');
2055 return ['status' => 'error'];
2056 } catch (\Throwable $e) {
2057 $migration->log(__('Error: ', 'backup-backup') . $e, 'ERROR');
2058 $migration->log(__('Removing downloaded file', 'backup-backup'), 'ERROR');
2059 if (file_exists($dest)) @unlink($dest);
2060
2061 $migration->log('#002', 'END-CODE');
2062 return ['status' => 'error'];
2063
2064 }
2065
2066 } else {
2067
2068 // $migration->log(__('Error during manifest check: ', 'backup-backup') . print_r($content, true), 'ERROR');
2069 if ($this->lastCurlCode == '403') {
2070 $migration->log(__('Backup is not available to download (Error 403).', 'backup-backup'), 'ERROR');
2071 $migration->log(__('It is restricted by remote server configuration.', 'backup-backup'), 'ERROR');
2072 } elseif ($this->lastCurlCode == '423') {
2073 $migration->log(__('Backup is locked on remote site, please unlock remote downloading.', 'backup-backup'), 'ERROR');
2074 $migration->log(__('You can find the setting in "Where shall the backup(s) be stored?" section.', 'backup-backup'), 'ERROR');
2075 } elseif ($this->lastCurlCode == '200' || $this->lastCurlCode == '404') {
2076 $migration->log(__('Backup does not exist under provided URL.', 'backup-backup'), 'ERROR');
2077 $migration->log(__('Please confirm that you can download the backup file via provided URL.', 'backup-backup'), 'ERROR');
2078 $migration->log(__('...or the manifest file does not exist in the backup.', 'backup-backup'), 'ERROR');
2079 $migration->log(__('Missing manifest means that the backup is probably invalid.', 'backup-backup'), 'ERROR');
2080 } else {
2081 $migration->log(__('Manifest file does not exist', 'backup-backup'), 'ERROR');
2082 $migration->log(__('Downloaded backup may be incomplete (missing manifest)', 'backup-backup'), 'ERROR');
2083 $migration->log(__('...or provided URL is not a direct download of ZIP file.', 'backup-backup'), 'ERROR');
2084 $migration->log(__('Removing downloaded file', 'backup-backup'), 'ERROR');
2085 }
2086
2087 if (file_exists($dest)) @unlink($dest);
2088
2089 $migration->log('#002', 'END-CODE');
2090 return ['status' => 'error'];
2091
2092 }
2093 }
2094 }
2095
2096 public function handleChunkUpload() {
2097 require_once BMI_INCLUDES . '/uploader/chunks.php';
2098 }
2099
2100 public function removeBackupFile() {
2101 $files = $this->post['filenames'];
2102 $deleteCloud = $this->post['deleteCloud'] === 'yes' ? true : false;
2103 $cloudDetails = $this->post['cloudDetails'];
2104
2105 $md5_file_summary_path = BMI_BACKUPS . DIRECTORY_SEPARATOR. 'md5summary.php';
2106 $md5summary = [];
2107
2108 if (file_exists($md5_file_summary_path)) {
2109 $md5summary = file_get_contents($md5_file_summary_path);
2110 $md5summary = substr($md5summary, 18, -2);
2111 if (is_serialized($md5summary)) {
2112 $md5summary = maybe_unserialize($md5summary);
2113 }
2114 }
2115
2116 if ($deleteCloud) {
2117 //Initialize externall storages for backup deletion action to be initiated
2118 require_once BMI_INCLUDES . '/external/controller.php';
2119 new ExternalStorage();
2120
2121 if (defined('BMI_BACKUP_PRO') && defined('BMI_PRO_INC')) {
2122 $proPath = BMI_PRO_INC . 'external/controller.php';
2123 if (file_exists($proPath)) {
2124 require_once $proPath;
2125 new ExternalStoragePremium();
2126 }
2127 }
2128 }
2129
2130 try {
2131 if (is_array($files)) {
2132 for ($i = 0; $i < sizeof($files); $i++) {
2133
2134 $removeByMD5 = false;
2135 $file = $files[$i];
2136 $file = preg_replace('/\.\./', '', $file);
2137
2138 if (file_exists(BMI_BACKUPS . '/' . $file)) {
2139
2140 if ($deleteCloud) {
2141 do_action('bmi_premium_remove_backup_file', md5_file(BMI_BACKUPS . '/' . $file));
2142 }
2143
2144 unlink(BMI_BACKUPS . '/' . $file);
2145
2146 } else if ($deleteCloud) $removeByMD5 = true;
2147
2148 if (isset($md5summary[$file])) {
2149 $md5s = $md5summary[$file];
2150
2151 for ($j = 0; $j < sizeof($md5s); ++$j) {
2152 $md5_file_path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $md5s[$j] . '.json';
2153 if (file_exists($md5_file_path)) {
2154 if ($deleteCloud) {
2155 do_action('bmi_premium_remove_backup_json_file', $md5s[$j] . '.json');
2156 }
2157 unlink($md5_file_path);
2158 } else if ($deleteCloud) $removeByMD5 = true;
2159 }
2160
2161 unset($md5summary[$file]);
2162 }
2163
2164 if ($deleteCloud && $removeByMD5) {
2165 if (isset($cloudDetails[$file])) {
2166 do_action('bmi_premium_remove_backup_file', $cloudDetails[$file]['md5']);
2167 do_action('bmi_premium_remove_backup_json_file', $cloudDetails[$file]['md5'] . '.json');
2168 }
2169 }
2170
2171 }
2172 }
2173 } catch (\Exception $e) {
2174 return ['status' => 'error', 'e' => $e];
2175 } catch (\Throwable $e) {
2176 return ['status' => 'error', 'e' => $e];
2177 }
2178
2179 $cacheMd5String = "<?php exit; \$x = '" . serialize($md5summary) . "';";
2180 file_put_contents($md5_file_summary_path, $cacheMd5String);
2181
2182 return ['status' => 'success'];
2183 }
2184
2185 public function saveStorageConfig() {
2186 $dir_path = $this->post['directory']; // STORAGE::LOCAL::PATH
2187 $accessible = $this->post['access']; // STORAGE::DIRECT::URL
2188 $gdrivedirname = 'BACKUP_MIGRATION_BACKUPS'; // STORAGE::EXTERNAL::GDRIVE::DIRNAME // $this->post['gdrivedirname']
2189 $curr_path = Dashboard\bmi_get_config('STORAGE::LOCAL::PATH');
2190
2191 $error = 0;
2192 $created = false;
2193
2194 if (!preg_match("/^[a-zA-Z0-9\_\-\/\.]+$/", $dir_path)) {
2195 return ['status' => 'msg', 'why' => __('Entered directory/path name does not match allowed characters (Local Storage).', 'backup-backup'), 'level' => 'warning'];
2196 }
2197
2198 if (!is_string($dir_path) || $dir_path === '' ||
2199 !(preg_match('/^[A-Z]:[\/\\\\]/i', $dir_path) || strpos($dir_path, '/') === 0)) {
2200 return ['status' => 'msg', 'why' => __('Please enter full path to the directory (Local Storage).', 'backup-backup'), 'level' => 'warning'];
2201 }
2202 if (!file_exists($dir_path)) {
2203 $created = @mkdir($dir_path, 0755, true);
2204 }
2205
2206 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO === 1) {
2207
2208 if (isset($this->post['gdrive'])) {
2209 $gdriveenabled = $this->post['gdrive'];
2210 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::GDRIVE', $gdriveenabled)) {
2211 $errors++;
2212 }
2213
2214 if (isset($this->post['gdrivedirname'])) {
2215 $gdrivedirname = $this->post['gdrivedirname'];
2216
2217 if (!preg_match("/^[a-zA-Z0-9\_\-\.]+$/", $gdrivedirname)) {
2218 return ['status' => 'msg', 'why' => __('Entered directory name does not match allowed characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
2219 }
2220
2221 if (strlen(trim($gdrivedirname)) < 3) {
2222 return ['status' => 'msg', 'why' => __('Entered directory name is too short, min 3 characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
2223 }
2224
2225 if (strlen(trim($gdrivedirname)) > 48) {
2226 return ['status' => 'msg', 'why' => __('Entered directory name is too long, max 48 characters (Google Drive).', 'backup-backup'), 'level' => 'warning'];
2227 }
2228
2229 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::GDRIVE::DIRNAME', $gdrivedirname)) {
2230 $errors++;
2231 }
2232 }
2233 }
2234
2235 if (isset($this->post['backupbliss'])) {
2236 $backupblissenabled = $this->post['backupbliss'];
2237 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::backupbliss', $backupblissenabled)) {
2238 $errors++;
2239 }
2240 }
2241
2242 if (isset($this->post['onedrive'])) {
2243 $onedriveenabled = $this->post['onedrive'];
2244 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::ONEDRIVE', $onedriveenabled)) {
2245 $errors++;
2246 }
2247 }
2248
2249 if (isset($this->post['sftp'])) {
2250 $sftpenabled = $this->post['sftp'];
2251 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::SFTP', $sftpenabled)) {
2252 $errors++;
2253 }
2254
2255 }
2256
2257 if (isset($this->post['ftp'])) {
2258 $ftpenabled = $this->post['ftp'];
2259 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::FTP', $ftpenabled)) {
2260 $errors++;
2261 }
2262
2263 if ($ftpenabled != "false"){
2264 if (isset($this->post['ftphostip'])) {
2265 $ftpiphost = $this->post['ftphostip'];
2266 update_option('bmi_pro_ftp_host', $ftpiphost);
2267 }
2268
2269 if (isset($this->post['ftphostusername'])) {
2270 $ftpHostUsername = $this->post['ftphostusername'];
2271 update_option('bmi_pro_ftp_username', $ftpHostUsername);
2272 }
2273
2274 if (isset($this->post['ftppassword'])) {
2275 $ftpHostPassword = $this->post['ftppassword'];
2276 if (!empty($ftpHostPassword) && is_string($ftpHostPassword) && strlen(trim($ftpHostPassword)) > 0)
2277 update_option('bmi_pro_ftp_password', $ftpHostPassword);
2278 }
2279
2280 if (isset($this->post['ftpport'])) {
2281 $ftpHostPort = $this->post['ftpport'];
2282 update_option('bmi_pro_ftp_port', $ftpHostPort);
2283 }
2284
2285 if (isset($this->post['ftpdir'])) {
2286 $ftpHostDir = $this->post['ftpdir'];
2287 update_option('bmi_pro_ftp_backup_dir', $ftpHostDir);
2288 }
2289 } else {
2290 delete_option('bmi_pro_ftp_host');
2291 delete_option('bmi_pro_ftp_username');
2292 delete_option('bmi_pro_ftp_password');
2293 }
2294
2295 } else {
2296 delete_option('bmi_pro_ftp_host');
2297 delete_option('bmi_pro_ftp_username');
2298 delete_option('bmi_pro_ftp_password');
2299 }
2300
2301 if (isset($this->post['aws'])) {
2302 $s3enabled = $this->post['aws'];
2303 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::AWS', $s3enabled)) {
2304 $errors++;
2305 }
2306 }
2307
2308 if (isset($this->post['wasabi'])) {
2309 $wasabienabled = $this->post['wasabi'];
2310 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::WASABI', $wasabienabled)) {
2311 $errors++;
2312 }
2313 }
2314
2315 if (isset($this->post['dropbox'])) {
2316 $dropboxenabled = $this->post['dropbox'];
2317 if (!Dashboard\bmi_set_config('STORAGE::EXTERNAL::DROPBOX', $dropboxenabled)) {
2318 $errors++;
2319 }
2320
2321
2322 }
2323
2324 }
2325
2326 if (is_writable($dir_path)) {
2327 if (!Dashboard\bmi_set_config('STORAGE::DIRECT::URL', $accessible)) {
2328 Logger::error('Backup Storage Direct Url Error');
2329 $error++;
2330 }
2331 if (!Dashboard\bmi_set_config('STORAGE::LOCAL::PATH', esc_attr($dir_path))) {
2332 Logger::error('Backup Storage Local Path Error');
2333 $error++;
2334 } else {
2335 $cur_dir = BMP::fixSlashes($curr_path);
2336 $new_dir = BMP::fixSlashes($dir_path);
2337
2338 $backups_cur_dir = BMP::fixSlashes($curr_path) . DIRECTORY_SEPARATOR . 'backups';
2339 $backups_new_dir = BMP::fixSlashes($dir_path) . DIRECTORY_SEPARATOR . 'backups';
2340
2341 $staging_cur_dir = BMP::fixSlashes($curr_path) . DIRECTORY_SEPARATOR . 'staging';
2342 $staging_new_dir = BMP::fixSlashes($dir_path) . DIRECTORY_SEPARATOR . 'staging';
2343
2344 $tmp_cur_dir = BMP::fixSlashes($curr_path) . DIRECTORY_SEPARATOR . 'tmp';
2345 $tmp_new_dir = BMP::fixSlashes($dir_path) . DIRECTORY_SEPARATOR . 'tmp';
2346
2347 update_option('BMI::STORAGE::LOCAL::PATH', $new_dir);
2348
2349 if ($cur_dir != $new_dir) {
2350
2351 if (!file_exists($new_dir)) @mkdir($new_dir, 0755, true);
2352 if (!file_exists($backups_new_dir)) @mkdir($backups_new_dir, 0755, true);
2353 if (!file_exists($staging_new_dir)) @mkdir($staging_new_dir, 0755, true);
2354 if (!file_exists($tmp_new_dir)) @mkdir($tmp_new_dir, 0755, true);
2355
2356 $scanned_directory_staging = array_diff(scandir($staging_cur_dir), ['..', '.']);
2357 foreach ($scanned_directory_staging as $i => $file) {
2358 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($staging_cur_dir . DIRECTORY_SEPARATOR . $file)) {
2359 rename($staging_cur_dir . DIRECTORY_SEPARATOR . $file, $staging_new_dir . DIRECTORY_SEPARATOR . $file);
2360 }
2361 }
2362
2363 $scanned_directory_tmp = array_diff(scandir($tmp_cur_dir), ['..', '.']);
2364 foreach ($scanned_directory_tmp as $i => $file) {
2365 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($tmp_cur_dir . DIRECTORY_SEPARATOR . $file)) {
2366 rename($tmp_cur_dir . DIRECTORY_SEPARATOR . $file, $tmp_new_dir . DIRECTORY_SEPARATOR . $file);
2367 }
2368 }
2369
2370 $scanned_directory_backups = array_diff(scandir($backups_cur_dir), ['..', '.']);
2371 foreach ($scanned_directory_backups as $i => $file) {
2372 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($backups_cur_dir . DIRECTORY_SEPARATOR . $file)) {
2373 rename($backups_cur_dir . DIRECTORY_SEPARATOR . $file, $backups_new_dir . DIRECTORY_SEPARATOR . $file);
2374 }
2375 }
2376
2377 $scanned_directory = array_diff(scandir($cur_dir), ['..', '.']);
2378 foreach ($scanned_directory as $i => $file) {
2379 if (file_exists($cur_dir . DIRECTORY_SEPARATOR . $file) && !is_dir($cur_dir . DIRECTORY_SEPARATOR . $file)) {
2380 rename($cur_dir . DIRECTORY_SEPARATOR . $file, $new_dir . DIRECTORY_SEPARATOR . $file);
2381 }
2382 }
2383
2384 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . '.htaccess')) @unlink($backups_cur_dir . DIRECTORY_SEPARATOR . '.htaccess');
2385 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.php')) @unlink($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.php');
2386 if (file_exists($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.html')) @unlink($backups_cur_dir . DIRECTORY_SEPARATOR . 'index.html');
2387 if (file_exists($backups_cur_dir)) @rmdir($backups_cur_dir);
2388
2389 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . '.htaccess')) @unlink($staging_cur_dir . DIRECTORY_SEPARATOR . '.htaccess');
2390 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.php')) @unlink($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.php');
2391 if (file_exists($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.html')) @unlink($staging_cur_dir . DIRECTORY_SEPARATOR . 'index.html');
2392 if (file_exists($staging_cur_dir)) @rmdir($staging_cur_dir);
2393
2394 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . '.htaccess')) @unlink($tmp_cur_dir . DIRECTORY_SEPARATOR . '.htaccess');
2395 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.php')) @unlink($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.php');
2396 if (file_exists($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.html')) @unlink($tmp_cur_dir . DIRECTORY_SEPARATOR . 'index.html');
2397 if (file_exists($tmp_cur_dir)) @rmdir($tmp_cur_dir);
2398
2399 if (file_exists($cur_dir . DIRECTORY_SEPARATOR . 'complete_logs.log')) @unlink($cur_dir . DIRECTORY_SEPARATOR . 'complete_logs.log');
2400 if (file_exists($cur_dir)) @rmdir($cur_dir);
2401
2402 if (is_dir($cur_dir) && file_exists($cur_dir)) {
2403 $left_files = array_diff(scandir($cur_dir), ['..', '.']);
2404 if (sizeof($left_files) == 0) {
2405 if (file_exists($cur_dir)) {
2406 @rmdir($cur_dir);
2407 }
2408 }
2409 }
2410
2411 }
2412 }
2413 } else {
2414 if ($created === true) {
2415 if (file_exists($dir_path)) @unlink($dir_path);
2416 }
2417
2418 return ['status' => 'msg', 'why' => __('Entered path is not writable, cannot be used.', 'backup-backup'), 'level' => 'warning'];
2419 }
2420
2421 return ['status' => 'success', 'errors' => $error];
2422 }
2423
2424 public function saveOtherOptions() {
2425
2426 // Errors
2427 $invalid_email = __('Provided email addess is not valid.', 'backup-backup');
2428 $title_long = __('Your email title is too long, please change the title (max 64 chars).', 'backup-backup');
2429 $title_short = __('Your email title is too short, please use longer one (at least 3 chars).', 'backup-backup');
2430 $title_empty = __('Title field is required, please fill it.', 'backup-backup');
2431 $email_empty = __('Email field cannot be empty, please fill it.', 'backup-backup');
2432 $cli_no_exist = __('Path to executable that you provided for PHP CLI does not exist.', 'backup-backup');
2433 $db_query_too_low = __('The value for query amount cannot be smaller than 15.', 'backup-backup');
2434 $db_query_too_much = __('The value for query amount cannot be larger than 15000.', 'backup-backup');
2435 $db_sr_max_too_low = __('The value for search replace max page cannot be smaller than 10.', 'backup-backup');
2436 $db_sr_max_too_much = __('The value for search replace max page cannot be larger than 30000.', 'backup-backup');
2437 $fl_ex_max_too_low = __('The value for extraction limit cannot be smaller than 50.', 'backup-backup');
2438 $fl_ex_max_too_much = __('The value for extraction limit cannot be larger than 20000.', 'backup-backup');
2439
2440 $email = sanitize_email(trim($this->post['email'])); // OTHER:EMAIL
2441 $email_title = sanitize_text_field(trim($this->post['email_title'])); // OTHER:EMAIL:TITLE
2442 $schedule_issues = $this->post['schedule_issues'] === 'true' ? true : false; // OTHER:EMAIL:NOTIS
2443 $experiment_timeout = $this->post['experiment_timeout'] === 'true' ? true : false; // OTHER:EXPERIMENT:TIMEOUT
2444 $experiment_timeout_hard = $this->post['experimental_hard_timeout'] === 'true' ? true : false; // OTHER:EXPERIMENT:TIMEOUT:HARD
2445 $php_cli_manual_path = isset($this->post['php_cli_manual_path']) ? trim($this->post['php_cli_manual_path']) : ''; // OTHER:CLI:PATH
2446 $php_cli_disable_others = $this->post['php_cli_disable_others'] === 'true' ? true : false; // OTHER:CLI:DISABLE
2447 $normal_timeout = $this->post['normal_timeout'] === 'true' ? true : false; // OTHER:USE:TIMEOUT:NORMAL
2448 $insecure_download = $this->post['download_technique'] === 'true' ? true : false; // OTHER:DOWNLOAD:DIRECT
2449 $db_query_size = isset($this->post['db_queries_amount']) ? trim($this->post['db_queries_amount']) : '2000'; // OTHER:DB:QUERIES
2450 $db_search_replace_max = isset($this->post['db_search_replace_max']) ? trim($this->post['db_search_replace_max']) : '300'; // OTHER:DB:SEARCHREPLACE:MAX
2451 $file_limit_extraction_max = isset($this->post['file_limit_extraction_max']) ? trim($this->post['file_limit_extraction_max']) : 'auto'; // OTHER:FILE:EXTRACT:MAX
2452 $db_restore_splitting = $this->post['bmi-restore-splitting'] === 'true' ? true : false; // OTHER:RESTORE:SPLITTING
2453 $db_restore_v3_engine = $this->post['bmi-db-v3-restore-engine'] === 'true' ? true : false; // OTHER:RESTORE:DB:V3
2454
2455 $no_assets_b4_restore = $this->post['remove-assets-before-restore'] === 'true' ? true : false; // OTHER:RESTORE:BEFORE:CLEANUP
2456 $single_file_db_force = $this->post['bmi-db-single-file-backup'] === 'true' ? true : false; // OTHER:BACKUP:DB:SINGLE:FILE
2457 $db_batching_backup = $this->post['bmi-db-batching-backup'] === 'true' ? true : false; // OTHER:BACKUP:DB:BATCHING
2458
2459 $bmi_disable_space_check = $this->post['bmi-disable-space-check-function'] === 'true' ? true : false; // OTHER:BACKUP:SPACE:CHECKING
2460
2461 $uninstall_config = $this->post['uninstall_config'] === 'true' ? true : false; // OTHER:UNINSTALL:CONFIGS
2462 $uninstall_backups = $this->post['uninstall_backups'] === 'true' ? true : false; // OTHER:UNINSTALL:BACKUPS
2463
2464 if ($experiment_timeout_hard === true) {
2465 $experiment_timeout = false;
2466 }
2467
2468 if ($normal_timeout === true) {
2469 $experiment_timeout = false;
2470 $experiment_timeout_hard = false;
2471 }
2472
2473 if (!is_numeric($db_query_size) || empty($db_query_size)) {
2474 $db_query_size = "2000";
2475 }
2476
2477 if (!is_numeric($file_limit_extraction_max) || empty($file_limit_extraction_max)) {
2478 $file_limit_extraction_max = "auto";
2479 }
2480
2481 if (!is_numeric($db_search_replace_max) || empty($db_search_replace_max)) {
2482 $db_search_replace_max = "300";
2483 }
2484
2485 if (strlen($email) <= 0) {
2486 return ['status' => 'msg', 'why' => $email_empty, 'level' => 'warning'];
2487 }
2488 if (strlen($email_title) <= 0) {
2489 return ['status' => 'msg', 'why' => $title_empty, 'level' => 'warning'];
2490 }
2491 if (strlen($email_title) > 64) {
2492 return ['status' => 'msg', 'why' => $title_long, 'level' => 'warning'];
2493 }
2494 if (strlen($email_title) < 3) {
2495 return ['status' => 'msg', 'why' => $title_short, 'level' => 'warning'];
2496 }
2497 if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
2498 return ['status' => 'msg', 'why' => $invalid_email, 'level' => 'warning'];
2499 }
2500 if ($php_cli_manual_path != '' && !file_exists($php_cli_manual_path)) {
2501 return ['status' => 'msg', 'why' => $cli_no_exist, 'level' => 'warning'];
2502 }
2503 if (intval($db_query_size) > 15000) {
2504 return ['status' => 'msg', 'why' => $db_query_too_much, 'level' => 'warning'];
2505 }
2506 if (intval($db_query_size) < 15) {
2507 return ['status' => 'msg', 'why' => $db_query_too_low, 'level' => 'warning'];
2508 }
2509 if (intval($db_search_replace_max) > 30000) {
2510 return ['status' => 'msg', 'why' => $db_sr_max_too_much, 'level' => 'warning'];
2511 }
2512 if (intval($db_search_replace_max) < 10) {
2513 return ['status' => 'msg', 'why' => $db_sr_max_too_low, 'level' => 'warning'];
2514 }
2515 if ($file_limit_extraction_max != 'auto' && intval($file_limit_extraction_max) > 20000) {
2516 return ['status' => 'msg', 'why' => $fl_ex_max_too_much, 'level' => 'warning'];
2517 }
2518 if ($file_limit_extraction_max != 'auto' && intval($file_limit_extraction_max) < 50) {
2519 return ['status' => 'msg', 'why' => $fl_ex_max_too_low, 'level' => 'warning'];
2520 }
2521
2522 $error = 0;
2523 if (!Dashboard\bmi_set_config('OTHER:EMAIL', $email)) {
2524 Logger::error('Backup Other Email Error');
2525 $error++;
2526 }
2527 if (!Dashboard\bmi_set_config('OTHER:EMAIL:TITLE', $email_title)) {
2528 Logger::error('Backup Other Email Title Error');
2529 $error++;
2530 }
2531 if (!Dashboard\bmi_set_config('OTHER:EMAIL:NOTIS', $schedule_issues)) {
2532 Logger::error('Backup Other Email Notis Error');
2533 $error++;
2534 }
2535 if (!Dashboard\bmi_set_config('OTHER:CLI:PATH', $php_cli_manual_path)) {
2536 Logger::error('Backup Other CLI Path Error');
2537 $error++;
2538 }
2539 if (!Dashboard\bmi_set_config('OTHER:CLI:DISABLE', $php_cli_disable_others)) {
2540 Logger::error('Backup Other CLI Disable Error');
2541 $error++;
2542 }
2543 if (!Dashboard\bmi_set_config('OTHER:EXPERIMENT:TIMEOUT', $experiment_timeout)) {
2544 Logger::error('Backup Other Experiment Timeout Error');
2545 $error++;
2546 }
2547 if (!Dashboard\bmi_set_config('OTHER:EXPERIMENT:TIMEOUT:HARD', $experiment_timeout_hard)) {
2548 Logger::error('Backup Other Experiment Timeout Hard Error');
2549 $error++;
2550 }
2551 if (!Dashboard\bmi_set_config('OTHER:USE:TIMEOUT:NORMAL', $normal_timeout)) {
2552 Logger::error('Backup Other Experiment Timeout Normal Error');
2553 $error++;
2554 }
2555 if (!Dashboard\bmi_set_config('OTHER:RESTORE:DB:V3', $db_restore_v3_engine)) {
2556 Logger::error('Backup Other Restore DB V3 Error');
2557 $error++;
2558 }
2559 if (!Dashboard\bmi_set_config('OTHER:DB:QUERIES', $db_query_size)) {
2560 Logger::error('Backup Other DB Queries Error');
2561 $error++;
2562 }
2563 if (!Dashboard\bmi_set_config('OTHER:DB:SEARCHREPLACE:MAX', $db_search_replace_max)) {
2564 Logger::error('Backup Other DB Queries Error');
2565 $error++;
2566 }
2567 if (!Dashboard\bmi_set_config('OTHER:FILE:EXTRACT:MAX', $file_limit_extraction_max)) {
2568 Logger::error('Backup Other File Extract Max Error');
2569 $error++;
2570 }
2571 if (!Dashboard\bmi_set_config('OTHER:DOWNLOAD:DIRECT', $insecure_download)) {
2572 Logger::error('Backup Other Download Direct Error');
2573 $error++;
2574 }
2575 if (!Dashboard\bmi_set_config('OTHER:UNINSTALL:CONFIGS', $uninstall_config)) {
2576 Logger::error('Backup Other Uninstall Configs Error');
2577 $error++;
2578 }
2579 if (!Dashboard\bmi_set_config('OTHER:UNINSTALL:BACKUPS', $uninstall_backups)) {
2580 Logger::error('Backup Other Uninstall Backups Error');
2581 $error++;
2582 }
2583 if (!Dashboard\bmi_set_config('OTHER:RESTORE:SPLITTING', $db_restore_splitting)) {
2584 Logger::error('Backup Other Restore Splitting Error');
2585 $error++;
2586 }
2587 if (!Dashboard\bmi_set_config('OTHER:BACKUP:DB:SINGLE:FILE', $single_file_db_force)) {
2588 Logger::error('Backup Other Backup DB Single File Error');
2589 $error++;
2590 }
2591 if (!Dashboard\bmi_set_config('OTHER:BACKUP:DB:BATCHING', $db_batching_backup)) {
2592 Logger::error('Backup Other Backup DB Batching Error');
2593 $error++;
2594 }
2595 if (!Dashboard\bmi_set_config('OTHER:BACKUP:SPACE:CHECKING', $bmi_disable_space_check)) {
2596 Logger::error('Backup Other Backup Space Checking Error');
2597 $error++;
2598 }
2599 if (!Dashboard\bmi_set_config('OTHER:RESTORE:BEFORE:CLEANUP', $no_assets_b4_restore)) {
2600 Logger::error('Backup Other Restore Before Cleanup Error');
2601 $error++;
2602 }
2603
2604 if (has_action('bmi_premium_other_options')) {
2605 do_action('bmi_premium_other_options', $this->post);
2606 }
2607
2608 return ['status' => 'success', 'errors' => $error];
2609 }
2610
2611 public function saveStorageTypeConfig() {
2612
2613 // Errors
2614 $name_empty = __('Name is required, please fill the input.', 'backup-backup');
2615 $name_long = __('Your name is too long, please change the name.', 'backup-backup');
2616 $name_short = __('Your name is too short, please create longer one.', 'backup-backup');
2617 $name_space = __('Please, do not use spaces in file name.', 'backup-backup');
2618 $name_forbidden = __('Your name contains character(s) that are not allowed in file names: ', 'backup-backup');
2619
2620 $forbidden_chars = ['/', '\\', '<', '>', ':', '"', "'", '|', '?', '*', '.', ';', '@', '!', '~', '`', ',', '#', '$', '&', '=', '+'];
2621 $name = trim($this->post['name']); // BACKUP:NAME
2622 $extensionType = trim($this->post['extension']); // BACKUP:EXTENSION:TYPE
2623
2624 if (strlen($name) == 0) {
2625 return ['status' => 'msg', 'why' => $name_empty, 'level' => 'warning'];
2626 }
2627 if (strlen($name) > 40) {
2628 return ['status' => 'msg', 'why' => $name_long, 'level' => 'warning'];
2629 }
2630 if (strlen($name) < 3) {
2631 return ['status' => 'msg', 'why' => $name_short, 'level' => 'warning'];
2632 }
2633 if (strpos($name, ' ') !== false) {
2634 return ['status' => 'msg', 'why' => $name_space, 'level' => 'warning'];
2635 }
2636
2637 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO == 1) {
2638 if (!in_array($extensionType, ['.zip', '.tar.gz', '.tar'])) {
2639 return ['status' => 'msg', 'why' => $name_space, 'level' => 'warning'];
2640 }
2641 }
2642
2643 for ($i = 0; $i < sizeof($forbidden_chars); ++$i) {
2644 $char = $forbidden_chars[$i];
2645 if (strpos($name, $char) !== false) {
2646 return ['status' => 'msg', 'why' => $name_forbidden . $char, 'level' => 'warning'];
2647 }
2648 }
2649
2650 $error = 0;
2651 if (!Dashboard\bmi_set_config('BACKUP:NAME', $name)) {
2652 Logger::error('Backup Name Error');
2653 $error++;
2654 }
2655
2656 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO == 1) {
2657 if (!Dashboard\bmi_set_config('BACKUP:EXTENSION:TYPE', $extensionType)) {
2658 Logger::error('Backup Extension Type Error');
2659 $error++;
2660 }
2661 }
2662
2663 return ['status' => 'success', 'errors' => $error];
2664 }
2665
2666 public function saveFilesConfig() {
2667 $db_group = $this->post['database_group']; // BACKUP:DATABASE
2668 $files_group = $this->post['files_group']; // BACKUP:FILES
2669
2670 $fgp = $this->post['files-group-plugins']; // BACKUP:FILES::PLUGINS
2671 $fgu = $this->post['files-group-uploads']; // BACKUP:FILES::UPLOADS
2672 $fgt = $this->post['files-group-themes']; // BACKUP:FILES::THEMES
2673 $fgoc = $this->post['files-group-other-contents']; // BACKUP:FILES::OTHERS
2674 $fgwp = $this->post['files-group-wp-install']; // BACKUP:FILES::WP
2675
2676 $file_filters = $this->post['files_by_filters']; // BACKUP:FILES::FILTER
2677 $ffs = $this->post['ex_b_fs']; // BACKUP:FILES::FILTER:SIZE
2678 $ffsizemax = $this->post['BFFSIN']; // BACKUP:FILES::FILTER:SIZE:IN
2679 $ffn = $this->post['ex_b_names']; // BACKUP:FILES::FILTER:NAMES
2680 $ffp = $this->post['ex_b_fpaths']; // BACKUP:FILES::FILTER:FPATHS
2681 $ffd = $this->post['ex_b_dpaths']; // BACKUP:FILES::FILTER:DPATHS
2682
2683 $dbeg = $this->post['db-exclude-tables-group']; // BACKUP:DATABASE:EXCLUDE
2684 $dbet = $this->post['db-excluded-tables']; // BACKUP:DATABASE:EXCLUDE:LIST
2685
2686 $existant = [];
2687 $parsed = [];
2688 $ffnames = $this->post['dynamic-names']; // BACKUP:FILES::FILTER:NAMES:IN
2689 $ffpnames = array_unique($this->post['dynamic-fpaths-names']); // BACKUP:FILES::FILTER:FPATHS:IN
2690 $ffdnames = array_unique($this->post['dynamic-dpaths-names']); // BACKUP:FILES::FILTER:DPATHS:IN
2691
2692 if (is_array($dbet) || is_object($dbet)) {
2693 if (sizeof($dbet) == 1 && $dbet[0] == 'empty') {
2694 $dbet = [];
2695 }
2696 }
2697
2698 if ($dbeg === 'true' || $dbeg === true) $dbeg = true;
2699 else $dbeg = false;
2700
2701 $max = sizeof($ffpnames);
2702 for ($i = 0; $i < $max; ++$i) {
2703 if (!is_string($ffpnames[$i]) || trim(strlen($ffpnames[$i])) <= 1) {
2704 array_splice($ffpnames, $i, 1);
2705 $i--;
2706 $max--;
2707 }
2708 }
2709
2710 $max = sizeof($ffdnames);
2711 for ($i = 0; $i < $max; ++$i) {
2712 if (!is_string($ffdnames[$i]) || trim(strlen($ffdnames[$i])) <= 1) {
2713 array_splice($ffdnames, $i, 1);
2714 $i--;
2715 $max--;
2716 }
2717 }
2718
2719 for ($i = 0; $i < sizeof($ffnames); ++$i) {
2720 $row = $ffnames[$i];
2721 $txt = array_key_exists('txt', $row) ? "" . $row['txt'] . "" : false;
2722 $pos = array_key_exists('pos', $row) ? $row['pos'] : false;
2723 $whr = array_key_exists('whr', $row) ? $row['whr'] : false;
2724
2725 if ($txt === false || $pos === false || $whr === false) {
2726 continue;
2727 }
2728 if (trim(strlen($txt)) <= 0) {
2729 continue;
2730 }
2731 if (!in_array($pos, ["1", "2", "3"])) {
2732 continue;
2733 }
2734 if (!in_array($whr, ["1", "2"])) {
2735 continue;
2736 }
2737 if (in_array($txt . $pos . $whr, $existant)) {
2738 continue;
2739 } else {
2740 $existant[] = $txt . $pos . $whr;
2741 }
2742
2743 $parsed[] = ['txt' => $txt, 'pos' => $pos, 'whr' => $whr];
2744 }
2745
2746 if ($ffs == 'true' && !is_numeric($ffsizemax)) {
2747 return ['status' => 'msg', 'why' => __('Entred file size limit, is not correct number.', 'backup-backup'), 'level' => 'warning'];
2748 }
2749
2750 $error = 0;
2751 if (!Dashboard\bmi_set_config('BACKUP:DATABASE', $db_group)) {
2752 Logger::error('Backup Database Error');
2753 $error++;
2754 }
2755 if (!Dashboard\bmi_set_config('BACKUP:FILES', $files_group)) {
2756 Logger::error('Backup Files Error');
2757 $error++;
2758 }
2759
2760 if (!Dashboard\bmi_set_config('BACKUP:FILES::PLUGINS', $fgp)) {
2761 Logger::error('Backup Files Plugins Error');
2762 $error++;
2763 }
2764 if (!Dashboard\bmi_set_config('BACKUP:FILES::UPLOADS', $fgu)) {
2765 Logger::error('Backup Files Uploads Error');
2766 $error++;
2767 }
2768 if (!Dashboard\bmi_set_config('BACKUP:FILES::THEMES', $fgt)) {
2769 Logger::error('Backup Files Themes Error');
2770 $error++;
2771 }
2772 if (!Dashboard\bmi_set_config('BACKUP:FILES::OTHERS', $fgoc)) {
2773 Logger::error('Backup Files Others Error');
2774 $error++;
2775 }
2776 if (!Dashboard\bmi_set_config('BACKUP:FILES::WP', $fgwp)) {
2777 Logger::error('Backup Files WP Error');
2778 $error++;
2779 }
2780
2781 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER', $file_filters)) {
2782 Logger::error('Backup Files Filter Error');
2783 $error++;
2784 }
2785 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:SIZE', $ffs)) {
2786 Logger::error('Backup Files Filter Size Error');
2787 $error++;
2788 }
2789 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:NAMES', $ffn)) {
2790 Logger::error('Backup Files Names Error');
2791 $error++;
2792 }
2793 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:FPATHS', $ffp)) {
2794 Logger::error('Backup Files Fpaths Error');
2795 $error++;
2796 }
2797 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:DPATHS', $ffd)) {
2798 Logger::error('Backup Files Dpaths Error');
2799 $error++;
2800 }
2801
2802 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:SIZE:IN', $ffsizemax)) {
2803 Logger::error('Backup Files Filter Size In Error');
2804 $error++;
2805 }
2806 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:NAMES:IN', $parsed)) {
2807 Logger::error('Backup Files Filter Names In Error');
2808 $error++;
2809 }
2810 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:FPATHS:IN', $ffpnames)) {
2811 Logger::error('Backup Files Filter Fpaths In Error');
2812 $error++;
2813 }
2814 if (!Dashboard\bmi_set_config('BACKUP:FILES::FILTER:DPATHS:IN', $ffdnames)) {
2815 Logger::error('Backup Files Filter Dpaths In Error');
2816 $error++;
2817 }
2818
2819 if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO == 1) {
2820 if (!Dashboard\bmi_set_config('BACKUP:DATABASE:EXCLUDE', $dbeg)) {
2821 Logger::error('Backup Files Filter Database Exclude Error');
2822 $error++;
2823 }
2824 if (!Dashboard\bmi_set_config('BACKUP:DATABASE:EXCLUDE:LIST', $dbet)) {
2825 Logger::error('Backup Files Filter Database Exclude List Error');
2826 $error++;
2827 }
2828 }
2829
2830 if (has_action('bmip_smart_exclusion_options')){
2831 do_action('bmip_smart_exclusion_options', $this->post);
2832 }
2833
2834 // return array('status' => 'msg', 'why' => __('Entred path is not writable or does not exist.', 'backup-backup'), 'level' => 'warning');
2835
2836 return ['status' => 'success', 'errors' => $error];
2837 }
2838
2839 public function scanFilesForBackup(&$progress, $stgSites = [], $fileCalcType = false) {
2840 require_once BMI_INCLUDES . '/scanner/files.php';
2841
2842 $stagingSites = [];
2843
2844 // Get all directory names of staging sites
2845 foreach ($stgSites as $index => $site) {
2846
2847 // Convert every directory to their location path
2848 $stagingSites[] = '***ABSPATH***/' . $site['name'];
2849
2850 }
2851
2852 // Use filters?
2853 $is = Dashboard\bmi_get_config('BACKUP:FILES::FILTER') === 'true' ? true : false;
2854
2855 // Get settings form config
2856 $fgp = Dashboard\bmi_get_config('BACKUP:FILES::PLUGINS');
2857 $fgt = Dashboard\bmi_get_config('BACKUP:FILES::THEMES');
2858 $fgu = Dashboard\bmi_get_config('BACKUP:FILES::UPLOADS');
2859 $fgoc = Dashboard\bmi_get_config('BACKUP:FILES::OTHERS');
2860 $fgwp = Dashboard\bmi_get_config('BACKUP:FILES::WP');
2861 $dpathsis = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:DPATHS') === 'true' ? true : false;
2862 $dpaths = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:DPATHS:IN');
2863 $dynamesis = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES') === 'true' ? true : false;
2864 $dynames = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES:IN');
2865 $dynparsed = [];
2866
2867 $isSmartExclusion =defined("BMI_BACKUP_PRO") && BMI_BACKUP_PRO && Dashboard\bmi_get_config('SMART:EXCLUSION:ENABLED') == 'true' ? true : false;
2868 $isCacheExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:CACHE') == 'true' ? true : false);
2869 $isDeactivePluginsExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:DPLUGINS') == 'true' ? true : false);
2870 $isNotUsedThemesExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:NUTHEMES') == 'true' ? true : false);
2871 $isDebugLogsExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:DLOGS') == 'true' ? true : false);
2872 $isPostRevisionsExcluded = $isSmartExclusion &&(Dashboard\bmi_get_config('SMART:EXCLUSION:PREVISIONS') == 'true' ? true : false);
2873
2874
2875 if ($fileCalcType != false) {
2876 $fgp = ($fileCalcType == 'plugins') ? true : false;
2877 $fgt = ($fileCalcType == 'themes') ? true : false;
2878 $fgu = ($fileCalcType == 'uploads') ? true : false;
2879 $fgoc = ($fileCalcType == 'contents_others') ? true : false;
2880 $fgwp = ($fileCalcType == 'wordpress') ? true : false;
2881 }
2882
2883 // Filter dynames to for smaller size
2884 if ($is && $dynamesis) {
2885 for ($i = 0; $i < sizeof($dynames); ++$i) {
2886 $s = $dynames[$i];
2887 if ($s->whr == '2') {
2888 $dynparsed[] = ['s' => $s->txt, 'w' => $s->pos, 'z' => strlen($s->txt)];
2889 }
2890 }
2891 }
2892
2893 // Set exclusion rules
2894 $ignored_folders_default = [];
2895 if ($is && $dynamesis) {
2896 BMP::merge_arrays($ignored_folders_default, $dynparsed);
2897 }
2898 $ignored_folders = $ignored_folders_default;
2899 $ignored_paths_default = [BMI_CONFIG_DIR, BMI_BACKUPS, BMI_ROOT_DIR];
2900 $ignored_paths_default[] = "***ABSPATH***/wp-content/ai1wm-backups";
2901 $ignored_paths_default[] = "***ABSPATH***/wp-content/ai1wm-backups-old";
2902 $ignored_paths_default[] = "***ABSPATH***/wp-content/mwp-download";
2903 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-clone";
2904 $ignored_paths_default[] = "***ABSPATH***/wp-content/updraft";
2905 $ignored_paths_default[] = "***ABSPATH***/wp-content/ebwp-backups";
2906 $ignored_paths_default[] = "***ABSPATH***/wp-content/cache/seraphinite-accelerator";
2907 $ignored_paths_default[] = "***ABSPATH***/wp-content/backups-dup-pro";
2908 $ignored_paths_default[] = "***ABSPATH***/wp-content/wpvividbackups";
2909 $ignored_paths_default[] = "***ABSPATH***/wp-content/backup-guard";
2910 $ignored_paths_default[] = "***ABSPATH***/wp-content/backuply";
2911 $ignored_paths_default[] = "***ABSPATH***/wp-content/backups-dup-lite";
2912 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/backupbuddy_backups";
2913 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-file-manager-pro";
2914 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-file-manager";
2915 $ignored_paths_default[] = "***ABSPATH***/wp-content/plugins/akeebabackupwp";
2916 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/jetbackup";
2917 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/backup-guard";
2918 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-migrate-db";
2919
2920 $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/wp-staging";
2921
2922 if ($isSmartExclusion && ($fileCalcType == false || $fileCalcType == 'database')) {
2923 if ($isCacheExcluded) {
2924 $ignored_paths_default = apply_filters('bmip_smart_exclusion_cache', $ignored_paths_default);
2925 }
2926 if ($isDeactivePluginsExcluded) {
2927 $ignored_paths_default = apply_filters('bmip_smart_exclusion_deactive_plugins', $ignored_paths_default);
2928 }
2929 if ($isNotUsedThemesExcluded) {
2930 $ignored_paths_default = apply_filters('bmip_smart_exclusion_not_used_themes', $ignored_paths_default);
2931 }
2932 }
2933
2934 // Exclude cache directory permanently as it's just cache
2935 // $ignored_paths_default[] = "***ABSPATH***/wp-content/cache";
2936 // $ignored_paths_default[] = "***ABSPATH***/wp-content/cache_bak";
2937 // $ignored_paths_default[] = "***ABSPATH***/wp-content/uploads/cache";
2938
2939 // Add staging sites to permanent exclusion rules
2940 for ($i = 0; $i < sizeof($stagingSites); ++$i) {
2941 $ignored_paths_default[] = $stagingSites[$i];
2942 }
2943
2944 if (defined('BMI_PRO_ROOT_DIR')) $ignored_paths_default[] = BMI_PRO_ROOT_DIR;
2945 if ($is && $dpathsis) {
2946 BMP::merge_arrays($ignored_paths_default, $dpaths);
2947 }
2948 $ignored_paths = $ignored_paths_default;
2949
2950 // Fix slashes for current system (directories)
2951 for ($i = 0; $i < sizeof($ignored_paths); ++$i) {
2952 $ignored_paths[$i] = str_replace('***ABSPATH***', untrailingslashit(ABSPATH), $ignored_paths[$i]);
2953 $ignored_paths[$i] = BMP::fixSlashes($ignored_paths[$i]);
2954 }
2955
2956 // WordPress Paths
2957 $plugins_path = BMP::fixSlashes(WP_PLUGIN_DIR);
2958 $themes_path = BMP::fixSlashes(dirname(get_template_directory()));
2959 $uploads_path = BMP::fixSlashes(wp_upload_dir()['basedir']);
2960 $wp_contents = BMP::fixSlashes(WP_CONTENT_DIR);
2961 $wp_install = BMP::fixSlashes(ABSPATH);
2962
2963 // Getting plugins
2964 $sfgp = Scanner::equalFolderByPath($wp_install, $plugins_path, $ignored_folders);
2965 if ($fgp == 'true' && !$sfgp) {
2966 $plugins_path_files = Scanner::scanFilesGetNamesWithIgnoreFBC($plugins_path, $ignored_folders, $ignored_paths);
2967 }
2968
2969 // Getting themes
2970 $sfgt = Scanner::equalFolderByPath($wp_install, $themes_path, $ignored_folders);
2971 if ($fgt == 'true' && !$sfgt) {
2972 $themes_path_files = Scanner::scanFilesGetNamesWithIgnoreFBC($themes_path, $ignored_folders, $ignored_paths);
2973 }
2974
2975 // Getting uploads
2976 $sfgu = Scanner::equalFolderByPath($wp_install, $uploads_path, $ignored_folders);
2977 if ($fgu == 'true' && !$sfgu) {
2978 $uploads_path_files = Scanner::scanFilesGetNamesWithIgnoreFBC($uploads_path, $ignored_folders, $ignored_paths);
2979 }
2980
2981 // Ignore above paths
2982 $sfgoc = Scanner::equalFolderByPath($wp_install, $wp_contents, $ignored_folders);
2983 if ($fgoc == 'true' && !$sfgoc) {
2984
2985 // Ignore common folders (already scanned)
2986 $content_folders = [$plugins_path, $themes_path, $uploads_path];
2987 BMP::merge_arrays($content_folders, $ignored_paths);
2988
2989 // Getting other contents
2990 $wp_contents_files = Scanner::scanFilesGetNamesWithIgnoreFBC($wp_contents, $ignored_folders, $content_folders);
2991 }
2992
2993 // Ignore contents path
2994 if ($fgwp == 'true') {
2995
2996 // Ignore contents file
2997 $ignored_paths[] = $wp_contents;
2998
2999 // Getting WP Installation
3000 $wp_install_files = Scanner::scanFilesGetNamesWithIgnoreFBC($wp_install, $ignored_folders, $ignored_paths);
3001 }
3002
3003 // Concat all file paths
3004 $all_files = [];
3005 if ($fgp == 'true' && !$sfgp) {
3006 BMP::merge_arrays($all_files, $plugins_path_files);
3007 unset($plugins_path_files);
3008 }
3009
3010 if ($fgt == 'true' && !$sfgt) {
3011 BMP::merge_arrays($all_files, $themes_path_files);
3012 unset($themes_path_files);
3013 }
3014
3015 if ($fgu == 'true' && !$sfgu) {
3016 BMP::merge_arrays($all_files, $uploads_path_files);
3017 unset($uploads_path_files);
3018 }
3019
3020 if ($fgoc == 'true' && !$sfgoc) {
3021 BMP::merge_arrays($all_files, $wp_contents_files);
3022 unset($wp_contents_files);
3023 }
3024
3025 if ($fgwp == 'true') {
3026 BMP::merge_arrays($all_files, $wp_install_files);
3027 unset($wp_install_files);
3028 }
3029
3030 return $all_files;
3031 }
3032
3033 public function parseFilesForBackup(&$files, &$progress, $cron = false, $dirCalc = false) {
3034
3035 $is = Dashboard\bmi_get_config('BACKUP:FILES::FILTER') === 'true' ? true : false;
3036 $acis = (Dashboard\bmi_get_config('BACKUP:FILES::FILTER:FPATHS') === 'true' && $is) ? true : false;
3037 $ac = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:FPATHS:IN');
3038
3039 $abis = (Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES') === 'true' && $is) ? true : false;
3040 $ab = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES:IN');
3041 $abres = [];
3042 $acres = new \stdClass();
3043
3044 $isSmartExclusion = defined("BMI_BACKUP_PRO") && BMI_BACKUP_PRO && Dashboard\bmi_get_config('SMART:EXCLUSION:ENABLED') == 'true' ? true : false;
3045 $isDebugLogsExcluded = $isSmartExclusion && (Dashboard\bmi_get_config('SMART:EXCLUSION:DLOGS') == 'true' ? true : false);
3046
3047 // Local list of permanently blocked files
3048 if ($acis == false) {
3049 $acis = true;
3050 $ac = [
3051 '***ABSPATH***/wp-content/uploads/wpforms/.htaccess.cpmh3129', // Binary broken file of wpforms
3052 '***ABSPATH***/wp-content/uploads/gravity_forms/.htaccess.cpmh3129', // Binary broken file of wpforms
3053 '***ABSPATH***/.htaccess.cpmh3129', // Binary broken file of wpforms
3054 '***ABSPATH***/logs/traffic.html/.md5sums', // Binary broken file of wpforms
3055 '***ABSPATH***/wp-config.php', // Exclude wp-config.php permanently
3056 '***ABSPATH***/wp-content/backup-migration-config.php' // Exclude BMI CONFIG hardly
3057 ];
3058 } else {
3059 $ac[] = '***ABSPATH***/wp-content/uploads/wpforms/.htaccess.cpmh3129'; // Binary broken file of wpforms
3060 $ac[] = '***ABSPATH***/wp-content/uploads/gravity_forms/.htaccess.cpmh3129'; // Binary broken file of wpforms
3061 $ac[] = '***ABSPATH***/.htaccess.cpmh3129'; // Binary broken file of wpforms
3062 $ac[] = '***ABSPATH***/logs/traffic.html/.md5sums'; // Binary broken file of wpforms
3063 $ac[] = '***ABSPATH***/wp-config.php'; // Exclude wp-config.php permanently
3064 $ac[] = '***ABSPATH***/wp-content/backup-migration-config.php'; // Exclude BMI CONFIG hardly
3065 }
3066
3067 if ($isDebugLogsExcluded) {
3068 $ac = apply_filters('bmip_smart_exclusion_debug_logs', $ac);
3069 }
3070
3071 $temp_is = false;
3072 if ($is == false) {
3073 $temp_is = true;
3074 }
3075
3076 if (($is && $acis) || $temp_is) {
3077 foreach ($ac as $key => $value) {
3078 $value = str_replace('***ABSPATH***', untrailingslashit(ABSPATH), $value);
3079 $value = BMP::fixSlashes($value);
3080 $acres->{$value} = 1;
3081 }
3082 }
3083
3084 if ($is && $abis) {
3085 for ($i = 0; $i < sizeof($ab); ++$i) {
3086 $s = $ab[$i];
3087 if ($s->whr == '1') {
3088 $abres[] = ['s' => $s->txt, 'w' => $s->pos, 'z' => strlen($s->txt)];
3089 }
3090 }
3091 }
3092
3093 $limitcrl = 64;
3094 $cliEnabled = false;
3095 if (defined('BMI_CLI_ENABLED')) $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
3096 if ($dirCalc && $cliEnabled && !defined('BMI_CLI_FAILED')) $limitcrl = 128;
3097 $first_big = false;
3098 $sizemax = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:SIZE:IN');
3099 $usesize = (Dashboard\bmi_get_config('BACKUP:FILES::FILTER:SIZE') === 'true' && $is) ? true : false;
3100 if (!is_numeric($sizemax)) {
3101 $usesize = false;
3102 $sizemax = 99999;
3103 } else {
3104 $sizemax = intval($sizemax);
3105 }
3106
3107 // If legacy === false it will use background process to bypass the timeout
3108 if ($dirCalc) {
3109 $legacy = true;
3110 } else {
3111 $legacyVersion = apply_filters('bmi_legacy_version', BMI_LEGACY_VERSION);
3112 $legacyHardVersion = apply_filters('bmi_legacy_hard_version', BMI_LEGACY_HARD_VERSION);
3113 $functionNormal = apply_filters('bmi_function_normal', BMI_FUNCTION_NORMAL);
3114 if (!defined('BMI_LEGACY_VERSION')) $legacy = true;
3115 else $legacy = $legacyVersion;
3116 if ($legacy && defined('BMI_LEGACY_HARD_VERSION') && !$legacyHardVersion) $legacy = $legacyHardVersion;
3117 $cliEnabled = false;
3118 if (defined('BMI_CLI_ENABLED')) $cliEnabled = apply_filters('bmi_cli_enabled', BMI_CLI_ENABLED);
3119 if (defined('BMI_FUNCTION_NORMAL') && $cliEnabled === true && $functionNormal === true && !defined('BMI_CLI_FAILED')) $legacy = false;
3120 }
3121
3122 $total_size = 0;
3123 $excludedBytes = 0;
3124 $max = $sizemax * (1024 * 1024);
3125 $maxfor = sizeof($files);
3126
3127 // Non-legacy variables
3128 if ($legacy === false) {
3129 $Hx = trailingslashit(WP_CONTENT_DIR);
3130 $Hz = trailingslashit(ABSPATH);
3131 $Hxs = strlen($Hx);
3132 $Hzs = strlen($Hz);
3133 }
3134
3135 // Sort it by size
3136 if ($legacy === false) {
3137 usort($files, function ($a, $b) {
3138 $a = explode(',', $a);
3139 $last = sizeof($a) - 1;
3140 $sizea = intval($a[$last]);
3141
3142 $b = explode(',', $b);
3143 $last = sizeof($b) - 1;
3144 $sizeb = intval($b[$last]);
3145
3146 if ($sizea == $sizeb) return 0;
3147 if ($sizea < $sizeb) return -1;
3148 else return 1;
3149 });
3150 }
3151
3152 // Process due to rules
3153 for ($i = 0; $i < $maxfor; ++$i) {
3154
3155 // Remove size from path and get the size
3156 $files[$i] = explode(',', $files[$i]);
3157 $last = sizeof($files[$i]) - 1;
3158 $size = intval($files[$i][$last]);
3159 unset($files[$i][$last]);
3160 $files[$i] = implode(',', $files[$i]);
3161
3162 if ($usesize && Scanner::fileTooLarge($size, $max)) {
3163 if (!$dirCalc) $progress->log(__("Removing file from backup (too large) ", 'backup-backup') . $files[$i] . ' (' . number_format(($size / 1024 / 1024), 2) . ' MB)', 'WARN');
3164 array_splice($files, $i, 1);
3165 $maxfor--;
3166 $i--;
3167
3168 $excludedBytes += $size;
3169 continue;
3170 }
3171
3172 if ($abis && Scanner::equalFolder(basename($files[$i]), $abres)) {
3173 if (!$dirCalc) $progress->log(__("Removing file from backup (due to exclude rules): ", 'backup-backup') . $files[$i], 'WARN');
3174 array_splice($files, $i, 1);
3175 $maxfor--;
3176 $i--;
3177
3178 $excludedBytes += $size;
3179 continue;
3180 }
3181
3182 if ($acis && property_exists($acres, $files[$i])) {
3183 if (!$dirCalc) $progress->log(__("Removing file from backup (due to path rules): ", 'backup-backup') . $files[$i], 'WARN');
3184 array_splice($files, $i, 1);
3185 $maxfor--;
3186 $i--;
3187
3188 $excludedBytes += $size;
3189 continue;
3190 }
3191
3192 // if ($size === 0) {
3193 // array_splice($files, $i, 1);
3194 // $maxfor--;
3195 // $i--;
3196
3197 // $excludedBytes += $size;
3198 // continue;
3199 // }
3200
3201 if (strpos($files[$i], 'bmi-pclzip-') !== false || strpos($files[$i], 'backup-migration') !== false) {
3202 array_splice($files, $i, 1);
3203 $maxfor--;
3204 $i--;
3205
3206 $excludedBytes += $size;
3207 continue;
3208 }
3209
3210 if ($size > ($limitcrl * (1024 * 1024))) {
3211 if ($first_big === false) $first_big = $i;
3212 if (!$dirCalc) $progress->log(__("This file is quite big consider to exclude it, if backup fails: ", 'backup-backup') . $files[$i] . ' (' . BMP::humanSize($size) . ')', 'WARN');
3213 }
3214
3215 $functionNormal = apply_filters('bmi_function_normal', BMI_FUNCTION_NORMAL);
3216 $cliEnabled = apply_filters('bmi_cli_enabled', defined('BMI_CLI_ENABLED') ? BMI_CLI_ENABLED : false);
3217 if (($legacy === false && ($functionNormal === false || ($functionNormal === true && $cliEnabled === true))) && (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false)) {
3218 $fx = strpos($files[$i], $Hx);
3219 $fz = strpos($files[$i], $Hz);
3220
3221 if ($fx !== false) $files[$i] = substr_replace($files[$i], '@1@', $fx, $Hxs);
3222 else if ($fz !== false) $files[$i] = substr_replace($files[$i], '@2@', $fz, $Hzs);
3223
3224 $files[$i] .= ',' . $size;
3225 }
3226 $total_size += $size;
3227 }
3228
3229 if ($legacy === false && (!defined('BMI_USING_CLI_FUNCTIONALITY') || BMI_USING_CLI_FUNCTIONALITY === false)) {
3230 $list_file = BMI_TMP . DIRECTORY_SEPARATOR . 'files_latest.list';
3231 if (file_exists($list_file)) @unlink($list_file);
3232 $files_list = fopen($list_file, 'a');
3233 if ($first_big === false) fwrite($files_list, sizeof($files) . "_-1\r\n");
3234 else fwrite($files_list, sizeof($files) . '_' . $first_big . "\r\n");
3235 for ($i = 0; $i < sizeof($files); ++$i) {
3236 fwrite($files_list, $files[$i] . "\r\n");
3237 }
3238 fclose($files_list);
3239 $this->first_big = $first_big;
3240 }
3241
3242 $this->total_excluded_size_for_backup = $excludedBytes;
3243 $this->total_size_for_backup = $total_size;
3244 $this->total_size_for_backup_in_mb = ($total_size / 1024 / 1024);
3245
3246 return $files;
3247 }
3248
3249 public function toggleBackupLock($unlock = false) {
3250
3251 // Require lib
3252 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'zipper' . DIRECTORY_SEPARATOR . 'zipping.php';
3253
3254 // Backup name
3255 $filename = $this->post['filename'];
3256
3257 // Init Zipper
3258 $zipper = new Zipper();
3259
3260 // Path to Backup
3261 $path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $filename;
3262 $path_dir = BMP::fixSlashes(dirname($path));
3263
3264 // Check if file exists
3265 if (!file_exists($path)) {
3266 return ['status' => 'fail'];
3267 }
3268
3269 // Check if directory is correct
3270 if ($path_dir != BMP::fixSlashes(BMI_BACKUPS)) {
3271 return ['status' => 'fail'];
3272 }
3273
3274 // Toggle the lock
3275 $status = $zipper->lock_zip($path, $unlock);
3276
3277 // Return the status
3278 return ['status' => ($status ? 'success' : 'fail')];
3279 }
3280
3281 public function getDynamicNames() {
3282 $data = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:NAMES:IN');
3283 $fpdata = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:FPATHS:IN');
3284 $fddata = Dashboard\bmi_get_config('BACKUP:FILES::FILTER:DPATHS:IN');
3285
3286 for ($i = 0; $i < sizeof($fpdata); ++$i) {
3287 $fpdata[$i] = BMP::fixSlashes($fpdata[$i]);
3288 }
3289
3290 for ($i = 0; $i < sizeof($fddata); ++$i) {
3291 $fddata[$i] = BMP::fixSlashes($fddata[$i]);
3292 }
3293
3294 return [
3295 'status' => 'success',
3296 'dynamic-fpaths-names' => $fpdata,
3297 'dynamic-dpaths-names' => $fddata,
3298 'data' => $data
3299 ];
3300 }
3301
3302 public function resetConfiguration() {
3303
3304 if (file_exists(BMI_CONFIG_PATH)) {
3305 @unlink(BMI_CONFIG_PATH);
3306 }
3307
3308 delete_option('bmi_hotfixes');
3309 delete_option('bmip_to_be_uploaded');
3310 delete_option('bmi_pro_gd_client_id');
3311 delete_option('bmi_pro_gd_token');
3312 delete_option('bmi_pro_cron_domain_done');
3313 delete_option('BMI::STORAGE::LOCAL::PATH');
3314
3315 // update_option('BMI_LOGS_SHARING_IS_ALLOWED', 'unknown');
3316
3317 return ['status' => 'success'];
3318
3319 }
3320
3321 public function getSiteData() {
3322 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'check' . DIRECTORY_SEPARATOR . 'system_info.php';
3323 $bmi = new SI();
3324 $bmi = $bmi->to_array();
3325
3326 return ['status' => 'success', 'data' => $bmi];
3327 }
3328
3329 public function calculateCron() {
3330 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'cron' . DIRECTORY_SEPARATOR . 'handler.php';
3331
3332 $minutes = [];
3333 $keeps = [];
3334 $days = [];
3335 $weeks = [];
3336 $hours = [];
3337
3338 for ($i = 1; $i <= 28; ++$i) {
3339 $days[] = substr('0' . $i, -2);
3340 }
3341 for ($i = 1; $i <= 7; ++$i) {
3342 $weeks[] = $i . '';
3343 }
3344 for ($i = 0; $i <= 23; ++$i) {
3345 $hours[] = substr('0' . $i, -2);
3346 }
3347 for ($i = 0; $i <= 55; $i += 5) {
3348 $minutes[] = substr('0' . $i, -2);
3349 }
3350 for ($i = 1; $i <= 20; ++$i) {
3351 $keeps[] = $i . '';
3352 }
3353
3354 $errors = 0;
3355 if (in_array($this->post['type'], ['month', 'week', 'day'])) {
3356 if (!Dashboard\bmi_set_config('CRON:TYPE', $this->post['type'])) {
3357 $errors++;
3358 }
3359 }
3360 if (in_array($this->post['day'], $days)) {
3361 if (!Dashboard\bmi_set_config('CRON:DAY', $this->post['day'])) {
3362 $errors++;
3363 }
3364 }
3365 if (in_array($this->post['week'], $weeks)) {
3366 if (!Dashboard\bmi_set_config('CRON:WEEK', $this->post['week'])) {
3367 $errors++;
3368 }
3369 }
3370 if (in_array($this->post['hour'], $hours)) {
3371 if (!Dashboard\bmi_set_config('CRON:HOUR', $this->post['hour'])) {
3372 $errors++;
3373 }
3374 }
3375 if (in_array($this->post['minute'], $minutes)) {
3376 if (!Dashboard\bmi_set_config('CRON:MINUTE', $this->post['minute'])) {
3377 $errors++;
3378 }
3379 }
3380 if (in_array($this->post['keep'], $keeps)) {
3381 if (!Dashboard\bmi_set_config('CRON:KEEP', $this->post['keep'])) {
3382 $errors++;
3383 }
3384 }
3385
3386 if ($this->post['enabled'] === 'true') {
3387 $this->post['enabled'] = true;
3388 } else {
3389 $this->post['enabled'] = false;
3390 }
3391
3392 if (!Dashboard\bmi_set_config('CRON:ENABLED', $this->post['enabled'])) {
3393 $errors++;
3394 }
3395
3396 if ($errors === 0) {
3397 $time = Crons::calculate_date([
3398 'type' => $this->post['type'],
3399 'week' => $this->post['week'],
3400 'day' => $this->post['day'],
3401 'hour' => $this->post['hour'],
3402 'minute' => $this->post['minute']
3403 ], time());
3404
3405 $file = BMI_TMP . DIRECTORY_SEPARATOR . '.plan';
3406 if (file_exists($file)) {
3407 $earlier = intval(file_get_contents($file));
3408 } else {
3409 $earlier = 0;
3410 }
3411
3412 if (!wp_next_scheduled('bmi_do_backup_right_now') || $earlier === 0 || (abs($time - $earlier) >= 15)) {
3413 wp_clear_scheduled_hook('bmi_do_backup_right_now');
3414 if ($this->post['enabled'] === true) {
3415 wp_schedule_single_event($time, 'bmi_do_backup_right_now');
3416 file_put_contents($file, $time);
3417 }
3418 }
3419
3420 return [
3421 'status' => 'success',
3422 'data' => date('Y-m-d H:i:s', $time),
3423 'currdata' => date('Y-m-d H:i:s')
3424 ];
3425 } else {
3426 return ['status' => 'error'];
3427 }
3428 }
3429
3430 public function dismissErrorNotice() {
3431 $optionId = isset($this->post['option_id']) ? $this->post['option_id'] : '';
3432 if (in_array($optionId, ['backupbliss-issues', 'backupbliss-dismiss-upload-issue']))
3433 {
3434 require_once BMI_INCLUDES . '/external/backupbliss.php';
3435 $backupbliss = new BackupBliss();
3436 }
3437
3438 switch ($optionId) {
3439 case 'email-issues':
3440 delete_option('bmi_display_email_issues');
3441 break;
3442 case 'before-update-issues':
3443 delete_option('bmi_display_before_update_backup_issues');
3444 break;
3445 case 'aws-issues':
3446 update_option('bmip_aws_dismiss_issue', true);
3447 break;
3448 case 'wasabi-issues':
3449 update_option('bmip_wasabi_dismiss_issue', true);
3450 break;
3451 case 'sftp-issues':
3452 update_option('bmip_sftp_dismiss_issue', true);
3453 break;
3454 case 'gdrive-issues':
3455 delete_transient('bmip_gd_issue');
3456 break;
3457 case 'backupbliss-issues':
3458 $backupbliss->removeNotice("invalid_key");
3459 $backupbliss->removeNotice("invalid_permission");
3460 if ($backupbliss->getNotice("storage_warn"))
3461 $backupbliss->hideNotice("storage_warn", 60 * 60);
3462 if ($backupbliss->getNotice("upload_issue"))
3463 $backupbliss->hideNotice("upload_issue", 60); //Hide only for a minute
3464 break;
3465 case 'backupbliss-dismiss-upload-issue':
3466 $backupbliss->hideFailureWarnNotice(14 * 24 * 60 * 60); //14 days
3467 break;
3468 case 'security-plugin-warning':
3469 update_option('bmi_security_warning_dismiss', true);
3470 default:
3471 break;
3472 }
3473 }
3474
3475 // recursive removal
3476 private function rrmdir($dir) {
3477
3478 if (is_dir($dir)) {
3479
3480 $objects = scandir($dir);
3481 foreach ($objects as $object) {
3482
3483 if ($object != "." && $object != "..") {
3484
3485 if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . DIRECTORY_SEPARATOR . $object)) {
3486
3487 $this->rrmdir($dir . DIRECTORY_SEPARATOR . $object);
3488
3489 } else {
3490
3491 @unlink($dir . DIRECTORY_SEPARATOR . $object);
3492
3493 }
3494
3495 }
3496
3497 }
3498
3499 @rmdir($dir);
3500
3501 } else {
3502
3503 if (file_exists($dir) && is_file($dir)) {
3504
3505 @unlink($dir);
3506
3507 }
3508
3509 }
3510
3511 }
3512
3513 public function forceBackupToStop() {
3514
3515 $filesToBeRemoved = [];
3516
3517 $tmp_dir = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp';
3518 if (!is_dir($tmp_dir)) @mkdir($tmp_dir, 0755, true);
3519
3520 foreach (scandir($tmp_dir) as $filename) {
3521
3522 if (in_array($filename, ['.', '..'])) continue;
3523 $path = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . $filename;
3524 $filesToBeRemoved[] = $path;
3525
3526 }
3527
3528 $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'];
3529 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . '.*') as $filename) {
3530
3531 $basename = basename($filename);
3532
3533 if (in_array($basename, ['.', '..'])) continue;
3534 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
3535 $filesToBeRemoved[] = $filename;
3536 }
3537
3538 }
3539
3540 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'BMI-*', GLOB_ONLYDIR) as $filename) {
3541
3542 $basename = basename($filename);
3543
3544 if (in_array($basename, ['.', '..'])) continue;
3545 if (is_dir($filename) && !in_array($filename, $allowedFiles)) {
3546 $filesToBeRemoved[] = $filename;
3547 }
3548
3549 }
3550
3551 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'bg-BMI-*', GLOB_ONLYDIR) as $filename) {
3552
3553 $basename = basename($filename);
3554
3555 if (in_array($basename, ['.', '..'])) continue;
3556 if (is_dir($filename) && !in_array($filename, $allowedFiles)) {
3557 $filesToBeRemoved[] = $filename;
3558 }
3559
3560 }
3561
3562 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.backup_cli_lock';
3563 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.backup_cli_lock_ended';
3564 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.backup_cli_lock_end';
3565 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.last_triggered';
3566 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running';
3567 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.space_check';
3568 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'db_tables';
3569 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'bmi_backup_manifest.json';
3570 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'files_latest.list';
3571 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . 'currentBackupConfig.php';
3572
3573 if (is_array($filesToBeRemoved) || is_object($filesToBeRemoved)) {
3574 foreach ((array) $filesToBeRemoved as $file) {
3575 $this->rrmdir($file);
3576 }
3577 }
3578
3579 return ['status' => 'success'];
3580
3581 }
3582
3583 public function forceRestoreToStop() {
3584
3585 $filesToBeRemoved = [];
3586
3587 $themedir = get_theme_root();
3588 $tempTheme = $themedir . DIRECTORY_SEPARATOR . 'backup_migration_restoration_in_progress';
3589 $filesToBeRemoved[] = $tempTheme;
3590
3591 $tmpDirectory = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp';
3592 if (!is_dir($tmpDirectory)) @mkdir($tmpDirectory, 0755, true);
3593
3594 foreach (scandir($tmpDirectory) as $filename) {
3595
3596 if (in_array($filename, ['.', '..'])) continue;
3597 $path = BMI_ROOT_DIR . DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . $filename;
3598 $filesToBeRemoved[] = $path;
3599
3600 }
3601
3602 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'backup-migration_??????????') as $filename) {
3603
3604 $basename = basename($filename);
3605
3606 if (is_dir($filename) && !in_array($basename, ['.', '..'])) {
3607 $filesToBeRemoved[] = $filename;
3608 }
3609
3610 }
3611
3612 $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'];
3613 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . '.*') as $filename) {
3614
3615 $basename = basename($filename);
3616
3617 if (in_array($basename, ['.', '..'])) continue;
3618 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
3619 $filesToBeRemoved[] = $filename;
3620 }
3621
3622 }
3623
3624 foreach (glob(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_scan_*') as $filename) {
3625
3626 $basename = basename($filename);
3627
3628 if (in_array($basename, ['.', '..'])) continue;
3629 if (is_file($filename) && !in_array($basename, $allowedFiles)) {
3630 $filesToBeRemoved[] = $filename;
3631 }
3632
3633 }
3634
3635 foreach (glob(untrailingslashit(ABSPATH) . DIRECTORY_SEPARATOR . 'wp-config.??????????.php') as $filename) {
3636
3637 $basename = basename($filename);
3638
3639 if (in_array($basename, ['.', '..'])) continue;
3640 if (is_file($filename) && !in_array($filename, $allowedFiles)) {
3641 $filesToBeRemoved[] = $filename;
3642 }
3643
3644 }
3645
3646 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock';
3647 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock_cli';
3648 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock_cli_end';
3649 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock_ended';
3650 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.cli_download_last';
3651 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running';
3652 $filesToBeRemoved[] = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.space_check';
3653 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . '.restore_secret';
3654 $filesToBeRemoved[] = BMI_TMP . DIRECTORY_SEPARATOR . '.table_map';
3655
3656 if (is_array($filesToBeRemoved) || is_object($filesToBeRemoved)) {
3657 foreach ((array) $filesToBeRemoved as $file) {
3658 $this->rrmdir($file);
3659 }
3660 }
3661
3662 return ['status' => 'success'];
3663
3664 }
3665
3666 public function sendTroubleshootingDetails($send_type = 'manual', $triggeredBy = false, $blocking = true) {
3667
3668 global $table_prefix;
3669
3670 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'check' . DIRECTORY_SEPARATOR . 'system_info.php';
3671 $bmiSiteData = new SI();
3672 $bmiSiteData = $bmiSiteData->to_array();
3673 $bmiSiteData['database_size'] = $this->getDatabaseSize();
3674 $bmiSiteData['database_size_mb'] = BMP::humanSize($bmiSiteData['database_size']);
3675 $bmiSiteData['xhria'] = get_option('z__bmi_xhria', 'none');
3676 $bmiSiteData['current_table_prefix'] = $table_prefix;
3677
3678 $wpconfigPath = ABSPATH . DIRECTORY_SEPARATOR . 'wp-config.php';
3679 if (file_exists($wpconfigPath)) {
3680 $bmiSiteData['is_wp_config_writable'] = is_writable($wpconfigPath) ? "yes" : "no";
3681 } else {
3682 $bmiSiteData['is_wp_config_writable'] = "file_does_not_exist?";
3683 }
3684
3685 $latestBackupLogs = 'does_not_exist';
3686 $latestBackupProgress = 'does_not_exist';
3687 $latestRestorationLogs = 'does_not_exist';
3688 $latestRestorationProgress = 'does_not_exist';
3689 $latestStagingLogs = 'does_not_exist';
3690 $latestStagingProgress = 'does_not_exist';
3691 $currentPluginConfig = 'does_not_exist';
3692 $pluginGlobalLogs = 'does_not_exist';
3693 $backgroundErrors = 'does_not_exist';
3694
3695 if (file_exists(BMI_BACKUPS . '/latest.log')) {
3696 $latestBackupLogs = file_get_contents(BMI_BACKUPS . '/latest.log');
3697 }
3698
3699 if (file_exists(BMI_BACKUPS . '/latest_progress.log')) {
3700 $latestBackupProgress = file_get_contents(BMI_BACKUPS . '/latest_progress.log');
3701 }
3702
3703 if (file_exists(BMI_BACKUPS . '/latest_migration.log')) {
3704 $latestRestorationLogs = file_get_contents(BMI_BACKUPS . '/latest_migration.log');
3705 }
3706
3707 if (file_exists(BMI_BACKUPS . '/latest_migration_progress.log')) {
3708 $latestRestorationProgress = file_get_contents(BMI_BACKUPS . '/latest_migration_progress.log');
3709 }
3710
3711 if (file_exists(BMI_STAGING . '/latest_staging.log')) {
3712 $latestStagingLogs = file_get_contents(BMI_STAGING . '/latest_staging.log');
3713 }
3714
3715 if (file_exists(BMI_STAGING . '/latest_staging_progress.log')) {
3716 $latestStagingProgress = file_get_contents(BMI_STAGING . '/latest_staging_progress.log');
3717 }
3718
3719 if (file_exists(BMI_CONFIG_PATH)) {
3720 $currentPluginConfig = substr(file_get_contents(BMI_CONFIG_PATH), 8);
3721 }
3722
3723 $completeLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.log';
3724 if (file_exists($completeLogsPath)) {
3725 if ((filesize($completeLogsPath) / 1024 / 1024) <= 4) {
3726 $pluginGlobalLogs = file_get_contents($completeLogsPath);
3727 } else {
3728 $fp = fopen($completeLogsPath, 'rb');
3729 if ($fp) {
3730 $seekPos = max(0, $fileSize - (4 * 1024 * 1024));
3731 fseek($fp, $seekPos, SEEK_SET);
3732 $pluginGlobalLogs = fread($fp, 4 * 1024 * 1024);
3733 fclose($fp);
3734 file_put_contents($completeLogsPath, $pluginGlobalLogs); // Save the last 4MB
3735 } else {
3736 $pluginGlobalLogs = 'could_not_open_file';
3737 }
3738 }
3739 }
3740
3741 $backgroundLogsPath = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'background-errors.log';
3742 if (file_exists($backgroundLogsPath)) {
3743 if ((filesize($backgroundLogsPath) / 1024 / 1024) <= 4) {
3744 $backgroundErrors = file_get_contents($backgroundLogsPath);
3745 } else {
3746 @unlink($backgroundLogsPath);
3747 @touch($backgroundLogsPath);
3748 $backgroundErrors = 'file_too_large';
3749 }
3750 }
3751
3752 $ifCLI = false;
3753 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
3754 $ifCLI = true;
3755 }
3756
3757 $logsSourceFrontEnd = 'manual';
3758 if ($triggeredBy != false) {
3759 $logsSourceFrontEnd = $triggeredBy;
3760 }
3761 if (isset($this->post['source']) && in_array($this->post['source'], ['backup', 'migration', 'staging'])) {
3762 $logsSourceFrontEnd = $this->post['source'];
3763 }
3764
3765 $latestBackupLogs = preg_replace('/\:\ ((.*)\.zip)/', ': *****.zip', $latestBackupLogs);
3766 $latestRestorationLogs = preg_replace('/backup\-id\=(.*)\.zip/', 'backup-id=[***redacted***].zip', $latestRestorationLogs);
3767 $latestStagingLogs = preg_replace('/\:\ ((.*)\.zip)/', ': *****.zip', $latestStagingLogs);
3768
3769 $currentPluginConfig = json_decode($currentPluginConfig);
3770 unset($currentPluginConfig->{"OTHER:EMAIL"});
3771 $currentPluginConfig = json_encode($currentPluginConfig);
3772
3773 $url = 'https://' . BMI_API_BACKUPBLISS_PUSH . '/v1' . '/push';
3774 $data = array(
3775 'method' => 'POST',
3776 'timeout' => 15,
3777 'blocking' => $blocking,
3778 'sslverify' => false,
3779 'send_type' => $send_type,
3780 'body' => array(
3781 'admin_url' => admin_url(),
3782 'home_url' => home_url(),
3783 'site_url' => get_site_url(),
3784 'is_multisite' => is_multisite() ? "yes" : "no",
3785 'is_abspath_writable' => is_writable(ABSPATH) ? "yes" : "no",
3786 'site_information' => $bmiSiteData,
3787 'latest_backup_logs' => $latestBackupLogs,
3788 'latest_backup_progress' => $latestBackupProgress,
3789 'latest_restoration_logs' => $latestRestorationLogs,
3790 'latest_restoration_progress' => $latestRestorationProgress,
3791 'latest_staging_logs' => $latestStagingLogs,
3792 'latest_staging_progress' => $latestStagingProgress,
3793 'current_plugin_config' => $currentPluginConfig,
3794 'plugin_global_logs' => $pluginGlobalLogs,
3795 'background_errors' => $backgroundErrors,
3796 'triggered_by' => $logsSourceFrontEnd,
3797 'is_defined' => defined('BMI_BACKUP_PRO') ? 'yes' : 'no',
3798 'is_cli' => $ifCLI
3799 )
3800 );
3801
3802 $disabled_functions = explode(',', ini_get('disable_functions'));
3803 $vA = !in_array('curl_exec', $disabled_functions);
3804 $vB = !in_array('curl_init', $disabled_functions);
3805 $vC = !in_array('http_build_query', $disabled_functions);
3806 $vD = !in_array('stream_context_create', $disabled_functions);
3807 $vE = !in_array('file_get_contents', $disabled_functions);
3808 $vF = false;
3809 $response = false;
3810
3811 if (function_exists('curl_version') && function_exists('curl_exec') && function_exists('curl_init') && $vA && $vB) {
3812
3813 $response = wp_remote_post($url, $data);
3814
3815 } else {
3816
3817 if (ini_get('allow_url_fopen') == true && $vC && $vD && $vE) {
3818
3819 $vF = true;
3820 $postdata = http_build_query($data['body']);
3821
3822 $opts = [
3823 'ssl' => [ 'verify_peer_name' => false, 'verify_peer' => false ],
3824 'http' => [
3825 'method' => 'POST',
3826 'header' => 'Content-type: application/x-www-form-urlencoded',
3827 'content' => $postdata
3828 ]
3829 ];
3830
3831 $context = stream_context_create($opts);
3832 $result = file_get_contents($url, false, $context);
3833
3834 $response = [ 'body' => $result ];
3835
3836 }
3837
3838 }
3839
3840 if ($response === false || is_wp_error($response)) {
3841 $error_message = $response->get_error_message();
3842 Logger::error($error_message, 'backup-backup');
3843 return ['status' => 'fail'];
3844 } else {
3845 try {
3846 $body = json_decode($response['body']);
3847 if (isset($body->code)) {
3848 return ['status' => 'success', 'code' => sanitize_text_field($body->code)];
3849 } else {
3850 return ['status' => 'fail'];
3851 }
3852 } catch (\Exception $e) {
3853 Logger::error(print_r($e, true), 'backup-backup');
3854 return ['status' => 'fail'];
3855 } catch (\Throwable $t) {
3856 Logger::error(print_r($t, true), 'backup-backup');
3857 return ['status' => 'fail'];
3858 }
3859 }
3860
3861 }
3862
3863 public function actionsAfterProcess($success = false, $triggeredBy = 'backup') {
3864
3865 $afterMigrationLock = BMI_TMP . DIRECTORY_SEPARATOR . '.migrationFinished';
3866 if ($success) {
3867
3868 file_put_contents($afterMigrationLock, '');
3869 Logger::log("Process (" . $triggeredBy . ") finished successfully via ajax.php");
3870
3871 } else {
3872
3873 Logger::log("Process (" . $triggeredBy . ") finished with errors via ajax.php");
3874 if (file_exists($afterMigrationLock)) @unlink($afterMigrationLock);
3875
3876 }
3877
3878 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json')) @unlink(BMI_TMP . DIRECTORY_SEPARATOR . 'restore_parts.json');
3879
3880
3881 if (has_action('bmi_premium_after_process') || (defined('BACKUP_TRIGGERED_BY_URL') && BACKUP_TRIGGERED_BY_URL === true)){
3882 do_action('bmi_premium_after_process', $success, $triggeredBy, defined('BACKUP_TRIGGERED_BY_URL') && BACKUP_TRIGGERED_BY_URL === true);
3883 }
3884
3885 BMP::handle_after_cron();
3886
3887 return null;
3888
3889 // REMOVED CODE:
3890 // $canShare = BMP::canShareLogsOrShouldAsk();
3891 // if ($canShare === 'allowed') {
3892 //
3893 // $send_type = 'error';
3894 // if ($success) $send_type = 'success';
3895 // $this->sendTroubleshootingDetails($send_type, $triggeredBy, false);
3896 //
3897 // }
3898
3899 }
3900
3901 public function logSharing() {
3902
3903 $type = $this->post['question'];
3904
3905 if ($type == 'set_yes') {
3906
3907 // $isOk = Dashboard\bmi_set_config('LOGS::SHARING', 'yes');
3908 // update_option('BMI_LOGS_SHARING_IS_ALLOWED', 'yes');
3909 return ['status' => 'success'];
3910
3911 } else if ($type == 'set_no') {
3912
3913 // $isOk = Dashboard\bmi_set_config('LOGS::SHARING', 'no');
3914 // update_option('BMI_LOGS_SHARING_IS_ALLOWED', 'no');
3915 return ['status' => 'success'];
3916
3917 } else if ($type == 'is_allowed') {
3918
3919 // $canShare = BMP::canShareLogsOrShouldAsk();
3920 // return ['status' => 'success', 'result' => $canShare];
3921 return ['status' => 'success', 'result' => 'not-allowed'];
3922
3923 } else {
3924
3925 return ['status' => 'fail'];
3926
3927 }
3928
3929 }
3930
3931 public function getLatestBackupFile() {
3932
3933 $dir = BMI_BACKUPS;
3934 $backupdir = array_diff(scandir($dir), ['..', '.']);
3935 $backups = [];
3936 foreach ($backupdir as $index => $name) {
3937
3938 $ext = pathinfo($dir . DIRECTORY_SEPARATOR . $name, PATHINFO_EXTENSION);
3939
3940 if (in_array($ext, ['zip', 'tar', 'gz'])) {
3941 $backups[] = [
3942 'cdate' => filemtime($dir . DIRECTORY_SEPARATOR . $name),
3943 'name' => $name
3944 ];
3945 }
3946
3947 }
3948
3949 usort($backups, function ($a, $b) {
3950 if (intval($a['cdate']) < intval($b['cdate'])) return 1;
3951 else return -1;
3952 });
3953
3954 $backups = array_values($backups);
3955
3956 if (sizeof($backups) > 0) {
3957 return $backups[0]['name'];
3958 } else {
3959 return '---';
3960 }
3961
3962 }
3963
3964 /**
3965 * isStagingSiteCreationOngoing - Checks if the process is ongoing or not
3966 *
3967 * @return {bool} true if the process is running false if its not
3968 */
3969 public function isStagingSiteCreationOngoing() {
3970
3971 $staging_lock = BMI_STAGING . '/.staging_lock';
3972 if (file_exists($staging_lock) && (time() - filemtime($staging_lock)) <= 15) {
3973 return true;
3974 } else {
3975 return false;
3976 }
3977
3978 }
3979
3980 /**
3981 * checkStagingLocalName - Verifies name of staging site and checks if it's not currently running
3982 * Can be called for verification pre start or during start on initial request
3983 *
3984 * @param {string} $name = false name of staging site if called without ajax
3985 * @return {array} with status/fail/progress data
3986 */
3987 public function checkStagingLocalName($name = false) {
3988
3989 if ($name == false && isset($this->post['name'])) {
3990 $name = $this->post['name'];
3991 }
3992
3993 $ongoing = __('Staging site creation is already ongoing, please wait and try again.', 'backup-backup');
3994 $empty = __('You have to provide some staging site name before process.', 'backup-backup');
3995 $toolong = __('Staging site name cannot be longer than 24 characters.', 'backup-backup');
3996 $invalid = __('Provided name contains prohibited characters.', 'backup-backup');
3997 $blacklisted = __('This name is not allowed to be used, please pick different one.', 'backup-backup');
3998 $exist = __('Seems like directory or staging site with that name already exist, pick different one.', 'backup-backup');
3999 $dashes = __('Name cannot start or end with dash or underscore.', 'backup-backup');
4000
4001 if ($this->isStagingSiteCreationOngoing()) {
4002 return ['status' => 'fail', 'message' => $ongoing];
4003 }
4004
4005 if (strlen($name) <= 0) {
4006 return ['status' => 'fail', 'message' => $empty];
4007 }
4008
4009 if (!preg_match('/^[a-zA-Z0-9-_]+$/', $name)) {
4010 return ['status' => 'fail', 'message' => $invalid];
4011 }
4012
4013 if (strlen($name) >= 24) {
4014 return ['status' => 'fail', 'message' => $toolong];
4015 }
4016
4017 if (in_array($name[0], ['_', '-']) || in_array($name[strlen($name) - 1], ['_', '-'])) {
4018 return ['status' => 'fail', 'message' => $dashes];
4019 }
4020
4021 $bannedNames = [
4022 'wp-content',
4023 'wp-admin',
4024 'wp-includes',
4025 'content',
4026 'admin',
4027 'includes',
4028 'tmp',
4029 '.well-known',
4030 'download',
4031 'downloads',
4032 'google',
4033 'temporary'
4034 ];
4035
4036 if (strpos($name, '.') !== false) {
4037 return ['status' => 'fail', 'message' => $blacklisted];
4038 }
4039
4040 if (in_array($name, $bannedNames)) {
4041 return ['status' => 'fail', 'message' => $blacklisted];
4042 }
4043
4044 $path = trailingslashit(ABSPATH) . $name;
4045 if (file_exists($path) || is_dir($path)) {
4046 return ['status' => 'fail', 'message' => $exist];
4047 }
4048
4049 return ['status' => 'success'];
4050
4051 }
4052
4053 /**
4054 * startLocalStagingCreation - Initials creation of staging site process
4055 *
4056 * @return {array} with status/fail/progress data
4057 */
4058 public function startLocalStagingCreation() {
4059
4060 // Verification of state
4061 $name = $this->post['name'];
4062 $verification = $this->checkStagingLocalName($name);
4063 $staging_lock = BMI_STAGING . '/.staging_lock';
4064
4065 // Fail in case of wrong data or state
4066 if (isset($verification['status']) && $verification['status'] != 'success') {
4067 return $verification;
4068 }
4069
4070 // Update lock file to prevent double processes
4071 touch($staging_lock);
4072
4073 // Include local staging site controller
4074 require_once BMI_INCLUDES . '/staging/local.php';
4075 $staging = new StagingLocal($name, true);
4076
4077 // Append the return if staging process requires more batches
4078 if ($staging->continue == true) return $staging->continuationData;
4079
4080 return [ 'status' => 'continue', 'data' => [ 'name' => $name ] ];
4081
4082 }
4083
4084 /**
4085 * stagingSitesGetList - Returns staging sites list
4086 *
4087 * @return {array} with staging sites data
4088 */
4089 public function stagingSitesGetList() {
4090
4091 // Include local staging site controller
4092 require_once BMI_INCLUDES . '/staging/controller.php';
4093 $staging = new Staging('..ajax..');
4094 $sites = $staging->getStagingSites();
4095
4096 return [ 'status' => 'success', 'sites' => $sites ];
4097
4098 }
4099
4100 /**
4101 * stagingRename - Renames display name
4102 *
4103 * @return {array} status
4104 */
4105 public function stagingRename() {
4106
4107 $name = $this->post['name'];
4108 $newName = $this->post['new'];
4109
4110 // Include local staging site controller
4111 require_once BMI_INCLUDES . '/staging/controller.php';
4112 $staging = new Staging('..ajax..');
4113 return $staging->rename($name, $newName);
4114
4115 }
4116
4117 /**
4118 * stagingPrepareLogin - Prepares login script
4119 *
4120 * @return {array} login credentials
4121 */
4122 public function stagingPrepareLogin() {
4123
4124 $name = $this->post['name'];
4125
4126 // Include local staging site controller
4127 require_once BMI_INCLUDES . '/staging/controller.php';
4128 $staging = new Staging('..ajax..');
4129 return $staging->prepareLogin($name);
4130
4131 }
4132
4133 /**
4134 * Handles secure backup via browser method
4135 */
4136 public function backupBrowserMethodHandler() {
4137
4138 try {
4139
4140 // Load bypasser
4141 require_once BMI_INCLUDES . '/backup-process.php';
4142 $request = new Bypasser(false, BMI_CONFIG_DIR, trailingslashit(WP_CONTENT_DIR), BMI_BACKUPS, trailingslashit(ABSPATH), plugin_dir_path(BMI_ROOT_FILE));
4143
4144 // Handle request
4145 $request->handle_batch();
4146 $request->shutdown();
4147 return;
4148
4149 } catch (\Exception $e) {
4150
4151 error_log('There was an error with Backup Migration plugin: ' . $e->getMessage());
4152 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $e->getMessage());
4153 error_log(strval($e));
4154
4155 } catch (\Throwable $t) {
4156
4157 error_log('There was an error with Backup Migration plugin: ' . $t->getMessage());
4158 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $t->getMessage());
4159 error_log(strval($t));
4160
4161 }
4162
4163 return [ 'status' => 'error' ];
4164
4165 }
4166
4167 /**
4168 * Handles ajax error on browser side, keep alive timeout etc.
4169 *
4170 * @return array static success
4171 */
4172 public function frontEndAjaxError() {
4173
4174 if ($this->post['call'] == 'create-backup') {
4175 require_once BMI_INCLUDES . '/progress/zip.php';
4176 $logger = new Progress('', 0, 0, false, false);
4177 } else if (in_array($this->post['call'], ['restore-backup', 'download-backup', 'continue_restore_process'])) {
4178 require_once BMI_INCLUDES . '/progress/migration.php';
4179 $logger = new MigrationProgress(true);
4180 } else if (in_array($this->post['call'], ['staging-start-local-creation', 'staging-local-creation-process', 'staging-tastewp-creation-process'])) {
4181 require_once BMI_INCLUDES . '/progress/staging.php';
4182 $logger = new StagingProgress(true);
4183 }
4184
4185 if (isset($this->post['error'])) {
4186
4187 Logger::error('Front End Ajax Error START');
4188 if (isset($logger)) $logger->log('Front End Ajax Error START', 'verbose');
4189
4190 if (is_array($this->post['error'])) {
4191
4192 $errors = $this->post['error'];
4193 foreach ($errors as $k => $val) {
4194 $error = sanitize_text_field(print_r($val, true));
4195 Logger::error($k . ' = ' . $error);
4196 if (isset($logger)) $logger->log($k . ' = ' . $error, 'verbose');
4197 }
4198
4199 } else {
4200
4201 $theError = sanitize_text_field(print_r($this->post->error, true));
4202 Logger::error('Front End Ajax Error: ' . $theError);
4203 if (isset($logger)) $logger->log($theError, 'verbose');
4204
4205 }
4206
4207 Logger::error('Front End Ajax Error END');
4208 if (isset($logger)) $logger->log('Front End Ajax Error END', 'verbose');
4209
4210 } else {
4211
4212 Logger::error('Front End Ajax Error was called, but no error included.');
4213
4214 }
4215
4216 if (isset($logger)) {
4217 $logger->log(__('Browser-side error detected, the process will try to restart with alternative methods, otherwise it will throw error window.', 'backup-backup'), 'error');
4218 $logger->log('Browser-side error detected, the process will try to restart with alternative methods, otherwise it will throw error window.', 'verbose');
4219 }
4220
4221 return [ 'status' => 'success' ];
4222
4223 }
4224
4225 /**
4226 * stagingDelete - Removes the staging site
4227 *
4228 * @return {array} status
4229 */
4230 public function stagingDelete() {
4231
4232 $name = $this->post['name'];
4233
4234 // Include local staging site controller
4235 require_once BMI_INCLUDES . '/staging/controller.php';
4236 $staging = new Staging('..ajax..');
4237 return $staging->delete($name);
4238
4239 }
4240
4241 /**
4242 * localStagingCreationProcess - Method that can continue batching of Staging process
4243 *
4244 * @return {array} data that should be send back to this function as POST
4245 */
4246 public function localStagingCreationProcess() {
4247
4248 // Get $name and declare lock file
4249 $name = $this->post['name'];
4250 $staging_lock = BMI_STAGING . '/.staging_lock';
4251
4252 // Update lock file to prevent double processes
4253 touch($staging_lock);
4254
4255 // Include local staging site controller
4256 require_once BMI_INCLUDES . '/staging/local.php';
4257 $staging = new StagingLocal($name);
4258
4259 // Process handler
4260 if (isset($this->post['delete'])) {
4261 $staging->requestDelete();
4262 } else $staging->continueProcess();
4263
4264 // Append the return if staging process requires more batches
4265 if ($staging->continue == true) return $staging->continuationData;
4266
4267 // Send success if nothing went wrong which finishes the process
4268 if (file_exists($staging_lock)) @unlink($staging_lock);
4269 return ['status' => 'error'];
4270
4271 }
4272
4273 /**
4274 * tastewpStagingCreation - Initializes and declares staging site will
4275 *
4276 * @return {array} batching status
4277 */
4278 public function tastewpStagingCreation() {
4279
4280 // Get $name and declare lock file
4281 $name = $this->post['name'];
4282 $backupName = isset($this->post['backupName']) ? $this->post['backupName'] : false;
4283 $initialize = isset($this->post['initialize']) ? $this->post['initialize'] : false;
4284 $staging_lock = BMI_STAGING . '/.staging_lock';
4285
4286 // Fix var type
4287 if ($initialize === true || $initialize == 'true') $initialize = true;
4288 else $initialize = false;
4289
4290 // Update lock file to prevent double processes
4291 touch($staging_lock);
4292
4293 // Include TasteWP staging site controller
4294 require_once BMI_INCLUDES . '/staging/tastewp.php';
4295
4296 // Process handler
4297 if (isset($this->post['delete'])) {
4298 $delete = true;
4299 } else $delete = false;
4300
4301 // Make first handshake with TasteWP
4302 $staging = new StagingTasteWP($name, $initialize, $backupName, $delete);
4303
4304 // Append the return if staging process requires more batches
4305 if ($staging->continue == true) return $staging->continuationData;
4306
4307 // Send success if nothing went wrong which finishes the process
4308 if (file_exists($staging_lock)) @unlink($staging_lock);
4309 return ['status' => 'error'];
4310
4311 }
4312
4313 public function debugging() {
4314
4315 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'scanner' . DIRECTORY_SEPARATOR . 'backups.php';
4316 $backups = new Backups();
4317 $availableBackups = $backups->getAvailableBackups();
4318 $list = $availableBackups['local'];
4319
4320 // $cron_list = [];
4321 // $cron_dates = [];
4322 // foreach ($list as $key => $value) {
4323 // if ($list[$key][6] == true) {
4324 // if ($list[$key][5] == 'unlocked') {
4325 // $cron_list[$list[$key][1]] = $list[$key][0];
4326 // $cron_dates[] = $list[$key][1];
4327 // }
4328 // }
4329 // }
4330
4331 // usort($cron_dates, function ($a, $b) {
4332 // return (strtotime($a) < strtotime($b)) ? -1 : 1;
4333 // });
4334
4335 // $cron_dates = array_slice($cron_dates, 0, -(intval(Dashboard\bmi_get_config('CRON:KEEP'))));
4336 // foreach ($cron_dates as $key => $value) {
4337 // $name = $cron_list[$cron_dates[$key]];
4338 // $name = explode('#%&', $name)[1];
4339 // Logger::log(__("Removing backup due to keep rules: ", 'backup-backup') . $name);
4340 // @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . $name);
4341 // }
4342
4343 if (isset($availableBackups['external']['gdrive'])) {
4344 $sortedMD5s = [];
4345 $gdrive = $availableBackups['external']['gdrive'];
4346 foreach ($gdrive as $md5 => $data) {
4347 if ($gdrive[$md5][6] == true && $gdrive[$md5][5] == 'unlocked') {
4348 $sortedMD5s[] = [$gdrive[$md5][1], $md5];
4349 }
4350 }
4351
4352 usort($sortedMD5s, function ($a, $b) {
4353 return (strtotime($a[0]) < strtotime($b[0])) ? -1 : 1;
4354 });
4355
4356 $gdrive_md5s = array_slice($sortedMD5s, 0, -(intval(Dashboard\bmi_get_config('CRON:KEEP'))));
4357 foreach ($sortedMD5s as $index => $data) {
4358 $md5 = $data[1];
4359
4360 }
4361 }
4362
4363 return ['availableBackups' => $availableBackups, '$gdrive' => $sortedMD5s];
4364
4365 }
4366
4367 public function checkCompatibility() {
4368
4369 $for = isset($this->post['for']) ? $this->post['for'] : 'backup';
4370
4371 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'check' . DIRECTORY_SEPARATOR . 'compatibility.php';
4372 $compatibility = new Compatibility($for);
4373 $errors = $compatibility->check();
4374 return ['status' => 'success', 'data' => $errors];
4375 }
4376
4377 public function checkDiskSpace(){
4378 $file = BMI_BACKUPS . '/' . '.space_check';
4379
4380 $backupSize = BMP::getRecentSize() * 1.4;
4381
4382 try {
4383 $size = $backupSize;
4384 $fh = fopen($file, 'w');
4385 while($size > 0){
4386 $chunk = 1024;
4387 fputs($fh, str_pad('', min($chunk, $size)));
4388 $size -= $chunk;
4389 }
4390 fclose($fh);
4391
4392 $fs = filesize($file);
4393 @unlink($file);
4394
4395 return ['status' => 'enough-space'];
4396
4397
4398 } catch (\Exception $e) {
4399 if (file_exists($file)){
4400 $fileSize = filesize($file);
4401 unlink($file);
4402
4403 return ['status' => 'not-enough-space', 'data' => ['available' => BMP::humanSize(intval($fileSize)), 'required' => BMP::humanSize(intval($backupSize))]];
4404 }
4405
4406 } catch (\Throwable $e) {
4407 if (file_exists($file)){
4408 $fileSize = filesize($file);
4409 unlink($file);
4410 return ['status' => 'not-enough-space', 'data' => ['available' => BMP::humanSize(intval($fileSize)), 'required' => BMP::humanSize(intval($backupSize))]];
4411 }
4412
4413 }
4414 }
4415
4416 public function cleanUpAfterError() {
4417 $runningFile = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running';
4418 $spaceCheckFile = BMI_BACKUPS . DIRECTORY_SEPARATOR . '.space_check';
4419
4420 if (file_exists($runningFile)){
4421 $backupName = file_get_contents($runningFile);
4422 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName)){
4423 $partialBackup = glob(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName . '.??????');
4424 if (is_array($partialBackup) && !empty($partialBackup)){
4425 foreach ($partialBackup as $file){
4426 @unlink($file);
4427 }
4428 }
4429 @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupName);
4430 }
4431 @unlink($runningFile);
4432 }
4433
4434 if (file_exists($spaceCheckFile)){
4435 @unlink($spaceCheckFile);
4436 }
4437 }
4438
4439 }
4440