PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 2.0.0
Backup Migration v2.0.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 / initializer.php
backup-backup / includes Last commit date
banner 8 months ago bodies 8 months ago check 8 months ago cli 8 months ago cron 8 months ago dashboard 8 months ago database 8 months ago external 8 months ago extracter 8 months ago htaccess 8 months ago notices 8 months ago progress 8 months ago scanner 8 months ago staging 8 months ago traits 8 months ago uploader 8 months ago vendor 8 months ago zipper 8 months ago .htaccess 8 months ago activation.php 8 months ago ajax.php 8 months ago ajax_offline.php 8 months ago analyst.php 8 months ago backup-process.php 8 months ago class-backup-method-mananger.php 8 months ago cli-handler.php 8 months ago compatibility.php 8 months ago config.php 8 months ago constants.php 8 months ago file-explorer.php 8 months ago initializer.php 8 months ago logger.php 8 months ago offline.php 8 months ago
initializer.php
1849 lines
1 <?php
2
3 // Namespace
4 namespace BMI\Plugin;
5
6 // Exit on direct access
7 if (!defined('ABSPATH')) {
8 exit;
9 }
10
11 // Require classes
12 require_once BMI_INCLUDES . '/logger.php';
13
14 // Alias for classes
15 use BMI\Plugin\BMI_Logger as Logger;
16 use BMI\Plugin\CRON\BMI_Crons as Crons;
17 use BMI\Plugin\Dashboard as Dashboard;
18 use BMI\Plugin\Scanner\BMI_BackupsScanner as Backups;
19 use BMI\Plugin\Heart\BMI_Backup_Heart as Bypasser;
20 use BMI\Plugin\Zipper\BMI_Zipper as Zipper;
21 use BMI\Plugin\Staging\BMI_Staging as Staging;
22 use BMI\Plugin\External\BMI_External_BackupBliss as BackupBliss;
23
24 // Uninstallator
25 if (!function_exists('bmi_uninstall_handler')) {
26 function bmi_uninstall_handler() {
27 require_once BMI_ROOT_DIR . '/uninstall.php';
28 }
29 }
30
31 /**
32 * Backup Migration Main Class
33 */
34 class Backup_Migration_Plugin {
35 public function initialize() {
36
37 // Determine which BMI version is used
38 add_action('wp_head', function () {
39 echo '<meta name="bmi-version" content="' . BMI_VERSION . '" />';
40 });
41
42 if (!file_exists(BMI_BACKUPS)) @mkdir(BMI_BACKUPS, 0755, true);
43 if (!file_exists(BMI_STAGING)) @mkdir(BMI_STAGING, 0755, true);
44
45 // Handle PHP CLI functions
46 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
47
48 // Below all WordPress functions and directives can be accessed
49 if (defined('BMI_CLI_FUNCTION')) {
50
51 if (BMI_CLI_FUNCTION == 'bmi_restore' && defined('BMI_CLI_ARGUMENT')) {
52
53 $_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest';
54 $_POST['f'] = 'restore-backup';
55 if (defined('BMI_CLI_ARGUMENT_2')) {
56 $_POST['remote'] = BMI_CLI_ARGUMENT_2;
57 } else $_POST['remote'] = false;
58 $_POST['file'] = BMI_CLI_ARGUMENT;
59
60 $this->ajax(true);
61
62 } elseif (BMI_CLI_FUNCTION == 'bmi_backup' || BMI_CLI_FUNCTION == 'bmi_backup_cron') {
63
64 if (BMI_CLI_FUNCTION == 'bmi_backup_cron') {
65 define('BMI_DOING_SCHEDULED_BACKUP', true);
66 define('BMI_DOING_SCHEDULED_BACKUP_VIA_CLI', true);
67 }
68
69 $_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest';
70 $_POST['f'] = 'create-backup';
71
72 $this->ajax(true);
73
74 } elseif (BMI_CLI_FUNCTION == 'bmi_quick_migration') {
75
76 $_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest';
77 $_POST['f'] = 'download-backup';
78 $_POST['url'] = BMI_CLI_ARGUMENT;
79
80 $this->ajax(true);
81
82 }
83
84 }
85
86 return;
87
88 }
89
90 if (defined('BMI_RESTORE_SECRET') && defined('BMI_POST_CONTINUE_RESTORE') && constant('BMI_POST_CONTINUE_RESTORE') === true) {
91
92 if (!isset($_POST['bmi_restore_secret'])) exit;
93
94 // Check the secret
95 $bmi_secret_storage = BMI_TMP . DIRECTORY_SEPARATOR . '.restore_secret';
96 if (file_exists($bmi_secret_storage)) {
97 $bmi_saved_secret = file_get_contents($bmi_secret_storage);
98 if ($bmi_saved_secret === $_POST['bmi_restore_secret']) {
99 $bmi_continue_module = true;
100 } else exit;
101 } else exit;
102
103 $_SERVER['HTTP_X_REQUESTED_WITH'] = 'xmlhttprequest';
104 $_POST['f'] = 'continue_restore_process';
105
106 $this->ajax(true);
107
108 return;
109
110 }
111
112 // Hooks
113 register_deactivation_hook(BMI_ROOT_FILE, [&$this, 'deactivation']);
114 register_uninstall_hook(BMI_ROOT_FILE, 'bmi_uninstall_handler');
115
116 // File downloading
117 add_action('wp_loaded', [&$this, 'handle_downloading']);
118
119 // Additional actions
120 if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] === 'GET') {
121 add_action('wp_loaded', [&$this, 'handle_after_actions'], 1000);
122 }
123 // Handle CRONs
124 add_action('bmi_do_backup_right_now', [&$this, 'handle_cron_backup']);
125 add_action('bmi_handle_cron_check', [&$this, 'handle_cron_check']);
126 add_action('wp_loaded', [&$this, 'handle_crons']);
127 add_action('wp_loaded', [&$this, 'include_offline']);
128 add_action('admin_notices', [&$this, 'incompatibility_notices']);
129
130 // Return if CRON time
131 if (function_exists('wp_doing_cron') && wp_doing_cron()) return;
132
133 // Check user permissions
134 $user = get_userdata(get_current_user_id());
135 if (!$user || !$user->roles) return;
136 if (!current_user_can('do_backups') && !in_array('administrator', (array) $user->roles)) return;
137
138 if (Dashboard\bmi_get_config('OTHER:PROMOTIONAL:DISPLAY') != 'true') {
139
140 // Include our cool banner
141 include_once BMI_INCLUDES . '/banner/misc.php';
142
143 // Review banner
144 if (!is_dir(WP_PLUGIN_DIR . '/backup-backup-pro')) {
145 if (!(class_exists('\Inisev\Subs\Inisev_Review') || class_exists('Inisev\Subs\Inisev_Review') || class_exists('Inisev_Review'))) {
146 require_once BMI_MODULES_DIR . 'review' . DIRECTORY_SEPARATOR . 'review.php';
147 }
148 $review_banner = new \Inisev\Subs\Inisev_Review(BMI_ROOT_FILE, BMI_ROOT_DIR, 'backup-backup', 'Backup & Migration', 'http://bit.ly/3vdk45L', 'backup-migration');
149 }
150
151 if (!(class_exists('\Inisev\Subs\New_BB_Banner') || class_exists('Inisev\Subs\New_BB_Banner') || class_exists('New_BB_Banner'))) {
152 require_once BMI_MODULES_DIR . 'new-bb-banner' . DIRECTORY_SEPARATOR . 'misc.php';
153 new \Inisev\Subs\New_BB_Banner(BMI_ROOT_FILE, BMI_ROOT_DIR, 'backup-backup', 'Backup & Migration', 'backup-migration');
154 }
155
156
157 // GDrive banner
158 if (!is_dir(WP_PLUGIN_DIR . '/backup-backup-pro')) {
159 if (!(class_exists('\Inisev\Subs\BMI_Banners_GDrive') || class_exists('Inisev\Subs\BMI_Banners_GDrive') || class_exists('BMI_Banners_GDrive'))) {
160 require_once BMI_MODULES_DIR . 'gdrivebanner' . DIRECTORY_SEPARATOR . 'misc.php';
161 }
162 $gdirve_banner = new \Inisev\Subs\BMI_Banners_GDrive('Backup & Migration', 'backup-migration');
163 }
164
165 }
166
167 // POST Logic
168 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
169
170 // Register AJAX Handler
171 add_action('wp_ajax_backup_migration', [&$this, 'ajax']);
172
173 // Stop GET Registration
174 // return; // Commented because of conflicts with USM Icons
175
176 }
177
178 // Actions
179 add_action('admin_init', [&$this, 'admin_init_hook']);
180 add_action('admin_menu', [&$this, 'submenu']);
181 add_action('admin_notices', [&$this, 'admin_notices']);
182
183
184 // Settings action
185 add_filter('plugin_action_links_' . plugin_basename(BMI_ROOT_FILE), [&$this, 'settings_action']);
186
187 // Whitelist configuration files for Security Ninja
188 add_filter('securityninja_whitelist', [&$this, 'securityninja_whitelist_config_files']);
189
190 // Ignore below actions if those true
191 if (function_exists('wp_doing_ajax') && wp_doing_ajax()) {
192 return;
193 }
194
195 // Styles & scripts
196 add_action('admin_enqueue_scripts', [&$this, 'enqueue_styles']);
197 add_action('admin_enqueue_scripts', [&$this, 'enqueue_scripts']);
198
199 // External storage errors
200 add_action('bmi_external_errors', function() {
201
202 if (file_exists(BMI_INCLUDES . 'notices/dropbox-issues-notice.php'))
203 require_once BMI_INCLUDES . 'notices/dropbox-issues-notice.php';
204
205 if (file_exists(BMI_INCLUDES . '/notices/aws-issues.php'))
206 require_once BMI_INCLUDES . '/notices/aws-issues.php';
207
208 if (file_exists(BMI_INCLUDES . '/notices/google-drive-issues.php'))
209 require_once BMI_INCLUDES . '/notices/google-drive-issues.php';
210
211 if (file_exists(BMI_INCLUDES . '/notices/wasabi-issues.php'))
212 require_once BMI_INCLUDES . '/notices/wasabi-issues.php';
213
214 require_once BMI_INCLUDES . '/notices/backupbliss.php';
215 });
216
217 $upload_issue_notice = $this->backupbliss_space_issues();
218
219 if ($upload_issue_notice) {
220 add_action("admin_notices", function() use ($upload_issue_notice) {
221 $global_warning = true;
222 $error_message = $upload_issue_notice;
223 include BMI_INCLUDES . '/dashboard/modals/bb-warning-notice.php';
224 });
225 }
226
227 }
228
229 public function incompatibility_notices() {
230
231 if (strpos(home_url(), 'instawp') === false && strpos(home_url(), 'playground.wordpress') === false) return;
232
233 $environment = 'sandbox';
234 if (strpos(home_url(), 'instawp') !== false) $environment = 'InstaWP';
235 if (strpos(home_url(), 'playground.wordpress') !== false) $environment = 'WordPress Playground';
236
237 $class = 'notice notice-warning';
238 $message = __('We noticed that you are using %s, our plugin may not work in this environment, please use %s environment instead.', 'backup-backup');
239
240 printf('<div class="%s"><p><b>Backup Migration:</b> %s</p></div>',
241 esc_attr($class),
242 sprintf(
243 esc_html($message),
244 '<i>' . $environment . '</i>',
245 '<a href="https://tastewp.com" target="_blank">TasteWP</a>'
246 )
247 );
248 }
249
250 public static function randomString($max = 16) {
251
252 $bank = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
253 $bank .= 'abcdefghijklmnopqrstuvwxyz';
254 $bank .= '0123456789';
255
256 $str = str_shuffle($bank);
257
258 while (is_numeric($str[0])) {
259 $str = str_shuffle($bank);
260 }
261
262 $str = substr($str, 0, $max);
263
264 return $str;
265
266 }
267
268 public static function isFunctionEnabled($func) {
269
270 $disabled = explode(',', ini_get('disable_functions'));
271 $isDisabled = in_array($func, $disabled);
272 if (!$isDisabled && function_exists($func)) return true;
273 else return false;
274
275 }
276
277 /**
278 * hotFixPatches - Function which fixes things for "old" users
279 *
280 * @return void
281 */
282 public function hotfix_patches() {
283
284 if (!is_admin()) return;
285
286 $current_patch = get_option('bmi_hotfixes', array());
287 if (!in_array('BMI_D20_M07_01', $current_patch)) {
288
289 $current_directory = Dashboard\bmi_get_config('STORAGE::LOCAL::PATH');
290 if (basename($current_directory) == 'backup-migration') {
291
292 require_once BMI_INCLUDES . '/ajax.php';
293 $handler_a = new BMI_Ajax(true);
294
295 $handler_a->post['directory'] = dirname($current_directory) . DIRECTORY_SEPARATOR . 'backup-migration-' . $this->randomString(10);
296 $handler_a->post['access'] = Dashboard\bmi_get_config('STORAGE::DIRECT::URL');
297
298 $res_a = $handler_a->saveStorageConfig();
299 if (isset($res_a['status']) && $res_a['status'] == 'success') {
300
301 $current_patch[] = 'BMI_D20_M07_01';
302
303 }
304
305 } else {
306
307 $current_patch[] = 'BMI_D20_M07_01';
308
309 }
310
311 }
312
313 if (!in_array('BMI_D17_M12_Y21_02', $current_patch)) {
314
315 $current_splitting_value = Dashboard\bmi_get_config('OTHER:RESTORE:SPLITTING');
316 $current_query_size = Dashboard\bmi_get_config('OTHER:DB:QUERIES');
317
318 $current_query_size = intval($current_query_size);
319 if ($current_splitting_value == 'true' || $current_splitting_value === true) {
320 $current_splitting_value = true;
321 } else {
322 $current_splitting_value = false;
323 }
324
325 if ($current_splitting_value === false || $current_query_size != 300) {
326
327 $b_db_restore_splitting = true;
328 $b_db_query_size = '2000';
329
330 $error_b = 0;
331 if (!Dashboard\bmi_set_config('OTHER:RESTORE:SPLITTING', $b_db_restore_splitting)) {
332 $error_b++;
333 }
334 if (!Dashboard\bmi_set_config('OTHER:DB:QUERIES', $b_db_query_size)) {
335 $error_b++;
336 }
337
338 if ($error_b <= 0) {
339
340 $current_patch[] = 'BMI_D17_M12_Y21_02';
341
342 }
343
344 } else {
345
346 $current_patch[] = 'BMI_D17_M12_Y21_02';
347
348 }
349
350 }
351
352 if (!in_array('BMI_D13_M08_Y23_01', $current_patch)) {
353
354 $current_direct_download_value = Dashboard\bmi_get_config('OTHER:DOWNLOAD:DIRECT');
355
356 if ($current_direct_download_value === false || $current_direct_download_value == 'false') {
357
358 $error_b = 0;
359 if (!Dashboard\bmi_set_config('OTHER:DOWNLOAD:DIRECT', true)) $error_b++;
360 if ($error_b <= 0) $current_patch[] = 'BMI_D13_M08_Y23_01';
361
362 } else $current_patch[] = 'BMI_D13_M08_Y23_01';
363
364 }
365
366 update_option('bmi_hotfixes', $current_patch);
367
368 }
369
370 public function ajax($cli = false) {
371 if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
372 if ((isset($_POST['token']) && $_POST['token'] == 'bmi' && isset($_POST['f']) && is_admin()) || $cli) {
373 try {
374
375 if (gettype($cli) != 'boolean') $cli = false;
376
377 // Extend execution time
378 if ($this->isFunctionEnabled('headers_sent') && $this->isFunctionEnabled('session_status')) {
379 if (!headers_sent() && session_status() === PHP_SESSION_DISABLED) {
380 if ($this->isFunctionEnabled('ignore_user_abort')) @ignore_user_abort(true);
381 if ($this->isFunctionEnabled('set_time_limit')) @set_time_limit(16000);
382 if ($this->isFunctionEnabled('ini_set')) {
383 @ini_set('max_execution_time', '259200');
384 @ini_set('max_input_time', '259200');
385 }
386 }
387 }
388
389 // May cause issues with auto login
390 // if (strlen(session_id()) > 0) session_write_close();
391
392 if ($this->isFunctionEnabled('register_shutdown_function')) {
393 register_shutdown_function([$this, 'execution_shutdown']);
394 }
395
396 // Require AJAX Handler
397 require_once BMI_INCLUDES . '/ajax.php';
398 $handler = new BMI_Ajax($cli);
399
400 } catch (\Exception $e) {
401
402 Logger::error('POST error:');
403 Logger::error($e);
404 if ($_POST['f'] == 'create-backup') {
405 $progress = &$GLOBALS['bmi_backup_progress'];
406 $this->handleErrorDuringBackup($e->getMessage(), $e->getFile(), $e->getLine(), $progress);
407 }
408 if ($_POST['f'] == 'restore-backup') {
409 $progress = &$GLOBALS['bmi_migration_progress'];
410 $this->handleErrorDuringRestore($e->getMessage(), $e->getFile(), $e->getLine(), $progress);
411 }
412
413 $this->res(['status' => 'error', 'error' => $e]);
414 exit;
415
416 } catch (\Throwable $e) {
417
418 Logger::error('POST error:');
419 Logger::error($e);
420 if ($_POST['f'] == 'create-backup') {
421 $progress = &$GLOBALS['bmi_backup_progress'];
422 $this->handleErrorDuringBackup($e->getMessage(), $e->getFile(), $e->getLine(), $progress);
423 }
424 if ($_POST['f'] == 'restore-backup') {
425 $progress = &$GLOBALS['bmi_migration_progress'];
426 $this->handleErrorDuringRestore($e->getMessage(), $e->getFile(), $e->getLine(), $progress);
427 }
428
429 $this->res(['status' => 'error', 'error' => $e]);
430 exit;
431
432 }
433 }
434 }
435 }
436
437 public function execution_shutdown() {
438 $err = error_get_last();
439
440 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
441 $lock_cli = BMI_BACKUPS . '/.migration_lock_cli';
442 $lock_cli_end = BMI_BACKUPS . '/.migration_lock_ended';
443 $cli_failed_lock = BMI_BACKUPS . '/.backup_lock_cli_failed';
444 $lock_cli_end_backup = BMI_BACKUPS . '/.backup_lock_cli_end';
445
446 if (file_exists($lock_cli)) @unlink($lock_cli);
447 if (file_exists($lock_cli_end)) @touch($lock_cli_end);
448 if (file_exists($cli_failed_lock)) @touch($cli_failed_lock);
449 if (file_exists($lock_cli_end_backup)) @touch($lock_cli_end_backup);
450 }
451
452 if ($err != null) {
453
454 $msg = $err['message'];
455 $file = $err['file'];
456 $line = $err['line'];
457 $type = $err['type'];
458
459 if ($type != '1' && ($type != E_ERROR && $type != E_CORE_ERROR && $type != E_COMPILE_ERROR && $type != E_USER_ERROR && $type != E_RECOVERABLE_ERROR)) {
460 Logger::error(__('There was an error before request shutdown (but it was not logged to backup/restore log)', 'backup-backup'));
461 Logger::error(__('Error message: ', 'backup-backup') . $msg);
462 Logger::error(__('Error file/line: ', 'backup-backup') . $file . '|' . $line);
463 Logger::error(__('Error handler: ', 'backup-backup') . 'init#01' . '|' . $type);
464 return;
465 }
466
467 if (isset($GLOBALS['bmi_error_handled']) && $GLOBALS['bmi_error_handled']) return;
468 if ($_POST['f'] == 'create-backup') {
469 Logger::error(__('There was an error during backup', 'backup-backup'));
470 Logger::error(__('Error message: ', 'backup-backup') . $msg);
471 Logger::error(__('Error file/line: ', 'backup-backup') . $file . '|' . $line);
472 Logger::error(__('Error handler: ', 'backup-backup') . 'init#02' . '|' . $type);
473 $progress = &$GLOBALS['bmi_backup_progress'];
474 if ($progress) {
475 $progress->log(__('Error message: ', 'backup-backup') . $msg, 'error');
476 $progress->log(__('You can get more pieces of information in troubleshooting log file.', 'backup-backup'), 'error');
477 }
478 $this->handleErrorDuringBackup($msg, $file, $line, $progress);
479
480 $fullPath = BMI_TMP . DIRECTORY_SEPARATOR;
481 array_map('unlink', glob($fullPath . '*.tmp'));
482 array_map('unlink', glob($fullPath . '*.gz'));
483 }
484
485 if ($_POST['f'] == 'restore-backup') {
486 Logger::error(__('There was an error during restore process', 'backup-backup'));
487 Logger::error(__('Error message: ', 'backup-backup') . $msg);
488 Logger::error(__('Error file/line: ', 'backup-backup') . $file . '|' . $line);
489 Logger::error(__('Error handler: ', 'backup-backup') . 'init#03' . '|' . $type);
490 $progress = &$GLOBALS['bmi_migration_progress'];
491 if ($progress) {
492 $progress->log(__('Error message: ', 'backup-backup') . $msg, 'error');
493 $progress->log(__('You can get more pieces of information in troubleshooting log file.', 'backup-backup'), 'error');
494 }
495 $this->handleErrorDuringRestore($msg, $file, $line, $progress);
496 }
497
498 $this->res(['status' => 'error', 'error' => $err]);
499 exit;
500 }
501 }
502
503 public function handleErrorDuringBackup($msg, $file, $line, &$progress) {
504 $backup = $GLOBALS['bmi_current_backup_name'];
505
506 Logger::log('Due to fatal error backup handled correctly (closed and removed).');
507 if ($progress) {
508 $progress->log(__('Something bad happened on PHP side.', 'backup-backup'), 'error');
509 $progress->log(__('Unfortunately we had to remove the backup (if partly created).', 'backup-backup'), 'error');
510 $progress->log(__('Error message: ', 'backup-backup') . $msg, 'error');
511 $progress->log(__('Error file/line: ', 'backup-backup') . $file . '|' . $line, 'error');
512 if (strpos($msg, 'execution time') !== false) {
513 $progress->log(__('Probably we could not increase the execution time, please edit your php.ini manually', 'backup-backup'), 'error');
514 }
515 }
516
517 $backup_path = BMI_BACKUPS . DIRECTORY_SEPARATOR . $backup;
518 $partial_backup_path = glob( BMI_BACKUPS . DIRECTORY_SEPARATOR . $backup . '.??????');
519 if (is_array($partial_backup_path) && count($partial_backup_path) > 0) {
520 foreach ($partial_backup_path as $key => $value) {
521 @unlink($value);
522 }
523 }
524 if (file_exists($backup_path)) @unlink($backup_path);
525 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.running');
526 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.abort');
527
528 if ($progress) {
529 $progress->log(__("Aborting backup...", 'backup-backup'), 'step');
530 $progress->log('#002', 'END-CODE');
531 $progress->end();
532 }
533 }
534
535 public function handleErrorDuringRestore($msg, $file, $line, &$progress) {
536 Logger::log('There was fatal error during restore.');
537 if ($progress) {
538 $progress->log(__('Something bad happened on PHP side.', 'backup-backup'), 'error');
539 $progress->log(__('Error message: ', 'backup-backup') . $msg, 'error');
540 $progress->log(__('Error file/line: ', 'backup-backup') . $file . '|' . $line, 'error');
541 }
542 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.migration_lock');
543 if ($progress) {
544 $progress->log(__("Aborting & unlocking restore process...", 'backup-backup'), 'step');
545 $progress->end();
546 }
547
548 $lock = BMI_BACKUPS . '/.migration_lock';
549 if (file_exists($lock)) @unlink($lock);
550 }
551
552 public function submenu() {
553
554 // Menu icon
555 $icon_url = $this->get_asset('images', 'logo-min.png');
556
557 // Main menu slug
558 $parentSlug = 'backup-migration';
559
560 // Content
561 $content = [$this, 'settings_page'];
562
563 // Main menu hook
564 add_menu_page('Backup Migration', '<span id="bmi-menu">Backup Migration</span>', 'read', $parentSlug, $content, $icon_url, 98);
565
566 // Remove default submenu by menu
567 remove_submenu_page($parentSlug, $parentSlug);
568
569 }
570
571 public function settings_action($links) {
572 $text = __('Manage', 'backup-backup');
573 $links['bmi-settings-link'] = '<a href="' . admin_url('/admin.php?page=backup-migration') . '">' . $text . '</a>';
574
575 return $links;
576 }
577
578 /**
579 * Whitelist configuration files for Security Ninja plugin.
580 *
581 * This filter callback prevents Security Ninja from deleting or flagging
582 * Backup Migration configuration files as suspicious. These files are
583 * essential for the plugin's operation and should be preserved.
584 *
585 * @param array $whitelist Existing whitelist array from Security Ninja
586 * @return array Modified whitelist array with our configuration files added
587 */
588 public function securityninja_whitelist_config_files($whitelist = array()) {
589 if (!is_array($whitelist)) {
590 $whitelist = array();
591 }
592
593 // Add all configuration files to the whitelist
594 $config_files = array(
595 BMI_CONFIG_DEFAULT,
596 BMI_STATIC_PHP_CONFIG,
597 BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '*'
598 );
599
600 // Add config directory if defined
601 if (defined('BMI_CONFIG_DIR') && BMI_CONFIG_DIR) {
602 $config_files[] = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . '*';
603 }
604
605 // Add config path if defined
606 if (defined('BMI_CONFIG_PATH') && BMI_CONFIG_PATH) {
607 $config_files[] = BMI_CONFIG_PATH;
608 }
609
610 // Merge with existing whitelist and remove duplicates
611 $whitelist = array_unique(array_merge($whitelist, $config_files));
612
613 return $whitelist;
614 }
615
616 public function include_offline() {
617
618
619 // Handle offline tasks
620 if (!class_exists('BMI_Offline')) {
621
622 if (file_exists(BMI_INCLUDES . '/offline.php')) {
623 require_once BMI_INCLUDES . '/offline.php';
624 new BMI_Offline();
625 }
626 }
627
628 }
629
630 public function settings_page() {
631
632 // Set email if does not exist
633 if (!Dashboard\bmi_get_config('OTHER:EMAIL')) {
634 Dashboard\bmi_set_config('OTHER:EMAIL', get_bloginfo('admin_email'));
635 }
636
637 // Require The HTML
638 require_once BMI_INCLUDES . '/dashboard/settings.php';
639 }
640
641 public function backupbliss_space_issues() {
642 require_once BMI_INCLUDES . '/external/backupbliss.php';
643 $backupbliss = new BackupBliss();
644 $upload_issue_notice = false;
645 if ($backupbliss->canShowFailureWarnNotice()) {
646 $upload_issue_notice = $backupbliss->getNotice("upload_issue_space");
647 }
648 return $upload_issue_notice;
649 }
650
651 public function admin_init_hook() {
652 $this->hotfix_patches();
653 if (get_option('_bmi_redirect', false)) {
654 $this->fixLitespeed();
655 delete_option('_bmi_redirect');
656 wp_safe_redirect(admin_url('admin.php?page=backup-migration'));
657 }
658 }
659
660 public function admin_notices() {
661 if (get_current_screen()->id != 'toplevel_page_backup-migration' && get_option('bmi_display_email_issues', false)) {
662 ?>
663 <div class="notice notice-warning">
664 <p>
665 <?php _e('There was an error during automated backup, please', 'backup-backup'); ?>
666 <?php echo '<a href="' . admin_url('/admin.php?page=backup-migration') . '">' . __('check that.', 'backup-backup') . '</a>'; ?>
667 </p>
668 </div>
669 <?php
670 }
671 }
672
673 public function handle_crons() {
674 if (Dashboard\bmi_get_config('CRON:ENABLED') !== true) return;
675
676 $time = get_option('bmi_backup_check', 0);
677 if ((time() - $time) > 60) {
678 update_option('bmi_backup_check', time());
679
680 do_action('bmi_handle_cron_check');
681 }
682 }
683
684 /**
685 * Retrieves a list of active security plugins detected on the site.
686 *
687 * This function checks the list of currently active plugins and identifies
688 * common security plugins by their slugs. It returns a key-value array
689 * where keys are plugin slugs and values are their human-readable names.
690 *
691 * Supported plugins:
692 * - Wordfence
693 * - Sucuri Security
694 *
695 * @return array<string, string> Associative array of detected security plugins.
696 * Format: [ 'plugin_slug' => 'Plugin Name' ]
697 */
698 public static function get_active_security_plugins() {
699 $active_plugins = [];
700 $plugins = get_option('active_plugins', []);
701 if (is_array($plugins) && count($plugins) > 0) {
702 foreach ($plugins as $plugin) {
703 if (strpos($plugin, 'wordfence') !== false) {
704 $active_plugins['wordfence'] = 'Wordfence';
705 } elseif (strpos($plugin, 'security-ninja') !== false) {
706 $active_plugins['security-ninja'] = 'Security Ninja';
707 }
708 }
709 }
710 return $active_plugins;
711 }
712
713 public static function email_error($msg) {
714 Logger::log('Displaying some issues about email sending...');
715 update_option('bmi_display_email_issues', $msg);
716 }
717
718 public function backup_inproper_time($should_time) {
719 $plan_file = BMI_TMP . DIRECTORY_SEPARATOR . '.plan';
720 if (!file_exists($plan_file) || intval($should_time) < 1234567890) return;
721
722 $currentDate = date('Y-m-d');
723 if (get_option('bmi_last_email_notification', false) == $currentDate) {
724 return;
725 }
726
727 Logger::log('Sending notification about backup being late');
728 $email = Dashboard\bmi_get_config('OTHER:EMAIL') != false ? Dashboard\bmi_get_config('OTHER:EMAIL') : get_bloginfo('admin_email');
729 $subject = Dashboard\bmi_get_config('OTHER:EMAIL:TITLE');
730 $message = __("Automatic backup was not on time because there was no traffic on the site.", 'backup-backup') . "\n";
731 $message .= __("Backup was made on: ", 'backup-backup') . date('Y-m-d H:i:s') . __(', but should be on: ', 'backup-backup') . date('Y-m-d H:i:s', $should_time);
732 $message .= ' ' . __("(server time)", 'backup-backup');
733
734 Logger::debug($message);
735 if (!self::send_notification_mail($email, $subject, $message)) {
736 $issue = __("Couldn't send mail to you, please check server configuration.", 'backup-backup') . '<br>';
737 $issue .= '<b>' . __("Message you missed because of this: ", 'backup-backup') . '</b>' . $message;
738 self::email_error($issue);
739 }
740 }
741
742 public function handle_cron_check() {
743
744 if (Dashboard\bmi_get_config('CRON:ENABLED') !== true) return;
745
746 $now = time();
747 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.last')) {
748 $last = @file_get_contents(BMI_TMP . DIRECTORY_SEPARATOR . '.last');
749 $last_status = explode('.', $last)[0];
750 $last_time = intval(explode('.', $last)[1]);
751 } else {
752 $last_time = 0;
753 $last_status = 0;
754 }
755
756 if (file_exists(BMI_TMP . DIRECTORY_SEPARATOR . '.plan')) {
757 $plan = intval(@file_get_contents(BMI_TMP . DIRECTORY_SEPARATOR . '.plan'));
758 if ($last_time < $plan && ((time() - $plan) > 7200)) {
759 if ($last_status !== '0') {
760 if (!wp_next_scheduled('bmi_do_backup_right_now')) {
761 wp_schedule_single_event(time(), 'bmi_do_backup_right_now');
762 }
763 }
764 }
765 }
766
767 }
768
769 public function get_next_cron($curr = false) {
770 if ($curr === false) {
771 $curr = time();
772 }
773
774 $time = Crons::calculate_date([
775 'type' => Dashboard\bmi_get_config('CRON:TYPE'),
776 'week' => Dashboard\bmi_get_config('CRON:WEEK'),
777 'day' => Dashboard\bmi_get_config('CRON:DAY'),
778 'hour' => Dashboard\bmi_get_config('CRON:HOUR'),
779 'minute' => Dashboard\bmi_get_config('CRON:MINUTE')
780 ], $curr);
781
782 return $time;
783 }
784
785 public function handle_cron_error($e) {
786 Logger::error(__("Automatic backup failed at time: ", 'backup-backup') . date('Y-m-d, H:i:s'));
787 if (is_object($e) || is_array($e)) {
788 Logger::error('Error: ' . $e->getMessage());
789 } else {
790 Logger::error('Error: ' . $e);
791 }
792
793 $notis = Dashboard\bmi_get_config('OTHER:EMAIL:NOTIS');
794 if (in_array($notis, [true, 'true'])) {
795 $email = Dashboard\bmi_get_config('OTHER:EMAIL') != false ? Dashboard\bmi_get_config('OTHER:EMAIL') : get_bloginfo('admin_email');
796 $subject = Dashboard\bmi_get_config('OTHER:EMAIL:TITLE');
797 $message = __("There was an error during automatic backup, please check the logs.", 'backup-backup');
798 if (is_string($e)) {
799 $message .= "\nError: " . $e;
800 }
801
802 if (!self::send_notification_mail($email, $subject, $message, true)) {
803 $issue = __("Couldn't send mail to you, please check server configuration.", 'backup-backup') . '<br>';
804 $issue .= '<b>' . __("Message you missed because of this: ", 'backup-backup') . '</b>' . $message;
805 self::email_error($issue);
806 }
807 }
808
809 if (file_exists(BMI_BACKUPS . '/.cron')) {
810 @unlink(BMI_BACKUPS . '/.cron');
811 }
812 }
813
814 public static function send_notification_mail($email, $subject, $message, $force = false) {
815
816 $currentDate = date('Y-m-d');
817 if (get_option('bmi_last_email_notification', false) == $currentDate && $force === false) {
818 Logger::log(__("Disallowing to send mail as today we already sent one.", 'backup-backup'));
819 return;
820 }
821
822 update_option('bmi_last_email_notification', $currentDate);
823
824 $email_fail = __("Could not send the email notification about that fail", 'backup-backup');
825
826 try {
827
828 if (wp_mail($email, $subject, $message)) {
829 Logger::log(__("Sent email notification to: ", 'backup-backup') . $email);
830
831 return true;
832 } else {
833 Logger::error($email_fail);
834 self::email_error(__("Couldn't send notification via email, please check the email and your server settings.", 'backup-backup'));
835
836 return false;
837 }
838
839 } catch (\Exception $e) {
840 Logger::error($email_fail);
841 self::email_error(__("Couldn't send notification via email due to error, please check plugin logs for more details.", 'backup-backup'));
842
843 return false;
844 } catch (\Throwable $e) {
845 Logger::error($email_fail);
846 self::email_error(__("Couldn't send notification via email due to error, please check plugin logs for more details.", 'backup-backup'));
847
848 return false;
849 }
850 }
851
852 public static function handle_after_cron() {
853 require_once BMI_INCLUDES . DIRECTORY_SEPARATOR . 'scanner' . DIRECTORY_SEPARATOR . 'backups.php';
854 $backups = new Backups();
855 $availableBackups = $backups->getAvailableBackups();
856 $list = $availableBackups['local'];
857
858 $cron_list = [];
859 $cron_dates = [];
860 $sortedMD5s = [];
861 foreach ($list as $key => $value) {
862 if ($list[$key][6] == true) {
863 if ($list[$key][5] == 'unlocked') {
864 $cron_list[$list[$key][1]] = $list[$key][0];
865 $cron_dates[] = $list[$key][1];
866 $sortedMD5s[] = [$list[$key][1], $list[$key][7]];
867 }
868 }
869 }
870
871 usort($cron_dates, function ($a, $b) {
872 return (strtotime($a) < strtotime($b)) ? -1 : 1;
873 });
874
875 $cron_dates = array_slice($cron_dates, 0, -(intval(Dashboard\bmi_get_config('CRON:KEEP'))));
876 foreach ($cron_dates as $key => $value) {
877 $name = $cron_list[$cron_dates[$key]];
878 $name = explode('#%&', $name)[1];
879 Logger::log(__("Removing backup due to keep rules: ", 'backup-backup') . $name);
880 @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . $name);
881 }
882
883 // Auto External Removal
884 $sortedMD5s = [];
885 $externalStorages = ['gdrive', 'dropbox', 'onedrive', 'FTP', 'sftp', 'aws', 'wasabi', 'backupbliss'];
886 foreach ($externalStorages as $storage) {
887 if (isset($availableBackups['external'][$storage])) {
888 $storageList = $availableBackups['external'][$storage];
889 foreach ($storageList as $md5 => $data) {
890 if ($storageList[$md5][6] == true && $storageList[$md5][5] == 'unlocked') {
891 $sortedMD5s[] = [$storageList[$md5][1], $md5];
892 }
893 }
894 }
895 }
896 $sortedMD5s = array_intersect_key($sortedMD5s, array_unique(array_map('serialize', $sortedMD5s)));
897
898 usort($sortedMD5s, function ($a, $b) {
899 return (strtotime($a[0]) < strtotime($b[0])) ? -1 : 1;
900 });
901
902 $sortedMD5s = array_slice($sortedMD5s, 0, -(intval(Dashboard\bmi_get_config('CRON:KEEP'))));
903 foreach ($sortedMD5s as $index => $data) {
904 $md5 = $data[1];
905
906 do_action('bmi_premium_remove_backup_file', $md5);
907 do_action('bmi_premium_remove_backup_json_file', $md5 . '.json');
908 }
909 }
910
911 public function set_last_cron($status, $time) {
912 $file = BMI_TMP . DIRECTORY_SEPARATOR . '.last';
913 file_put_contents($file, $status . '.' . $time);
914 }
915
916 public function readFileSensitive($file) {
917 if (!file_exists($file)) {
918 echo '';
919 return;
920 }
921
922 $file = new \SplFileObject($file);
923 $file->seek($file->getSize());
924 $total_lines = $file->key() + 1;
925
926 $current_directory = Dashboard\bmi_get_config('STORAGE::LOCAL::PATH');
927 $backups_path = $this->fixSlashes($current_directory . DIRECTORY_SEPARATOR . 'backups');
928 $scanned_directory_all = array_diff(scandir($backups_path), ['..', '.']);
929 $scanned_directory = array_values(preg_grep('/((.*).zip)/i', $scanned_directory_all));
930
931 for ($i = 0; $i < $total_lines; ++$i) {
932
933 $file->seek($i);
934 $line = $this->escapeSensitive($file->current(), $current_directory, $scanned_directory);
935
936 echo $line;
937 unset($line);
938
939 }
940
941 }
942
943 public function escapeSensitive($line, $current_directory, $scanned_directory) {
944
945 global $table_prefix;
946
947 $dir_name = basename($current_directory);
948
949 $line = preg_replace('/\:\ ((.*)\.zip)/', ': *****.zip', $line);
950 $line = preg_replace('/(\"filename\":(.*)\.zip)\"/', '"filename": "*****.zip"', $line);
951 $line = preg_replace('/\"http(.*)\"/', '"***site_url***"', $line);
952 $line = preg_replace('/\:\ http(.*)\n/', ": ***site_url***\n", $line);
953 $line = preg_replace('/\"\d{10}\"/', '"***secret_login***"', $line);
954 $line = str_replace(ABSPATH, '***ABSPATH***/', $line);
955 $line = str_replace($dir_name, '***backup_path***', $line);
956 $line = str_replace($table_prefix, '***_', $line);
957 $line = preg_replace('/^(.*?&sk=).*$/', '$1***', $line);
958
959 for ($i = 0; $i < sizeof($scanned_directory); ++$i) {
960
961 $backup_name = $scanned_directory[$i];
962 $line = str_replace($backup_name, '***some_backup***', $line);
963
964 }
965
966 return $line;
967
968 }
969
970 public function handle_cron_backup() {
971
972 $plan_file = BMI_TMP . DIRECTORY_SEPARATOR . '.plan';
973 $last_file = BMI_TMP . DIRECTORY_SEPARATOR . '.last';
974
975 // Abort if disabled
976 if (Dashboard\bmi_get_config('CRON:ENABLED') !== true) {
977
978
979 if (file_exists($plan_file)) @unlink($plan_file);
980 if (file_exists($last_file)) @unlink($last_file);
981
982 return;
983
984 }
985
986 if (!file_exists($plan_file)) return;
987
988 // Planned time
989 $plan = intval(@file_get_contents(BMI_TMP . DIRECTORY_SEPARATOR . '.plan'));
990
991 // Check difference
992 if ((time() - $plan) > 3600) {
993 Logger::log('Backup failed to run on proper time, but running now.');
994 Logger::log('Planned time: ' . date('Y-m-d H:i:s', $plan));
995 $this->backup_inproper_time($plan);
996 }
997
998 // Now
999 $now = time();
1000 $this->set_last_cron('0', $now);
1001
1002 // Extend execution time
1003 if ($this->isFunctionEnabled('headers_sent') && $this->isFunctionEnabled('session_status')) {
1004 if (!headers_sent() && session_status() === PHP_SESSION_DISABLED) {
1005 if ($this->isFunctionEnabled('ignore_user_abort')) @ignore_user_abort(true);
1006 if ($this->isFunctionEnabled('set_time_limit')) @set_time_limit(16000);
1007 if ($this->isFunctionEnabled('ini_set')) {
1008 @ini_set('max_execution_time', '259200');
1009 @ini_set('max_input_time', '259200');
1010 }
1011 }
1012 }
1013
1014 if (strlen(session_id()) > 0) session_write_close();
1015
1016 Logger::log(__("Automatic backup called at time: ", 'backup-backup') . date('Y-m-d, H:i:s'));
1017
1018 try {
1019 require_once BMI_INCLUDES . '/ajax.php';
1020 $isBackup = (file_exists(BMI_BACKUPS . '/.running') && (time() - filemtime(BMI_BACKUPS . '/.running')) <= 65) ? true : false;
1021 $isCron = (file_exists(BMI_BACKUPS . '/.cron') && (time() - filemtime(BMI_BACKUPS . '/.cron')) <= 65) ? true : false;
1022 if ($isCron) {
1023 return;
1024 }
1025
1026 if ($isBackup) {
1027 $this->handle_cron_error(__("Could not make the backup: Backup already running, please wait till it complete.", 'backup-backup'));
1028 $this->set_last_cron('2', $now);
1029 } else {
1030 touch(BMI_BACKUPS . '/.cron');
1031
1032 if (!defined('BMI_DOING_SCHEDULED_BACKUP')) {
1033 define('BMI_DOING_SCHEDULED_BACKUP', true);
1034 }
1035
1036 $handler = new BMI_Ajax();
1037 $handler->resetLatestLogs();
1038 $backup = $handler->prepareAndMakeBackup(true);
1039
1040 if ($backup['status'] == 'success') {
1041 if (isset($backup['filename'])) {
1042 Logger::log(__("Automatic backup successed: ", 'backup-backup') . $backup['filename']);
1043 } else {
1044 Logger::log(__("Automatic backup successed", 'backup-backup'));
1045 }
1046 $this->set_last_cron('1', $now);
1047 } elseif ($backup['status'] == 'background') {
1048 Logger::log(__('Scheduled backup is running in background: ', 'backup-backup') . $backup['filename']);
1049 $this->set_last_cron('1', $now);
1050 } elseif ($backup['status'] == 'msg') {
1051 $this->handle_cron_error($backup['why']);
1052 $this->set_last_cron('3', $now);
1053 } else {
1054 $this->handle_cron_error(__("Could not make the backup due to internal server error.", 'backup-backup'));
1055 $this->set_last_cron('4', $now);
1056 }
1057 }
1058 } catch (\Exception $e) {
1059 $this->handle_cron_error($e);
1060 $this->set_last_cron('5', $now);
1061 } catch (\Throwable $e) {
1062 $this->handle_cron_error($e);
1063 $this->set_last_cron('5', $now);
1064 }
1065
1066 $this->handle_after_cron();
1067
1068 if (file_exists(BMI_BACKUPS . '/.cron')) {
1069 @unlink(BMI_BACKUPS . '/.cron');
1070 }
1071 require_once BMI_INCLUDES . '/cron/handler.php';
1072 $time = $this->get_next_cron();
1073
1074 wp_clear_scheduled_hook('bmi_do_backup_right_now');
1075 wp_schedule_single_event($time, 'bmi_do_backup_right_now');
1076
1077 $file = BMI_TMP . DIRECTORY_SEPARATOR . '.plan';
1078 file_put_contents($file, $time);
1079 }
1080
1081 public function enqueue_scripts() {
1082
1083 // Global
1084 if (in_array(get_current_screen()->id, ['toplevel_page_backup-migration', 'plugins'])) { ?>
1085 <script type="text/javascript">
1086 let stars = '<?php echo plugin_dir_url(BMI_ROOT_FILE); ?>' + 'admin/images/stars.gif';
1087 let css_star = "background:url('" + stars + "')";
1088 document.addEventListener("DOMContentLoaded", function(event) {
1089 jQuery('[data-slug="backup-migration-pro"]').find('strong').html('<span>Backup Migration <b style="color: orange; ' + css_star + '">Pro</b></span>');
1090 jQuery('[data-slug="backup-backup-pro"]').find('strong').html('<span>Backup Migration <b style="color: orange; ' + css_star + '">Pro</b></span>');
1091 });
1092 </script>
1093 <?php }
1094
1095 // Only for BM Settings
1096 if (!in_array(get_current_screen()->id, ['toplevel_page_backup-migration', 'update-core', 'plugins', 'plugin-install', 'themes','customize', 'plugins-network', 'plugin-install-network', 'themes-network']) && $this->backupbliss_space_issues() === false) return;
1097 wp_enqueue_script('backup-migration-script', $this->get_asset('js', 'backup-migration.min.js'), ['jquery'], BMI_VERSION, true);
1098 wp_localize_script('backup-migration-script', 'bmiVariables', [
1099 'nonce' => wp_create_nonce('backup-migration-ajax'),
1100 'stgLoading' => __('Loading, please wait...', 'backup-backup'),
1101 'stgStagingDefaultName' => __('staging', 'backup-backup'),
1102 'urlCopies' => __('URL copied successfully', 'backup-backup'),
1103 'isBeforeUpdateEnabled' => dashboard\bmi_get_config('OTHER:TRIGGER:BEFORE:UPDATES') ? 'true' : 'false',
1104 'maxUploadSize' => $this->getMaxUploadSize()
1105 ]);
1106
1107 }
1108
1109 public function phpSizeToB($phpSize) {
1110
1111 $sSuffix = strtoupper(substr($phpSize, -1));
1112
1113 if (!in_array($sSuffix, array('P','T','G','M','K'))) {
1114 return (int) $phpSize;
1115 }
1116
1117 $iValue = substr($phpSize, 0, -1);
1118 switch ($sSuffix) {
1119 case 'P': $iValue *= 1024;
1120 case 'T': $iValue *= 1024;
1121 case 'G': $iValue *= 1024;
1122 case 'M': $iValue *= 1024;
1123 case 'K': $iValue *= 1024;
1124 break;
1125 }
1126
1127 return (int) $iValue;
1128
1129 }
1130
1131 public function getMaxUploadSize() {
1132 $ten = (10 * 1024 * 1024);
1133 $max = min($this->phpSizeToB(ini_get('post_max_size')), $this->phpSizeToB(ini_get('upload_max_filesize')), $ten);
1134 return intval($max / 1024 / 1024);
1135 }
1136
1137 public function enqueue_styles() {
1138
1139 // Global styles
1140 wp_enqueue_style('backup-migration-style-icon', $this->get_asset('css', 'bmi-plugin-icon.min.css'), [], BMI_VERSION);
1141
1142 // Only for BM Settings and Update Core page and if there's no backupbliss space issues do not include the stylesheet.
1143 if (!in_array(get_current_screen()->id, ['toplevel_page_backup-migration', 'update-core', 'plugins', 'plugin-install', 'themes','customize', 'plugins-network', 'plugin-install-network', 'themes-network']) && $this->backupbliss_space_issues() === false) return;
1144
1145 // Enqueue the style
1146 wp_enqueue_style('backup-migration-style', $this->get_asset('css', 'bmi-plugin.min.css'), [], BMI_VERSION);
1147
1148 }
1149
1150 public function handle_after_actions() {
1151
1152 // Handle After Migration actions
1153 $afterMigrationLock = BMI_TMP . DIRECTORY_SEPARATOR . '.migrationFinished';
1154 if (file_exists($afterMigrationLock)) {
1155 if (strpos(site_url(), 'tastewp') !== false) {
1156
1157 if (function_exists('wp_load_alloptions')) {
1158 wp_load_alloptions(true);
1159 }
1160
1161 update_option('__tastewp_redirection_performed', true);
1162 update_option('auto_smart_tastewp_redirect_performed', 1);
1163 update_option('tastewp_auto_activated', true);
1164 update_option('__tastewp_sub_requested', true);
1165
1166 }
1167
1168 unlink($afterMigrationLock);
1169 }
1170
1171 }
1172
1173 public function handle_downloading() {
1174 global $wpdb;
1175 @error_reporting(0);
1176 $autologin_file = BMI_BACKUPS . '/.autologin';
1177 $ip = '127.0.0.1';
1178 if (isset($_SERVER['HTTP_CLIENT_IP'])) {
1179 $ip = $_SERVER['HTTP_CLIENT_IP'];
1180 } else {
1181 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
1182 $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
1183 }
1184 if ($ip === false) {
1185 if (isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
1186 }
1187 }
1188 $allowed = ['BMI_BACKUP', 'BMI_BACKUP_LOGS', 'PROGRESS_LOGS', 'AFTER_RESTORE', 'CURL_BACKUP'];
1189 $get_bmi = !empty($_GET['backup-migration']) ? sanitize_text_field($_GET['backup-migration']) : false;
1190 $get_bid = !empty($_GET['backup-id']) ? sanitize_text_field($_GET['backup-id']) : false;
1191 $get_pid = !empty($_GET['progress-id']) ? sanitize_text_field($_GET['progress-id']) : false;
1192 $get_is_uncensored = !empty($_GET['uncensored']) ? sanitize_text_field($_GET['uncensored']) : false;
1193 $crons_enabled = !empty($_GET['crons']) ? sanitize_text_field($_GET['crons']) : false;
1194 $secret_key = !empty($_GET['sk']) ? sanitize_text_field($_GET['sk']) : false;
1195
1196 if (isset($get_bmi) && in_array($get_bmi, $allowed)) {
1197 if (isset($get_bid) && strlen($get_bid) > 0 && isset($secret_key) && $secret_key === Dashboard\bmi_get_config('REQUEST:SECRET')) {
1198 $type = $get_bmi;
1199
1200 if ($type == 'AFTER_RESTORE' && isset($get_pid)) {
1201 if (file_exists($autologin_file)) {
1202 $autoLoginMD = file_get_contents($autologin_file);
1203 $autoLoginMD = explode('_', $autoLoginMD);
1204 $aID = intval($autoLoginMD[0]);
1205 $aID2 = intval($autoLoginMD[0]) - 1;
1206 $aID3 = intval($autoLoginMD[0]) + 1;
1207 $aID4 = intval($autoLoginMD[0]) + 2;
1208 $aID5 = intval($autoLoginMD[0]) + 3;
1209 $aID6 = intval($autoLoginMD[0]) + 4;
1210 $aIP = $autoLoginMD[1];
1211 $aIZ = $autoLoginMD[2];
1212
1213 // Allow 1 second delay
1214 $timeIsProper = false;
1215 if ($aID === intval($get_bid)) $timeIsProper = true;
1216 if ($aID2 === intval($get_bid)) $timeIsProper = true;
1217 if ($aID3 === intval($get_bid)) $timeIsProper = true;
1218 if ($aID4 === intval($get_bid)) $timeIsProper = true;
1219 if ($aID5 === intval($get_bid)) $timeIsProper = true;
1220 if ($aID6 === intval($get_bid)) $timeIsProper = true;
1221
1222 if ($timeIsProper && $aIP === $ip && trim($aIZ) === $get_pid) {
1223 $query = new \WP_User_Query(['role' => 'Administrator', 'count_total' => false, 'fields' => 'all']);
1224 $sqlres = $wpdb->get_results($query->request);
1225
1226 if (sizeof($sqlres) > 0 && isset($sqlres[0]->ID) && isset($sqlres[0]->user_login)) {
1227
1228 $user = $sqlres[0];
1229 $adminID = $sqlres[0]->ID;
1230 $adminLogin = $sqlres[0]->user_login;
1231
1232 remove_all_actions('wp_login', -1000);
1233 wp_load_alloptions(true);
1234 clean_user_cache(get_current_user_id());
1235 clean_user_cache($adminID);
1236 wp_clear_auth_cookie();
1237 wp_set_current_user($adminID, $adminLogin);
1238 wp_set_auth_cookie($adminID, 1, is_ssl());
1239 do_action('wp_login', $adminLogin, $user);
1240 update_user_caches($user);
1241
1242 }
1243 $cronsEnabledParam = $crons_enabled ? "&crons=true" : "";
1244
1245 $url = admin_url('admin.php?page=backup-migration' . $cronsEnabledParam);
1246 header('Location: ' . $url);
1247
1248 @unlink($autologin_file);
1249 exit;
1250 }
1251 }
1252
1253 } else if ($type == 'BMI_BACKUP') {
1254 if (Dashboard\bmi_get_config('STORAGE::DIRECT::URL') === 'true' || current_user_can('administrator')) {
1255
1256 $backupname = $get_bid;
1257 $file = $this->fixSlashes(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupname);
1258
1259 $outsideDir = false;
1260 if (!(file_exists($file) && $this->fixSlashes(dirname($file)) == $this->fixSlashes(BMI_BACKUPS))) {
1261 $outsideDir = true;
1262 }
1263
1264 if ($outsideDir || strpos(strtolower(mime_content_type($file)), 'zip') === false) {
1265 header('HTTP/1.0 423 Locked');
1266 _e("Incorrect usage of the query request.", 'backup-backup');
1267 exit;
1268 }
1269
1270 if (Dashboard\bmi_get_config('OTHER:DOWNLOAD:DIRECT') == 'true') {
1271 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.htaccess')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.htaccess');
1272 if (file_exists(dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . '.htaccess')) @unlink(dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . '.htaccess');
1273 $wpcontent = trailingslashit(WP_CONTENT_DIR);
1274 $wpcs = strlen($wpcontent);
1275 $url = $this->fixSlashes(content_url(substr($file, $wpcs)), '/');
1276 $path = wp_redirect($url);
1277 exit;
1278 }
1279
1280 // Prevent parent directory downloading
1281 if (ob_get_contents()) ob_end_clean();
1282
1283 if ($this->isFunctionEnabled('ignore_user_abort')) @ignore_user_abort(true);
1284 if ($this->isFunctionEnabled('set_time_limit')) @set_time_limit(16000);
1285 if ($this->isFunctionEnabled('headers_sent') && $this->isFunctionEnabled('session_status')) {
1286 if (!headers_sent() && session_status() === PHP_SESSION_DISABLED) {
1287 if ($this->isFunctionEnabled('ini_set')) {
1288 @ini_set('max_execution_time', '259200');
1289 @ini_set('max_input_time', '259200');
1290 @ini_set('memory_limit', '-1');
1291 if (@ini_get('zlib.output_compression')) {
1292 @ini_set('zlib.output_compression', 'Off');
1293 }
1294 }
1295 }
1296 }
1297
1298 if (strlen(session_id()) > 0) session_write_close();
1299
1300 $fp = @fopen($file, 'rb');
1301
1302 // header('X-Sendfile: ' . $file);
1303 // header('X-Sendfile-Type: X-Accel-Redirect');
1304 // header('X-Accel-Redirect: ' . $file);
1305 // header('X-Accel-Buffering: yes');
1306 header('Expires: 0');
1307 header('Pragma: public');
1308 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1309 header('Content-Disposition: attachment; filename="' . $backupname . '"');
1310 header('Content-Type: application/octet-stream');
1311 header('Content-Transfer-Encoding: binary');
1312 header('Content-Length: ' . filesize($file));
1313 header('Content-Description: File Transfer');
1314 http_response_code(200);
1315
1316 if (ob_get_level()) ob_end_clean();
1317
1318 fpassthru($fp);
1319 fclose($fp);
1320 exit;
1321
1322 } else {
1323 if (ob_get_contents()) ob_end_clean();
1324 header('HTTP/1.0 423 Locked');
1325 if (ob_get_level()) ob_end_clean();
1326 echo __("Backup download is restricted (allowed for admins only).", 'backup-backup');
1327 exit;
1328 }
1329 } else if ($type == 'BMI_BACKUP_LOGS') {
1330
1331 // Only Admin can download backup logs
1332 if (!(current_user_can('administrator') || current_user_can('do_backups'))) return;
1333
1334 if (ob_get_contents()) ob_end_clean();
1335 $backupname = $get_bid;
1336 $file = $this->fixSlashes(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupname);
1337
1338 // Prevent parent directory downloading
1339 if (file_exists($file) && $this->fixSlashes(dirname($file)) == $this->fixSlashes(BMI_BACKUPS)) {
1340 require_once BMI_INCLUDES . '/zipper/zipping.php';
1341
1342 $zipper = new Zipper();
1343 $logs = $zipper->getZipFileContentPlain($file, 'bmi_logs_this_backup.log');
1344 header('Content-Type: text/plain');
1345
1346 if ($logs) {
1347 header('Content-Disposition: attachment; filename="' . substr($backupname, 0, -4) . '.log"');
1348 http_response_code(200);
1349 if (ob_get_level()) ob_end_clean();
1350
1351 $logs = explode('\n', $logs);
1352 $current_directory = Dashboard\bmi_get_config('STORAGE::LOCAL::PATH');
1353 $backups_path = $this->fixSlashes($current_directory . DIRECTORY_SEPARATOR . 'backups');
1354 $scanned_directory_all = array_diff(scandir($backups_path), ['..', '.']);
1355 $scanned_directory = array_values(preg_grep('/((.*).zip)/i', $scanned_directory_all));
1356
1357 for ($i = 0; $i < sizeof($logs); ++$i) {
1358
1359 $line = $logs[$i];
1360 echo $this->escapeSensitive($line, $current_directory, $scanned_directory) . "\n";
1361
1362 }
1363
1364 exit;
1365 } else {
1366 if (ob_get_level()) ob_end_clean();
1367 header('HTTP/1.0 404 Not found');
1368 echo __("There was an error during getting logs, this file is not right log file.", 'backup-backup');
1369 exit;
1370 }
1371 }
1372
1373 } else if ($type == 'PROGRESS_LOGS') {
1374 $allowed_progress = [
1375 'latest_full.log',
1376 'latest.log',
1377 'latest_progress.log',
1378 'latest_migration_full.log',
1379 'latest_migration.log',
1380 'latest_migration_progress.log',
1381 'latest_staging_full.log',
1382 'latest_staging.log',
1383 'latest_staging_progress.log',
1384 'complete_logs.log'
1385 ];
1386 if (isset($get_pid) && in_array($get_pid, $allowed_progress)) {
1387
1388 $restricted_progress = ['complete_logs.log'];
1389 if (in_array($get_pid, $restricted_progress)) {
1390
1391 // Only Admin can download backup logs
1392 if (!(current_user_can('administrator') || current_user_can('do_backups'))) return;
1393
1394 }
1395
1396 header('Content-Type: text/plain');
1397 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1398 http_response_code(200);
1399 if (ob_get_contents()) ob_end_clean();
1400 if ($get_pid == 'complete_logs.log') {
1401 $file = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.log';
1402 if (ob_get_level()) ob_end_clean();
1403 $this->readFileSensitive($file);
1404 exit;
1405 } else if ($get_pid == 'latest_full.log') {
1406 $progress = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_progress.log';
1407 $logs = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest.log';
1408 if ((file_exists($progress) && file_exists($logs) && ((time() - filemtime($progress)) < (60 * 1))) || current_user_can('administrator')) {
1409 if (ob_get_level()) ob_end_clean();
1410 readfile($progress);
1411 echo "\n";
1412 if (isset($get_is_uncensored) && $get_is_uncensored && current_user_can('administrator')) readfile($logs);
1413 else $this->readFileSensitive($logs);
1414 exit;
1415 } else {
1416 if (file_exists($progress) && !(time() - filemtime($progress)) < (60 * 1)) {
1417 if (ob_get_level()) ob_end_clean();
1418 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1419 echo __("Human readable: file expired.", 'backup-backup');
1420 exit;
1421 } else {
1422 if (ob_get_level()) ob_end_clean();
1423 echo '';
1424 exit;
1425 }
1426 }
1427 } else if ($get_pid == 'latest_migration_full.log') {
1428 $progress = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_migration_progress.log';
1429 $logs = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_migration.log';
1430 if ((file_exists($progress) && file_exists($logs) && ((time() - filemtime($progress)) < (60 * 1))) || current_user_can('administrator')) {
1431 if (ob_get_level()) ob_end_clean();
1432 readfile($progress);
1433 echo "\n";
1434 if (isset($get_is_uncensored) && $get_is_uncensored && current_user_can('administrator')) readfile($logs);
1435 else $this->readFileSensitive($logs);
1436 exit;
1437 } else {
1438 if (file_exists($progress) && !(time() - filemtime($progress)) < (60 * 1)) {
1439 if (ob_get_level()) ob_end_clean();
1440 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1441 echo __("Human readable: file expired.", 'backup-backup');
1442 exit;
1443 } else {
1444 if (ob_get_level()) ob_end_clean();
1445 echo '';
1446 exit;
1447 }
1448 }
1449 } else if ($get_pid == 'latest_staging_full.log') {
1450 $progress = BMI_STAGING . DIRECTORY_SEPARATOR . 'latest_staging_progress.log';
1451 $logs = BMI_STAGING . DIRECTORY_SEPARATOR . 'latest_staging.log';
1452 if ((file_exists($progress) && file_exists($logs) && ((time() - filemtime($progress)) < (60 * 1))) || current_user_can('administrator')) {
1453 if (ob_get_level()) ob_end_clean();
1454 readfile($progress);
1455 echo "\n";
1456 $this->readFileSensitive($logs);
1457 exit;
1458 } else {
1459 if (file_exists($progress) && !(time() - filemtime($progress)) < (60 * 1)) {
1460 if (ob_get_level()) ob_end_clean();
1461 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1462 echo __("Human readable: file expired.", 'backup-backup');
1463 exit;
1464 } else {
1465 if (ob_get_level()) ob_end_clean();
1466 echo '';
1467 exit;
1468 }
1469 }
1470 } else {
1471 $file = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . $get_pid;
1472 if ($get_pid == 'latest_staging.log') $file = BMI_STAGING . DIRECTORY_SEPARATOR . $get_pid;
1473 if ($get_pid == 'latest_staging_progress.log') $file = BMI_STAGING . DIRECTORY_SEPARATOR . $get_pid;
1474 if (file_exists($file) && (((time() - filemtime($file)) < (60 * 1)) || current_user_can('administrator'))) {
1475 if (ob_get_level()) ob_end_clean();
1476
1477 if (isset($get_is_uncensored) && $get_is_uncensored && current_user_can('administrator')) readfile($file);
1478 else $this->readFileSensitive($file);
1479
1480 echo "\n";
1481 if ($get_pid == 'latest.log') $file = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_progress.log';
1482 if ($get_pid == 'latest_migration.log') $file = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_migration_progress.log';
1483 if ($get_pid == 'latest_staging.log') $file = BMI_STAGING . DIRECTORY_SEPARATOR . 'latest_staging_progress.log';
1484 echo __("[DOWNLOAD GENERATED] File downloaded on (server time): ", 'backup-backup') . date('Y-m-d H:i:s') . "\n";
1485 echo __("[DOWNLOAD GENERATED] Last update (seconds): ", 'backup-backup') . (time() - filemtime($file)) . __(" seconds ago ", 'backup-backup') . "\n";
1486 echo __("[DOWNLOAD GENERATED] Last update (date): ", 'backup-backup') . date('Y-m-d H:i:s', filemtime($file)) . " \n";
1487 exit;
1488 } else {
1489 if (file_exists($file) && !(time() - filemtime($file)) < (60 * 1)) {
1490 if (ob_get_level()) ob_end_clean();
1491 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1492 echo __("Human readable: file expired.", 'backup-backup');
1493 exit;
1494 } else {
1495 if (ob_get_level()) ob_end_clean();
1496 echo '';
1497 exit;
1498 }
1499 }
1500 }
1501 }
1502 } else if ($type == 'CURL_BACKUP') {
1503
1504 // We tried to use nonces here, but turns out that WordPress does not work well with generating nonces for cURL session.
1505 // We also tries to use cookiejar etc. but for researchers, this function is "verified" by process identy.
1506 // It's similarly safe as nonce, but it works in case we need, nonces gets rejected after second request.
1507 //
1508 // At the end, user who indeed would like to abuse this functionality, he can't do anything than helping the site owner.
1509 // Free browser will keep the process ongoing, user won't receive any details other than "success" - as long as the user know the process identy.
1510
1511 try {
1512
1513 // Load bypasser
1514 require_once BMI_INCLUDES . '/backup-process.php';
1515 $request = new Bypasser($get_bid, BMI_CONFIG_DIR, trailingslashit(WP_CONTENT_DIR), BMI_BACKUPS, trailingslashit(ABSPATH), plugin_dir_path(BMI_ROOT_FILE));
1516
1517 if (sizeof($request->remote_settings) === 0) return;
1518
1519 // Handle request
1520 $request->handle_batch();
1521 exit;
1522
1523 } catch (\Exception $e) {
1524
1525 error_log('There was an error with Backup Migration plugin: ' . $e->getMessage());
1526 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $e->getMessage());
1527 error_log(strval($e));
1528
1529 } catch (\Throwable $t) {
1530
1531 error_log('There was an error with Backup Migration plugin: ' . $t->getMessage());
1532 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $t->getMessage());
1533 error_log(strval($t));
1534
1535 }
1536
1537 }
1538 }
1539 }
1540 }
1541
1542 public function deactivation() {
1543 Logger::log(__("Plugin has been deactivated", 'backup-backup'));
1544 $this->revertLitespeed();
1545 }
1546
1547 public static function res($array) {
1548 $GLOBALS['BMI::RESPONSE::SENT'] = true;
1549 echo json_encode(Backup_Migration_Plugin::sanitize($array));
1550
1551 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
1552 Logger::log('CLI response:');
1553 Logger::log(json_encode(Backup_Migration_Plugin::sanitize($array)));
1554 }
1555
1556 exit;
1557 }
1558
1559 public static function getAvailableMemoryInBytes() {
1560
1561 $totalMemory = @ini_get('memory_limit');
1562 if ($totalMemory == -1) {
1563
1564 $totalMemory = 32 * 1024 * 1024;
1565
1566 } else {
1567
1568 if (strpos($totalMemory, 'M') !== false || strpos($totalMemory, 'm') !== false) {
1569 $totalMemory = intval($totalMemory) * 1024 * 1024;
1570 } else if (strpos($totalMemory, 'G') !== false || strpos($totalMemory, 'g') !== false) {
1571 $totalMemory = intval($totalMemory) * 1024 * 1024 * 1024;
1572 } else if (strpos($totalMemory, 'K') !== false || strpos($totalMemory, 'k') !== false) {
1573 $totalMemory = intval($totalMemory) * 1024;
1574 } else {
1575 $totalMemory = intval($totalMemory);
1576 }
1577
1578 }
1579
1580 $availableMemory = $totalMemory - memory_get_usage(true);
1581
1582 return $availableMemory;
1583
1584 }
1585
1586 public static function sanitize($data = []) {
1587 $array = [];
1588
1589 if (is_array($data) || is_object($data)) {
1590 foreach ($data as $key => $value) {
1591 $key = ((is_numeric($key))?intval($key):sanitize_text_field($key));
1592
1593 if (is_array($value) || is_object($value)) {
1594 $array[$key] = Backup_Migration_Plugin::sanitize($value);
1595 } else {
1596 $array[$key] = sanitize_text_field($value);
1597 }
1598 }
1599 } elseif (is_string($data)) {
1600 return sanitize_text_field($data);
1601 } elseif (is_bool($data)) {
1602 return $data;
1603 } elseif (is_null($data)) {
1604 return 'false';
1605 } else {
1606 Logger::log(__("Unknow AJAX Sanitize Type: ", 'backup-backup') . gettype($data));
1607 wp_die();
1608 }
1609
1610 return $array;
1611 }
1612
1613 public static function fixLitespeed() {
1614 $litepath = BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '.litespeed';
1615 $htpath = ABSPATH . DIRECTORY_SEPARATOR . '.htaccess';
1616 if (!is_writable($htpath)) return ['status' => 'success'];
1617 if (file_exists($htpath)) {
1618 Backup_Migration_Plugin::revertLitespeed();
1619 $litespeed = @file_get_contents($litepath);
1620 $htaccess = @file_get_contents($htpath);
1621 $htaccess = explode("\n", $htaccess);
1622 $litespeed = explode("\n", $litespeed);
1623
1624 $hasAlready = false;
1625 for ($i = 0; $i < sizeof($htaccess); ++$i) {
1626 if (strpos($htaccess[$i], 'Backup Migration') !== false) {
1627 $hasAlready = true;
1628
1629 break;
1630 }
1631 }
1632
1633 if ($hasAlready) {
1634 return ['status' => 'success'];
1635 }
1636 $htaccess[] = '';
1637 for ($i = 0; $i < sizeof($litespeed); ++$i) {
1638 $htaccess[] = $litespeed[$i];
1639 }
1640
1641 file_put_contents($htpath, implode("\n", $htaccess));
1642 } else {
1643 copy($litepath, $htpath);
1644 }
1645
1646 return ['status' => 'success'];
1647 }
1648
1649 public static function revertLitespeed() {
1650 $htpath = ABSPATH . DIRECTORY_SEPARATOR . '.htaccess';
1651 $addline = true;
1652
1653 if (!is_writable($htpath)) return ['status' => 'success'];
1654 $htaccess = @file_get_contents($htpath);
1655 $htaccess = explode("\n", $htaccess);
1656 $htFilter = [];
1657
1658 for ($i = 0; $i < sizeof($htaccess); ++$i) {
1659 if (strpos($htaccess[$i], 'Backup Migration START')) {
1660 $addline = false;
1661
1662 continue;
1663 } elseif (strpos($htaccess[$i], 'Backup Migration END')) {
1664 $addline = true;
1665
1666 continue;
1667 } else {
1668 if ($addline == true) {
1669 $htFilter[] = $htaccess[$i];
1670 }
1671 }
1672 }
1673
1674 file_put_contents($htpath, trim(implode("\n", $htFilter)));
1675
1676 return ['status' => 'success'];
1677 }
1678
1679 public static function humanSize($bytes) {
1680 if (is_int($bytes)) {
1681 $label = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
1682 for ($i = 0; $bytes >= 1024 && $i < (count($label) - 1); $bytes /= 1024, $i++);
1683
1684 return (round($bytes, 2) . " " . $label[$i]);
1685 } else return $bytes;
1686 }
1687
1688 public static function fixSlashes($str, $slash = false) {
1689 // Old version
1690 // $str = str_replace('\\\\', DIRECTORY_SEPARATOR, $str);
1691 // $str = str_replace('\\', DIRECTORY_SEPARATOR, $str);
1692 // $str = str_replace('\/', DIRECTORY_SEPARATOR, $str);
1693 // $str = str_replace('/', DIRECTORY_SEPARATOR, $str);
1694
1695 // if ($str[strlen($str) - 1] == DIRECTORY_SEPARATOR) {
1696 // $str = substr($str, 0, -1);
1697 // }
1698
1699 // Since 1.3.2
1700 $protocol = '';
1701 if ($slash == false) $slash = DIRECTORY_SEPARATOR;
1702 if (substr($str, 0, 7) == 'http://') $protocol = 'http://';
1703 else if (substr($str, 0, 8) == 'https://') $protocol = 'https://';
1704
1705 $str = substr($str, strlen($protocol));
1706 $str = preg_replace('/[\\\\\/]+/', $slash, $str);
1707 $str = untrailingslashit($str);
1708
1709 return $protocol . $str;
1710 }
1711
1712 public static function canShareLogsOrShouldAsk() {
1713
1714 return 'not-allowed';
1715
1716 // REMOVED CODE:
1717 // $isAllowed = get_option('BMI_LOGS_SHARING_IS_ALLOWED', 'unknown');
1718 // $isAllowedConfig = Dashboard\bmi_get_config('LOGS::SHARING');
1719 //
1720 // if ($isAllowed == 'unknown' || empty($isAllowedConfig)) return 'ask';
1721 // else if ($isAllowed === 'yes' && $isAllowedConfig === 'yes') {
1722 // return 'allowed';
1723 // } else if ($isAllowed === 'no' && $isAllowedConfig === 'no') {
1724 // return 'not-allowed';
1725 // } else return 'ask';
1726
1727 }
1728
1729 public static function getRecentSize() {
1730 $folderNames = [ 'BACKUP:DATABASE' => 'database',
1731 "BACKUP:FILES::PLUGINS" => 'plugins',
1732 "BACKUP:FILES::UPLOADS" => 'uploads',
1733 "BACKUP:FILES::THEMES" => 'themes',
1734 "BACKUP:FILES::OTHERS" => 'contents_others',
1735 "BACKUP:FILES::WP" => 'wordpress'
1736 ];
1737
1738 $size = 0;
1739 foreach ($folderNames as $setting => $fileName) {
1740 if (Dashboard\bmi_get_config($setting) === 'true') {
1741 $size += get_transient('bmi_latest_size_' . $fileName);
1742 }
1743
1744 }
1745 return $size;
1746 }
1747
1748 public static function merge_arrays(&$array1, &$array2) {
1749 for ($i = 0; $i < sizeof($array2); ++$i) {
1750 $array1[] = $array2[$i];
1751 }
1752 }
1753
1754 public static function getDefaultDisabledPaths() {
1755 require_once BMI_INCLUDES . '/staging/controller.php';
1756 $staging = new Staging('..ajax..');
1757 $stagingSites = $staging->getStagingSites(true);
1758 $stagingSitesPaths = [];
1759 // Get all directory names of staging sites
1760 foreach ($stagingSites as $index => $site) {
1761
1762 // Convert every directory to their location path
1763 $stagingSitesPaths[] = '***ABSPATH***/' . $site['name'];
1764
1765 }
1766
1767 $ignored_paths_default = [
1768 BMI_CONFIG_DIR,
1769 BMI_BACKUPS,
1770 BMI_ROOT_DIR,
1771 constant('BMI_PRO_ROOT_DIR'),
1772 "***ABSPATH***/wp-content/ai1wm-backups",
1773 "***ABSPATH***/wp-content/ai1wm-backups-old",
1774 "***ABSPATH***/wp-content/mwp-download",
1775 "***ABSPATH***/wp-content/uploads/wp-clone",
1776 "***ABSPATH***/wp-content/updraft",
1777 "***ABSPATH***/wp-content/backups-dup-pro",
1778 "***ABSPATH***/wp-content/wpvividbackups",
1779 "***ABSPATH***/wp-content/backup-guard",
1780 "***ABSPATH***/wp-content/backuply",
1781 "***ABSPATH***/wp-content/backups-dup-lite",
1782 "***ABSPATH***/wp-content/uploads/backupbuddy_backups",
1783 "***ABSPATH***/wp-content/uploads/wp-file-manager-pro",
1784 "***ABSPATH***/wp-content/uploads/wp-file-manager",
1785 "***ABSPATH***/wp-content/plugins/akeebabackupwp",
1786 "***ABSPATH***/wp-content/uploads/jetbackup",
1787 "***ABSPATH***/wp-content/uploads/backup-guard",
1788 "***ABSPATH***/wp-content/uploads/wp-migrate-db",
1789 "***ABSPATH***/wp-content/uploads/wpforms/.htaccess.cpmh3129",
1790 "***ABSPATH***/wp-content/uploads/gravity_forms/.htaccess.cpmh3129",
1791 "***ABSPATH***/.htaccess.cpmh3129",
1792 "***ABSPATH***/logs/traffic.html/.md5sums",
1793 "***ABSPATH***/wp-config.php",
1794 "***ABSPATH***/wp-content/backup-migration-config.php",
1795 ];
1796 $ignored_paths = array_merge($ignored_paths_default, $stagingSitesPaths);
1797 array_walk($ignored_paths, function(&$path){
1798 $path = self::fixSlashes(str_replace('***ABSPATH***', ABSPATH, $path));
1799 });
1800 return $ignored_paths;
1801 }
1802
1803 private function get_asset($base = '', $asset = '') {
1804 return BMI_ASSETS . '/' . $base . '/' . $asset;
1805 }
1806
1807 /**
1808 * Extend the execution time for the plugin
1809 *
1810 * @return void
1811 */
1812 public static function extend_execution_time() {
1813 if (self::isFunctionEnabled('headers_sent') && self::isFunctionEnabled('session_status')) {
1814 if (!headers_sent() && session_status() === PHP_SESSION_DISABLED) {
1815 if (self::isFunctionEnabled('ignore_user_abort')) @ignore_user_abort(true);
1816 if (self::isFunctionEnabled('set_time_limit')) @set_time_limit(16000);
1817 if (self::isFunctionEnabled('ini_set')) {
1818 @ini_set('max_execution_time', '259200');
1819 @ini_set('max_input_time', '259200');
1820 }
1821 }
1822 }
1823 }
1824
1825 public static function getRetryAfterIfAvailable($ch, $response)
1826 {
1827 $phpVersion = phpversion();
1828 $curlVersion = curl_version();
1829 // Available as of PHP 8.2.0 and cURL 7.66.0
1830 if (version_compare($phpVersion, '8.2.0', '>=') && version_compare($curlVersion['version'], '7.66.0', '>=')) {
1831 $retryAfter = curl_getinfo($ch, CURLINFO_RETRY_AFTER);
1832 if ($retryAfter !== false) {
1833 return $retryAfter;
1834 }
1835 }else {
1836 $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
1837 $header = substr($response, 0, $header_size);
1838 $headers = explode("\r\n", $header);
1839 foreach ($headers as $h) {
1840 if (preg_match('/^Retry-After:\s+(\d+)/i', $h, $matches)) {
1841 return intval($matches[1]);
1842 }
1843 }
1844 }
1845 return false;
1846
1847 }
1848 }
1849