OS : Linux
PHP Version : 7.4.33
Software : Apache/2.4.6 (CentOS) PHP/7.4.33
Information System : $key) {
if (!is_array($key)) return;
$ud_rpc = $updraftplus->get_udrpc($name_hash.'.migrator.updraftplus.com');
if (!empty($key['sender_public'])) {
$ud_rpc->set_message_format(2);
$ud_rpc->set_key_local($key['key']);
$ud_rpc->set_key_remote($key['sender_public']);
} else {
$ud_rpc->set_message_format(1);
$ud_rpc->set_key_local($key['key']);
}
$this->receivers[$name_hash] = $ud_rpc;
// Create listener (which causes WP actions to be fired when messages are received)
$ud_rpc->activate_replay_protection();
$ud_rpc->create_listener();
}
add_filter('udrpc_command_send_chunk', array($this, 'udrpc_command_send_chunk'), 10, 3);
add_filter('udrpc_command_get_file_status', array($this, 'udrpc_command_get_file_status'), 10, 3);
add_filter('udrpc_command_upload_complete', array($this, 'udrpc_command_upload_complete'), 10, 3);
add_filter('udrpc_action', array($this, 'udrpc_action'), 10, 4);
}
}
/**
* This function will return a response to the remote site on any action
*
* @param string $response - a string response
* @param string $command - the incoming command
* @param array $data - an array of response data
* @param string $name_indicator - a string to identify the request
*
* @return array - the array response
*/
public function udrpc_action($response, $command, $data, $name_indicator) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Unused parameter is present because the method is used as a WP filter.
if (is_array($data) && isset($data['sender_public'])) {
// Do we already know the sender's public key?
$our_keys = UpdraftPlus_Options::get_updraft_option('updraft_migrator_localkeys');
if (is_array($our_keys) && preg_match('/^([a-f0-9]+)\.migrator.updraftplus.com$/', $name_indicator, $matches) && !empty($our_keys[$matches[1]]) && empty($our_keys[$matches[1]]['sender_public'])) {
// N.B. When the sender sends a public key, that indicates that *all* future communications will use it
$our_keys[$matches[1]]['sender_public'] = $data['sender_public'];
UpdraftPlus_Options::update_updraft_option('updraft_migrator_localkeys', $our_keys);
if (!is_array($response['data'])) $response['data'] = array();
$response['data']['got_public'] = 1;
}
}
return $response;
}
protected function initialise_listener_error_handling($hash) {
global $updraftplus;
$updraftplus->error_reporting_stop_when_logged = true;
set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
$this->php_events = array();
add_filter('updraftplus_logline', array($this, 'updraftplus_logline'), 10, 4);
if (!UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) return;
$updraftplus->nonce = $hash;
$updraftplus->logfile_open($hash);
}
protected function return_rpc_message($msg) {
if (is_array($msg) && isset($msg['response']) && 'error' == $msg['response']) {
global $updraftplus;
$updraftplus->log('Unexpected response code in remote communications: '.serialize($msg));
}
if (!empty($this->php_events)) {
if (!isset($msg['data'])) $msg['data'] = null;
$msg['data'] = array('php_events' => array(), 'previous_data' => $msg['data']);
foreach ($this->php_events as $logline) {
$msg['data']['php_events'][] = $logline;
}
}
restore_error_handler();
return $msg;
}
public function updraftplus_logline($line, $nonce, $level, $uniq_id) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Unused parameter is present because the method is used as a WP filter.
if ('notice' === $level && 'php_event' === $uniq_id) {
$this->php_events[] = $line;
}
return $line;
}
public function udrpc_command_send_chunk($response, $data, $name_indicator) {
if (!preg_match('/^([a-f0-9]+)\.migrator.updraftplus.com$/', $name_indicator, $matches)) return $response;
$name_hash = $matches[1];
$this->initialise_listener_error_handling($name_hash);
global $updraftplus;
// send_message('send_chunk', array('file' => $file, 'data' => $chunk, 'start' => $upload_start))
if (!is_array($data)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_expected_array'));
if (!isset($data['file'])) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_no_file'));
if (!isset($data['data'])) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_no_data'));
if (!isset($data['start'])) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_no_start'));
// Make sure the parameters are valid
if (!is_numeric($data['start']) || absint($data['start']) != $data['start']) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_start'));
// Sanity-check the file name
$file = $data['file'];
if (!preg_match('/(-db\.gz|-db\.gz\.crypt|-db|\.(sql|sql\.gz|sql\.bz2|zip|tar|tar\.bz2|tar\.gz|txt))/i', $file)) return array('response' => 'error', 'data' => 'illegal_file_name1');
if (basename($file) != $file) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_illegal_character'));
$start = $data['start'];
$is_last_chunk = empty($data['last_chunk']) ? 0 : 1;
if (!$is_last_chunk) {
} else {
$orig_file = $file;
if (!empty($data['label'])) $label = $data['label'];
}
$file .= '.tmp';
// Intentionally over-write the variable, in case memory is short and in case PHP's garbage collector is this clever
$data = base64_decode($data['data']);
$updraft_dir = $updraftplus->backups_dir_location();
$fullpath = $updraft_dir.'/'.$file;
$existing_size = file_exists($fullpath) ? filesize($fullpath) : 0;
if ($start > $existing_size) {
return $this->return_rpc_message(array('response' => 'error', 'data' => "invalid_start_too_big:start={$start},existing_size={$existing_size}"));
}
if (false == ($fhandle = fopen($fullpath, 'ab'))) {
return $this->return_rpc_message(array('response' => 'error', 'data' => 'file_open_failure'));
}
// fseek() returns 0 for success, or -1 for failure
if ($start != $existing_size && -1 == fseek($fhandle, $start)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'fseek_failure'));
$write_status = fwrite($fhandle, $data);
if (false === $write_status || (false == $write_status && !empty($data))) return $this->return_rpc_message(array('response' => 'error', 'data' => 'fwrite_failure'));
@fclose($fhandle);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
$our_keys = UpdraftPlus_Options::get_updraft_option('updraft_migrator_localkeys');
if (is_array($our_keys) && isset($our_keys[$name_hash]) && !empty($our_keys[$name_hash]['name'])) $updraftplus->log("Received data chunk on key ".$our_keys[$name_hash]['name']. " ($file, ".$start.", is_last=$is_last_chunk)");
if ($is_last_chunk) {
if (!rename($fullpath, $updraft_dir.'/'.$orig_file)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'rename_failure'));
$only_add_this_file = array('file' => $orig_file);
if (isset($label)) $only_add_this_file['label'] = $label;
UpdraftPlus_Backup_History::rebuild(false, $only_add_this_file);
}
return $this->return_rpc_message(array(
'response' => 'file_status',
'data' => $this->get_file_status($file)
));
}
protected function get_file_status($file) {
global $updraftplus;
$fullpath = $updraftplus->backups_dir_location().'/'.basename($file);
if (file_exists($fullpath)) {
$size = filesize($fullpath);
$status = 1;
} elseif (file_exists($fullpath.'.tmp')) {
$size = filesize($fullpath.'.tmp');
$status = 0;
} else {
$size = 0;
$status = 0;
}
return array(
'size' => $size,
'status' => $status,
);
}
public function udrpc_command_get_file_status($response, $data, $name_indicator) {
if (!preg_match('/^([a-f0-9]+)\.migrator.updraftplus.com$/', $name_indicator, $matches)) return $response;
$name_hash = $matches[1];
$this->initialise_listener_error_handling($name_hash);
if (!is_string($data)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_expected_string'));
if (basename($data) != $data) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_illegal_character'));
return $this->return_rpc_message(array(
'response' => 'file_status',
'data' => $this->get_file_status($data)
));
}
/**
* This function will return a response to the remote site to acknowledge that we have received the upload_complete message and if this is a clone it call the ready_for_restore action
*
* @param string $response - a string response
* @param array $data - an array of data
* @param string $name_indicator - a string to identify the request
*
* @return array - the array response
*/
public function udrpc_command_upload_complete($response, $data, $name_indicator) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Unused parameter is present because the method is used as a WP filter.
if (!preg_match('/^([a-f0-9]+)\.migrator.updraftplus.com$/', $name_indicator, $matches)) return $response;
if (defined('UPDRAFTPLUS_THIS_IS_CLONE') && UPDRAFTPLUS_THIS_IS_CLONE) {
$job_id = (is_array($data) && !empty($data['job_id'])) ? $data['job_id'] : null;
$signal_ready_for_restore_now = true;
if (class_exists('UpdraftPlus_Remote_Communications_V2')) {
$test_udrpc = new UpdraftPlus_Remote_Communications_V2();
if (version_compare($test_udrpc->version, '1.4.21', '>=')) {
$signal_ready_for_restore_now = false;
$this->job_id = $job_id;
add_action('udrpc_action_send_response', array($this, 'udrpc_action_send_response'));
}
}
if ($signal_ready_for_restore_now) {
do_action('updraftplus_temporary_clone_ready_for_restore', $job_id);
}
}
return $this->return_rpc_message(array(
'response' => 'file_status',
'data' => ''
));
}
/**
* UpdraftPlus_Remote_Communications is going to echo a response and then die. We pre-empt it.
*
* @param String $response
*/
public function udrpc_action_send_response($response) {
global $updraftplus;
$updraftplus->close_browser_connection($response);
do_action('updraftplus_temporary_clone_ready_for_restore', $this->job_id);
die;
}
public function updraftplus_initial_jobdata($initial_jobdata, $options, $split_every) {
if (is_array($options) && !empty($options['extradata']) && !empty($options['extradata']['services']) && preg_match('#remotesend/(\d+)#', $options['extradata']['services'], $matches)) {
// Load the option now - don't wait until send time
$site_id = $matches[1];
$remotesites = UpdraftPlus_Options::get_updraft_option('updraft_remotesites');
if (!is_array($remotesites)) $remotesites = array();
if (empty($remotesites[$site_id]) || empty($remotesites[$site_id]['url']) || empty($remotesites[$site_id]['key']) || empty($remotesites[$site_id]['name_indicator'])) {
throw new Exception("Remote site id ($site_id) not found - send aborted"); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Error messages should be escaped when caught and printed.
}
array_push($initial_jobdata, 'remotesend_info', $remotesites[$site_id]);
// Reduce to 100MB if it was above. Since the user isn't expected to directly manipulate these zip files, the potentially higher number of zip files doesn't matter.
$split_every_key = array_search('split_every', $initial_jobdata) + 1;
if ($split_every > 100) $initial_jobdata[$split_every_key] = 100;
}
return $initial_jobdata;
}
public function updraft_printjob_beforewarnings($ret, $jobdata) {
if (!empty($jobdata['remotesend_info']) && !empty($jobdata['remotesend_info']['url'])) {
$ret .= ' '.__('Backup data will be sent to:', 'updraftplus').' '.htmlspecialchars($jobdata['remotesend_info']['url']).' '.sprintf(__('The site URL you are sending to (%s) looks like a local development website.', 'updraftplus'), htmlspecialchars($url)).' '.__('If you are sending from an external network, it is likely that a firewall will be blocking this.', 'updraftplus').' '.__('If sending directly from site to site does not work for you, then there are three other methods - please try one of these instead.', 'updraftplus').' '.__('For longer help, including screenshots, follow this link.', 'updraftplus').' '.__('Testing connection...', 'updraftplus').' '.__('OK', 'updraftplus').' ';
$ret .= ' '.__('No receiving sites have yet been added.', 'updraftplus').' ';
$ret .= ' ';
$ret .= ' '.__('Existing keys', 'updraftplus').'
';
}
$ret .= htmlspecialchars($key['name']);
$ret .= ' - '.__('Delete', 'updraftplus').'';
$ret .= '
';
}
if ($ret) $ret .= '