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