$this->setup_all_admin_notices_global($service);
$this->setup_all_admin_notices_udonly($service);
do_action('all_admin_notices');
if (!$really_is_writable) { // Check if writable
$this->show_admin_warning_unwritable();
if ($return_array['saved']) { //
$this->show_admin_warning(__('Your settings have been saved.', 'updraftplus'), 'updated fade');
if (isset($return_array['error_message'])) {
$this->show_admin_warning($return_array['error_message'], 'error');
$this->show_admin_warning(__('Your settings failed to save. Please refresh the settings page and try again', 'updraftplus'), 'error');
$messages_output = ob_get_contents();
// Backup schedule output
$this->next_scheduled_backups_output('line');
$scheduled_output = ob_get_clean();
$return_array['messages'] = $messages_output;
$return_array['scheduled'] = $scheduled_output;
$return_array['files_scheduled'] = $this->next_scheduled_files_backups_output(true);
$return_array['database_scheduled'] = $this->next_scheduled_database_backups_output(true);
// Add the updated options to the return message, so we can update on screen
* Authenticate remote storage instance
* @param array - $data It consists of below key elements:
* $remote_method - Remote storage service
* $instance_id - Remote storage instance id
* @return array An array response containing the status of the authentication
public function auth_remote_method($data) {
if (isset($data['remote_method']) && isset($data['instance_id'])) {
$response['result'] = 'success';
$remote_method = $data['remote_method'];
$instance_id = $data['instance_id'];
$storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array($remote_method));
$storage_objects_and_ids[$remote_method]['object']->authenticate_storage($instance_id);
$response['result'] = 'error';
$response['message'] = $updraftplus->backup_methods[$remote_method] . ' ' . __('authentication error', 'updraftplus') . ' ' . $e->getMessage();
$response['result'] = 'error';
$response['message'] = __('Remote storage method and instance id are required for authentication.', 'updraftplus');
* Deauthenticate remote storage instance
* @param array - $data It consists of below key elements:
* $remote_method - Remote storage service
* $instance_id - Remote storage instance id
* @return array An array response containing the status of the deauthentication
public function deauth_remote_method($data) {
if (isset($data['remote_method']) && isset($data['instance_id'])) {
$response['result'] = 'success';
$remote_method = $data['remote_method'];
$instance_id = $data['instance_id'];
$storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array($remote_method));
$storage_objects_and_ids[$remote_method]['object']->deauthenticate_storage($instance_id);
$response['result'] = 'error';
$response['message'] = $updraftplus->backup_methods[$remote_method] . ' deauthentication error ' . $e->getMessage();
$response['result'] = 'error';
$response['message'] = 'Remote storage method and instance id are required for deauthentication.';
* A method to remove UpdraftPlus settings from the options table.
* @param boolean $wipe_all_settings Set to true as default as we want to remove all options, set to false if calling from UpdraftCentral, as we do not want to remove the UpdraftCentral key or we will lose connection to the site.
public function wipe_settings($wipe_all_settings = true) {
$settings = $updraftplus->get_settings_keys();
// if this is false the UDC has called it we don't want to remove the UDC key other wise we will lose connection to the remote site.
if (false == $wipe_all_settings) {
$key = array_search('updraft_central_localkeys', $settings);
foreach ($settings as $s) UpdraftPlus_Options::delete_updraft_option($s);
if (is_multisite()) $updraftplus->wipe_state_data(true, 'sitemeta');
$updraftplus->wipe_state_data(true);
$site_options = array('updraft_oneshotnonce');
foreach ($site_options as $s) delete_site_option($s);
$this->show_admin_warning(__("Your settings have been wiped.", 'updraftplus'));
* This get the details for updraft vault and to be used globally
* @param string $instance_id - the instance_id of the current instance being used
* @return object - the UpdraftVault option setup to use the passed in instance id or if one wasn't passed then use the default set of options
public function get_updraftvault($instance_id = '') {
$storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array('updraftvault'));
if (isset($storage_objects_and_ids['updraftvault']['instance_settings'][$instance_id])) {
$opts = $storage_objects_and_ids['updraftvault']['instance_settings'][$instance_id];
$vault = $storage_objects_and_ids['updraftvault']['object'];
$vault->set_options($opts, false, $instance_id);
include_once(UPDRAFTPLUS_DIR.'/methods/updraftvault.php');
$vault = new UpdraftPlus_BackupModule_updraftvault();
* http_get will allow the HTTP Fetch execute available in advanced tools
* @param String $uri Specific URL passed to curl
* @param Boolean $curl True or False if cURL is to be used
* @return String - JSON encoded results
public function http_get($uri = null, $curl = false) {
if (!preg_match('/^https?/', $uri)) return json_encode(array('e' => 'Non-http URL specified'));
if (!function_exists('curl_exec')) {
return json_encode(array('e' => 'No Curl installed'));
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FAILONERROR, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_STDERR, $output = fopen('php://temp', "w+"));
$response = curl_exec($ch);
$error = curl_error($ch);
$getinfo = curl_getinfo($ch);
$verb = stream_get_contents($output);
if (false === $response) {
$resp['e'] = htmlspecialchars($error);
$resp['r'] = (empty($response)) ? '' : htmlspecialchars(substr($response, 0, 2048));
if (!empty($verb)) $resp['r'] = htmlspecialchars($verb)."\n\n".$resp['r'];
// Extra info returned for Central
$resp['response'] = $response;
$resp['status'] = $getinfo;
return json_encode($resp);
$response = wp_remote_get($uri, array('timeout' => 10));
if (is_wp_error($response)) {
return json_encode(array('e' => htmlspecialchars($response->get_error_message())));
'r' => wp_remote_retrieve_response_code($response).': '.htmlspecialchars(substr(wp_remote_retrieve_body($response), 0, 2048)),
'code' => wp_remote_retrieve_response_code($response),
'html_response' => htmlspecialchars(substr(wp_remote_retrieve_body($response), 0, 2048)),
* This will return all the details for raw backup and file list, in HTML format
* @param Boolean $no_pre_tags - if set, then <pre></pre> tags will be removed from the output
public function show_raw_backups($no_pre_tags = false) {
$response['html'] = '<h3 id="ud-debuginfo-rawbackups">'.__('Known backups (raw)', 'updraftplus').'</h3><pre>';
$history = UpdraftPlus_Backup_History::get_history();
$response["html"] .= ob_get_clean();
$response['html'] .= '</pre>';
$response['html'] .= '<h3 id="ud-debuginfo-files">'.__('Files', 'updraftplus').'</h3><pre>';
$updraft_dir = $updraftplus->backups_dir_location();
while (false !== ($entry = $d->read())) {
$fp = $updraft_dir.'/'.$entry;
} elseif (is_link($fp)) {
} elseif (is_file($fp)) {
$size = sprintf("%8.1f", round(filesize($fp)/1024, 1)).' '.gmdate('r', $mtime);
if (preg_match('/^log\.(.*)\.txt$/', $entry, $lmatch)) $entry = '<a target="_top" href="?action=downloadlog&page=updraftplus&updraftplus_backup_nonce='.htmlspecialchars($lmatch[1]).'">'.$entry.'</a>';
$raw_output[$mtime] = empty($raw_output[$mtime]) ? sprintf("%s %s\n", $size, $entry) : $raw_output[$mtime].sprintf("%s %s\n", $size, $entry);
@$d->close();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
krsort($raw_output, SORT_NUMERIC);
foreach ($raw_output as $line) {
$response['html'] .= $line;
$response['html'] .= '</pre>';
$response['html'] .= '<h3 id="ud-debuginfo-options">'.__('Options (raw)', 'updraftplus').'</h3>';
$opts = $updraftplus->get_settings_keys();
// <tr><th>'.__('Key', 'updraftplus').'</th><th>'.__('Value', 'updraftplus').'</th></tr>
$response['html'] .= '<table><thead></thead><tbody>';
foreach ($opts as $opt) {
$response['html'] .= '<tr><td>'.htmlspecialchars($opt).'</td><td>'.htmlspecialchars(print_r(UpdraftPlus_Options::get_updraft_option($opt), true)).'</td>';
// Get the option saved by yahnis-elsts/plugin-update-checker
$response['html'] .= '<tr><td>external_updates-updraftplus</td><td><pre>'.htmlspecialchars(print_r(get_site_option('external_updates-updraftplus'), true)).'</pre></td>';
$response['html'] .= '</tbody></table>';
do_action('updraftplus_showrawinfo');
$response['html'] .= ob_get_clean();
if (true == $no_pre_tags) {
$response['html'] = str_replace('<pre>', '', $response['html']);
$response['html'] = str_replace('</pre>', '', $response['html']);
* This will call any wp_action
* @param Array|Null $data The array of data with the vaules for wpaction
* @param Callable|Boolean $close_connection_callable A callable to call to close the browser connection, or true for a default suitable for internal use, or false for none
* @return Array - results
public function call_wp_action($data = null, $close_connection_callable = false) {
$res = '<em>Request received: </em>';
if (preg_match('/^([^:]+)+:(.*)$/', $data['wpaction'], $matches)) {
if (null === ($args = json_decode($matches[2], true))) {
$res .= "The parameters (should be JSON) could not be decoded";
if (is_string($args)) $args = array($args);
$res .= "Will despatch action: ".htmlspecialchars($action).", parameters: ".htmlspecialchars(implode(',', $args));
$action = $data['wpaction'];
$res .= "Will despatch action: ".htmlspecialchars($action).", no parameters";
// Need to add this as the close browser should only work for UDP
if ($close_connection_callable) {
if (is_callable($close_connection_callable)) {
call_user_func($close_connection_callable, array('r' => $res));
$updraftplus->close_browser_connection(json_encode(array('r' => $res)));
$returned = do_action_ref_array($action, $args);
$output = ob_get_clean();
$res .= " - do_action_ref_array Trigger ";
$output = ob_get_contents();
$res .= " - do_action Trigger ";
$response['response'] = $res;
$response['log'] = $output;
// Check if response is empty
if (!empty($returned)) $response['status'] = $returned;
* Enqueue JSTree JavaScript and CSS, taking into account whether it is already enqueued, and current debug settings
public function enqueue_jstree() {
static $already_enqueued = false;
if ($already_enqueued) return;
$already_enqueued = true;
$jstree_enqueue_version = $updraftplus->use_unminified_scripts() ? '3.3.12-rc.0'.'.'.time() : '3.3.12-rc.0';
$min_or_not = $updraftplus->use_unminified_scripts() ? '' : '.min';
wp_enqueue_script('jstree', UPDRAFTPLUS_URL.'/includes/jstree/jstree'.$min_or_not.'.js', array('jquery'), $jstree_enqueue_version);
wp_enqueue_style('jstree', UPDRAFTPLUS_URL.'/includes/jstree/themes/default/style'.$min_or_not.'.css', array(), $jstree_enqueue_version);
* Detects byte-order mark at the start of common files and change waning message texts
* @return string|boolean BOM warning text or false if not bom characters detected
public function get_bom_warning_text() {
get_template_directory().DIRECTORY_SEPARATOR.'functions.php',
$files_to_check[] = get_stylesheet_directory().DIRECTORY_SEPARATOR.'functions.php';
$corrupted_files = array();
foreach ($files_to_check as $file) {
if (!file_exists($file)) continue;
if (false === ($fp = fopen($file, 'r'))) continue;
if (false === ($file_data = fread($fp, 8192)));
$substr_file_data = array();
for ($substr_length = 2; $substr_length <= 5; $substr_length++) {
$substr_file_data[$substr_length] = substr($file_data, 0, $substr_length);
// Detect UTF-7, UTF-8, UTF-16 (BE), UTF-16 (LE), UTF-32 (BE) & UTF-32 (LE) Byte order marks (BOM)
$bom_decimal_representations = array(
array(43, 47, 118, 56), // UTF-7 (Hexadecimal: 2B 2F 76 38)
array(43, 47, 118, 57), // UTF-7 (Hexadecimal: 2B 2F 76 39)
array(43, 47, 118, 43), // UTF-7 (Hexadecimal: 2B 2F 76 2B)
array(43, 47, 118, 47), // UTF-7 (Hexadecimal: 2B 2F 76 2F)
array(43, 47, 118, 56, 45), // UTF-7 (Hexadecimal: 2B 2F 76 38 2D)
array(239, 187, 191), // UTF-8 (Hexadecimal: 2B 2F 76 38 2D)
array(254, 255), // UTF-16 (BE) (Hexadecimal: FE FF)
array(255, 254), // UTF-16 (LE) (Hexadecimal: FF FE)
array(0, 0, 254, 255), // UTF-32 (BE) (Hexadecimal: 00 00 FE FF)
array(255, 254, 0, 0), // UTF-32 (LE) (Hexadecimal: FF FE 00 00)
foreach ($bom_decimal_representations as $bom_decimal_representation) {
$no_of_chars = count($bom_decimal_representation);
array_unshift($bom_decimal_representation, 'C*');
$binary = call_user_func_array('pack', $bom_decimal_representation);
if ($binary == $substr_file_data[$no_of_chars]) {
$corrupted_files[] = $file;
if (empty($corrupted_files)) {
$corrupted_files_count = count($corrupted_files);
return '<strong>'.__('Warning', 'updraftplus').':</strong> '.sprintf(_n('The file %s has a "byte order mark" (BOM) at its beginning.', 'The files %s have a "byte order mark" (BOM) at their beginning.', $corrupted_files_count, 'updraftplus'), '<strong>'.implode('</strong>, <strong>', $corrupted_files).'</strong>').' <a href="'.apply_filters('updraftplus_com_link', "https://updraftplus.com/problems-with-extra-white-space/").'" target="_blank">'.__('Follow this link for more information', 'updraftplus').'</a>';
* Gets an instance of the "UpdraftPlus_UpdraftCentral_Cloud" class which will be
* used to login or register the user to the UpdraftCentral cloud
public function get_updraftcentral_cloud() {
if (!class_exists('UpdraftPlus_UpdraftCentral_Cloud')) include_once(UPDRAFTPLUS_DIR.'/includes/updraftcentral.php');
return new UpdraftPlus_UpdraftCentral_Cloud();
* This function will build and return the UpdraftPlus tempoaray clone ui widget
* @param boolean $include_testing_ui - a boolean to indicate if testing-only UI elements should be shown (N.B. they can only work if the user also has testing permissions)
* @param array $supported_wp_versions - an array of supported WordPress versions
* @param array $supported_packages - an array of supported clone packages
* @param array $supported_regions - an array of supported clone regions
* @param string $nearest_region - the user's nearest region
* @return string - the clone UI widget
public function updraftplus_clone_ui_widget($include_testing_ui, $supported_wp_versions, $supported_packages, $supported_regions, $nearest_region = '') {
$output = '<p class="updraftplus-option updraftplus-option-inline php-version">';
$output .= '<span class="updraftplus-option-label">'.sprintf(__('%s version:', 'updraftplus'), 'PHP').'</span> ';
$output .= $this->output_select_data($this->php_versions, 'php');
$output .= '<p class="updraftplus-option updraftplus-option-inline wp-version">';
$output .= ' <span class="updraftplus-option-label">'.sprintf(__('%s version:', 'updraftplus'), 'WordPress').'</span> ';
$output .= $this->output_select_data($this->get_wordpress_versions($supported_wp_versions), 'wp');
$output .= '<p class="updraftplus-option updraftplus-option-inline region">';
$output .= ' <span class="updraftplus-option-label">'.__('Clone region:', 'updraftplus').'</span> ';
$output .= $this->output_select_data($supported_regions, 'region', $nearest_region);
$backup_history = UpdraftPlus_Backup_History::get_history();
foreach ($backup_history as $key => $backup) {
$backup_complete = $this->check_backup_is_complete($backup, false, true, false);
$remote_sent = !empty($backup['service']) && ((is_array($backup['service']) && in_array('remotesend', $backup['service'])) || 'remotesend' === $backup['service']);
if (!$backup_complete || $remote_sent) unset($backup_history[$key]);
$output .= '<p class="updraftplus-option updraftplus-option-inline updraftclone-backup">';
$output .= ' <span class="updraftplus-option-label">'.__('Clone:', 'updraftplus').'</span> ';
$output .= '<select id="updraftplus_clone_backup_options" name="updraftplus_clone_backup_options">';
$output .= '<option value="current" data-nonce="current" data-timestamp="current" selected="selected">'. __('This current site', 'updraftplus') .'</option>';
$output .= '<option value="wp_only" data-nonce="wp_only" data-timestamp="wp_only">'. __('An empty WordPress install', 'updraftplus') .'</option>';
if (!empty($backup_history)) {
foreach ($backup_history as $key => $backup) {
$total_size = round($updraftplus->get_total_backup_size($backup) / 1073741824, 1);
$pretty_date = get_date_from_gmt(gmdate('Y-m-d H:i:s', (int) $key), 'M d, Y G:i');
$label = isset($backup['label']) ? ' ' . $backup['label'] : '';
$output .= '<option value="'.$key. '" data-nonce="'.$backup['nonce'].'" data-timestamp="'.$key.'" data-size="'.$total_size.'">' . $pretty_date . $label . '</option>';
$output .= '<p class="updraftplus-option updraftplus-option-inline package">';
$output .= ' <span class="updraftplus-option-label">'.__('Clone package', 'updraftplus').' (<a href="'.$updraftplus->get_url('clone_packages').'" target="_blank">'.__('more info', 'updraftplus').'</a>):</span> ';
$output .= '<select id="updraftplus_clone_package_options" name="updraftplus_clone_package_options" data-package_version="starter">';
foreach ($supported_packages as $key => $value) {
$output .= '<option value="'.esc_attr($key).'" data-size="'.esc_attr($value).'"';
if ('starter' == $key) $output .= 'selected="selected"';
$output .= ">".htmlspecialchars($key) . ('starter' == $key ? ' ' . __('(current version)', 'updraftplus') : '')."</option>\n";