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