PluginProbe ʕ •ᴥ•ʔ
Backup Migration / 1.4.4
Backup Migration v1.4.4
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 backup-process.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
1601 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 $get_is_uncensored = !empty($_GET['uncensored']) ? sanitize_text_field($_GET['uncensored']) : false;
1036 $crons_enabled = !empty($_GET['crons']) ? sanitize_text_field($_GET['crons']) : false;
1037 $secret_key = !empty($_GET['sk']) ? sanitize_text_field($_GET['sk']) : false;
1038
1039 if (isset($get_bmi) && in_array($get_bmi, $allowed)) {
1040 if (isset($get_bid) && strlen($get_bid) > 0 && isset($secret_key) && $secret_key === Dashboard\bmi_get_config('REQUEST:SECRET')) {
1041 $type = $get_bmi;
1042
1043 if ($type == 'AFTER_RESTORE' && isset($get_pid)) {
1044 if (file_exists($autologin_file)) {
1045 $autoLoginMD = file_get_contents($autologin_file);
1046 $autoLoginMD = explode('_', $autoLoginMD);
1047 $aID = intval($autoLoginMD[0]);
1048 $aID2 = intval($autoLoginMD[0]) - 1;
1049 $aID3 = intval($autoLoginMD[0]) + 1;
1050 $aID4 = intval($autoLoginMD[0]) + 2;
1051 $aID5 = intval($autoLoginMD[0]) + 3;
1052 $aID6 = intval($autoLoginMD[0]) + 4;
1053 $aIP = $autoLoginMD[1];
1054 $aIZ = $autoLoginMD[2];
1055
1056 // Allow 1 second delay
1057 $timeIsProper = false;
1058 if ($aID === intval($get_bid)) $timeIsProper = true;
1059 if ($aID2 === intval($get_bid)) $timeIsProper = true;
1060 if ($aID3 === intval($get_bid)) $timeIsProper = true;
1061 if ($aID4 === intval($get_bid)) $timeIsProper = true;
1062 if ($aID5 === intval($get_bid)) $timeIsProper = true;
1063 if ($aID6 === intval($get_bid)) $timeIsProper = true;
1064
1065 if ($timeIsProper && $aIP === $ip && trim($aIZ) === $get_pid) {
1066 $query = new \WP_User_Query(['role' => 'Administrator', 'count_total' => false, 'fields' => 'all']);
1067 $sqlres = $wpdb->get_results($query->request);
1068
1069 if (sizeof($sqlres) > 0 && isset($sqlres[0]->ID) && isset($sqlres[0]->user_login)) {
1070
1071 $user = $sqlres[0];
1072 $adminID = $sqlres[0]->ID;
1073 $adminLogin = $sqlres[0]->user_login;
1074
1075 remove_all_actions('wp_login', -1000);
1076 wp_load_alloptions(true);
1077 clean_user_cache(get_current_user_id());
1078 clean_user_cache($adminID);
1079 wp_clear_auth_cookie();
1080 wp_set_current_user($adminID, $adminLogin);
1081 wp_set_auth_cookie($adminID, 1, is_ssl());
1082 do_action('wp_login', $adminLogin, $user);
1083 update_user_caches($user);
1084
1085 }
1086 $cronsEnabledParam = $crons_enabled ? "&crons=true" : "";
1087
1088 $url = admin_url('admin.php?page=backup-migration' . $cronsEnabledParam);
1089 header('Location: ' . $url);
1090
1091 @unlink($autologin_file);
1092 exit;
1093 }
1094 }
1095
1096 } else if ($type == 'BMI_BACKUP') {
1097 if (Dashboard\bmi_get_config('STORAGE::DIRECT::URL') === 'true' || current_user_can('administrator')) {
1098
1099 $backupname = $get_bid;
1100 $file = $this->fixSlashes(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupname);
1101
1102 $outsideDir = false;
1103 if (!(file_exists($file) && $this->fixSlashes(dirname($file)) == $this->fixSlashes(BMI_BACKUPS))) {
1104 $outsideDir = true;
1105 }
1106
1107 if ($outsideDir || strpos(strtolower(mime_content_type($file)), 'zip') === false) {
1108 header('HTTP/1.0 423 Locked');
1109 _e("Incorrect usage of the query request.", 'backup-backup');
1110 exit;
1111 }
1112
1113 if (Dashboard\bmi_get_config('OTHER:DOWNLOAD:DIRECT') == 'true') {
1114 if (file_exists(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.htaccess')) @unlink(BMI_BACKUPS . DIRECTORY_SEPARATOR . '.htaccess');
1115 if (file_exists(dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . '.htaccess')) @unlink(dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . '.htaccess');
1116 $wpcontent = trailingslashit(WP_CONTENT_DIR);
1117 $wpcs = strlen($wpcontent);
1118 $url = $this->fixSlashes(content_url(substr($file, $wpcs)), '/');
1119 $path = wp_redirect($url);
1120 exit;
1121 }
1122
1123 // Prevent parent directory downloading
1124 if (ob_get_contents()) ob_end_clean();
1125
1126 if ($this->isFunctionEnabled('ignore_user_abort')) @ignore_user_abort(true);
1127 if ($this->isFunctionEnabled('set_time_limit')) @set_time_limit(16000);
1128 if ($this->isFunctionEnabled('headers_sent') && $this->isFunctionEnabled('session_status')) {
1129 if (!headers_sent() && session_status() === PHP_SESSION_DISABLED) {
1130 if ($this->isFunctionEnabled('ini_set')) {
1131 @ini_set('max_execution_time', '259200');
1132 @ini_set('max_input_time', '259200');
1133 @ini_set('session.gc_maxlifetime', '1200');
1134 @ini_set('memory_limit', '-1');
1135 if (@ini_get('zlib.output_compression')) {
1136 @ini_set('zlib.output_compression', 'Off');
1137 }
1138 }
1139 }
1140 }
1141
1142 if (strlen(session_id()) > 0) session_write_close();
1143
1144 $fp = @fopen($file, 'rb');
1145
1146 // header('X-Sendfile: ' . $file);
1147 // header('X-Sendfile-Type: X-Accel-Redirect');
1148 // header('X-Accel-Redirect: ' . $file);
1149 // header('X-Accel-Buffering: yes');
1150 header('Expires: 0');
1151 header('Pragma: public');
1152 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1153 header('Content-Disposition: attachment; filename="' . $backupname . '"');
1154 header('Content-Type: application/octet-stream');
1155 header('Content-Transfer-Encoding: binary');
1156 header('Content-Length: ' . filesize($file));
1157 header('Content-Description: File Transfer');
1158 http_response_code(200);
1159
1160 if (ob_get_level()) ob_end_clean();
1161
1162 fpassthru($fp);
1163 fclose($fp);
1164 exit;
1165
1166 } else {
1167 if (ob_get_contents()) ob_end_clean();
1168 header('HTTP/1.0 423 Locked');
1169 if (ob_get_level()) ob_end_clean();
1170 echo __("Backup download is restricted (allowed for admins only).", 'backup-backup');
1171 exit;
1172 }
1173 } else if ($type == 'BMI_BACKUP_LOGS') {
1174
1175 // Only Admin can download backup logs
1176 if (!(current_user_can('administrator') || current_user_can('do_backups'))) return;
1177
1178 if (ob_get_contents()) ob_end_clean();
1179 $backupname = $get_bid;
1180 $file = $this->fixSlashes(BMI_BACKUPS . DIRECTORY_SEPARATOR . $backupname);
1181
1182 // Prevent parent directory downloading
1183 if (file_exists($file) && $this->fixSlashes(dirname($file)) == $this->fixSlashes(BMI_BACKUPS)) {
1184 require_once BMI_INCLUDES . '/zipper/zipping.php';
1185
1186 $zipper = new Zipper();
1187 $logs = $zipper->getZipFileContentPlain($file, 'bmi_logs_this_backup.log');
1188 header('Content-Type: text/plain');
1189
1190 if ($logs) {
1191 header('Content-Disposition: attachment; filename="' . substr($backupname, 0, -4) . '.log"');
1192 http_response_code(200);
1193 if (ob_get_level()) ob_end_clean();
1194
1195 $logs = explode('\n', $logs);
1196 $current_directory = Dashboard\bmi_get_config('STORAGE::LOCAL::PATH');
1197 $backups_path = $this->fixSlashes($current_directory . DIRECTORY_SEPARATOR . 'backups');
1198 $scanned_directory_all = array_diff(scandir($backups_path), ['..', '.']);
1199 $scanned_directory = array_values(preg_grep('/((.*).zip)/i', $scanned_directory_all));
1200
1201 for ($i = 0; $i < sizeof($logs); ++$i) {
1202
1203 $line = $logs[$i];
1204 echo $this->escapeSensitive($line, $current_directory, $scanned_directory) . "\n";
1205
1206 }
1207
1208 exit;
1209 } else {
1210 if (ob_get_level()) ob_end_clean();
1211 header('HTTP/1.0 404 Not found');
1212 echo __("There was an error during getting logs, this file is not right log file.", 'backup-backup');
1213 exit;
1214 }
1215 }
1216
1217 } else if ($type == 'PROGRESS_LOGS') {
1218 $allowed_progress = [
1219 'latest_full.log',
1220 'latest.log',
1221 'latest_progress.log',
1222 'latest_migration_full.log',
1223 'latest_migration.log',
1224 'latest_migration_progress.log',
1225 'latest_staging_full.log',
1226 'latest_staging.log',
1227 'latest_staging_progress.log',
1228 'complete_logs.log'
1229 ];
1230 if (isset($get_pid) && in_array($get_pid, $allowed_progress)) {
1231
1232 $restricted_progress = ['complete_logs.log'];
1233 if (in_array($get_pid, $restricted_progress)) {
1234
1235 // Only Admin can download backup logs
1236 if (!(current_user_can('administrator') || current_user_can('do_backups'))) return;
1237
1238 }
1239
1240 header('Content-Type: text/plain');
1241 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1242 http_response_code(200);
1243 if (ob_get_contents()) ob_end_clean();
1244 if ($get_pid == 'complete_logs.log') {
1245 $file = BMI_CONFIG_DIR . DIRECTORY_SEPARATOR . 'complete_logs.log';
1246 if (ob_get_level()) ob_end_clean();
1247 $this->readFileSensitive($file);
1248 exit;
1249 } else if ($get_pid == 'latest_full.log') {
1250 $progress = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_progress.log';
1251 $logs = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest.log';
1252 if ((file_exists($progress) && file_exists($logs) && ((time() - filemtime($progress)) < (60 * 1))) || current_user_can('administrator')) {
1253 if (ob_get_level()) ob_end_clean();
1254 readfile($progress);
1255 echo "\n";
1256 if (isset($get_is_uncensored) && $get_is_uncensored && current_user_can('administrator')) readfile($logs);
1257 else $this->readFileSensitive($logs);
1258 exit;
1259 } else {
1260 if (file_exists($progress) && !(time() - filemtime($progress)) < (60 * 1)) {
1261 if (ob_get_level()) ob_end_clean();
1262 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1263 echo __("Human readable: file expired.", 'backup-backup');
1264 exit;
1265 } else {
1266 if (ob_get_level()) ob_end_clean();
1267 echo '';
1268 exit;
1269 }
1270 }
1271 } else if ($get_pid == 'latest_migration_full.log') {
1272 $progress = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_migration_progress.log';
1273 $logs = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_migration.log';
1274 if ((file_exists($progress) && file_exists($logs) && ((time() - filemtime($progress)) < (60 * 1))) || current_user_can('administrator')) {
1275 if (ob_get_level()) ob_end_clean();
1276 readfile($progress);
1277 echo "\n";
1278 $this->readFileSensitive($logs);
1279 exit;
1280 } else {
1281 if (file_exists($progress) && !(time() - filemtime($progress)) < (60 * 1)) {
1282 if (ob_get_level()) ob_end_clean();
1283 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1284 echo __("Human readable: file expired.", 'backup-backup');
1285 exit;
1286 } else {
1287 if (ob_get_level()) ob_end_clean();
1288 echo '';
1289 exit;
1290 }
1291 }
1292 } else if ($get_pid == 'latest_staging_full.log') {
1293 $progress = BMI_STAGING . DIRECTORY_SEPARATOR . 'latest_staging_progress.log';
1294 $logs = BMI_STAGING . DIRECTORY_SEPARATOR . 'latest_staging.log';
1295 if ((file_exists($progress) && file_exists($logs) && ((time() - filemtime($progress)) < (60 * 1))) || current_user_can('administrator')) {
1296 if (ob_get_level()) ob_end_clean();
1297 readfile($progress);
1298 echo "\n";
1299 $this->readFileSensitive($logs);
1300 exit;
1301 } else {
1302 if (file_exists($progress) && !(time() - filemtime($progress)) < (60 * 1)) {
1303 if (ob_get_level()) ob_end_clean();
1304 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1305 echo __("Human readable: file expired.", 'backup-backup');
1306 exit;
1307 } else {
1308 if (ob_get_level()) ob_end_clean();
1309 echo '';
1310 exit;
1311 }
1312 }
1313 } else {
1314 $file = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . $get_pid;
1315 if ($get_pid == 'latest_staging.log') $file = BMI_STAGING . DIRECTORY_SEPARATOR . $get_pid;
1316 if ($get_pid == 'latest_staging_progress.log') $file = BMI_STAGING . DIRECTORY_SEPARATOR . $get_pid;
1317 if (file_exists($file) && (((time() - filemtime($file)) < (60 * 1)) || current_user_can('administrator'))) {
1318 if (ob_get_level()) ob_end_clean();
1319
1320 if (isset($get_is_uncensored) && $get_is_uncensored && current_user_can('administrator')) readfile($file);
1321 else $this->readFileSensitive($file);
1322
1323 echo "\n";
1324 if ($get_pid == 'latest.log') $file = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_progress.log';
1325 if ($get_pid == 'latest_migration.log') $file = dirname(BMI_BACKUPS) . DIRECTORY_SEPARATOR . 'backups' . DIRECTORY_SEPARATOR . 'latest_migration_progress.log';
1326 if ($get_pid == 'latest_staging.log') $file = BMI_STAGING . DIRECTORY_SEPARATOR . 'latest_staging_progress.log';
1327 echo __("[DOWNLOAD GENERATED] File downloaded on (server time): ", 'backup-backup') . date('Y-m-d H:i:s') . "\n";
1328 echo __("[DOWNLOAD GENERATED] Last update (seconds): ", 'backup-backup') . (time() - filemtime($file)) . __(" seconds ago ", 'backup-backup') . "\n";
1329 echo __("[DOWNLOAD GENERATED] Last update (date): ", 'backup-backup') . date('Y-m-d H:i:s', filemtime($file)) . " \n";
1330 exit;
1331 } else {
1332 if (file_exists($file) && !(time() - filemtime($file)) < (60 * 1)) {
1333 if (ob_get_level()) ob_end_clean();
1334 echo __("Due to security reasons access to this file is disabled at this moment.", 'backup-backup') . "\n";
1335 echo __("Human readable: file expired.", 'backup-backup');
1336 exit;
1337 } else {
1338 if (ob_get_level()) ob_end_clean();
1339 echo '';
1340 exit;
1341 }
1342 }
1343 }
1344 exit;
1345 }
1346 } else if ($type == 'CURL_BACKUP') {
1347
1348 // We tried to use nonces here, but turns out that WordPress does not work well with generating nonces for cURL session.
1349 // We also tries to use cookiejar etc. but for researchers, this function is "verified" by process identy.
1350 // It's similarly safe as nonce, but it works in case we need, nonces gets rejected after second request.
1351 //
1352 // At the end, user who indeed would like to abuse this functionality, he can't do anything than helping the site owner.
1353 // 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.
1354
1355 try {
1356
1357 // Load bypasser
1358 require_once BMI_INCLUDES . '/backup-process.php';
1359 $request = new Bypasser($get_bid, BMI_CONFIG_DIR, trailingslashit(WP_CONTENT_DIR), BMI_BACKUPS, trailingslashit(ABSPATH), plugin_dir_path(BMI_ROOT_FILE));
1360
1361 if (sizeof($request->remote_settings) === 0) return;
1362
1363 // Handle request
1364 $request->handle_batch();
1365 exit;
1366
1367 } catch (\Exception $e) {
1368
1369 error_log('There was an error with Backup Migration plugin: ' . $e->getMessage());
1370 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $e->getMessage());
1371 error_log(strval($e));
1372
1373 } catch (\Throwable $t) {
1374
1375 error_log('There was an error with Backup Migration plugin: ' . $t->getMessage());
1376 Logger::error(__('Error handler: ', 'backup-backup') . 'ajax#01' . '|' . $t->getMessage());
1377 error_log(strval($t));
1378
1379 }
1380
1381 }
1382 }
1383 }
1384 }
1385
1386 public function deactivation() {
1387 Logger::log(__("Plugin has been deactivated", 'backup-backup'));
1388 $this->revertLitespeed();
1389 }
1390
1391 public static function res($array) {
1392 echo json_encode(Backup_Migration_Plugin::sanitize($array));
1393
1394 if (defined('BMI_USING_CLI_FUNCTIONALITY') && BMI_USING_CLI_FUNCTIONALITY === true) {
1395 Logger::log('CLI response:');
1396 Logger::log(json_encode(Backup_Migration_Plugin::sanitize($array)));
1397 }
1398
1399 exit;
1400 }
1401
1402 public static function getAvailableMemoryInBytes() {
1403
1404 $totalMemory = @ini_get('memory_limit');
1405 if ($totalMemory == -1) {
1406
1407 $totalMemory = 32 * 1024 * 1024;
1408
1409 } else {
1410
1411 if (strpos($totalMemory, 'M') !== false || strpos($totalMemory, 'm') !== false) {
1412 $totalMemory = intval($totalMemory) * 1024 * 1024;
1413 } else if (strpos($totalMemory, 'G') !== false || strpos($totalMemory, 'g') !== false) {
1414 $totalMemory = intval($totalMemory) * 1024 * 1024 * 1024;
1415 } else if (strpos($totalMemory, 'K') !== false || strpos($totalMemory, 'k') !== false) {
1416 $totalMemory = intval($totalMemory) * 1024;
1417 } else {
1418 $totalMemory = intval($totalMemory);
1419 }
1420
1421 }
1422
1423 $availableMemory = $totalMemory - memory_get_usage(true);
1424
1425 return $availableMemory;
1426
1427 }
1428
1429 public static function sanitize($data = []) {
1430 $array = [];
1431
1432 if (is_array($data) || is_object($data)) {
1433 foreach ($data as $key => $value) {
1434 $key = ((is_numeric($key))?intval($key):sanitize_text_field($key));
1435
1436 if (is_array($value) || is_object($value)) {
1437 $array[$key] = Backup_Migration_Plugin::sanitize($value);
1438 } else {
1439 $array[$key] = sanitize_text_field($value);
1440 }
1441 }
1442 } elseif (is_string($data)) {
1443 return sanitize_text_field($data);
1444 } elseif (is_bool($data)) {
1445 return $data;
1446 } elseif (is_null($data)) {
1447 return 'false';
1448 } else {
1449 Logger::log(__("Unknow AJAX Sanitize Type: ", 'backup-backup') . gettype($data));
1450 wp_die();
1451 }
1452
1453 return $array;
1454 }
1455
1456 public static function fixLitespeed() {
1457 $litepath = BMI_INCLUDES . DIRECTORY_SEPARATOR . 'htaccess' . DIRECTORY_SEPARATOR . '.litespeed';
1458 $htpath = ABSPATH . DIRECTORY_SEPARATOR . '.htaccess';
1459 if (!is_writable($htpath)) return ['status' => 'success'];
1460 if (file_exists($htpath)) {
1461 Backup_Migration_Plugin::revertLitespeed();
1462 $litespeed = @file_get_contents($litepath);
1463 $htaccess = @file_get_contents($htpath);
1464 $htaccess = explode("\n", $htaccess);
1465 $litespeed = explode("\n", $litespeed);
1466
1467 $hasAlready = false;
1468 for ($i = 0; $i < sizeof($htaccess); ++$i) {
1469 if (strpos($htaccess[$i], 'Backup Migration') !== false) {
1470 $hasAlready = true;
1471
1472 break;
1473 }
1474 }
1475
1476 if ($hasAlready) {
1477 return ['status' => 'success'];
1478 }
1479 $htaccess[] = '';
1480 for ($i = 0; $i < sizeof($litespeed); ++$i) {
1481 $htaccess[] = $litespeed[$i];
1482 }
1483
1484 file_put_contents($htpath, implode("\n", $htaccess));
1485 } else {
1486 copy($litepath, $htpath);
1487 }
1488
1489 return ['status' => 'success'];
1490 }
1491
1492 public static function revertLitespeed() {
1493 $htpath = ABSPATH . DIRECTORY_SEPARATOR . '.htaccess';
1494 $addline = true;
1495
1496 if (!is_writable($htpath)) return ['status' => 'success'];
1497 $htaccess = @file_get_contents($htpath);
1498 $htaccess = explode("\n", $htaccess);
1499 $htFilter = [];
1500
1501 for ($i = 0; $i < sizeof($htaccess); ++$i) {
1502 if (strpos($htaccess[$i], 'Backup Migration START')) {
1503 $addline = false;
1504
1505 continue;
1506 } elseif (strpos($htaccess[$i], 'Backup Migration END')) {
1507 $addline = true;
1508
1509 continue;
1510 } else {
1511 if ($addline == true) {
1512 $htFilter[] = $htaccess[$i];
1513 }
1514 }
1515 }
1516
1517 file_put_contents($htpath, trim(implode("\n", $htFilter)));
1518
1519 return ['status' => 'success'];
1520 }
1521
1522 public static function humanSize($bytes) {
1523 if (is_int($bytes)) {
1524 $label = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
1525 for ($i = 0; $bytes >= 1024 && $i < (count($label) - 1); $bytes /= 1024, $i++);
1526
1527 return (round($bytes, 2) . " " . $label[$i]);
1528 } else return $bytes;
1529 }
1530
1531 public static function fixSlashes($str, $slash = false) {
1532 // Old version
1533 // $str = str_replace('\\\\', DIRECTORY_SEPARATOR, $str);
1534 // $str = str_replace('\\', DIRECTORY_SEPARATOR, $str);
1535 // $str = str_replace('\/', DIRECTORY_SEPARATOR, $str);
1536 // $str = str_replace('/', DIRECTORY_SEPARATOR, $str);
1537
1538 // if ($str[strlen($str) - 1] == DIRECTORY_SEPARATOR) {
1539 // $str = substr($str, 0, -1);
1540 // }
1541
1542 // Since 1.3.2
1543 $protocol = '';
1544 if ($slash == false) $slash = DIRECTORY_SEPARATOR;
1545 if (substr($str, 0, 7) == 'http://') $protocol = 'http://';
1546 else if (substr($str, 0, 8) == 'https://') $protocol = 'https://';
1547
1548 $str = substr($str, strlen($protocol));
1549 $str = preg_replace('/[\\\\\/]+/', $slash, $str);
1550 $str = untrailingslashit($str);
1551
1552 return $protocol . $str;
1553 }
1554
1555 public static function canShareLogsOrShouldAsk() {
1556
1557 return 'not-allowed';
1558
1559 // REMOVED CODE:
1560 // $isAllowed = get_option('BMI_LOGS_SHARING_IS_ALLOWED', 'unknown');
1561 // $isAllowedConfig = Dashboard\bmi_get_config('LOGS::SHARING');
1562 //
1563 // if ($isAllowed == 'unknown' || empty($isAllowedConfig)) return 'ask';
1564 // else if ($isAllowed === 'yes' && $isAllowedConfig === 'yes') {
1565 // return 'allowed';
1566 // } else if ($isAllowed === 'no' && $isAllowedConfig === 'no') {
1567 // return 'not-allowed';
1568 // } else return 'ask';
1569
1570 }
1571
1572 public static function getRecentSize() {
1573 $folderNames = [ 'BACKUP:DATABASE' => 'database',
1574 "BACKUP:FILES::PLUGINS" => 'plugins',
1575 "BACKUP:FILES::UPLOADS" => 'uploads',
1576 "BACKUP:FILES::THEMES" => 'themes',
1577 "BACKUP:FILES::OTHERS" => 'contents_others',
1578 "BACKUP:FILES::WP" => 'wordpress'
1579 ];
1580
1581 $size = 0;
1582 foreach ($folderNames as $setting => $fileName) {
1583 if (Dashboard\bmi_get_config($setting) === 'true') {
1584 $size += get_transient('bmi_latest_size_' . $fileName);
1585 }
1586
1587 }
1588 return $size;
1589 }
1590
1591 public static function merge_arrays(&$array1, &$array2) {
1592 for ($i = 0; $i < sizeof($array2); ++$i) {
1593 $array1[] = $array2[$i];
1594 }
1595 }
1596
1597 private function get_asset($base = '', $asset = '') {
1598 return BMI_ASSETS . '/' . $base . '/' . $asset;
1599 }
1600 }
1601