PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.16.5
UpdraftPlus: WP Backup & Migration Plugin v1.16.5
1.26.7 1.26.6 1.26.5 1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 All 371 releases
updraftplus / includes / class-remote-send.php

class-remote-send.php in UpdraftPlus: WP Backup & Migration Plugin 1.16.5, at includes/class-remote-send.php

563 lines 23.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('UPDRAFTPLUS_DIR')) die('No direct access allowed.');
4
5 abstract class UpdraftPlus_RemoteSend {
6
7 protected $receivers = array();
8
9 protected $php_events = array();
10
11 public function __construct() {
12 add_action('updraft_migrate_newdestination', array($this, 'updraft_migrate_newdestination'));
13 add_action('updraft_remote_ping_test', array($this, 'updraft_remote_ping_test'));
14 add_action('updraft_migrate_key_create', array($this, 'updraft_migrate_key_create'));
15 add_filter('updraft_migrate_key_create_return', array($this, 'updraft_migrate_key_create_return'), 10, 2);
16 add_action('updraft_migrate_key_delete', array($this, 'updraft_migrate_key_delete'));
17 add_filter('updraftplus_initial_jobdata', array($this, 'updraftplus_initial_jobdata'), 10, 3);
18 add_filter('updraft_printjob_beforewarnings', array($this, 'updraft_printjob_beforewarnings'), 10, 2);
19 add_action('plugins_loaded', array($this, 'plugins_loaded'));
20 }
21
22 public function plugins_loaded() {
23
24 global $updraftplus;
25
26 // Prevent fatal errors if UD was not loaded (e.g. some CLI method)
27 if (!is_a($updraftplus, 'UpdraftPlus')) return;
28
29 // Create a receiver for each key
30 if (!class_exists('UpdraftPlus_Options')) {
31 error_log("UpdraftPlus_Options class not found: is UpdraftPlus properly installed?");
32 return;
33 }
34 $our_keys = UpdraftPlus_Options::get_updraft_option('updraft_migrator_localkeys');
35 if (is_array($our_keys) && !empty($our_keys)) {
36 foreach ($our_keys as $name_hash => $key) {
37 if (!is_array($key)) return;
38 $ud_rpc = $updraftplus->get_udrpc($name_hash.'.migrator.updraftplus.com');
39 $ud_rpc->set_message_format(1);
40 $this->receivers[$name_hash] = $ud_rpc;
41 $ud_rpc->set_key_local($key['key']);
42 // Create listener (which causes WP actions to be fired when messages are received)
43 $ud_rpc->activate_replay_protection();
44 $ud_rpc->create_listener();
45 }
46 add_filter('udrpc_command_send_chunk', array($this, 'udrpc_command_send_chunk'), 10, 3);
47 add_filter('udrpc_command_get_file_status', array($this, 'udrpc_command_get_file_status'), 10, 3);
48 add_filter('udrpc_command_upload_complete', array($this, 'udrpc_command_upload_complete'), 10, 3);
49 }
50 }
51
52 protected function initialise_listener_error_handling($hash) {
53 global $updraftplus;
54 $updraftplus->error_reporting_stop_when_logged = true;
55 set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
56 $this->php_events = array();
57 add_filter('updraftplus_logline', array($this, 'updraftplus_logline'), 10, 4);
58 if (!UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) return;
59 $updraftplus->nonce = $hash;
60 $updraftplus->logfile_open($hash);
61 }
62
63 protected function return_rpc_message($msg) {
64 if (is_array($msg) && isset($msg['response']) && 'error' == $msg['response']) {
65 global $updraftplus;
66 $updraftplus->log('Unexpected response code in remote communications: '.serialize($msg));
67 }
68 if (!empty($this->php_events)) {
69 if (!isset($msg['data'])) $msg['data'] = null;
70 $msg['data'] = array('php_events' => array(), 'previous_data' => $msg['data']);
71 foreach ($this->php_events as $logline) {
72 $msg['data']['php_events'][] = $logline;
73 }
74 }
75 restore_error_handler();
76
77 return $msg;
78 }
79
80 public function updraftplus_logline($line, $nonce, $level, $uniq_id) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
81 if ('notice' === $level && 'php_event' === $uniq_id) {
82 $this->php_events[] = $line;
83 }
84 return $line;
85 }
86
87 public function udrpc_command_send_chunk($response, $data, $name_indicator) {
88
89 if (!preg_match('/^([a-f0-9]+)\.migrator.updraftplus.com$/', $name_indicator, $matches)) return $response;
90 $name_hash = $matches[1];
91
92 $this->initialise_listener_error_handling($name_hash);
93
94 global $updraftplus;
95
96 // send_message('send_chunk', array('file' => $file, 'data' => $chunk, 'start' => $upload_start))
97
98 if (!is_array($data)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_expected_array'));
99
100 if (!isset($data['file'])) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_no_file'));
101
102 if (!isset($data['data'])) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_no_data'));
103
104 if (!isset($data['start'])) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_no_start'));
105
106 // Make sure the parameters are valid
107 if (!is_numeric($data['start']) || absint($data['start']) != $data['start']) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_start'));
108
109 // Sanity-check the file name
110 $file = $data['file'];
111 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');
112 if (basename($file) != $file) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_illegal_character'));
113
114 $start = $data['start'];
115
116 $is_last_chunk = empty($data['last_chunk']) ? 0 : 1;
117 if (!$is_last_chunk) {
118 } else {
119 $orig_file = $file;
120 if (!empty($data['label'])) $label = $data['label'];
121 }
122 $file .= '.tmp';
123
124 // Intentionally over-write the variable, in case memory is short and in case PHP's garbage collector is this clever
125 $data = base64_decode($data['data']);
126
127 $updraft_dir = $updraftplus->backups_dir_location();
128 $fullpath = $updraft_dir.'/'.$file;
129
130 $existing_size = file_exists($fullpath) ? filesize($fullpath) : 0;
131
132 if ($start > $existing_size) {
133 return $this->return_rpc_message(array('response' => 'error', 'data' => "invalid_start_too_big:start=${start},existing_size=${existing_size}"));
134 }
135
136 if (false == ($fhandle = fopen($fullpath, 'ab'))) {
137 return $this->return_rpc_message(array('response' => 'error', 'data' => 'file_open_failure'));
138 }
139
140 // fseek() returns 0 for success, or -1 for failure
141 if ($start != $existing_size && -1 == fseek($fhandle, $start)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'fseek_failure'));
142
143 $write_status = fwrite($fhandle, $data);
144
145 if (false === $write_status || (false == $write_status && !empty($data))) return $this->return_rpc_message(array('response' => 'error', 'data' => 'fwrite_failure'));
146
147 @fclose($fhandle);
148
149 $our_keys = UpdraftPlus_Options::get_updraft_option('updraft_migrator_localkeys');
150 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)");
151
152 if ($is_last_chunk) {
153 if (!rename($fullpath, $updraft_dir.'/'.$orig_file)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'rename_failure'));
154 $only_add_this_file = array('file' => $orig_file);
155 if (isset($label)) $only_add_this_file['label'] = $label;
156 UpdraftPlus_Backup_History::rebuild(false, $only_add_this_file);
157 }
158
159 return $this->return_rpc_message(array(
160 'response' => 'file_status',
161 'data' => $this->get_file_status($file)
162 ));
163 }
164
165 protected function get_file_status($file) {
166
167 global $updraftplus;
168 $fullpath = $updraftplus->backups_dir_location().'/'.basename($file);
169
170 if (file_exists($fullpath)) {
171 $size = filesize($fullpath);
172 $status = 1;
173 } elseif (file_exists($fullpath.'.tmp')) {
174 $size = filesize($fullpath.'.tmp');
175 $status = 0;
176 } else {
177 $size = 0;
178 $status = 0;
179 }
180
181 return array(
182 'size' => $size,
183 'status' => $status,
184 );
185 }
186
187 public function udrpc_command_get_file_status($response, $data, $name_indicator) {
188 if (!preg_match('/^([a-f0-9]+)\.migrator.updraftplus.com$/', $name_indicator, $matches)) return $response;
189 $name_hash = $matches[1];
190
191 $this->initialise_listener_error_handling($name_hash);
192
193 if (!is_string($data)) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_expected_string'));
194
195 if (basename($data) != $data) return $this->return_rpc_message(array('response' => 'error', 'data' => 'invalid_input_illegal_character'));
196
197 return $this->return_rpc_message(array(
198 'response' => 'file_status',
199 'data' => $this->get_file_status($data)
200 ));
201 }
202
203 /**
204 * This function will return a response to the remote site to acknowledge that we have recieved the upload_complete message and if this is a clone it call the ready_for_restore action
205 *
206 * @param string $response - a string response
207 * @param array $data - an array of data
208 * @param string $name_indicator - a string to identify the request
209 *
210 * @return array - the array response
211 */
212 public function udrpc_command_upload_complete($response, $data, $name_indicator) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
213 if (!preg_match('/^([a-f0-9]+)\.migrator.updraftplus.com$/', $name_indicator, $matches)) return $response;
214
215 if (defined('UPDRAFTPLUS_THIS_IS_CLONE')) {
216 $job_id = (is_array($data) && !empty($data['job_id'])) ? $data['job_id'] : null;
217 do_action('updraftplus_temporary_clone_ready_for_restore', $job_id);
218 }
219
220 return $this->return_rpc_message(array(
221 'response' => 'file_status',
222 'data' => ''
223 ));
224 }
225
226 public function updraftplus_initial_jobdata($initial_jobdata, $options, $split_every) {
227
228 if (is_array($options) && !empty($options['extradata']) && !empty($options['extradata']['services']) && preg_match('#remotesend/(\d+)#', $options['extradata']['services'], $matches)) {
229
230 // Load the option now - don't wait until send time
231 $site_id = $matches[1];
232 $remotesites = UpdraftPlus_Options::get_updraft_option('updraft_remotesites');
233 if (!is_array($remotesites)) $remotesites = array();
234
235 if (empty($remotesites[$site_id]) || empty($remotesites[$site_id]['url']) || empty($remotesites[$site_id]['key']) || empty($remotesites[$site_id]['name_indicator'])) {
236 throw new Exception("Remote site id ($site_id) not found - send aborted");
237 }
238
239 array_push($initial_jobdata, 'remotesend_info', $remotesites[$site_id]);
240
241 // 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.
242 if ($split_every > 100) array_push($initial_jobdata, 'split_every', 100);
243
244 }
245
246 return $initial_jobdata;
247 }
248
249 public function updraft_printjob_beforewarnings($ret, $jobdata) {
250 if (!empty($jobdata['remotesend_info']) && !empty($jobdata['remotesend_info']['url'])) {
251 $ret .= '<p style="padding:0px; margin:2px 0;">'.__('Backup data will be sent to:', 'updraftplus').' '.htmlspecialchars($jobdata['remotesend_info']['url']).'</p>';
252 }
253 return $ret;
254 }
255
256 public function updraft_remote_ping_test($data) {
257
258 global $updraftplus;
259
260 if (!isset($data['id']) || !is_numeric($data['id']) || empty($data['url'])) die;
261
262 $remotesites = UpdraftPlus_Options::get_updraft_option('updraft_remotesites');
263 if (!is_array($remotesites)) $remotesites = array();
264
265 if (empty($remotesites[$data['id']]) || $data['url'] != $remotesites[$data['id']]['url'] || empty($remotesites[$data['id']]['key']) || empty($remotesites[$data['id']]['name_indicator'])) {
266 echo json_encode(array('e' => 1, 'r' => __('Error:', 'updraftplus').' '.__('site not found', 'updraftplus')));
267 die();
268 }
269
270 try {
271
272 $updraftplus->error_reporting_stop_when_logged = true;
273 set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
274 $this->php_events = array();
275 add_filter('updraftplus_logline', array($this, 'updraftplus_logline'), 10, 4);
276
277 $opts = $remotesites[$data['id']];
278
279 $ud_rpc = $updraftplus->get_udrpc($opts['name_indicator']);
280 $ud_rpc->set_message_format(1);
281 $ud_rpc->set_key_local($opts['key']);
282 $ud_rpc->set_destination_url($data['url']);
283 $ud_rpc->activate_replay_protection();
284
285 do_action('updraftplus_remotesend_udrpc_object_obtained', $ud_rpc, $opts);
286
287 $response = $ud_rpc->send_message('ping');
288
289 restore_error_handler();
290
291 if (is_wp_error($response)) {
292
293 $err_msg = __('Error:', 'updraftplus').' '.$response->get_error_message();
294 $err_data = $response->get_error_data();
295 $err_code = $response->get_error_code();
296
297 } elseif (!is_array($response) || empty($response['response']) || 'pong' != $response['response']) {
298
299 $err_msg = __('Error:', 'updraftplus').' '.sprintf(__('You should check that the remote site is online, not firewalled, does not have security modules that may be blocking access, has UpdraftPlus version %s or later active and that the keys have been entered correctly.', 'updraftplus'), '2.10.3');
300 $err_data = $response;
301 $err_code = 'no_pong';
302
303 }
304
305 if (isset($err_msg)) {
306
307 $res = array('e' => 1, 'r' => $err_msg);
308
309 if ($this->url_looks_internal($data['url'])) {
310 $res['moreinfo'] = '<p>'.sprintf(__('The site URL you are sending to (%s) looks like a local development website. If you are sending from an external network, it is likely that a firewall will be blocking this.', 'updraftplus'), htmlspecialchars($data['url'])).'</p>';
311 }
312
313 // We got several support requests from people who didn't seem to be aware of other methods
314 $msg_try_other_method = '<p>'.__('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').'<a href="https://updraftplus.com/faqs/how-do-i-migrate-to-a-new-site-location/#importing" target="_blank">'.__('For longer help, including screenshots, follow this link.', 'updraftplus').'</a></p>';
315
316 $res['moreinfo'] = isset($res['moreinfo']) ? $res['moreinfo'].$msg_try_other_method : $msg_try_other_method;
317
318 if (isset($err_data)) $res['data'] = $err_data;
319 if (isset($err_code)) $res['code'] = $err_code;
320
321 if (!empty($this->php_events)) $res['php_events'] = $this->php_events;
322
323 echo json_encode($res);
324 die;
325 }
326
327 $ret = '<p>'.__('Testing connection...', 'updraftplus').' '.__('OK', 'updraftplus').'</p>';
328
329 global $updraftplus, $updraftplus_admin;
330
331 $ret .= '<input type="checkbox" checked="checked" id="remotesend_backupnow_db"> <label for="remotesend_backupnow_db">'.__("Database", 'updraftplus').'</label><br>';
332 $ret .= $updraftplus_admin->files_selector_widgetry('remotesend_', false, false);
333
334 $service = $updraftplus->just_one(UpdraftPlus_Options::get_updraft_option('updraft_service'));
335 if (is_string($service)) $service = array($service);
336
337 if (is_array($service) && !empty($service) && array('none') !== $service) {
338 $first_one = true;
339 foreach ($service as $s) {
340 if (!$s) continue;
341 if (isset($updraftplus->backup_methods[$s])) {
342 if ($first_one) {
343 $first_one = false;
344 $ret .= '<p>';
345 $ret .= '<input type="checkbox" id="remotesend_backupnow_cloud"> <label for="remotesend_backupnow_cloud">'.__("Also send this backup to the active remote storage locations", 'updraftplus');
346 $ret .= ' (';
347 } else {
348 $ret .= ', ';
349 }
350 $ret .= $updraftplus->backup_methods[$s];
351 }
352 }
353 if (!$first_one) $ret .= ')';
354 $ret .= '</label></p>';
355 }
356
357 $ret .= apply_filters('updraft_backupnow_modal_afteroptions', '', 'remotesend_');
358 $ret .= '<button class="button-primary" style="height:30px; font-size:16px; margin-left: 3px; width:85px;" id="updraft_migrate_send_button" onclick="updraft_migrate_go_backup();">'.__('Send', 'updraftplus').'</button>';
359
360 echo json_encode(array('success' => 1, 'r' => $ret));
361 } catch (Exception $e) {
362 echo json_encode(array('e' => 1, 'r' => __('Error:', 'updraftplus').' '.$e->getMessage().' (line: '.$e->getLine().', file: '.$e->getFile().')'));
363 }
364 die;
365 }
366
367 /**
368 * This is used only for an advisory warning - does not have to be able to always detect
369 *
370 * @param string $url
371 */
372 protected function url_looks_internal($url) {
373 $url_host = strtolower(parse_url($url, PHP_URL_HOST));
374 if ('localhost' == $url_host || strpos($url_host, '127.') === 0 || strpos($url_host, '10.') === 0 || '::1' == $url_host || strpos($url_host, 'localhost') !== false || substr($url_host, -4, 4) == '.dev') return true;
375 return false;
376 }
377
378 public function updraft_migrate_key_delete($data) {
379 if (empty($data['keyid'])) die;
380 $our_keys = UpdraftPlus_Options::get_updraft_option('updraft_migrator_localkeys');
381 if (!is_array($our_keys)) $our_keys = array();
382 unset($our_keys[$data['keyid']]);
383 UpdraftPlus_Options::update_updraft_option('updraft_migrator_localkeys', $our_keys);
384 echo json_encode(array('ourkeys' => $this->list_our_keys($our_keys)));
385 die;
386 }
387
388 /**
389 * This function is a wrapper for updraft_migrate_key_create when being called from WP_CLI it allows us to return the created key rather than echo it, by passing return_instead_of_echo as part of $data.
390 *
391 * @param string $string - empty string to filter on
392 * @param array $data - an array of data needed to create the RSA keypair should also include return_instead_of_echo to return the result
393 *
394 * @return string - the RSA remote key
395 */
396 public function updraft_migrate_key_create_return($string, $data) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
397 return $this->updraft_migrate_key_create($data);
398 }
399
400 /**
401 * Called upon the WP action updraft_s3_newuser. Dies.
402 *
403 * @param array $data - the posted data
404 *
405 * @return void
406 */
407 public function updraft_migrate_key_create($data) {
408
409 if (empty($data['name'])) die;
410 $name = stripslashes($data['name']);
411
412 $size = (empty($data['size']) || !is_numeric($data['size']) || $data['size'] < 512) ? 2048 : (int) $data['size'];
413
414 $name_hash = md5($name); // 32 characters
415 $indicator_name = $name_hash.'.migrator.updraftplus.com';
416
417 $our_keys = UpdraftPlus_Options::get_updraft_option('updraft_migrator_localkeys');
418 if (!is_array($our_keys)) $our_keys = array();
419
420 if (isset($our_keys[$name_hash])) {
421 echo json_encode(array('e' => 1, 'r' => __('Error:', 'updraftplus').' '.__('A key with this name already exists; you must use a unique name.', 'updraftplus')));
422 die;
423 }
424
425 global $updraftplus;
426 $ud_rpc = $updraftplus->get_udrpc($indicator_name);
427
428 if (is_object($ud_rpc) && $ud_rpc->generate_new_keypair($size)) {
429 $local_bundle = $ud_rpc->get_portable_bundle('base64_with_count');
430
431 $our_keys[$name_hash] = array('name' => $name, 'key' => $ud_rpc->get_key_local());
432 UpdraftPlus_Options::update_updraft_option('updraft_migrator_localkeys', $our_keys);
433
434 if (isset($data['return_instead_of_echo']) && $data['return_instead_of_echo']) return $local_bundle;
435
436 echo json_encode(array(
437 'bundle' => $local_bundle,
438 'r' => __('Key created successfully.', 'updraftplus').' '.__('You must copy and paste this key on the sending site now - it cannot be shown again.', 'updraftplus'),
439 'selector' => $this->get_remotesites_selector(array()),
440 'ourkeys' => $this->list_our_keys($our_keys),
441 ));
442 die;
443 }
444
445 if (extension_loaded('mbstring')) {
446 // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.mbstring_func_overloadDeprecated -- Commented out as this flags as not compatible with PHP 5.2
447 if (ini_get('mbstring.func_overload') & 2) {
448 echo json_encode(array('e' => 1, 'r' => __('Error:', 'updraftplus').' '.sprintf(__('The setting %s is turned on in your PHP settings. It is deprecated, causes encryption to malfunction, and should be turned off.', 'updraftplus'), 'mbstring.func_overload')));
449 die;
450 }
451 }
452
453 echo json_encode(array('e' => 1));
454 die;
455 }
456
457 public function updraft_migrate_newdestination($data) {
458
459 global $updraftplus;
460 $ret = array();
461
462 if (empty($data['key'])) {
463 $ret['e'] = sprintf(__("Failure: No %s was given.", 'updraftplus'), __('key', 'updraftplus'));
464 } else {
465 $ud_rpc = $updraftplus->get_udrpc();
466
467 // A bundle has these keys: key, name_indicator, url
468 $decode_bundle = $ud_rpc->decode_portable_bundle($data['key'], 'base64_with_count');
469
470 if (!is_array($decode_bundle) || !empty($decode_bundle['code'])) {
471 $ret['e'] = __('Error:', 'updraftplus');
472 if (!empty($decode_bundle['code']) && 'invalid_wrong_length' == $decode_bundle['code']) {
473 $ret['e'] .= ' '.__('The entered key was the wrong length - please try again.', 'updraftplus');
474 } elseif (!empty($decode_bundle['code']) && 'invalid_corrupt' == $decode_bundle['code']) {
475 $ret['e'] .= ' '.__('The entered key was corrupt - please try again.', 'updraftplus').' ('.$decode_bundle['data'].')';
476 } elseif (empty($decode_bundle['key']) || empty($decode_bundle['url'])) {
477 $ret['e'] .= ' '.__('The entered key was corrupt - please try again.', 'updraftplus');
478 $ret['data'] = $decode_bundle;
479 }
480 } elseif (empty($decode_bundle['key']) || empty($decode_bundle['url'])) {
481 $ret['e'] = __('Error:', 'updraftplus').' '.__('The entered key was corrupt - please try again.', 'updraftplus');
482 $ret['data'] = $decode_bundle;
483 } else {
484
485 if (trailingslashit(network_site_url()) == $decode_bundle['url']) {
486 $ret['e'] = __('Error:', 'updraftplus').' '.__('The entered key does not belong to a remote site (it belongs to this one).', 'updraftplus');
487 } else {
488
489 // Store the information
490 $remotesites = UpdraftPlus_Options::get_updraft_option('updraft_remotesites');
491 if (!is_array($remotesites)) $remotesites = array();
492 foreach ($remotesites as $k => $rsite) {
493 if (!is_array($rsite)) continue;
494 if ($rsite['url'] == $decode_bundle['url']) unset($remotesites[$k]);
495 }
496 $remotesites[] = $decode_bundle;
497 UpdraftPlus_Options::update_updraft_option('updraft_remotesites', $remotesites);
498
499 $ret['selector'] = $this->get_remotesites_selector($remotesites);
500
501 // Return the new HTML widget to the front end
502 $ret['r'] = __('The key was successfully added.', 'updraftplus').' '.__('It is for sending backups to the following site: ', 'updraftplus').htmlspecialchars($decode_bundle['url']);
503
504 }
505 }
506
507 }
508
509 echo json_encode($ret);
510 die;
511 }
512
513 protected function get_remotesites_selector($remotesites = false) {
514
515 if (false === $remotesites) {
516 $remotesites = UpdraftPlus_Options::get_updraft_option('updraft_remotesites');
517 if (!is_array($remotesites)) $remotesites = array();
518 }
519
520 if (empty($remotesites)) {
521 return '<p id="updraft_migrate_receivingsites_nonemsg"><em>'.__('No receiving sites have yet been added.', 'updraftplus').'</em></p>';
522 } else {
523 $ret = '<p class="updraftplus-remote-sites-selector"><label>'.__('Send to site:', 'updraftplus').'</label> <select id="updraft_remotesites_selector">';
524 foreach ($remotesites as $k => $rsite) {
525 if (!is_array($rsite) || empty($rsite['url'])) continue;
526 $ret .= '<option value="'.esc_attr($k).'">'.htmlspecialchars($rsite['url']).'</option>';
527 }
528 $ret .= '</select>';
529 $ret .= ' <button class="button-primary" style="height:30px; font-size:16px; margin-left: 3px; width:85px;" id="updraft_migrate_send_button" onclick="updraft_migrate_send_backup();">'.__('Send', 'updraftplus').'</button>';
530 $ret .= '</p>';
531 }
532
533 return $ret;
534 }
535
536 protected function list_our_keys($our_keys = false) {
537 if (false === $our_keys) {
538 $our_keys = UpdraftPlus_Options::get_updraft_option('updraft_migrator_localkeys');
539 }
540
541 if (empty($our_keys)) return '<em>'.__('No keys to allow remote sites to send backup data here have yet been created.', 'updraftplus').'</em>';
542
543 $ret = '';
544 $first_one = true;
545
546 foreach ($our_keys as $k => $key) {
547 if (!is_array($key)) continue;
548 if ($first_one) {
549 $first_one = false;
550 $ret .= '<p><strong>'.__('Existing keys', 'updraftplus').'</strong><br>';
551 }
552 $ret .= htmlspecialchars($key['name']);
553 $ret .= ' - <a href="'.UpdraftPlus::get_current_clean_url().'" onclick="updraft_migrate_local_key_delete(\''.esc_attr($k).'\'); return false;" class="updraft_migrate_local_key_delete" data-keyid="'.esc_attr($k).'">'.__('Delete', 'updraftplus').'</a>';
554 $ret .= '<br>';
555 }
556
557 if ($ret) $ret .= '</p>';
558
559 return $ret;
560
561 }
562 }
563