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