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