public function boot_backup($backup_files, $backup_database, $restrict_files_to_override = false, $one_shot = false, $service = false, $options = array()) { @ignore_user_abort(true); @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT); if (false === $restrict_files_to_override && isset($options['restrict_files_to_override'])) { $restrict_files_to_override = $options['restrict_files_to_override']; } // Generate backup information $use_nonce = empty($options['use_nonce']) ? false : $options['use_nonce']; $this->backup_time_nonce($use_nonce); // The current_resumption is consulted within logfile_open() $this->current_resumption = 0; $this->logfile_open($this->nonce); if (!is_file($this->logfile_name)) { $this->log('Failed to open log file (' . $this->logfile_name . ') - you need to check your UpdraftPlus settings (your chosen directory for creating files in is not writable, or you ran out of disk space). Backup aborted.'); $this->log(__('Could not create files in the backup directory. Backup aborted - check your UpdraftPlus settings.', 'updraftplus'), 'error'); return false; } // Some house-cleaning $this->clean_temporary_files(); // Log some information that may be helpful $this->log("Tasks: Backup files: {$backup_files} (schedule: " . UpdraftPlus_Options::get_updraft_option('updraft_interval', 'unset') . ") Backup DB: {$backup_database} (schedule: " . UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'unset') . ")"); // The is_bool() check here is confirming that we're allowed to adjust the parameters if (false === $one_shot && is_bool($backup_database)) { # If the files and database schedules are the same, and if this the file one, then we rope in database too. # On the other hand, if the schedules were the same and this was the database run, then there is nothing to do. $files_schedule = UpdraftPlus_Options::get_updraft_option('updraft_interval'); $db_schedule = UpdraftPlus_Options::get_updraft_option('updraft_interval_database'); $sched_log_extra = ''; if ('manual' != $files_schedule) { if ($files_schedule == $db_schedule || UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'xyz') == 'xyz') { $sched_log_extra = 'Combining jobs from identical schedules. '; $backup_database = $backup_files == true ? true : false; } elseif ($files_schedule && $db_schedule && $files_schedule != $db_schedule) { // This stored value is the earliest of the two apparently-close jobs $combine_around = empty($this->combine_jobs_around) ? false : $this->combine_jobs_around; if (preg_match('/^(cancel:)?(\\d+)$/', $combine_around, $matches)) { $combine_around = $matches[2]; // Re-save the option, since otherwise it will have been reset and not be accessible to the 'other' run UpdraftPlus_Options::update_updraft_option('updraft_combine_jobs_around', 'cancel:' . $this->combine_jobs_around); $margin = defined('UPDRAFTPLUS_COMBINE_MARGIN') && is_numeric(UPDRAFTPLUS_COMBINE_MARGIN) ? UPDRAFTPLUS_COMBINE_MARGIN : 600; $time_now = time(); // The margin is doubled, to cope with the lack of predictability in WP's cron system if ($time_now >= $combine_around && $time_now <= $combine_around + 2 * $margin) { $sched_log_extra = 'Combining jobs from co-inciding events. '; if ('cancel:' == $matches[1]) { $backup_database = false; $backup_files = false; } else { // We want them both to happen on whichever run is first (since, afterwards, the updraft_combine_jobs_around option will have been removed when the event is rescheduled). $backup_database = true; $backup_files = true; } } } } } $this->log("Processed schedules. {$sched_log_extra}Tasks now: Backup files: {$backup_files} Backup DB: {$backup_database}"); } $semaphore = ($backup_files ? 'f' : '') . ($backup_database ? 'd' : ''); $this->ensure_semaphore_exists($semaphore); if (false == apply_filters('updraftplus_boot_backup', true, $backup_files, $backup_database, $one_shot)) { $this->log("Backup aborted (via filter)"); return false; } if (!is_string($service) && !is_array($service)) { $service = UpdraftPlus_Options::get_updraft_option('updraft_service'); } $service = $this->just_one($service); if (is_string($service)) { $service = array($service); } if (!is_array($service)) { $service = array('none'); } if (!empty($options['extradata']) && preg_match('#services=remotesend/(\\d+)#', $options['extradata'])) { if ($service === array('none')) { $service = array(); } $service[] = 'remotesend'; } $option_cache = array(); foreach ($service as $serv) { if ('' == $serv || 'none' == $serv) { continue; } include_once UPDRAFTPLUS_DIR . '/methods/' . $serv . '.php'; $cclass = 'UpdraftPlus_BackupModule_' . $serv; $obj = new $cclass(); if (method_exists($cclass, 'get_credentials')) { $opts = $obj->get_credentials(); if (is_array($opts)) { foreach ($opts as $opt) { $option_cache[$opt] = UpdraftPlus_Options::get_updraft_option($opt); } } } } $option_cache = apply_filters('updraftplus_job_option_cache', $option_cache); // If nothing to be done, then just finish if (!$backup_files && !$backup_database) { $ret = $this->backup_finish(1, false, false, 0); // Don't keep useless log files if (!UpdraftPlus_Options::get_updraft_option('updraft_debug_mode') && !empty($this->logfile_name) && file_exists($this->logfile_name)) { unlink($this->logfile_name); } return $ret; } // Are we doing an action called by the WP scheduler? If so, we want to check when that last happened; the point being that the dodgy WP scheduler, when overloaded, can call the event multiple times - and sometimes, it evades the semaphore because it calls a second run after the first has finished, or > 3 minutes (our semaphore lock time) later // doing_action() was added in WP 3.9 // wp_cron() can be called from the 'init' action if (function_exists('doing_action') && (doing_action('init') || @constant('DOING_CRON')) && (doing_action('updraft_backup_database') || doing_action('updraft_backup'))) { $last_scheduled_action_called_at = get_option("updraft_last_scheduled_{$semaphore}"); // 11 minutes - so, we're assuming that they haven't custom-modified their schedules to run scheduled backups more often than that. If they have, they need also to use the filter to over-ride this check. $seconds_ago = time() - $last_scheduled_action_called_at; if ($last_scheduled_action_called_at && $seconds_ago < 660 && apply_filters('updraft_check_repeated_scheduled_backups', true)) { $this->log(sprintf('Scheduled backup aborted - another backup of this type was apparently invoked by the WordPress scheduler only %d seconds ago - the WordPress scheduler invoking events multiple times usually indicates a very overloaded server (or other plugins that mis-use the scheduler)', $seconds_ago)); return; } } update_option("updraft_last_scheduled_{$semaphore}", time()); require_once UPDRAFTPLUS_DIR . '/includes/class-semaphore.php'; $this->semaphore = UpdraftPlus_Semaphore::factory(); $this->semaphore->lock_name = $semaphore; $semaphore_log_message = 'Requesting semaphore lock (' . $semaphore . ')'; if (!empty($last_scheduled_action_called_at)) { $semaphore_log_message .= " (apparently via scheduler: last_scheduled_action_called_at={$last_scheduled_action_called_at}, seconds_ago={$seconds_ago})"; } else { $semaphore_log_message .= " (apparently not via scheduler)"; } $this->log($semaphore_log_message); if (!$this->semaphore->lock()) { $this->log('Failed to gain semaphore lock (' . $semaphore . ') - another backup of this type is apparently already active - aborting (if this is wrong - i.e. if the other backup crashed without removing the lock, then another can be started after 3 minutes)'); return; } // Allow the resume interval to be more than 300 if last time we know we went beyond that - but never more than 600 if (defined('UPDRAFTPLUS_INITIAL_RESUME_INTERVAL') && is_numeric(UPDRAFTPLUS_INITIAL_RESUME_INTERVAL)) { $resume_interval = UPDRAFTPLUS_INITIAL_RESUME_INTERVAL; } else { $resume_interval = (int) min(max(300, get_site_transient('updraft_initial_resume_interval')), 600); } # We delete it because we only want to know about behaviour found during the very last backup run (so, if you move servers then old data is not retained) delete_site_transient('updraft_initial_resume_interval'); $job_file_entities = array(); if ($backup_files) { $possible_backups = $this->get_backupable_file_entities(true); foreach ($possible_backups as $youwhat => $whichdir) { if (false === $restrict_files_to_override && UpdraftPlus_Options::get_updraft_option("updraft_include_{$youwhat}", apply_filters("updraftplus_defaultoption_include_{$youwhat}", true)) || is_array($restrict_files_to_override) && in_array($youwhat, $restrict_files_to_override)) { // The 0 indicates the zip file index $job_file_entities[$youwhat] = array('index' => 0); } } } $followups_allowed = !$one_shot && defined('DOING_CRON') && DOING_CRON || defined('UPDRAFTPLUS_FOLLOWUPS_ALLOWED') && UPDRAFTPLUS_FOLLOWUPS_ALLOWED; $split_every = max(intval(UpdraftPlus_Options::get_updraft_option('updraft_split_every', 400)), UPDRAFTPLUS_SPLIT_MIN); $initial_jobdata = array('resume_interval', $resume_interval, 'job_type', 'backup', 'jobstatus', 'begun', 'backup_time', $this->backup_time, 'job_time_ms', $this->job_time_ms, 'service', $service, 'split_every', $split_every, 'maxzipbatch', 26214400, 'job_file_entities', $job_file_entities, 'option_cache', $option_cache, 'uploaded_lastreset', 9, 'one_shot', $one_shot, 'followsups_allowed', $followups_allowed); if ($one_shot) { update_site_option('updraft_oneshotnonce', $this->nonce); } if (!empty($options['extradata']) && 'autobackup' == $options['extradata']) { array_push($initial_jobdata, 'is_autobackup', true); } // Save what *should* be done, to make it resumable from this point on if ($backup_database) { $dbs = apply_filters('updraft_backup_databases', array('wp' => 'begun')); if (is_array($dbs)) { foreach ($dbs as $key => $db) { if ('wp' != $key && (!is_array($db) || empty($db['dbinfo']) || !is_array($db['dbinfo']) || empty($db['dbinfo']['host']))) { unset($dbs[$key]); } } } } else { $dbs = "no"; } array_push($initial_jobdata, 'backup_database', $dbs); array_push($initial_jobdata, 'backup_files', $backup_files ? 'begun' : 'no'); if (is_array($options) && !empty($options['label'])) { array_push($initial_jobdata, 'label', $options['label']); } try { // Use of jobdata_set_multi saves around 200ms call_user_func_array(array($this, 'jobdata_set_multi'), apply_filters('updraftplus_initial_jobdata', $initial_jobdata, $options, $split_every)); } catch (Exception $e) { $this->log($e->getMessage()); return false; } // Everything is set up; now go $this->backup_resume(0, $this->nonce); if ($one_shot) { delete_site_option('updraft_oneshotnonce'); } }
public function boot_backup($backup_files, $backup_database, $restrict_files_to_override = false, $one_shot = false, $service = false, $options = array()) { @ignore_user_abort(true); @set_time_limit(900); if (false === $restrict_files_to_override && isset($options['restrict_files_to_override'])) { $restrict_files_to_override = $options['restrict_files_to_override']; } // Generate backup information $use_nonce = empty($options['use_nonce']) ? false : $options['use_nonce']; $this->backup_time_nonce($use_nonce); // The current_resumption is consulted within logfile_open() $this->current_resumption = 0; $this->logfile_open($this->nonce); if (!is_file($this->logfile_name)) { $this->log('Failed to open log file (' . $this->logfile_name . ') - you need to check your UpdraftPlus settings (your chosen directory for creating files in is not writable, or you ran out of disk space). Backup aborted.'); $this->log(__('Could not create files in the backup directory. Backup aborted - check your UpdraftPlus settings.', 'updraftplus'), 'error'); return false; } // Some house-cleaning $this->clean_temporary_files(); // Log some information that may be helpful $this->log("Tasks: Backup files: {$backup_files} (schedule: " . UpdraftPlus_Options::get_updraft_option('updraft_interval', 'unset') . ") Backup DB: {$backup_database} (schedule: " . UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'unset') . ")"); if (false === $one_shot && is_bool($backup_database)) { # If the files and database schedules are the same, and if this the file one, then we rope in database too. # On the other hand, if the schedules were the same and this was the database run, then there is nothing to do. if ('manual' != UpdraftPlus_Options::get_updraft_option('updraft_interval') && (UpdraftPlus_Options::get_updraft_option('updraft_interval') == UpdraftPlus_Options::get_updraft_option('updraft_interval_database') || UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'xyz') == 'xyz')) { $backup_database = $backup_files == true ? true : false; } $this->log("Processed schedules. Tasks now: Backup files: {$backup_files} Backup DB: {$backup_database}"); } $semaphore = ($backup_files ? 'f' : '') . ($backup_database ? 'd' : ''); $this->ensure_semaphore_exists($semaphore); if (false == apply_filters('updraftplus_boot_backup', true, $backup_files, $backup_database, $one_shot)) { $updraftplus->log("Backup aborted (via filter)"); return false; } if (!is_string($service) && !is_array($service)) { $service = UpdraftPlus_Options::get_updraft_option('updraft_service'); } $service = $this->just_one($service); if (is_string($service)) { $service = array($service); } if (!is_array($service)) { $service = array('none'); } if (!empty($options['extradata']) && preg_match('#services=remotesend/(\\d+)#', $options['extradata'])) { if ($service === array('none')) { $service = array(); } $service[] = 'remotesend'; } $option_cache = array(); foreach ($service as $serv) { if ('' == $serv || 'none' == $serv) { continue; } include_once UPDRAFTPLUS_DIR . '/methods/' . $serv . '.php'; $cclass = 'UpdraftPlus_BackupModule_' . $serv; $obj = new $cclass(); if (method_exists($cclass, 'get_credentials')) { $opts = $obj->get_credentials(); if (is_array($opts)) { foreach ($opts as $opt) { $option_cache[$opt] = UpdraftPlus_Options::get_updraft_option($opt); } } } } $option_cache = apply_filters('updraftplus_job_option_cache', $option_cache); // If nothing to be done, then just finish if (!$backup_files && !$backup_database) { $ret = $this->backup_finish(1, false, false, 0); // Don't keep useless log files if (!UpdraftPlus_Options::get_updraft_option('updraft_debug_mode') && !empty($this->logfile_name) && file_exists($this->logfile_name)) { unlink($this->logfile_name); } return $ret; } require_once UPDRAFTPLUS_DIR . '/includes/class-semaphore.php'; $this->semaphore = UpdraftPlus_Semaphore::factory(); $this->semaphore->lock_name = $semaphore; $this->log('Requesting semaphore lock (' . $semaphore . ')'); if (!$this->semaphore->lock()) { $this->log('Failed to gain semaphore lock (' . $semaphore . ') - another backup of this type is apparently already active - aborting (if this is wrong - i.e. if the other backup crashed without removing the lock, then another can be started after 3 minutes)'); return; } // Allow the resume interval to be more than 300 if last time we know we went beyond that - but never more than 600 if (defined('UPDRAFTPLUS_INITIAL_RESUME_INTERVAL') && is_numeric(UPDRAFTPLUS_INITIAL_RESUME_INTERVAL)) { $resume_interval = UPDRAFTPLUS_INITIAL_RESUME_INTERVAL; } else { $resume_interval = (int) min(max(300, get_site_transient('updraft_initial_resume_interval')), 600); } # We delete it because we only want to know about behaviour found during the very last backup run (so, if you move servers then old data is not retained) delete_site_transient('updraft_initial_resume_interval'); $job_file_entities = array(); if ($backup_files) { $possible_backups = $this->get_backupable_file_entities(true); foreach ($possible_backups as $youwhat => $whichdir) { if (false === $restrict_files_to_override && UpdraftPlus_Options::get_updraft_option("updraft_include_{$youwhat}", apply_filters("updraftplus_defaultoption_include_{$youwhat}", true)) || is_array($restrict_files_to_override) && in_array($youwhat, $restrict_files_to_override)) { // The 0 indicates the zip file index $job_file_entities[$youwhat] = array('index' => 0); } } } $followups_allowed = !$one_shot && defined('DOING_CRON') && DOING_CRON || defined('UPDRAFTPLUS_FOLLOWUPS_ALLOWED') && UPDRAFTPLUS_FOLLOWUPS_ALLOWED; $split_every = max(intval(UpdraftPlus_Options::get_updraft_option('updraft_split_every', 500)), UPDRAFTPLUS_SPLIT_MIN); $initial_jobdata = array('resume_interval', $resume_interval, 'job_type', 'backup', 'jobstatus', 'begun', 'backup_time', $this->backup_time, 'job_time_ms', $this->job_time_ms, 'service', $service, 'split_every', $split_every, 'maxzipbatch', 26214400, 'job_file_entities', $job_file_entities, 'option_cache', $option_cache, 'uploaded_lastreset', 9, 'one_shot', $one_shot, 'followsups_allowed', $followups_allowed); if ($one_shot) { update_site_option('updraft_oneshotnonce', $this->nonce); } if (!empty($options['extradata']) && 'autobackup' == $options['extradata']) { array_push($initial_jobdata, 'is_autobackup', true); } // Save what *should* be done, to make it resumable from this point on if ($backup_database) { $dbs = apply_filters('updraft_backup_databases', array('wp' => 'begun')); if (is_array($dbs)) { foreach ($dbs as $key => $db) { if ('wp' != $key && (!is_array($db) || empty($db['dbinfo']) || !is_array($db['dbinfo']) || empty($db['dbinfo']['host']))) { unset($dbs[$key]); } } } } else { $dbs = "no"; } array_push($initial_jobdata, 'backup_database', $dbs); array_push($initial_jobdata, 'backup_files', $backup_files ? 'begun' : 'no'); if (is_array($options) && !empty($options['label'])) { array_push($initial_jobdata, 'label', $options['label']); } try { // Use of jobdata_set_multi saves around 200ms call_user_func_array(array($this, 'jobdata_set_multi'), apply_filters('updraftplus_initial_jobdata', $initial_jobdata, $options, $split_every)); } catch (Exception $e) { $this->log($e->getMessage()); return false; } // Everything is set up; now go $this->backup_resume(0, $this->nonce); if ($one_shot) { delete_site_option('updraft_oneshotnonce'); } }
public function boot_backup($backup_files, $backup_database, $restrict_files_to_override = false, $one_shot = false, $service = false) { @ignore_user_abort(true); // 15 minutes @set_time_limit(900); //generate backup information $this->backup_time_nonce(); // The current_resumption is consulted within logfile_open() $this->current_resumption = 0; $this->logfile_open($this->nonce); if (!is_file($this->logfile_name)) { $this->log('Failed to open log file (' . $this->logfile_name . ') - you need to check your UpdraftPlus settings (your chosen directory for creating files in is not writable, or you ran out of disk space). Backup aborted.'); $this->log(__('Could not create files in the backup directory. Backup aborted - check your UpdraftPlus settings.', 'updraftplus'), 'error'); return false; } // Some house-cleaning $this->clean_temporary_files(); do_action('updraftplus_boot_backup'); // Log some information that may be helpful $this->log("Tasks: Backup files: {$backup_files} (schedule: " . UpdraftPlus_Options::get_updraft_option('updraft_interval', 'unset') . ") Backup DB: {$backup_database} (schedule: " . UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'unset') . ")"); if (false === $one_shot && is_bool($backup_database)) { # If the files and database schedules are the same, and if this the file one, then we rope in database too. # On the other hand, if the schedules were the same and this was the database run, then there is nothing to do. if ('manual' != UpdraftPlus_Options::get_updraft_option('updraft_interval') && (UpdraftPlus_Options::get_updraft_option('updraft_interval') == UpdraftPlus_Options::get_updraft_option('updraft_interval_database') || UpdraftPlus_Options::get_updraft_option('updraft_interval_database', 'xyz') == 'xyz')) { $backup_database = $backup_files == true ? true : false; } $this->log("Processed schedules. Tasks now: Backup files: {$backup_files} Backup DB: {$backup_database}"); } $semaphore = ($backup_files ? 'f' : '') . ($backup_database ? 'd' : ''); // Make sure the options for semaphores exist global $wpdb; $results = $wpdb->get_results("\n\t\t\tSELECT option_id\n\t\t\t\tFROM {$wpdb->options}\n\t\t\t\tWHERE option_name IN ('updraftplus_locked_{$semaphore}', 'updraftplus_unlocked_{$semaphore}')\n\t\t"); // Use of update_option() is correct here - since it is what is used in class-semaphore.php if (!count($results)) { update_option('updraftplus_unlocked_' . $semaphore, '1'); update_option('updraftplus_last_lock_time_' . $semaphore, current_time('mysql', 1)); update_option('updraftplus_semaphore_' . $semaphore, '0'); } if (!is_string($service) && !is_array($service)) { $service = UpdraftPlus_Options::get_updraft_option('updraft_service'); } $service = $this->just_one($service); if (is_string($service)) { $service = array($service); } $option_cache = array(); foreach ($service as $serv) { if ('' == $serv || 'none' == $serv) { continue; } include_once UPDRAFTPLUS_DIR . '/methods/' . $serv . '.php'; $cclass = 'UpdraftPlus_BackupModule_' . $serv; $obj = new $cclass(); if (method_exists($cclass, 'get_credentials')) { $opts = $obj->get_credentials(); if (is_array($opts)) { foreach ($opts as $opt) { $option_cache[$opt] = UpdraftPlus_Options::get_updraft_option($opt); } } } } $option_cache = apply_filters('updraftplus_job_option_cache', $option_cache); # If nothing to be done, then just finish if (!$backup_files && !$backup_database) { $this->backup_finish(1, false, false, 0); return; } require_once UPDRAFTPLUS_DIR . '/includes/class-semaphore.php'; $this->semaphore = UpdraftPlus_Semaphore::factory(); $this->semaphore->lock_name = $semaphore; $this->log('Requesting semaphore lock (' . $semaphore . ')'); if (!$this->semaphore->lock()) { $this->log('Failed to gain semaphore lock (' . $semaphore . ') - another backup of this type is apparently already active - aborting (if this is wrong - i.e. if the other backup crashed without removing the lock, then another can be started after 3 minutes)'); return; } // Allow the resume interval to be more than 300 if last time we know we went beyond that - but never more than 600 $resume_interval = (int) min(max(300, get_site_transient('updraft_initial_resume_interval')), 600); # We delete it because we only want to know about behaviour found during the very last backup run (so, if you move servers then old data is not retained) delete_site_transient('updraft_initial_resume_interval'); $job_file_entities = array(); if ($backup_files) { $possible_backups = $this->get_backupable_file_entities(true); foreach ($possible_backups as $youwhat => $whichdir) { if (false === $restrict_files_to_override && UpdraftPlus_Options::get_updraft_option("updraft_include_{$youwhat}", apply_filters("updraftplus_defaultoption_include_{$youwhat}", true)) || is_array($restrict_files_to_override) && in_array($youwhat, $restrict_files_to_override)) { // The 0 indicates the zip file index $job_file_entities[$youwhat] = array('index' => 0); } } } $initial_jobdata = array('resume_interval', $resume_interval, 'job_type', 'backup', 'jobstatus', 'begun', 'backup_time', $this->backup_time, 'job_time_ms', $this->job_time_ms, 'service', $service, 'split_every', max(intval(UpdraftPlus_Options::get_updraft_option('updraft_split_every', 800)), UPDRAFTPLUS_SPLIT_MIN), 'maxzipbatch', 26214400, 'job_file_entities', $job_file_entities, 'option_cache', $option_cache, 'uploaded_lastreset', 9, 'one_shot', $one_shot); if ($one_shot) { update_site_option('updraft_oneshotnonce', $this->nonce); } // Save what *should* be done, to make it resumable from this point on array_push($initial_jobdata, 'backup_database', $backup_database ? 'begun' : 'no'); array_push($initial_jobdata, 'backup_files', $backup_files ? 'begun' : 'no'); // Use of jobdata_set_multi saves around 200ms call_user_func_array(array($this, 'jobdata_set_multi'), $initial_jobdata); // Everything is set up; now go $this->backup_resume(0, $this->nonce); if ($one_shot) { delete_site_option('updraft_oneshotnonce'); } }