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