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