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