} elseif (preg_match('/^downloaded:(\d+):(.*)$/', $file, $matches) && file_exists($matches[2])) {
$response['f'] = $matches[2];
$response['s'] = (int) $matches[1];
$response['t'] = (int) $matches[1];
$response['m'] = __('File ready.', 'updraftplus');
if ('db' != substr($type, 0, 2)) $response['can_show_contents'] = true;
} elseif (preg_match('/^downloading:(\d+):(.*)$/', $file, $matches) && file_exists($matches[2])) {
$response['f'] = $matches[2];
$total_size = (int) max($matches[1], 1);
$cur_size = filesize($matches[2]);
$response['s'] = $cur_size;
$file_age = time() - filemtime($matches[2]);
if ($file_age > 20) $response['a'] = time() - filemtime($matches[2]);
$response['t'] = $total_size;
$response['m'] .= __("Download in progress", 'updraftplus').' ('.round($cur_size/1024).' / '.round(($total_size/1024)).' KB)';
$response['p'] = round(100*$cur_size/$total_size);
$response['m'] .= __('No local copy present.', 'updraftplus');
* Used with the WP filter upload_dir to adjust where uploads go to when uploading a backup
* @param Array $uploads - pre-filter array
* @return Array - filtered array
public function upload_dir($uploads) {
$updraft_dir = $updraftplus->backups_dir_location();
if (is_writable($updraft_dir)) $uploads['path'] = $updraft_dir;
* We do actually want to over-write
* @param String $dir Directory
* @param String $name Name
* @param String $ext File extension
public function unique_filename_callback($dir, $name, $ext) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Filter use
public function sanitize_file_name($filename) {
// WordPress 3.4.2 on multisite (at least) adds in an unwanted underscore
return preg_replace('/-db(.*)\.gz_\.crypt$/', '-db$1.gz.crypt', $filename);
* Runs upon the WordPress action plupload_action
public function plupload_action() {
if (function_exists('set_time_limit')) @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
if (!UpdraftPlus_Options::user_can_manage()) return;
check_ajax_referer('updraft-uploader');
$updraft_dir = $updraftplus->backups_dir_location();
if (!@UpdraftPlus_Filesystem_Functions::really_is_writable($updraft_dir)) {// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
echo json_encode(array('e' => sprintf(__("Backup directory (%s) is not writable, or does not exist.", 'updraftplus'), $updraft_dir).' '.__('You will find more information about this in the Settings section.', 'updraftplus')));
add_filter('upload_dir', array($this, 'upload_dir'));
add_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
$farray = array('test_form' => true, 'action' => 'plupload_action');
$farray['test_type'] = false;
$farray['ext'] = 'x-gzip';
$farray['type'] = 'application/octet-stream';
if (!isset($_POST['chunks'])) {
$farray['unique_filename_callback'] = array($this, 'unique_filename_callback');
$status = wp_handle_upload(
remove_filter('upload_dir', array($this, 'upload_dir'));
remove_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
if (isset($status['error'])) {
echo json_encode(array('e' => $status['error']));
// If this was the chunk, then we should instead be concatenating onto the final file
if (isset($_POST['chunks']) && isset($_POST['chunk']) && preg_match('/^[0-9]+$/', $_POST['chunk'])) {
$final_file = basename($_POST['name']);
if (!rename($status['file'], $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp')) {
@unlink($status['file']);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftplus'), __('This file could not be uploaded', 'updraftplus'))));
$status['file'] = $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp';
if (!isset($_POST['chunks']) || (isset($_POST['chunk']) && preg_match('/^[0-9]+$/', $_POST['chunk']) && $_POST['chunk'] == $_POST['chunks']-1) && isset($final_file)) {
if (!preg_match('/^log\.[a-f0-9]{12}\.txt/i', $final_file) && !preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-([\-a-z]+)([0-9]+)?(\.(zip|gz|gz\.crypt))?$/i', $final_file, $matches)) {
$accept = apply_filters('updraftplus_accept_archivename', array());
foreach ($accept as $acc) {
if (preg_match('/'.$acc['pattern'].'/i', $final_file)) {
$response['dm'] = sprintf(__('This backup was created by %s, and can be imported.', 'updraftplus'), $acc['desc']);
if (empty($response['dm'])) {
if (isset($status['file'])) @unlink($status['file']);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftplus'), __('Bad filename format - this does not look like a file created by UpdraftPlus', 'updraftplus'))));
$backupable_entities = $updraftplus->get_backupable_file_entities(true);
$type = isset($matches[3]) ? $matches[3] : '';
if (!preg_match('/^log\.[a-f0-9]{12}\.txt/', $final_file) && 'db' != $type && !isset($backupable_entities[$type])) {
if (isset($status['file'])) @unlink($status['file']);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
echo json_encode(array('e' => sprintf(__('Error: %s', 'updraftplus'), sprintf(__('This looks like a file created by UpdraftPlus, but this install does not know about this type of object: %s. Perhaps you need to install an add-on?', 'updraftplus'), htmlspecialchars($type)))));
// Final chunk? If so, then stich it all back together
if (isset($_POST['chunk']) && $_POST['chunk'] == $_POST['chunks']-1 && !empty($final_file)) {
if ($wh = fopen($updraft_dir.'/'.$final_file, 'wb')) {
for ($i = 0; $i < $_POST['chunks']; $i++) {
$rf = $updraft_dir.'/'.$final_file.'.'.$i.'.zip.tmp';
if ($rh = fopen($rf, 'rb+')) {
// April 1st 2020 - Due to a bug during uploads to Dropbox some backups had string "null" appended to the end which caused warnings, this removes the string "null" from these backups
fseek($rh, -4, SEEK_END);
ftruncate($rh, filesize($rf) - 4);
while ($line = fread($rh, 262144)) {
@unlink($rf);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
$status['file'] = $updraft_dir.'/'.$final_file;
if ('.tar' == substr($final_file, -4, 4)) {
if (file_exists($status['file'].'.gz')) unlink($status['file'].'.gz');
if (file_exists($status['file'].'.bz2')) unlink($status['file'].'.bz2');
} elseif ('.tar.gz' == substr($final_file, -7, 7)) {
if (file_exists(substr($status['file'], 0, strlen($status['file'])-3))) unlink(substr($status['file'], 0, strlen($status['file'])-3));
if (file_exists(substr($status['file'], 0, strlen($status['file'])-3).'.bz2')) unlink(substr($status['file'], 0, strlen($status['file'])-3).'.bz2');
} elseif ('.tar.bz2' == substr($final_file, -8, 8)) {
if (file_exists(substr($status['file'], 0, strlen($status['file'])-4))) unlink(substr($status['file'], 0, strlen($status['file'])-4));
if (file_exists(substr($status['file'], 0, strlen($status['file'])-4).'.gz')) unlink(substr($status['file'], 0, strlen($status['file'])-3).'.gz');
// send the uploaded file url in response
$response['m'] = $status['url'];
echo json_encode($response);
* Database decrypter - runs upon the WP action plupload_action2
public function plupload_action2() {
if (function_exists('set_time_limit')) @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
if (!UpdraftPlus_Options::user_can_manage()) return;
check_ajax_referer('updraft-uploader');
$updraft_dir = $updraftplus->backups_dir_location();
if (!is_writable($updraft_dir)) exit;
add_filter('upload_dir', array($this, 'upload_dir'));
add_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
$farray = array('test_form' => true, 'action' => 'plupload_action2');
$farray['test_type'] = false;
$farray['ext'] = 'crypt';
$farray['type'] = 'application/octet-stream';
if (isset($_POST['chunks'])) {
// $farray['ext'] = 'zip';
// $farray['type'] = 'application/zip';
$farray['unique_filename_callback'] = array($this, 'unique_filename_callback');
$status = wp_handle_upload(
remove_filter('upload_dir', array($this, 'upload_dir'));
remove_filter('sanitize_file_name', array($this, 'sanitize_file_name'));
if (isset($status['error'])) die('ERROR: '.$status['error']);
// If this was the chunk, then we should instead be concatenating onto the final file
if (isset($_POST['chunks']) && isset($_POST['chunk']) && preg_match('/^[0-9]+$/', $_POST['chunk'])) {
$final_file = basename($_POST['name']);
rename($status['file'], $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp');
$status['file'] = $updraft_dir.'/'.$final_file.'.'.$_POST['chunk'].'.zip.tmp';
if (!isset($_POST['chunks']) || (isset($_POST['chunk']) && $_POST['chunk'] == $_POST['chunks']-1)) {
if (!preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-db([0-9]+)?\.(gz\.crypt)$/i', $final_file)) {
@unlink($status['file']);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
echo 'ERROR:'.__('Bad filename format - this does not look like an encrypted database file created by UpdraftPlus', 'updraftplus');
// Final chunk? If so, then stich it all back together
if (isset($_POST['chunk']) && $_POST['chunk'] == $_POST['chunks']-1 && isset($final_file)) {
if ($wh = fopen($updraft_dir.'/'.$final_file, 'wb')) {
for ($i=0; $i<$_POST['chunks']; $i++) {
$rf = $updraft_dir.'/'.$final_file.'.'.$i.'.zip.tmp';
if ($rh = fopen($rf, 'rb')) {
while ($line = fread($rh, 32768)) {
@unlink($rf);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
// send the uploaded file url in response
if (isset($final_file)) echo 'OK:'.$final_file;
* Show footer review message and link.
public function display_footer_review_message() {
__('Enjoyed %s? Please leave us a %s rating. We really appreciate your support!', 'updraftplus'),
'<a href="https://www.g2.com/products/updraftplus/reviews" target="_blank">★★★★★</a>'
* Include the settings header template
public function settings_header() {
$this->include_template('wp-admin/settings/header.php');
* Include the settings footer template
public function settings_footer() {
$this->include_template('wp-admin/settings/footer.php');
* Output the settings page content. Will also run a restore if $_REQUEST so indicates.
public function settings_output() {
if (false == ($render = apply_filters('updraftplus_settings_page_render', true))) {
do_action('updraftplus_settings_page_render_abort', $render);
do_action('updraftplus_settings_page_init');
* We use request here because the initial restore is triggered by a POSTed form. we then may need to obtain credential for the WP_Filesystem. to do this WP outputs a form, but we don't pass our parameters via that. So the values are passed back in as GET parameters.
if (isset($_REQUEST['action']) && (('updraft_restore' == $_REQUEST['action'] && isset($_REQUEST['backup_timestamp'])) || ('updraft_restore_continue' == $_REQUEST['action'] && !empty($_REQUEST['job_id'])))) {
$this->prepare_restore();
if (isset($_REQUEST['action']) && 'updraft_delete_old_dirs' == $_REQUEST['action']) {
$nonce = empty($_REQUEST['updraft_delete_old_dirs_nonce']) ? '' : $_REQUEST['updraft_delete_old_dirs_nonce'];
if (!wp_verify_nonce($nonce, 'updraftplus-credentialtest-nonce')) die('Security check');
$this->delete_old_dirs_go();
if (!empty($_REQUEST['action']) && 'updraftplus_broadcastaction' == $_REQUEST['action'] && !empty($_REQUEST['subaction'])) {
$nonce = (empty($_REQUEST['nonce'])) ? "" : $_REQUEST['nonce'];
if (!wp_verify_nonce($nonce, 'updraftplus-credentialtest-nonce')) die('Security check');
do_action($_REQUEST['subaction']);
if (isset($_GET['error'])) {
// This is used by Microsoft OneDrive authorisation failures (May 15). I am not sure what may have been using the 'error' GET parameter otherwise - but it is harmless.
if (!empty($_GET['error_description'])) {
$this->show_admin_warning(htmlspecialchars($_GET['error_description']).' ('.htmlspecialchars($_GET['error']).')', 'error');
$this->show_admin_warning(htmlspecialchars($_GET['error']), 'error');
if (isset($_GET['message'])) $this->show_admin_warning(htmlspecialchars($_GET['message']));
if (isset($_GET['action']) && 'updraft_create_backup_dir' == $_GET['action'] && isset($_GET['nonce']) && wp_verify_nonce($_GET['nonce'], 'create_backup_dir')) {
$created = $this->create_backup_dir();
if (is_wp_error($created)) {
echo '<p>'.__('Backup directory could not be created', 'updraftplus').'...<br>';
echo '<ul class="disc">';
foreach ($created->get_error_messages() as $msg) {
echo '<li>'.htmlspecialchars($msg).'</li>';
} elseif (false !== $created) {
echo '<p>'.__('Backup directory successfully created.', 'updraftplus').'</p><br>';
echo '<b>'.__('Actions', 'updraftplus').':</b> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus">'.__('Return to UpdraftPlus configuration', 'updraftplus').'</a>';
if (substr($updraftplus->version, 0, 1) === '2') {
* Add filter for display footer review message and link.
add_filter('admin_footer_text', array($this, 'display_footer_review_message'));
echo '<div id="updraft_backup_started" class="updated updraft-hidden" style="display:none;"></div>';
$this->settings_header();
<div id="updraft-hidethis">
<strong><?php _e('Warning:', 'updraftplus'); ?> <?php _e("If you can still read these words after the page finishes loading, then there is a JavaScript or jQuery problem in the site.", 'updraftplus'); ?></strong>
<?php if (false !== strpos(basename(UPDRAFTPLUS_URL), ' ')) { ?>
<strong><?php _e('The UpdraftPlus directory in wp-content/plugins has white-space in it; WordPress does not like this. You should rename the directory to wp-content/plugins/updraftplus to fix this problem.', 'updraftplus');?></strong>
<a href="<?php echo apply_filters('updraftplus_com_link', "https://updraftplus.com/do-you-have-a-javascript-or-jquery-error/");?>" target="_blank"><?php _e('Go here for more information.', 'updraftplus'); ?></a>
$include_deleteform_div = true;
// Opens a div, which needs closing later
if (isset($_GET['updraft_restore_success'])) {
if (get_template() === 'optimizePressTheme' || is_plugin_active('optimizePressPlugin') || is_plugin_active_for_network('optimizePressPlugin')) {
$this->show_admin_warning("<a href='https://optimizepress.zendesk.com/hc/en-us/articles/203699826-Update-URL-References-after-moving-domain' target='_blank'>" . __("OptimizePress 2.0 encodes its contents, so search/replace does not work.", "updraftplus") . ' ' . __("To fix this problem go here.", "updraftplus") . "</a>", "notice notice-warning");
$success_advert = (isset($_GET['pval']) && 0 == $_GET['pval'] && !$updraftplus->have_addons) ? '<p>'.__('For even more features and personal support, check out ', 'updraftplus').'<strong><a href="'.$updraftplus->get_url('premium').'" target="_blank">UpdraftPlus Premium</a>.</strong></p>' : "";
echo "<div class=\"updated backup-restored\"><span><strong>".__('Your backup has been restored.', 'updraftplus').'</strong></span><br>';
// Unnecessary - will be advised of this below
// if (2 == $_GET['updraft_restore_success']) echo ' '.__('Your old (themes, uploads, plugins, whatever) directories have been retained with "-old" appended to their name. Remove them when you are satisfied that the backup worked properly.');
$include_deleteform_div = false;
if ($this->scan_old_dirs(true)) $this->print_delete_old_dirs_form(true, $include_deleteform_div);
// Close the div opened by the earlier section
if (isset($_GET['updraft_restore_success'])) echo '</div>';
if (empty($success_advert) && empty($this->no_settings_warning)) {
if (!class_exists('UpdraftPlus_Notices')) include_once(UPDRAFTPLUS_DIR.'/includes/updraftplus-notices.php');
global $updraftplus_notices;
$backup_history = UpdraftPlus_Backup_History::get_history();
$review_dismiss = UpdraftPlus_Options::get_updraft_option('dismissed_review_notice', 0);
$backup_dir = $updraftplus->backups_dir_location();
// N.B. Not an exact proxy for the installed time; they may have tweaked the expert option to move the directory
$installed = @filemtime($backup_dir.'/index.html');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
$installed_for = time() - $installed;
if (!empty($backup_history) && $installed && time() > $review_dismiss && $installed_for > 28*86400 && $installed_for < 84*86400) {
$updraftplus_notices->do_notice($advert);
if (!$updraftplus->memory_check(64)) {
// HS8390 - A case where UpdraftPlus::memory_check_current() returns -1
$memory_check_current = $updraftplus->memory_check_current();
if ($memory_check_current > 0) {
<div class="updated memory-limit"><?php _e('Your PHP memory limit (set by your web hosting company) is very low. UpdraftPlus attempted to raise it but was unsuccessful. This plugin may struggle with a memory limit of less than 64 Mb - especially if you have very large files uploaded (though on the other hand, many sites will be successful with a 32Mb limit - your experience may vary).', 'updraftplus');?> <?php _e('Current limit is:', 'updraftplus');?> <?php echo $updraftplus->memory_check_current(); ?> MB</div>
if (!empty($updraftplus->errors)) {
echo '<div class="error updraft_list_errors">';
$updraftplus->list_errors();
$backup_history = UpdraftPlus_Backup_History::get_history();
if (empty($backup_history)) {
UpdraftPlus_Backup_History::rebuild();
$backup_history = UpdraftPlus_Backup_History::get_history();
$main_tabs = $this->get_main_tabs_array();
if (isset($_REQUEST['tab'])) {
$request_tab = sanitize_text_field($_REQUEST['tab']);
$valid_tabflags = array_keys($main_tabs);
if (in_array($request_tab, $valid_tabflags)) {
$this->include_template('wp-admin/settings/tab-bar.php', false, array('main_tabs' => $main_tabs, 'backup_history' => $backup_history, 'tabflag' => $tabflag));
<div id="updraft-poplog" >
<pre id="updraft-poplog-content"></pre>
$this->include_template('wp-admin/settings/delete-and-restore-modals.php');
<div id="updraft-navtab-backups-content" <?php if ('backups' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('backups' != $tabflag) echo 'display:none;'; ?>">
$is_opera = (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/'));
$tmp_opts = array('include_opera_warning' => $is_opera);
$this->include_template('wp-admin/settings/tab-backups.php', false, array('backup_history' => $backup_history, 'options' => $tmp_opts));
$this->include_template('wp-admin/settings/upload-backups-modal.php');
<div id="updraft-navtab-migrate-content"<?php if ('migrate' != $tabflag) echo ' class="updraft-hidden"'; ?> style="<?php if ('migrate' != $tabflag) echo 'display:none;'; ?>">
if (has_action('updraftplus_migrate_tab_output')) {
do_action('updraftplus_migrate_tab_output');
$this->include_template('wp-admin/settings/migrator-no-migrator.php');
<div id="updraft-navtab-settings-content" <?php if ('settings' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('settings' != $tabflag) echo 'display:none;'; ?>">
<h2 class="updraft_settings_sectionheading"><?php _e('Backup Contents And Schedule', 'updraftplus');?></h2>
<?php UpdraftPlus_Options::options_form_begin(); ?>