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