';
$entities_to_restore = $this->get_entities_to_restore_from_jobdata($backup_set);
if (empty($entities_to_restore)) {
$restore_jobdata = $updraftplus->jobdata_getarray($updraftplus->nonce);
echo '
'.__('ABORT: Could not find the information on which entities to restore.', 'updraftplus').'
'.__('If making a request for support, please include this information:', 'updraftplus').' '.count($restore_jobdata).' : '.htmlspecialchars(serialize($restore_jobdata)).'
';
return new WP_Error('missing_info', 'Backup information not found');
}
// This is used in painting the admin page after a successful restore
$this->entities_to_restore = $entities_to_restore;
// This will be removed by Updraft_Restorer::post_restore_clean_up()
set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
// Set $restore_options, either from the continuation data, or from $_POST
if (!empty($continuation_data['restore_options'])) {
$restore_options = $continuation_data['restore_options'];
} else {
// Gather the restore options into one place - code after here should read the options
$restore_options = $this->get_restore_options_from_jobdata();
$updraftplus->jobdata_set('restore_options', $restore_options);
}
add_action('updraftplus_restoration_title', array($this, 'restoration_title'));
// We use a single object for each entity, because we want to store information about the backup set
$updraftplus_restorer = new Updraft_Restorer(new Updraft_Restorer_Skin, $backup_set, false, $restore_options, $continuation_data);
$restore_result = $updraftplus_restorer->perform_restore($entities_to_restore, $restore_options);
$updraftplus_restorer->post_restore_clean_up($restore_result);
return $restore_result;
}
/**
* Called when the restore process wants to print a title
*
* @param String $title - title
*/
public function restoration_title($title) {
echo '
'.$title.'
';
}
/**
* Logs a line from the restore process, being called from UpdraftPlus::log().
* Hooks the WordPress filter updraftplus_logline
* In future, this can get more sophisticated. For now, things are funnelled through here, giving the future possibility.
*
* @param String $line - the line to be logged
* @param String $nonce - the job ID of the restore job
* @param String $level - the level of the log notice
* @param String|Boolean $uniq_id - a unique ID for the log if it should only be logged once; or false otherwise
* @param String $destination - the type of job ongoing. If it is not 'restore', then we will skip the logging.
*
* @return String|Boolean - the filtered value. If set to false, then UpdraftPlus::log() will stop processing the log line.
*/
public function updraftplus_logline($line, $nonce, $level, $uniq_id, $destination) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
if ('progress' != $destination || (defined('WP_CLI') && WP_CLI) || false === $line || false === strpos($line, 'RINFO:')) return $line;
echo $line;
// Indicate that we have completely handled all logging needed
return false;
}
/**
* Ensure that what is returned is an array. Used as a WP options filter.
*
* @param Array $input - input
*
* @return Array
*/
public function return_array($input) {
return is_array($input) ? $input : array();
}
/**
* Called upon the WP action wp_ajax_updraft_savesettings. Will die().
*/
public function updraft_ajax_savesettings() {
try {
global $updraftplus;
if (empty($_POST) || empty($_POST['subaction']) || 'savesettings' != $_POST['subaction'] || !isset($_POST['nonce']) || !is_user_logged_in() || !UpdraftPlus_Options::user_can_manage() || !wp_verify_nonce($_POST['nonce'], 'updraftplus-settings-nonce')) die('Security check');
if (empty($_POST['settings']) || !is_string($_POST['settings'])) die('Invalid data');
parse_str(stripslashes($_POST['settings']), $posted_settings);
// We now have $posted_settings as an array
if (!empty($_POST['updraftplus_version'])) $posted_settings['updraftplus_version'] = $_POST['updraftplus_version'];
echo json_encode($this->save_settings($posted_settings));
} catch (Exception $e) {
$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during save settings. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
error_log($log_message);
echo json_encode(array(
'fatal_error' => true,
'fatal_error_message' => $log_message
));
// @codingStandardsIgnoreLine
} catch (Error $e) {
$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during save settings. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
error_log($log_message);
echo json_encode(array(
'fatal_error' => true,
'fatal_error_message' => $log_message
));
}
die;
}
public function updraft_ajax_importsettings() {
try {
global $updraftplus;
if (empty($_POST) || empty($_POST['subaction']) || 'importsettings' != $_POST['subaction'] || !isset($_POST['nonce']) || !is_user_logged_in() || !UpdraftPlus_Options::user_can_manage() || !wp_verify_nonce($_POST['nonce'], 'updraftplus-settings-nonce')) die('Security check');
if (empty($_POST['settings']) || !is_string($_POST['settings'])) die('Invalid data');
$this->import_settings($_POST);
} catch (Exception $e) {
$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during import settings. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
error_log($log_message);
echo json_encode(array(
'fatal_error' => true,
'fatal_error_message' => $log_message
));
// @codingStandardsIgnoreLine
} catch (Error $e) {
$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during import settings. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
error_log($log_message);
echo json_encode(array(
'fatal_error' => true,
'fatal_error_message' => $log_message
));
}
}
/**
* This method handles the imported json settings it will convert them into a readable format for the existing save settings function, it will also update some of the options to match the new remote storage options format (Apr 2017)
*
* @param Array $settings - The settings from the imported json file
*/
public function import_settings($settings) {
global $updraftplus;
// A bug in UD releases around 1.12.40 - 1.13.3 meant that it was saved in URL-string format, instead of JSON
$perhaps_not_yet_parsed = json_decode(stripslashes($settings['settings']), true);
if (!is_array($perhaps_not_yet_parsed)) {
parse_str($perhaps_not_yet_parsed, $posted_settings);
} else {
$posted_settings = $perhaps_not_yet_parsed;
}
if (!empty($settings['updraftplus_version'])) $posted_settings['updraftplus_version'] = $settings['updraftplus_version'];
// Handle the settings name change of WebDAV and SFTP (Apr 2017) if someone tries to import an old settings to this version
if (isset($posted_settings['updraft_webdav_settings'])) {
$posted_settings['updraft_webdav'] = $posted_settings['updraft_webdav_settings'];
unset($posted_settings['updraft_webdav_settings']);
}
if (isset($posted_settings['updraft_sftp_settings'])) {
$posted_settings['updraft_sftp'] = $posted_settings['updraft_sftp_settings'];
unset($posted_settings['updraft_sftp_settings']);
}
// We also need to wrap some of the options in the new style settings array otherwise later on we will lose the settings if this information is missing
if (empty($posted_settings['updraft_webdav']['settings'])) $posted_settings['updraft_webdav'] = UpdraftPlus_Storage_Methods_Interface::wrap_remote_storage_options($posted_settings['updraft_webdav']);
if (empty($posted_settings['updraft_googledrive']['settings'])) $posted_settings['updraft_googledrive'] = UpdraftPlus_Storage_Methods_Interface::wrap_remote_storage_options($posted_settings['updraft_googledrive']);
if (empty($posted_settings['updraft_googlecloud']['settings'])) $posted_settings['updraft_googlecloud'] = UpdraftPlus_Storage_Methods_Interface::wrap_remote_storage_options($posted_settings['updraft_googlecloud']);
if (empty($posted_settings['updraft_onedrive']['settings'])) $posted_settings['updraft_onedrive'] = UpdraftPlus_Storage_Methods_Interface::wrap_remote_storage_options($posted_settings['updraft_onedrive']);
if (empty($posted_settings['updraft_azure']['settings'])) $posted_settings['updraft_azure'] = UpdraftPlus_Storage_Methods_Interface::wrap_remote_storage_options($posted_settings['updraft_azure']);
if (empty($posted_settings['updraft_dropbox']['settings'])) $posted_settings['updraft_dropbox'] = UpdraftPlus_Storage_Methods_Interface::wrap_remote_storage_options($posted_settings['updraft_dropbox']);
echo json_encode($this->save_settings($posted_settings));
die;
}
private function backup_now_remote_message() {
global $updraftplus;
$service = $updraftplus->just_one(UpdraftPlus_Options::get_updraft_option('updraft_service'));
if (is_string($service)) $service = array($service);
if (!is_array($service)) $service = array();
$no_remote_configured = (empty($service) || array('none') === $service || array('') === $service) ? true : false;
if ($no_remote_configured) {
return '
'.sprintf(__("Backup won't be sent to any remote storage - none has been saved in the %s", 'updraftplus'), ''.__('settings', 'updraftplus')).'. '.__('Not got any remote storage?', 'updraftplus').' '.__("Check out UpdraftPlus Vault.", 'updraftplus').'';
} else {
return '
';
}
}
/**
* This method works through the passed in settings array and saves the settings to the database clearing old data and setting up a return array with content to update the page via ajax
*
* @param array $settings An array of settings taking from the admin page ready to be saved to the database
* @return array An array response containing the status of the update along with content to be used to update the admin page.
*/
public function save_settings($settings) {
global $updraftplus;
// Make sure that settings filters are registered
UpdraftPlus_Options::admin_init();
$more_files_path_updated = false;
if (isset($settings['updraftplus_version']) && $updraftplus->version == $settings['updraftplus_version']) {
$return_array = array('saved' => true);
$add_to_post_keys = array('updraft_interval', 'updraft_interval_database', 'updraft_interval_increments', 'updraft_starttime_files', 'updraft_starttime_db', 'updraft_startday_files', 'updraft_startday_db');
// If database and files are on same schedule, override the db day/time settings
if (isset($settings['updraft_interval_database']) && isset($settings['updraft_interval_database']) && $settings['updraft_interval_database'] == $settings['updraft_interval'] && isset($settings['updraft_starttime_files'])) {
$settings['updraft_starttime_db'] = $settings['updraft_starttime_files'];
$settings['updraft_startday_db'] = $settings['updraft_startday_files'];
}
foreach ($add_to_post_keys as $key) {
// For add-ons that look at $_POST to find saved settings, add the relevant keys to $_POST so that they find them there
if (isset($settings[$key])) {
$_POST[$key] = $settings[$key];
}
}
// Check if updraft_include_more_path is set, if it is then we need to update the page, if it's not set but there's content already in the database that is cleared down below so again we should update the page.
$more_files_path_updated = false;
// i.e. If an option has been set, or if it was currently active in the settings
if (isset($settings['updraft_include_more_path']) || UpdraftPlus_Options::get_updraft_option('updraft_include_more_path')) {
$more_files_path_updated = true;
}
// Wipe the extra retention rules, as they are not saved correctly if the last one is deleted
UpdraftPlus_Options::update_updraft_option('updraft_retain_extrarules', array());
UpdraftPlus_Options::update_updraft_option('updraft_email', array());
UpdraftPlus_Options::update_updraft_option('updraft_report_warningsonly', array());
UpdraftPlus_Options::update_updraft_option('updraft_report_wholebackup', array());
UpdraftPlus_Options::update_updraft_option('updraft_extradbs', array());
UpdraftPlus_Options::update_updraft_option('updraft_include_more_path', array());
$relevant_keys = $updraftplus->get_settings_keys();
if (method_exists('UpdraftPlus_Options', 'mass_options_update')) {
$original_settings = $settings;
$settings = UpdraftPlus_Options::mass_options_update($settings);
$mass_updated = true;
}
foreach ($settings as $key => $value) {
if (in_array($key, $relevant_keys)) {
if ('updraft_service' == $key && is_array($value)) {
foreach ($value as $subkey => $subvalue) {
if ('0' == $subvalue) unset($value[$subkey]);
}
}
// This flag indicates that either the stored database option was changed, or that the supplied option was changed before being stored. It isn't comprehensive - it's only used to update some UI elements with invalid input.
$updated = empty($mass_updated) ? (is_string($value) && UpdraftPlus_Options::get_updraft_option($key) != $value) : (is_string($value) && (!isset($original_settings[$key]) || $original_settings[$key] != $value));
$db_updated = empty($mass_updated) ? UpdraftPlus_Options::update_updraft_option($key, $value) : true;
// Add information on what has changed to array to loop through to update links etc.
// Restricting to strings for now, to prevent any unintended leakage (since this is just used for UI updating)
if ($updated) {
$value = UpdraftPlus_Options::get_updraft_option($key);
if (is_string($value)) $return_array['changed'][$key] = $value;
}
// @codingStandardsIgnoreLine
} else {
// This section is ignored by CI otherwise it will complain the ELSE is empty.
// When last active, it was catching: option_page, action, _wpnonce, _wp_http_referer, updraft_s3_endpoint, updraft_dreamobjects_endpoint. The latter two are empty; probably don't need to be in the page at all.
// error_log("Non-UD key when saving from POSTed data: ".$key);
}
}
} else {
$return_array = array('saved' => false, 'error_message' => sprintf(__('UpdraftPlus seems to have been updated to version (%s), which is different to the version running when this settings page was loaded. Please reload the settings page before trying to save settings.', 'updraftplus'), $updraftplus->version));
}
// Checking for various possible messages
$updraft_dir = $updraftplus->backups_dir_location(false);
$really_is_writable = UpdraftPlus_Filesystem_Functions::really_is_writable($updraft_dir);
$dir_info = $this->really_writable_message($really_is_writable, $updraft_dir);
$button_title = esc_attr(__('This button is disabled because your backup directory is not writable (see the settings).', 'updraftplus'));
$return_array['backup_now_message'] = $this->backup_now_remote_message();
$return_array['backup_dir'] = array('writable' => $really_is_writable, 'message' => $dir_info, 'button_title' => $button_title);
// Check if $more_files_path_updated is true, is so then there's a change and we should update the backup modal
if ($more_files_path_updated) {
$return_array['updraft_include_more_path'] = $this->files_selector_widgetry('backupnow_files_', false, 'sometimes');
}
// Because of the single AJAX call, we need to remove the existing UD messages from the 'all_admin_notices' action
remove_all_actions('all_admin_notices');
// Moving from 2 to 1 ajax call
ob_start();
$service = UpdraftPlus_Options::get_updraft_option('updraft_service');
$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');
} else {
if (isset($return_array['error_message'])) {
$this->show_admin_warning($return_array['error_message'], 'error');
} else {
$this->show_admin_warning(__('Your settings failed to save. Please refresh the settings page and try again', 'updraftplus'), 'error');
}
}
$messages_output = ob_get_contents();
ob_clean();
// 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
return $return_array;
}
/**
* 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) {
global $updraftplus;
$response = array();
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));
try {
$storage_objects_and_ids[$remote_method]['object']->authenticate_storage($instance_id);
} catch (Exception $e) {
$response['result'] = 'error';
$response['message'] = $updraftplus->backup_methods[$remote_method] . ' ' . __('authentication error', 'updraftplus') . ' ' . $e->getMessage();
}
} else {
$response['result'] = 'error';
$response['message'] = __('Remote storage method and instance id are required for authentication.', 'updraftplus');
}
return $response;
}
/**
* 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) {
global $updraftplus;
$response = array();
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));
try {
$storage_objects_and_ids[$remote_method]['object']->deauthenticate_storage($instance_id);
} catch (Exception $e) {
$response['result'] = 'error';
$response['message'] = $updraftplus->backup_methods[$remote_method] . ' deauthentication error ' . $e->getMessage();
}
} else {
$response['result'] = 'error';
$response['message'] = 'Remote storage method and instance id are required for deauthentication.';
}
return $response;
}
/**
* 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.
* @return boolean
*/
public function wipe_settings($wipe_all_settings = true) {
global $updraftplus;
$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);
unset($settings[$key]);
}
foreach ($settings as $s) UpdraftPlus_Options::delete_updraft_option($s);
// These aren't in get_settings_keys() because they are always in the options table, regardless of context
global $wpdb;
$wpdb->query("DELETE FROM $wpdb->options WHERE (option_name LIKE 'updraftplus_unlocked_%' OR option_name LIKE 'updraftplus_locked_%' OR option_name LIKE 'updraftplus_last_lock_time_%' OR option_name LIKE 'updraftplus_semaphore_%' OR option_name LIKE 'updraft_jobdata_%' OR option_name LIKE 'updraft_last_scheduled_%' )");
$site_options = array('updraft_oneshotnonce');
foreach ($site_options as $s) delete_site_option($s);
$this->show_admin_warning(__("Your settings have been wiped.", 'updraftplus'));
return true;
}
/**
* 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 = '') {
global $updraftplus;
$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);
} else {
include_once(UPDRAFTPLUS_DIR.'/methods/updraftvault.php');
$vault = new UpdraftPlus_BackupModule_updraftvault();
}
return $vault;
}
/**
* 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 ($curl) {
if (!function_exists('curl_exec')) {
return json_encode(array('e' => 'No Curl installed'));
die;
}
$ch = curl_init();
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);
curl_close($ch);
rewind($output);
$verb = stream_get_contents($output);
$resp = array();
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['verb'] = $verb;
$resp['response'] = $response;
$resp['status'] = $getinfo;
return json_encode($resp);
} else {
$response = wp_remote_get($uri, array('timeout' => 10));
if (is_wp_error($response)) {
return json_encode(array('e' => htmlspecialchars($response->get_error_message())));
}
return json_encode(
array(
'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)),
'response' => $response
)
);
}
}
/**
* This will return all the details for raw backup and file list, in HTML format
*
* @param Boolean $no_pre_tags - if set, then
tags will be removed from the output
*
* @return String
*/
public function show_raw_backups($no_pre_tags = false) {
global $updraftplus;
$response = array();
$response['html'] = '
'.__('Known backups (raw)', 'updraftplus').'
';
ob_start();
$history = UpdraftPlus_Backup_History::get_history();
var_dump($history);
$response["html"] .= ob_get_clean();
$response['html'] .= '
';
$response['html'] .= '
'.__('Files', 'updraftplus').'
';
$updraft_dir = $updraftplus->backups_dir_location();
$raw_output = array();
$d = dir($updraft_dir);
while (false !== ($entry = $d->read())) {
$fp = $updraft_dir.'/'.$entry;
$mtime = filemtime($fp);
if (is_dir($fp)) {
$size = ' d';
} elseif (is_link($fp)) {
$size = ' l';
} elseif (is_file($fp)) {
$size = sprintf("%8.1f", round(filesize($fp)/1024, 1)).' '.gmdate('r', $mtime);
} else {
$size = ' ?';
}
if (preg_match('/^log\.(.*)\.txt$/', $entry, $lmatch)) $entry = ''.$entry.'';
$raw_output[$mtime] = empty($raw_output[$mtime]) ? sprintf("%s %s\n", $size, $entry) : $raw_output[$mtime].sprintf("%s %s\n", $size, $entry);
}
@$d->close();
krsort($raw_output, SORT_NUMERIC);
foreach ($raw_output as $line) {
$response['html'] .= $line;
}
$response['html'] .= '
';
$response['html'] .= '
'.__('Options (raw)', 'updraftplus').'
';
$opts = $updraftplus->get_settings_keys();
asort($opts);
//
'.__('Key', 'updraftplus').' | '.__('Value', 'updraftplus').' |
---|
$response['html'] .= '
';
foreach ($opts as $opt) {
$response['html'] .= ''.htmlspecialchars($opt).' | '.htmlspecialchars(print_r(UpdraftPlus_Options::get_updraft_option($opt), true)).' | ';
}
// Get the option saved by yahnis-elsts/plugin-update-checker
$response['html'] .= '
external_updates-updraftplus | '.htmlspecialchars(print_r(get_site_option('external_updates-updraftplus'), true)).' | ';
$response['html'] .= '
';
ob_start();
do_action('updraftplus_showrawinfo');
$response['html'] .= ob_get_clean();
if (true == $no_pre_tags) {
$response['html'] = str_replace('
', '', $response['html']);
$response['html'] = str_replace('
', '', $response['html']);
}
return $response;
}
/**
* 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) {
global $updraftplus;
ob_start();
$res = '
Request received: ';
if (preg_match('/^([^:]+)+:(.*)$/', $data['wpaction'], $matches)) {
$action = $matches[1];
if (null === ($args = json_decode($matches[2], true))) {
$res .= "The parameters (should be JSON) could not be decoded";
$action = false;
} else {
if (is_string($args)) $args = array($args);
$res .= "Will despatch action: ".htmlspecialchars($action).", parameters: ".htmlspecialchars(implode(',', $args));
}
} else {
$action = $data['wpaction'];
$res .= "Will despatch action: ".htmlspecialchars($action).", no parameters";
}
$ret = ob_get_clean();
// 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));
} else {
$updraftplus->close_browser_connection(json_encode(array('r' => $res)));
}
}
if (!empty($action)) {
if (!empty($args)) {
ob_start();
$returned = do_action_ref_array($action, $args);
$output = ob_get_clean();
$res .= " - do_action_ref_array Trigger ";
} else {
ob_start();
do_action($action);
$output = ob_get_contents();
ob_end_clean();
$res .= " - do_action Trigger ";
}
}
$response['response'] = $res;
$response['log'] = $output;
// Check if response is empty
if (!empty($returned)) $response['status'] = $returned;
return $response;
}
/**
* Enqueue JSTree JavaScript and CSS, taking into account whether it is already enqueued, and current debug settings
*/
public function enqueue_jstree() {
global $updraftplus;
static $already_enqueued = false;
if ($already_enqueued) return;
$already_enqueued = true;
$jstree_enqueue_version = $updraftplus->use_unminified_scripts() ? '3.3'.'.'.time() : '3.3';
$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() {
$files_to_check = array(
ABSPATH.'wp-config.php',
get_template_directory().DIRECTORY_SEPARATOR.'functions.php',
);
if (is_child_theme()) {
$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)));
fclose($fp);
$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;
break;
}
}
}
if (empty($corrupted_files)) {
return false;
} else {
$corrupted_files_count = count($corrupted_files);
return '
'.__('Warning', 'updraftplus').': '.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'), '
'.implode(',
', $corrupted_files).'').'
'.__('Follow this link for more information', 'updraftplus').'';
}
}
/**
* Gets an instance of the "UpdraftPlus_UpdraftCentral_Cloud" class which will be
* used to login or register the user to the UpdraftCentral cloud
*
* @return object
*/
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 $is_admin_user - a boolean to indicate if the user who requested the clone has clone management permissions
*
* @return string - the clone UI widget
*/
public function updraftplus_clone_ui_widget($is_admin_user = false) {
$output = '
';
$output .= ''.sprintf(__('%s version:', 'updraftplus'), 'PHP').' ';
$output .= $this->output_select_data($this->php_versions, 'php');
$output .= '
';
$output .= '
';
$output .= ' '.sprintf(__('%s version:', 'updraftplus'), 'WordPress').' ';
$output .= $this->output_select_data($this->get_wordpress_versions(), 'wp');
$output .= '
';
$output .= '
';
$output .= ' '.__('Clone region:', 'updraftplus').' ';
$output .= $this->output_select_data($this->regions, 'region');
$output .= '
';
$backup_history = UpdraftPlus_Backup_History::get_history();
foreach ($backup_history as $key => $backup) {
$backup_local = $this->check_backup_is_present_on_fs($backup, false, true);
if (!$backup_local) unset($backup_history[$key]);
}
if (!empty($backup_history)) {
$output .= '
';
$output .= ' '.__('Clone:', 'updraftplus').' ';
$output .= '';
$output .= '
';
}
if ((defined('UPDRAFTPLUS_UPDRAFTCLONE_DEVELOPMENT') && UPDRAFTPLUS_UPDRAFTCLONE_DEVELOPMENT) || $is_admin_user) {
$output .= '
';
$output .= ' UpdraftClone Branch: ';
$output .= '';
$output .= '
';
$output .= '
';
$output .= ' UpdraftPlus Branch: ';
$output .= '';
$output .= '
';
}
$output .= '
';
$output .= '';
$output .= '';
$output .= '
';
return $output;
}
/**
* This function will output a select input using the passed in values.
*
* @param array $data - the keys and values for the select
* @param string $name - the name of the items in the select input
*
* @return string - the output of the select input
*/
public function output_select_data($data, $name) {
$name_version = $this->get_current_version($name);
$output = '
';
return $output;
}
/**
* This function will output the clones network information
*
* @param string $url - the clone URL
*
* @return string - the clone network information
*/
public function updraftplus_clone_info($url) {
global $updraftplus;
if (!empty($url)) {
$content = '
';
$content .= '
'.__('You can find your temporary clone information in your updraftplus.com account here.', 'updraftplus').'
';
} else {
$content = '
' . __('Your clone has started, network information is not yet available but will be displayed here and at your updraftplus.com account once it is ready.', 'updraftplus') . '
';
$content .= '
' . __('You can find your temporary clone information in your updraftplus.com account here.', 'updraftplus') . '
';
}
return $content;
}
/**
* This function will build and return an array of major WordPress versions, the array is built by calling the WordPress version API once every 24 hours and adding any new entires to our existing array of versions.
*
* @return array - an array of WordPress major versions
*/
public function get_wordpress_versions() {
$versions_info = get_site_transient('update_core');
if (isset($versions_info->updates)) {
foreach ($versions_info->updates as $key => $info) {
if (!isset($info->version)) continue;
$parts = explode(".", $info->version);
$version = $parts[0] . "." . $parts[1];
if (in_array($version, $this->wp_versions)) continue;
$this->wp_versions[] = $version;
}
}
$key = array_search($this->get_current_version('wp'), $this->wp_versions);
if ($key) {
$this->wp_versions = array_slice($this->wp_versions, $key);
}
$version_array = $this->wp_versions;
return $version_array;
}
/**
* This function will get the current version the server is running for the passed in item e.g WordPress or PHP
*
* @param string $name - the thing we want to get the version for e.g WordPress or PHP
*
* @return string - returns the current version of the passed in item
*/
public function get_current_version($name) {
$version = '';
if ('php' == $name) {
$parts = explode(".", PHP_VERSION);
$version = $parts[0] . "." . $parts[1];
} elseif ('wp' == $name) {
global $updraftplus;
$wp_version = $updraftplus->get_wordpress_version();
$parts = explode(".", $wp_version);
$version = $parts[0] . "." . $parts[1];
}
return $version;
}
/**
* Show remote storage settings are empty warning
*/
public function show_admin_warning_if_remote_storage_settting_are_empty() {
if ((isset($_REQUEST['page']) && 'updraftplus' == $_REQUEST['page']) || (defined('DOING_AJAX') && DOING_AJAX)) {
$this->show_admin_warning(sprintf(__('You have requested saving to remote storage (%s), but without entering any settings for that storage.', 'updraftplus'), implode(', ', $this->storage_service_without_settings)), 'error');
} else {
$this->show_admin_warning('UpdraftPlus: '.sprintf(__('You have requested saving to remote storage (%s), but without entering any settings for that storage.', 'updraftplus'), implode(', ', $this->storage_service_without_settings)).'
'.__('Return to UpdraftPlus configuration', 'updraftplus').'', 'error');
}
}
/**
* Receive Heartbeat data and respond.
*
* Processes data received via a Heartbeat request, and returns additional data to pass back to the front end.
*
* @param array $response - Heartbeat response data to pass back to front end.
* @param array $data - Data received from the front end (unslashed).
*/
public function process_status_in_heartbeat($response, $data) {
if (!is_array($response) || empty($data['updraftplus'])) return $response;
try {
$response['updraftplus'] = $this->get_activejobs_list(UpdraftPlus_Manipulation_Functions::wp_unslash($data['updraftplus']));
} catch (Exception $e) {
$log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
error_log($log_message);
$response['updraftplus'] = array(
'fatal_error' => true,
'fatal_error_message' => $log_message
);
// @codingStandardsIgnoreLine
} catch (Error $e) {
$log_message = 'PHP Fatal error ('.get_class($e).') has occurred during get active job list. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
error_log($log_message);
$response['updraftplus'] = array(
'fatal_error' => true,
'fatal_error_message' => $log_message
);
}
return $response;
}
}