UpdraftPlus WordPress Backup Plugin - Version 1.14.9

Version Description

  • 24/May/2018 =

  • FEATURE: Make it more seamless to sign up to UpdraftCentral Cloud

  • FEATURE: Microsoft Azure storage (Premium) compatibility with Azure Germany

  • FEATURE: Added the ability to create migration keys from WP-CLI (Premium)

  • FIX: A backup icon/storage shows for a storage type even if all instances were disabled

  • FIX: WP CLI updraftplus command was not running on few enviroments like the Windows command line

  • FIX: A PHP fatal error was occurring when a user try to restore an encrypted DB when defining the "UPDRAFTPLUS_DECRYPTION_ENGINE" constant

  • TWEAK: Added the ability to schedule incremental backups (Note you can not yet take incremental backups)

  • REFACTOR: Completed factoring for tabs of the settings page.

  • TWEAK: Some re-factoring and tidying of the restoration code for easier maintenance

  • TWEAK: Add a longer timeout on SFTP logins to cope with a 'long delay, but then worked' situation seen in the wild

  • TWEAK: An "Incremental backups" extension was displayed in the Premium / Extensions tab, causing confusion since it is not yet finished/launched

  • TWEAK: Displays a Byte Order Mark (BOM) warning by giving the file names along with the path in the "Existing Backups" tab, if a BOM is detected at the start of common files that people tend to edit

  • TWEAK: A WP CLI Existing backup command didn't display a date time in the "job_identifier" column

  • TWEAK: Add links to the relevant app privacy policies within the settings sections for storage methods using OAuth authorization apps

  • TWEAK: Log user and group IDs of process and file/folder, when permissions for an operation is denied

  • TWEAK: Prevent a potential PHP debugging notice when showing the 'Upload' button

  • TWEAK: Update an out-of-date "wrong password" link

  • TWEAK: Added the "Web-server disk space in use by UpdraftPlus" information to "Site information" section in the "Advanced Tools" tab; it won't show in the 'Existing Backups' tab if you are using less than 100MB.

  • TWEAK: When a Google Cloud token was invalid, a PHP Fatal could result instead of catching the error and informing/logging nicely

  • TWEAK: If php-xml (SimpleXMLElement) is not installed, then show an appropriate warning in the Azure configuration section

  • TWEAK: If the user tries to install another version of UpdraftPlus, then tweak the default error message that they are shown by WP, which is too obscure/cryptic for many users

Download this release

Release Info

Developer DavidAnderson
Plugin Icon 128x128 UpdraftPlus WordPress Backup Plugin
Version 1.14.9
Comparing to
See all releases

Code changes from version 1.14.7 to 1.14.9

admin.php CHANGED
@@ -17,6 +17,10 @@ class UpdraftPlus_Admin {
17
 
18
  private $auth_instance_ids = array('dropbox' => array(), 'onedrive' => array(), 'googledrive' => array(), 'googlecloud' => array());
19
 
 
 
 
 
20
  public function __construct() {
21
  $this->admin_init();
22
  }
@@ -224,7 +228,7 @@ class UpdraftPlus_Admin {
224
  }
225
 
226
  private function setup_all_admin_notices_udonly($service, $override = false) {
227
- global $wp_version;
228
 
229
  if (UpdraftPlus_Options::user_can_manage() && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON && (!defined('UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE') || !UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE)) {
230
  add_action('all_admin_notices', array($this, 'show_admin_warning_disabledcron'));
@@ -261,7 +265,7 @@ class UpdraftPlus_Admin {
261
  }
262
  }
263
 
264
- if (version_compare($wp_version, '3.2', '<')) add_action('all_admin_notices', array($this, 'show_admin_warning_wordpressversion'));
265
  }
266
 
267
  /**
@@ -349,7 +353,7 @@ class UpdraftPlus_Admin {
349
  // UpdraftPlus templates
350
  $this->register_template_directories();
351
 
352
- global $updraftplus, $wp_version, $pagenow;
353
  add_filter('updraftplus_dirlist_others', array($updraftplus, 'backup_others_dirlist'));
354
  add_filter('updraftplus_dirlist_uploads', array($updraftplus, 'backup_uploads_dirlist'));
355
 
@@ -598,13 +602,16 @@ class UpdraftPlus_Admin {
598
  $this->include_template('wp-admin/notices/thanks-for-using-main-dash.php');
599
  }
600
 
 
 
 
601
  private function ensure_sufficient_jquery_and_enqueue() {
602
- global $updraftplus, $wp_version;
603
 
604
  $enqueue_version = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? $updraftplus->version.'.'.time() : $updraftplus->version;
605
  $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
606
 
607
- if (version_compare($wp_version, '3.3', '<')) {
608
  // Require a newer jQuery (3.2.1 has 1.6.1, so we go for something not too much newer). We use .on() in a way that is incompatible with < 1.7
609
  wp_deregister_script('jquery');
610
  $jquery_enqueue_version = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '1.7.2'.'.'.time() : '1.7.2';
@@ -798,7 +805,19 @@ class UpdraftPlus_Admin {
798
  'local_upload_started' => __('Local backup upload has started; please check the current status tab to see the upload progress', 'updraftplus'),
799
  'local_upload_error' => __('You must select at least one remote storage destination to upload this backup set to.', 'updrafplus'),
800
  'already_uploaded' => __('(already uploaded)', 'updraftplus'),
801
- 'onedrive_folder_url_warning' => __('Please specify the Microsoft OneDrive folder name, not the URL.', 'updraftplus')
 
 
 
 
 
 
 
 
 
 
 
 
802
  ));
803
  }
804
 
@@ -1064,22 +1083,6 @@ class UpdraftPlus_Admin {
1064
  }
1065
  }
1066
 
1067
- /**
1068
- * This options filter removes ABSPATH off the front of updraft_dir, if it is given absolutely and contained within it
1069
- *
1070
- * @param string $updraft_dir Directory
1071
- * @return string
1072
- */
1073
- public function prune_updraft_dir_prefix($updraft_dir) {
1074
- if ('/' == substr($updraft_dir, 0, 1) || "\\" == substr($updraft_dir, 0, 1) || preg_match('/^[a-zA-Z]:/', $updraft_dir)) {
1075
- $wcd = trailingslashit(WP_CONTENT_DIR);
1076
- if (strpos($updraft_dir, $wcd) === 0) {
1077
- $updraft_dir = substr($updraft_dir, strlen($wcd));
1078
- }
1079
- }
1080
- return $updraft_dir;
1081
- }
1082
-
1083
  /**
1084
  * Start a download of a backup. This method is called via the AJAX action updraft_download_backup. May die instead of returning depending upon the mode in which it is called.
1085
  */
@@ -1256,7 +1259,7 @@ class UpdraftPlus_Admin {
1256
  } else {
1257
  $updraftplus->close_browser_connection(json_encode($msg));
1258
  }
1259
- $this->get_remote_file($services, $file, $timestamp);
1260
  }
1261
 
1262
  // Now, be ready to spool the thing to the browser
@@ -1286,129 +1289,6 @@ class UpdraftPlus_Admin {
1286
 
1287
  }
1288
 
1289
- /**
1290
- * This method gets the remote storage information and objects and loops over each of them until we get a successful download of the passed in file.
1291
- *
1292
- * @param Array $services - a list of connected service identifiers (e.g. 'dropbox', 's3', etc.)
1293
- * @param String $file - the name of the file
1294
- * @param Integer $timestamp - the backup timestamp
1295
- * @param Boolean $restore - a boolean to indicate if the caller of this method is a restore or not; if so, different messages are logged
1296
- */
1297
- private function get_remote_file($services, $file, $timestamp, $restore = false) {
1298
- global $updraftplus;
1299
-
1300
- $fullpath = $updraftplus->backups_dir_location().'/'.$file;
1301
-
1302
- $storage_objects_and_ids = $updraftplus->get_storage_objects_and_ids($services);
1303
-
1304
- $is_downloaded = false;
1305
-
1306
- $updraftplus->register_wp_http_option_hooks();
1307
-
1308
- foreach ($services as $service) {
1309
-
1310
- if (empty($service) || 'none' == $service) continue;
1311
-
1312
- if ($is_downloaded) continue;
1313
-
1314
- if ($restore) {
1315
- $service_description = empty($updraftplus->backup_methods[$service]) ? $service : $updraftplus->backup_methods[$service];
1316
- $updraftplus->log(__("File is not locally present - needs retrieving from remote storage", 'updraftplus')." ($service_description)", 'notice-restore');
1317
- }
1318
-
1319
- $object = $storage_objects_and_ids[$service]['object'];
1320
-
1321
- if (!$object->supports_feature('multi_options')) {
1322
- error_log("UpdraftPlus_Admin::get_remote_file(): Multi-options not supported by: ".$service);
1323
- continue;
1324
- }
1325
-
1326
- $instance_ids = $storage_objects_and_ids[$service]['instance_settings'];
1327
- $backups_instance_ids = isset($backup_history[$timestamp]['service_instance_ids'][$service]) ? $backup_history[$timestamp]['service_instance_ids'][$service] : array(false);
1328
-
1329
- foreach ($backups_instance_ids as $instance_id) {
1330
-
1331
- if (isset($instance_ids[$instance_id])) {
1332
- $options = $instance_ids[$instance_id];
1333
- } else {
1334
- // If we didn't find a instance id match, it could be a new UpdraftPlus upgrade or a wipe settings with the same details entered so try the default options saved.
1335
- $options = $object->get_options();
1336
- }
1337
-
1338
- $object->set_options($options, false, $instance_id);
1339
-
1340
- $download = $this->download_file($file, $object);
1341
-
1342
- if (is_readable($fullpath) && false !== $download) {
1343
- if ($restore) {
1344
- $updraftplus->log(__("OK", 'updraftplus'), 'notice-restore');
1345
- } else {
1346
- clearstatcache();
1347
- $updraftplus->log('Remote fetch was successful (file size: '.round(filesize($fullpath)/1024, 1).' KB)');
1348
- $is_downloaded = true;
1349
- }
1350
- break 2;
1351
- } else {
1352
- if ($restore) {
1353
- $updraftplus->log(__("Error", 'updraftplus'), 'notice-restore');
1354
- } else {
1355
- clearstatcache();
1356
- if (0 === @filesize($fullpath)) @unlink($fullpath);
1357
- $updraftplus->log('Remote fetch failed');
1358
- }
1359
- }
1360
- }
1361
- }
1362
- $updraftplus->register_wp_http_option_hooks(false);
1363
- }
1364
-
1365
- /**
1366
- * Downloads a specified file into UD's directory
1367
- *
1368
- * @param String $file The name of the file
1369
- * @param array $object The object of the service to use to download with. UpdraftPlus_BackupModule.
1370
- * @return Boolean - Whether the operation succeeded. Inherited from the storage module's download() method. N.B. At the time of writing it looks like not all modules necessarily return true upon success; but false can be relied upon for detecting failure.
1371
- */
1372
- private function download_file($file, $object) {
1373
-
1374
- global $updraftplus;
1375
-
1376
- @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);
1377
-
1378
- $service = $object->get_id();
1379
-
1380
- $updraftplus->log("Requested file from remote service: $service: $file");
1381
-
1382
- if (method_exists($object, 'download')) {
1383
-
1384
- try {
1385
- return $object->download($file);
1386
- } catch (Exception $e) {
1387
- $log_message = 'Exception ('.get_class($e).') occurred during download: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
1388
- error_log($log_message);
1389
- // @codingStandardsIgnoreLine
1390
- if (function_exists('wp_debug_backtrace_summary')) $log_message .= ' Backtrace: '.wp_debug_backtrace_summary();
1391
- $updraftplus->log($log_message);
1392
- $updraftplus->log(sprintf(__('A PHP exception (%s) has occurred: %s', 'updraftplus'), get_class($e), $e->getMessage()), 'error');
1393
- return false;
1394
- // @codingStandardsIgnoreLine
1395
- } catch (Error $e) {
1396
- $log_message = 'PHP Fatal error ('.get_class($e).') has occurred during download. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
1397
- error_log($log_message);
1398
- // @codingStandardsIgnoreLine
1399
- if (function_exists('wp_debug_backtrace_summary')) $log_message .= ' Backtrace: '.wp_debug_backtrace_summary();
1400
- $updraftplus->log($log_message);
1401
- $updraftplus->log(sprintf(__('A PHP fatal error (%s) has occurred: %s', 'updraftplus'), get_class($e), $e->getMessage()), 'error');
1402
- return false;
1403
- }
1404
- } else {
1405
- $updraftplus->log("Automatic backup restoration is not available with the method: $service.");
1406
- $updraftplus->log("$file: ".sprintf(__("The backup archive for this file could not be found. The remote storage method in use (%s) does not allow us to retrieve files. To perform any restoration using UpdraftPlus, you will need to obtain a copy of this file and place it inside UpdraftPlus's working folder", 'updraftplus'), $service)." (".$this->prune_updraft_dir_prefix($updraftplus->backups_dir_location()).")", 'error');
1407
- return false;
1408
- }
1409
-
1410
- }
1411
-
1412
  /**
1413
  * This is used as a callback
1414
  *
@@ -1450,7 +1330,7 @@ class UpdraftPlus_Admin {
1450
  $data = in_array($subaction, $data_in_get) ? $_GET : $_POST;
1451
 
1452
  // Undo WP's slashing of GET/POST data
1453
- $data = $updraftplus->wp_unslash($data);
1454
 
1455
  // TODO: Once all commands come through here and through updraft_send_command(), the data should always come from this attribute (once updraft_send_command() is modified appropriately).
1456
  if (isset($data['action_data'])) $data = $data['action_data'];
@@ -1498,7 +1378,7 @@ class UpdraftPlus_Admin {
1498
  try {
1499
  // N.B. Also called from autobackup.php
1500
  // TODO: This should go into UpdraftPlus_Commands, once the add-ons have been ported to use updraft_send_command()
1501
- echo json_encode($this->get_activejobs_list($updraftplus->wp_unslash($_GET)));
1502
  } catch (Exception $e) {
1503
  $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().')';
1504
  error_log($log_message);
@@ -1520,7 +1400,7 @@ class UpdraftPlus_Admin {
1520
  try {
1521
  // httpget
1522
  $curl = empty($_REQUEST['curl']) ? false : true;
1523
- echo $this->http_get($updraftplus->wp_unslash($_REQUEST['uri']), $curl);
1524
  // @codingStandardsIgnoreLine
1525
  } catch (Error $e) {
1526
  $log_message = 'PHP Fatal error ('.get_class($e).') has occurred during http get. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
@@ -1542,7 +1422,7 @@ class UpdraftPlus_Admin {
1542
  $subsubaction = $_REQUEST['subsubaction'];
1543
  try {
1544
  // These generally echo and die - they will need further work to port to one of the command classes. Some may already have equivalents in UpdraftPlus_Commands, if they are used from UpdraftCentral.
1545
- do_action($updraftplus->wp_unslash($subsubaction));
1546
  } catch (Exception $e) {
1547
  $log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during doaction subaction with '.$subsubaction.' subsubaction. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
1548
  error_log($log_message);
@@ -1862,19 +1742,55 @@ class UpdraftPlus_Admin {
1862
  'data' => $data,
1863
  'cksum' => md5($output),
1864
  'logs_exist' => $logs_exist,
 
1865
  ));
1866
  }
1867
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1868
  /**
1869
  * Get information on disk space used by an entity, or by UD's internal directory. Returns as a human-readable string.
1870
  *
1871
  * @param String $entity - the entity (e.g. 'plugins'; 'all' for all entities, or 'ud' for UD's internal directory)
1872
- *
1873
- * @return String
1874
  */
1875
- public function get_disk_space_used($entity) {
1876
  global $updraftplus;
1877
- if ('updraft' == $entity) return $this->recursive_directory_size($updraftplus->backups_dir_location());
1878
 
1879
  $backupable_entities = $updraftplus->get_backupable_file_entities(true, false);
1880
 
@@ -1887,12 +1803,18 @@ class UpdraftPlus_Admin {
1887
  $size = $this->recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, 'numeric');
1888
  if (is_numeric($size) && $size>0) $total_size += $size;
1889
  }
1890
- return $updraftplus->convert_numeric_size_to_text($total_size);
 
 
 
 
 
 
1891
  } elseif (!empty($backupable_entities[$entity])) {
1892
  // Might be an array
1893
  $basedir = $backupable_entities[$entity];
1894
  $dirs = apply_filters('updraftplus_dirlist_'.$entity, $basedir);
1895
- return $this->recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir);
1896
  }
1897
 
1898
  // Default fallback
@@ -2401,6 +2323,9 @@ class UpdraftPlus_Admin {
2401
  $this->include_template('wp-admin/settings/header.php');
2402
  }
2403
 
 
 
 
2404
  public function settings_output() {
2405
 
2406
  if (false == ($render = apply_filters('updraftplus_settings_page_render', true))) {
@@ -2461,16 +2386,17 @@ class UpdraftPlus_Admin {
2461
  if ('db' != $v) $s_val = 2;
2462
  }
2463
  }
2464
- $pval = ($updraftplus->have_addons) ? 1 : 0;
2465
 
2466
  echo '<strong>'.__('Actions', 'updraftplus').':</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&updraft_restore_success='.$s_val.'&pval='.$pval.'">'.__('Return to UpdraftPlus Configuration', 'updraftplus').'</a>';
2467
  return;
 
2468
  } elseif (is_wp_error($backup_success)) {
2469
  echo '<p>';
2470
  $updraftplus->log_e('Restore failed...');
2471
  echo '</p>';
2472
  $updraftplus->log_wp_error($backup_success);
2473
- $updraftplus->log("Restore failed");
2474
  $updraftplus->list_errors();
2475
  echo '<strong>'.__('Actions', 'updraftplus').':</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus">'.__('Return to UpdraftPlus Configuration', 'updraftplus').'</a>';
2476
  return;
@@ -2603,36 +2529,29 @@ class UpdraftPlus_Admin {
2603
  $backup_history = UpdraftPlus_Backup_History::get_history();
2604
  }
2605
 
2606
-
2607
- ?>
2608
-
2609
- <?php
2610
-
2611
- $tabflag = 1;
 
 
 
 
 
2612
 
2613
  if (isset($_REQUEST['tab'])) {
2614
- switch ($_REQUEST['tab']) {
2615
- case 'status':
2616
- $tabflag = 1;
2617
- break;
2618
- case 'backups':
2619
- $tabflag = 2;
2620
- break;
2621
- case 'settings':
2622
- $tabflag = 3;
2623
- break;
2624
- case 'expert':
2625
- $tabflag = 4;
2626
- break;
2627
- case 'addons':
2628
- $tabflag = 5;
2629
- break;
2630
- default:
2631
- $tabflag = 1;
2632
  }
2633
  }
2634
-
2635
- $this->include_template('wp-admin/settings/tab-bar.php', false, array('backup_history' => $backup_history, 'tabflag' => $tabflag));
2636
 
2637
  $updraft_dir = $updraftplus->backups_dir_location();
2638
  $backup_disabled = $updraftplus->really_is_writable($updraft_dir) ? '' : 'disabled="disabled"';
@@ -2644,7 +2563,7 @@ class UpdraftPlus_Admin {
2644
 
2645
  <?php $this->include_template('wp-admin/settings/tab-status.php', false, array('tabflag' => $tabflag, 'backup_disabled' => $backup_disabled)); ?>
2646
 
2647
- <div id="updraft-navtab-backups-content" <?php if (2 != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if (2 != $tabflag) echo 'display:none;'; ?>">
2648
  <?php
2649
  $is_opera = (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/'));
2650
  $tmp_opts = array('include_opera_warning' => $is_opera);
@@ -2653,19 +2572,82 @@ class UpdraftPlus_Admin {
2653
  $this->include_template('wp-admin/settings/upload-backups-modal.php');
2654
  ?>
2655
  </div>
2656
-
2657
- <div id="updraft-navtab-settings-content" <?php if (3 != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if (3 != $tabflag) echo 'display:none;'; ?>">
2658
  <h2 class="updraft_settings_sectionheading"><?php _e('Backup Contents And Schedule', 'updraftplus');?></h2>
2659
  <?php UpdraftPlus_Options::options_form_begin(); ?>
2660
  <?php $this->settings_formcontents(); ?>
2661
  </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2662
  </div>
2663
 
2664
- <div id="updraft-navtab-expert-content"<?php if (4 != $tabflag) echo ' class="updraft-hidden"'; ?> style="<?php if (4 != $tabflag) echo 'display:none;'; ?>">
2665
  <?php $this->settings_advanced_tools(); ?>
2666
  </div>
2667
 
2668
- <div id="updraft-navtab-addons-content"<?php if (5 != $tabflag) echo ' class="updraft-hidden"'; ?> style="<?php if (5 != $tabflag) echo 'display:none;'; ?>">
2669
 
2670
  <?php
2671
  $tab_addons = $this->include_template('wp-admin/settings/tab-addons.php', true, array('tabflag' => $tabflag));
@@ -2677,6 +2659,7 @@ class UpdraftPlus_Admin {
2677
  </div>
2678
 
2679
  <?php
 
2680
  // settings_header() opens a div
2681
  echo '</div>';
2682
  }
@@ -2726,11 +2709,13 @@ class UpdraftPlus_Admin {
2726
  /**
2727
  * This method will build the UpdraftPlus.com login form and echo it to the page.
2728
  *
2729
- * @param string $option_page - the option page this form is being output to
 
2730
  *
2731
  * @return void
2732
  */
2733
- public function build_credentials_form($option_page) {
 
2734
 
2735
  $enter_credentials_begin = UpdraftPlus_Options::options_form_begin('', false, array(), 'updraftplus_com_login');
2736
 
@@ -2746,22 +2731,6 @@ class UpdraftPlus_Admin {
2746
 
2747
  $enter_credentials_end .= '</form>';
2748
 
2749
- $this->show_credentials_form($enter_credentials_begin, $enter_credentials_end, $option_page);
2750
- }
2751
-
2752
- /**
2753
- * This method will build the UpdraftPlus.com login form and echo it to the page.
2754
- *
2755
- * @param string $enter_credentials_begin - a string that contains the start of the form
2756
- * @param string $enter_credentials_end - a string that contains the end of the form
2757
- * @param string $option_page - the option page this form is being output to
2758
- *
2759
- * @return void
2760
- */
2761
- private function show_credentials_form($enter_credentials_begin, $enter_credentials_end, $option_page) {
2762
-
2763
- global $updraftplus;
2764
-
2765
  echo $enter_credentials_begin;
2766
 
2767
  // We have to duplicate settings_fields() in order to set our referer
@@ -2782,7 +2751,7 @@ class UpdraftPlus_Admin {
2782
 
2783
  echo $nonce_field;
2784
 
2785
- $referer = esc_attr($updraftplus->wp_unslash($_SERVER['REQUEST_URI']));
2786
 
2787
  // This one is used on single site installs
2788
  if (false === strpos($referer, '?')) {
@@ -2791,10 +2760,53 @@ class UpdraftPlus_Admin {
2791
  $referer .= '&tab=addons';
2792
  }
2793
 
 
 
2794
  echo '<input type="hidden" name="_wp_http_referer" value="'.$referer.'" />';
2795
  // End of duplication of settings-fields()
2796
 
2797
- do_settings_sections($option_page);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2798
  echo $enter_credentials_end;
2799
  }
2800
 
@@ -3223,6 +3235,7 @@ class UpdraftPlus_Admin {
3223
  if (!$wp_filesystem->delete($plugs.'-old', true)) {
3224
  $ret3 = false;
3225
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
 
3226
  } else {
3227
  $ret3 = true;
3228
  echo "<strong>".__('OK', 'updraftplus')."</strong><br>";
@@ -3258,6 +3271,7 @@ class UpdraftPlus_Admin {
3258
  if (!$wp_filesystem->delete($dir.$name, true)) {
3259
  $ret = false;
3260
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
 
3261
  } else {
3262
  echo "<strong>".__('OK', 'updraftplus')."</strong><br>";
3263
  }
@@ -3267,6 +3281,7 @@ class UpdraftPlus_Admin {
3267
  } else {
3268
  $ret = false;
3269
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
 
3270
  }
3271
  }
3272
  }
@@ -3493,7 +3508,7 @@ class UpdraftPlus_Admin {
3493
  } else {
3494
  $dir_info .= __('Backup directory specified exists, but is <b>not</b> writable.', 'updraftplus');
3495
  }
3496
- $dir_info .= '<span class="updraft-directory-not-writable-blurb"><span class="directory-permissions"><a class="updraft_create_backup_dir" href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraft_create_backup_dir&nonce='.wp_create_nonce('create_backup_dir').'">'.__('Follow this link to attempt to create the directory and set the permissions', 'updraftplus').'</a></span>, '.__('or, to reset this option', 'updraftplus').' <a href="#" class="updraft_backup_dir_reset">'.__('click here', 'updraftplus').'</a>. '.__('If that is unsuccessful check the permissions on your server or change it to another directory that is writable by your web server process.', 'updraftplus').'</span>';
3497
  }
3498
  return $dir_info;
3499
  }
@@ -3700,7 +3715,7 @@ class UpdraftPlus_Admin {
3700
  if ('numeric' == $format) return $size;
3701
 
3702
  global $updraftplus;
3703
- return $updraftplus->convert_numeric_size_to_text($size);
3704
 
3705
  }
3706
 
@@ -3802,7 +3817,7 @@ class UpdraftPlus_Admin {
3802
  $rawbackup .= $show_services;
3803
 
3804
  if (false !== $total_size) {
3805
- $rawbackup .= '</p><strong>'.__('Total backup size:', 'updraftplus').'</strong> '.$updraftplus->convert_numeric_size_to_text($total_size).'<p>';
3806
  }
3807
 
3808
 
@@ -4014,11 +4029,8 @@ class UpdraftPlus_Admin {
4014
  if (!empty($jobdata) && 'finished' != $jobdata['jobstatus']) return '';
4015
 
4016
  // Check that the user has remote storage setup.
4017
- $services = UpdraftPlus_Options::get_updraft_option('updraft_service');
4018
- $service = $updraftplus->just_one($services);
4019
- if (is_string($service)) $service = array($service);
4020
- if (!is_array($service)) $service = array('none');
4021
- if (empty($service) || array('none') == $service || array('') == $service || 'none' == $service) return '';
4022
 
4023
  $show_upload = false;
4024
  $not_uploaded = array();
@@ -4176,7 +4188,7 @@ ENDHERE;
4176
  $blog_name = $matches[2];
4177
  }
4178
 
4179
- if ($updraftplus->is_db_encrypted($db_backup_name)) $status = 'encrypted';
4180
 
4181
  if (is_array($db_info) && isset($db_info['status'])) {
4182
  $db_backups[$key]['status'] = $status;
@@ -4231,25 +4243,65 @@ ENDHERE;
4231
  }
4232
 
4233
  /**
4234
- * Carry out the restore process
 
4235
  *
4236
- * @param Integer $timestamp Identifying the backup to be restored
4237
- * @param Array|null $continuation_data For continuing a multi-stage restore (code believed to be incomplete)
4238
- * @return Boolean|WP_Error WP_Error indicates a terminal failure; false indicates not-yet complete (not necessarily terminal); true indicates complete.
4239
  */
4240
- private function restore_backup($timestamp, $continuation_data = null) {
4241
-
4242
- global $wp_filesystem, $updraftplus;
4243
-
4244
- @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);
4245
 
4246
- $backup_set = UpdraftPlus_Backup_History::get_history($timestamp);
4247
-
4248
- if (empty($backup_set)) {
4249
- echo '<p>'.__('This backup does not exist in the backup history - restoration aborted. Timestamp:', 'updraftplus')." $timestamp</p><br>";
4250
- return new WP_Error('does_not_exist', __('Backup does not exist in the backup history', 'updraftplus'));
 
 
 
 
 
4251
  }
4252
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4253
  // request_filesystem_credentials passes on fields just via hidden name/value pairs.
4254
  // Build array of parameters to be passed via this
4255
  $extra_fields = array();
@@ -4280,10 +4332,35 @@ ENDHERE;
4280
  foreach ($wp_filesystem->errors->get_error_messages() as $message) show_message($message);
4281
  exit;
4282
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4283
 
4284
- // If we make it this far then WP_Filesystem has been instantiated and is functional
 
 
 
 
4285
 
4286
- // Set up logging
4287
  $updraftplus->backup_time_nonce();
4288
  $updraftplus->jobdata_set('job_type', 'restore');
4289
  $updraftplus->jobdata_set('job_time_ms', $updraftplus->job_time_ms);
@@ -4293,49 +4370,13 @@ ENDHERE;
4293
  // TODO: Automatic purging of old log files
4294
  // TODO: Provide option to auto-email the log file
4295
 
4296
- echo '<h1>'.__('UpdraftPlus Restoration: Progress', 'updraftplus').'</h1><div id="updraft-restore-progress">';
4297
-
4298
  $this->show_admin_warning('<a target="_blank" href="?action=downloadlog&page=updraftplus&updraftplus_backup_nonce='.htmlspecialchars($updraftplus->nonce).'">'.__('Follow this link to download the log file for this restoration (needed for any support requests).', 'updraftplus').'</a>');
4299
 
4300
- $updraft_dir = trailingslashit($updraftplus->backups_dir_location());
4301
- $foreign_known = apply_filters('updraftplus_accept_archivename', array());
4302
-
4303
- $service = isset($backup_set['service']) ? $backup_set['service'] : array('none');
4304
- if (is_string($service)) $service = array($service);
4305
-
4306
  // Now, need to turn any updraft_restore_<entity> fields (that came from a potential WP_Filesystem form) back into parts of the _POST array (which we want to use)
4307
  if (empty($_POST['updraft_restore']) || (!is_array($_POST['updraft_restore']))) $_POST['updraft_restore'] = array();
4308
 
4309
- $entities_to_restore = array();
4310
- foreach ($_POST['updraft_restore'] as $entity) {
4311
- if (empty($backup_set['meta_foreign'])) {
4312
- $entities_to_restore[$entity] = $entity;
4313
- } else {
4314
- if ('db' == $entity && !empty($foreign_known[$backup_set['meta_foreign']]) && !empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
4315
- $entities_to_restore[$entity] = 'db';
4316
- } else {
4317
- $entities_to_restore[$entity] = 'wpcore';
4318
- }
4319
- }
4320
- }
4321
-
4322
- foreach ($_POST as $key => $value) {
4323
- if (0 === strpos($key, 'updraft_restore_')) {
4324
- $nkey = substr($key, 16);
4325
- if (!isset($entities_to_restore[$nkey])) {
4326
- $_POST['updraft_restore'][] = $nkey;
4327
- if (empty($backup_set['meta_foreign'])) {
4328
- $entities_to_restore[$nkey] = $nkey;
4329
- } else {
4330
- if ('db' == $entity && !empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
4331
- $entities_to_restore[$nkey] = 'db';
4332
- } else {
4333
- $entities_to_restore[$nkey] = 'wpcore';
4334
- }
4335
- }
4336
- }
4337
- }
4338
- }
4339
 
4340
  if (0 == count($_POST['updraft_restore'])) {
4341
  echo '<p>'.__('ABORT: Could not find the information on which entities to restore.', 'updraftplus').'</p>';
@@ -4343,17 +4384,17 @@ ENDHERE;
4343
  return new WP_Error('missing_info', 'Backup information not found');
4344
  }
4345
 
 
4346
  $this->entities_to_restore = $entities_to_restore;
4347
 
 
4348
  set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
4349
 
4350
- /*
4351
- $_POST['updraft_restore'] is typically something like: array(0=>'db', 1=>'plugins', 2=>'themes'), etc.
4352
- i.e. array ('db', 'plugins', themes')
4353
- */
4354
 
 
4355
  if (empty($restore_options)) {
4356
- // Gather the restore optons into one place - code after here should read the options, and not the HTTP layer
4357
  $restore_options = array();
4358
  if (!empty($_POST['updraft_restorer_restore_options'])) {
4359
  parse_str(stripslashes($_POST['updraft_restorer_restore_options']), $restore_options);
@@ -4364,17 +4405,12 @@ ENDHERE;
4364
  $updraftplus->jobdata_set('restore_options', $restore_options);
4365
  }
4366
 
4367
- $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
4368
-
4369
  // If updraft_incremental_restore_point is equal to -1 then this is either not a incremental restore or we are going to restore up to the latest increment, so there is no need to prune the backup set of any unwanted backup archives.
4370
  if (isset($restore_options['updraft_incremental_restore_point']) && $restore_options['updraft_incremental_restore_point'] > 0) {
4371
  $restore_point = $restore_options['updraft_incremental_restore_point'];
4372
- foreach ($backup_set['incremental_sets'] as $timestamp => $entities) {
4373
-
4374
- if ($timestamp > $restore_point) {
4375
-
4376
  foreach ($entities as $entity => $backups) {
4377
-
4378
  foreach ($backups as $key => $value) {
4379
  unset($backup_set[$entity][$key]);
4380
  }
@@ -4384,282 +4420,113 @@ ENDHERE;
4384
  }
4385
 
4386
  // Restore in the most helpful order
4387
- uksort($backup_set, array($this, 'sort_restoration_entities'));
4388
 
4389
- // Now log
4390
  $copy_restore_options = $restore_options;
4391
  if (!empty($copy_restore_options['updraft_encryptionphrase'])) $copy_restore_options['updraft_encryptionphrase'] = '***';
4392
  $updraftplus->log("Restore job started. Entities to restore: ".implode(', ', array_flip($entities_to_restore)).'. Restore options: '.json_encode($copy_restore_options));
4393
 
4394
  $backup_set['timestamp'] = $timestamp;
4395
 
4396
- // Allow add-ons to adjust the restore directory (but only in the case of restore - otherwise, they could just use the filter built into UpdraftPlus::get_backupable_file_entities)
4397
- $backupable_entities = apply_filters('updraft_backupable_file_entities_on_restore', $backupable_entities, $restore_options, $backup_set);
4398
-
4399
  // We use a single object for each entity, because we want to store information about the backup set
4400
- include_once(UPDRAFTPLUS_DIR.'/restorer.php');
 
 
4401
 
4402
  global $updraftplus_restorer;
4403
 
4404
  $updraftplus_restorer = new Updraft_Restorer(new Updraft_Restorer_Skin, $backup_set, false, $restore_options);
4405
-
4406
- $second_loop = array();
4407
-
4408
- echo "<h2>".__('Final checks', 'updraftplus').'</h2>';
4409
-
4410
- if (empty($backup_set['meta_foreign'])) {
4411
- $entities_to_download = $entities_to_restore;
4412
- } else {
4413
- if (!empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
4414
- $entities_to_download = array();
4415
- if (in_array('db', $entities_to_restore)) {
4416
- $entities_to_download['db'] = 1;
4417
- }
4418
- if (count($entities_to_restore) > 1 || !in_array('db', $entities_to_restore)) {
4419
- $entities_to_download['wpcore'] = 1;
4420
- }
4421
- } else {
4422
- $entities_to_download = array('wpcore' => 1);
4423
- }
4424
- }
4425
-
4426
- // First loop: make sure that files are present + readable; and populate array for second loop
4427
- foreach ($backup_set as $type => $files) {
4428
- // All restorable entities must be given explicitly, as we can store other arbitrary data in the history array
4429
- if (!isset($backupable_entities[$type]) && 'db' != $type) continue;
4430
- if (isset($backupable_entities[$type]['restorable']) && false == $backupable_entities[$type]['restorable']) continue;
4431
-
4432
- if (!isset($entities_to_download[$type])) continue;
4433
- if ('wpcore' == $type && is_multisite() && 0 === $updraftplus_restorer->ud_backup_is_multisite) {
4434
- echo "<p>$type: <strong>";
4435
- $updraftplus->log(__('Skipping restoration of WordPress core when importing a single site into a multisite installation. If you had anything necessary in your WordPress directory then you will need to re-add it manually from the zip file.', 'updraftplus'), 'notice-restore');
4436
- // TODO
4437
- // $updraftplus->log_e('Skipping restoration of WordPress core when importing a single site into a multisite installation. If you had anything necessary in your WordPress directory then you will need to re-add it manually from the zip file.');
4438
- echo "</strong></p>";
4439
- continue;
4440
- }
4441
-
4442
- if (is_string($files)) $files = array($files);
4443
-
4444
- foreach ($files as $ind => $file) {
4445
-
4446
- $fullpath = $updraft_dir.$file;
4447
- $updraftplus->log(sprintf(__("Looking for %s archive: file name: %s", 'updraftplus'), $type, $file), 'notice-restore');
4448
-
4449
- if (is_array($continuation_data) && isset($continuation_data['second_loop_entities'][$type]) && !in_array($file, $continuation_data['second_loop_entities'][$type])) {
4450
- echo __('Skipping: this archive was already restored.', 'updraftplus')."<br>";
4451
- // Set the marker so that the existing directory isn't moved out of the way
4452
- $updraftplus_restorer->been_restored[$type] = true;
4453
- continue;
4454
- }
4455
-
4456
- if (!is_readable($fullpath) || 0 == filesize($fullpath)) $this->get_remote_file($service, $file, $timestamp, true);
4457
-
4458
- $index = (0 == $ind) ? '' : $ind;
4459
- // If a file size is stored in the backup data, then verify correctness of the local file
4460
- if (isset($backup_set[$type.$index.'-size'])) {
4461
- $fs = $backup_set[$type.$index.'-size'];
4462
- $print_message = __("Archive is expected to be size:", 'updraftplus')." ".round($fs/1024, 1)." KB: ";
4463
- $as = @filesize($fullpath);
4464
- if ($as == $fs) {
4465
- $updraftplus->log($print_message.__('OK', 'updraftplus'), 'notice-restore');
4466
- } else {
4467
- $updraftplus->log($print_message.__('Error:', 'updraftplus')." ".__('file is size:', 'updraftplus')." ".round($as/1024)." ($fs, $as)", 'warning-restore');
4468
- }
4469
- } else {
4470
- $updraftplus->log(__("The backup records do not contain information about the proper size of this file.", 'updraftplus'), 'notice-restore');
4471
- }
4472
- if (!is_readable($fullpath)) {
4473
- $updraftplus->log(__('Could not find one of the files for restoration', 'updraftplus')." ($file)", 'warning-restore');
4474
- $updraftplus->log("$file: ".__('Could not find one of the files for restoration', 'updraftplus'), 'error');
4475
- echo '</div>';
4476
- restore_error_handler();
4477
- return false;
4478
- }
4479
- }
4480
-
4481
- if (empty($updraftplus_restorer->ud_foreign)) {
4482
- $types = array($type);
4483
- } else {
4484
- if ('db' != $type || empty($foreign_known[$updraftplus_restorer->ud_foreign]['separatedb'])) {
4485
- $types = array('wpcore');
4486
- } else {
4487
- $types = array('db');
4488
- }
4489
- }
4490
-
4491
- foreach ($types as $check_type) {
4492
- $info = (isset($backupable_entities[$check_type])) ? $backupable_entities[$check_type] : array();
4493
- $val = $updraftplus_restorer->pre_restore_backup($files, $check_type, $info, $continuation_data);
4494
- if (is_wp_error($val)) {
4495
- $updraftplus->log_wp_error($val);
4496
- foreach ($val->get_error_messages() as $msg) {
4497
- $updraftplus->log(__('Error:', 'updraftplus').' '.$msg, 'warning-restore');
4498
- }
4499
- foreach ($val->get_error_codes() as $code) {
4500
- if ('already_exists' == $code) $this->print_delete_old_dirs_form(false);
4501
- }
4502
- echo '</div>'; // close the updraft_restore_progress div even if we error
4503
- restore_error_handler();
4504
- return $val;
4505
- } elseif (false === $val) {
4506
- echo '</div>'; // close the updraft_restore_progress div even if we error
4507
- restore_error_handler();
4508
- return false;
4509
- }
4510
- }
4511
-
4512
- foreach ($entities_to_restore as $entity => $via) {
4513
- if ($via == $type) {
4514
- if ('wpcore' == $via && 'db' == $entity && count($files) > 1) {
4515
- $second_loop[$entity] = apply_filters('updraftplus_select_wpcore_file_with_db', $files, $updraftplus_restorer->ud_foreign);
4516
- } else {
4517
- $second_loop[$entity] = $files;
4518
  }
4519
  }
 
4520
  }
4521
-
4522
  }
4523
-
4524
- $updraftplus_restorer->delete = UpdraftPlus_Options::get_updraft_option('updraft_delete_local', 1) ? true : false;
4525
- if ('none' === $service || 'email' === $service || empty($service) || (is_array($service) && 1 == count($service) && (in_array('none', $service) || in_array('', $service) || in_array('email', $service))) || !empty($updraftplus_restorer->ud_foreign)) {
4526
- if ($updraftplus_restorer->delete) $updraftplus->log_e('Will not delete any archives after unpacking them, because there was no cloud storage for this backup');
4527
- $updraftplus_restorer->delete = false;
4528
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4529
 
4530
- if (!empty($updraftplus_restorer->ud_foreign)) $updraftplus->log("Foreign backup; created by: ".$updraftplus_restorer->ud_foreign);
4531
-
4532
- // Second loop: now actually do the restoration
4533
- uksort($second_loop, array($this, 'sort_restoration_entities'));
4534
-
4535
- // If continuing, then prune those already done
4536
- if (is_array($continuation_data)) {
4537
- foreach ($second_loop as $type => $files) {
4538
- if (isset($continuation_data['second_loop_entities'][$type])) $second_loop[$type] = $continuation_data['second_loop_entities'][$type];
4539
  }
4540
- }
4541
 
4542
- $updraftplus->jobdata_set('second_loop_entities', $second_loop);
4543
- $updraftplus->jobdata_set('backup_timestamp', $timestamp);
4544
- // use a site option, as otherwise on multisite when all the array of options is updated via UpdraftPlus_Options::update_site_option(), it will over-write any restored UD options from the backup
4545
- update_site_option('updraft_restore_in_progress', $updraftplus->nonce);
4546
 
4547
- foreach ($second_loop as $type => $files) {
4548
- // Types: uploads, themes, plugins, others, db
4549
- $info = (isset($backupable_entities[$type])) ? $backupable_entities[$type] : array();
4550
 
4551
- echo ('db' == $type) ? "<h2>".__('Database', 'updraftplus')."</h2>" : "<h2>".$info['description']."</h2>";
4552
- $updraftplus->log("Entity: ".$type);
4553
 
4554
- if (is_string($files)) $files = array($files);
4555
- foreach ($files as $fkey => $file) {
4556
- $last_one = (1 == count($second_loop) && 1 == count($files));
4557
- $last_entity = (1 == count($files));
4558
- try {
4559
- $val = $updraftplus_restorer->restore_backup($file, $type, $info, $last_one, $last_entity);
4560
- } catch (Exception $e) {
4561
- $log_message = 'Exception ('.get_class($e).') occurred during restore: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
4562
- $display_log_message = sprintf(__('A PHP exception (%s) has occurred: %s', 'updraftplus'), get_class($e), $e->getMessage());
4563
- error_log($log_message);
4564
- // @codingStandardsIgnoreLine
4565
- if (function_exists('wp_debug_backtrace_summary')) $log_message .= ' Backtrace: '.wp_debug_backtrace_summary();
4566
- $updraftplus->log($log_message);
4567
- $updraftplus->log($display_log_message, 'notice-restore');
4568
- die();
4569
- // @codingStandardsIgnoreLine
4570
- } catch (Error $e) {
4571
- $log_message = 'PHP Fatal error ('.get_class($e).') has occurred. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
4572
- error_log($log_message);
4573
- // @codingStandardsIgnoreLine
4574
- if (function_exists('wp_debug_backtrace_summary')) $log_message .= ' Backtrace: '.wp_debug_backtrace_summary();
4575
- $updraftplus->log($log_message);
4576
- $display_log_message = sprintf(__('A PHP fatal error (%s) has occurred: %s', 'updraftplus'), get_class($e), $e->getMessage());
4577
- $updraftplus->log($display_log_message, 'notice-restore');
4578
- die();
4579
  }
4580
- if (is_wp_error($val)) {
4581
- $codes = $val->get_error_codes();
4582
- if (is_array($codes) && in_array('not_found', $codes) && !empty($updraftplus_restorer->ud_foreign) && apply_filters('updraftplus_foreign_allow_missing_entity', false, $type, $updraftplus_restorer->ud_foreign)) {
4583
- $updraftplus->log("Entity to move not found in this zip - but this is possible with this foreign backup type");
4584
- } else {
4585
-
4586
- $updraftplus->log_e($val);
4587
- foreach ($val->get_error_messages() as $msg) {
4588
- $updraftplus->log(__('Error message', 'updraftplus').': '.$msg, 'notice-restore');
4589
- }
4590
- $codes = $val->get_error_codes();
4591
- if (is_array($codes)) {
4592
- foreach ($codes as $code) {
4593
- $data = $val->get_error_data($code);
4594
- if (!empty($data)) {
4595
- $pdata = (is_string($data)) ? $data : serialize($data);
4596
- $updraftplus->log(__('Error data:', 'updraftplus').' '.$pdata, 'warning-restore');
4597
- if (false !== strpos($pdata, 'PCLZIP_ERR_BAD_FORMAT (-10)')) {
4598
- echo '<a href="'.apply_filters('updraftplus_com_link', "https://updraftplus.com/faqs/error-message-pclzip_err_bad_format-10-invalid-archive-structure-mean/").'"><strong>'.__('Follow this link for more information', 'updraftplus').'</strong></a><br>';
4599
- }
4600
- }
4601
- }
4602
- }
4603
- echo '</div>'; // close the updraft_restore_progress div even if we error
4604
- restore_error_handler();
4605
- return $val;
4606
- }
4607
- } elseif (false === $val) {
4608
- echo '</div>'; // close the updraft_restore_progress div even if we error
4609
- restore_error_handler();
4610
- return false;
4611
- }
4612
- unset($files[$fkey]);
4613
- $second_loop[$type] = $files;
4614
- $updraftplus->jobdata_set('second_loop_entities', $second_loop);
4615
- $updraftplus->jobdata_set('backup_timestamp', $timestamp);
4616
-
4617
- do_action('updraft_restored_archive', $file, $type, $val, $fkey, $timestamp);
4618
 
4619
  }
4620
- unset($second_loop[$type]);
4621
- update_site_option('updraft_restore_in_progress', $updraftplus->nonce);
4622
- $updraftplus->jobdata_set('second_loop_entities', $second_loop);
4623
- $updraftplus->jobdata_set('backup_timestamp', $timestamp);
4624
- }
4625
-
4626
- // All done - remove
4627
- delete_site_option('updraft_restore_in_progress');
4628
-
4629
- foreach (array('template', 'stylesheet', 'template_root', 'stylesheet_root') as $opt) {
4630
- add_filter('pre_option_'.$opt, array($this, 'option_filter_'.$opt));
4631
- }
4632
 
4633
- // Clear any cached pages after the restore
4634
- $updraftplus_restorer->clear_cache();
4635
 
4636
- if (!function_exists('validate_current_theme')) include_once(ABSPATH.WPINC.'/themes');
4637
-
4638
- // Have seen a case where the current theme in the DB began with a capital, but not on disk - and this breaks migrating from Windows to a case-sensitive system
4639
- $template = get_option('template');
4640
- if (!empty($template) && WP_DEFAULT_THEME != $template && strtolower($template) != $template) {
4641
-
4642
- $theme_root = get_theme_root($template);
4643
- $theme_root2 = get_theme_root(strtolower($template));
4644
-
4645
- if (!file_exists("$theme_root/$template/style.css") && file_exists("$theme_root/".strtolower($template)."/style.css")) {
4646
- $updraftplus->log_e("Theme directory (%s) not found, but lower-case version exists; updating database option accordingly", $template);
4647
- update_option('template', strtolower($template));
4648
  }
4649
-
4650
  }
4651
 
4652
- if (!validate_current_theme()) {
4653
- echo '<strong>';
4654
- $updraftplus->log_e("The current theme was not found; to prevent this stopping the site from loading, your theme has been reverted to the default theme");
4655
- echo '</strong>';
4656
- }
4657
-
4658
- echo '</div>'; // Close the updraft_restore_progress div
4659
 
4660
  restore_error_handler();
4661
 
4662
- return true;
4663
  }
4664
 
4665
  public function option_filter_template($val) {
@@ -4682,21 +4549,6 @@ ENDHERE;
4682
  return $updraftplus->option_filter_get('stylesheet_root');
4683
  }
4684
 
4685
- public function sort_restoration_entities($a, $b) {
4686
- if ($a == $b) return 0;
4687
- // Put the database first
4688
- // Put wpcore after plugins/uploads/themes (needed for restores of foreign all-in-one formats)
4689
- if ('db' == $a || 'wpcore' == $b) return -1;
4690
- if ('db' == $b || 'wpcore' == $a) return 1;
4691
- // After wpcore, next last is others
4692
- if ('others' == $b) return -1;
4693
- if ('others' == $a) return 1;
4694
- // And then uploads - this is only because we want to make sure uploads is after plugins, so that we know before we get to the uploads whether the version of UD which might have to unpack them can do this new-style or not.
4695
- if ('uploads' == $b) return -1;
4696
- if ('uploads' == $a) return 1;
4697
- return strcmp($a, $b);
4698
- }
4699
-
4700
  public function return_array($input) {
4701
  if (!is_array($input)) $input = array();
4702
  return $input;
@@ -4838,7 +4690,7 @@ ENDHERE;
4838
 
4839
  $return_array = array('saved' => true);
4840
 
4841
- $add_to_post_keys = array('updraft_interval', 'updraft_interval_database', 'updraft_starttime_files', 'updraft_starttime_db', 'updraft_startday_files', 'updraft_startday_db');
4842
 
4843
  // If database and files are on same schedule, override the db day/time settings
4844
  if (isset($settings['updraft_interval_database']) && isset($settings['updraft_interval_database']) && $settings['updraft_interval_database'] == $settings['updraft_interval'] && isset($settings['updraft_starttime_files'])) {
@@ -5223,7 +5075,7 @@ ENDHERE;
5223
  /**
5224
  * This will call any wp_action
5225
  *
5226
- * @param Array $data The array of data with the vaules for wpaction
5227
  * @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
5228
  * @return Array - results
5229
  */
@@ -5297,4 +5149,171 @@ ENDHERE;
5297
  wp_enqueue_script('jstree', UPDRAFTPLUS_URL.'/includes/jstree/jstree'.$min_or_not.'.js', array('jquery'), $jstree_enqueue_version);
5298
  wp_enqueue_style('jstree', UPDRAFTPLUS_URL.'/includes/jstree/themes/default/style'.$min_or_not.'.css', array(), $jstree_enqueue_version);
5299
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5300
  }
17
 
18
  private $auth_instance_ids = array('dropbox' => array(), 'onedrive' => array(), 'googledrive' => array(), 'googlecloud' => array());
19
 
20
+ private $php_versions = array('5.4', '5.5', '5.6', '7.0', '7.1', '7.2');
21
+
22
+ private $wp_versions = array('3.2', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '4.0', '4.1', '4.2', '4.3', '4.4', '4.5', '4.6', '4.7', '4.8', '4.9');
23
+
24
  public function __construct() {
25
  $this->admin_init();
26
  }
228
  }
229
 
230
  private function setup_all_admin_notices_udonly($service, $override = false) {
231
+ global $updraftplus;
232
 
233
  if (UpdraftPlus_Options::user_can_manage() && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON && (!defined('UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE') || !UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE)) {
234
  add_action('all_admin_notices', array($this, 'show_admin_warning_disabledcron'));
265
  }
266
  }
267
 
268
+ if (version_compare($updraftplus->get_wordpress_version(), '3.2', '<')) add_action('all_admin_notices', array($this, 'show_admin_warning_wordpressversion'));
269
  }
270
 
271
  /**
353
  // UpdraftPlus templates
354
  $this->register_template_directories();
355
 
356
+ global $updraftplus, $pagenow;
357
  add_filter('updraftplus_dirlist_others', array($updraftplus, 'backup_others_dirlist'));
358
  add_filter('updraftplus_dirlist_uploads', array($updraftplus, 'backup_uploads_dirlist'));
359
 
602
  $this->include_template('wp-admin/notices/thanks-for-using-main-dash.php');
603
  }
604
 
605
+ /**
606
+ * Enqueue sufficient versions of jQuery and our own scripts
607
+ */
608
  private function ensure_sufficient_jquery_and_enqueue() {
609
+ global $updraftplus;
610
 
611
  $enqueue_version = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? $updraftplus->version.'.'.time() : $updraftplus->version;
612
  $min_or_not = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '' : '.min';
613
 
614
+ if (version_compare($updraftplus->get_wordpress_version(), '3.3', '<')) {
615
  // Require a newer jQuery (3.2.1 has 1.6.1, so we go for something not too much newer). We use .on() in a way that is incompatible with < 1.7
616
  wp_deregister_script('jquery');
617
  $jquery_enqueue_version = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? '1.7.2'.'.'.time() : '1.7.2';
805
  'local_upload_started' => __('Local backup upload has started; please check the current status tab to see the upload progress', 'updraftplus'),
806
  'local_upload_error' => __('You must select at least one remote storage destination to upload this backup set to.', 'updrafplus'),
807
  'already_uploaded' => __('(already uploaded)', 'updraftplus'),
808
+ 'onedrive_folder_url_warning' => __('Please specify the Microsoft OneDrive folder name, not the URL.', 'updraftplus'),
809
+ 'updraftcentral_cloud' => __('UpdraftCentral Cloud', 'updraftplus'),
810
+ 'login_successful' => __('Login successful.', 'updraftplus').' '.__('Please follow this link to open %s in a new window.', 'updraftplus'),
811
+ 'registration_successful' => __('Registration successful.', 'updraftplus').' '.__('Please follow this link to open %s in a new window.', 'updraftplus'),
812
+ 'username_password_required' => __('Both email and password fields are required.', 'updraftplus'),
813
+ 'valid_email_required' => __('An email is required and needs to be in a valid format.', 'updraftplus'),
814
+ 'trouble_connecting' => __('Trouble connecting? Try using an alternative method in the advanced security options.', 'updraftplus'),
815
+ 'perhaps_login' => __('Perhaps you would want to login instead.', 'updraftplus'),
816
+ 'generating_key' => __('Please wait while the system generates and registers an encryption key for your website with UpdraftCentral Cloud.', 'updraftplus'),
817
+ 'updraftcentral_cloud_redirect' => __('Please wait while you are redirected to UpdraftCentral Cloud.', 'updraftplus'),
818
+ 'data_consent_required' => __('You need to read and accept the UpdraftCentral Cloud data and privacy policies before you can proceed.', 'updraftplus'),
819
+ 'close_wizard' => __('You can also close this wizard.', 'updraftplus'),
820
+ 'control_udc_connections' => __('For future control of all your UpdraftCentral connections, go to the "Advanced Tools" tab.', 'updraftplus'),
821
  ));
822
  }
823
 
1083
  }
1084
  }
1085
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1086
  /**
1087
  * Start a download of a backup. This method is called via the AJAX action updraft_download_backup. May die instead of returning depending upon the mode in which it is called.
1088
  */
1259
  } else {
1260
  $updraftplus->close_browser_connection(json_encode($msg));
1261
  }
1262
+ $updraftplus->get_remote_file($services, $file, $timestamp);
1263
  }
1264
 
1265
  // Now, be ready to spool the thing to the browser
1289
 
1290
  }
1291
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1292
  /**
1293
  * This is used as a callback
1294
  *
1330
  $data = in_array($subaction, $data_in_get) ? $_GET : $_POST;
1331
 
1332
  // Undo WP's slashing of GET/POST data
1333
+ $data = UpdraftPlus_Manipulation_Functions::wp_unslash($data);
1334
 
1335
  // TODO: Once all commands come through here and through updraft_send_command(), the data should always come from this attribute (once updraft_send_command() is modified appropriately).
1336
  if (isset($data['action_data'])) $data = $data['action_data'];
1378
  try {
1379
  // N.B. Also called from autobackup.php
1380
  // TODO: This should go into UpdraftPlus_Commands, once the add-ons have been ported to use updraft_send_command()
1381
+ echo json_encode($this->get_activejobs_list(UpdraftPlus_Manipulation_Functions::wp_unslash($_GET)));
1382
  } catch (Exception $e) {
1383
  $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().')';
1384
  error_log($log_message);
1400
  try {
1401
  // httpget
1402
  $curl = empty($_REQUEST['curl']) ? false : true;
1403
+ echo $this->http_get(UpdraftPlus_Manipulation_Functions::wp_unslash($_REQUEST['uri']), $curl);
1404
  // @codingStandardsIgnoreLine
1405
  } catch (Error $e) {
1406
  $log_message = 'PHP Fatal error ('.get_class($e).') has occurred during http get. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
1422
  $subsubaction = $_REQUEST['subsubaction'];
1423
  try {
1424
  // These generally echo and die - they will need further work to port to one of the command classes. Some may already have equivalents in UpdraftPlus_Commands, if they are used from UpdraftCentral.
1425
+ do_action(UpdraftPlus_Manipulation_Functions::wp_unslash($subsubaction), $_REQUEST);
1426
  } catch (Exception $e) {
1427
  $log_message = 'PHP Fatal Exception error ('.get_class($e).') has occurred during doaction subaction with '.$subsubaction.' subsubaction. Error Message: '.$e->getMessage().' (Code: '.$e->getCode().', line '.$e->getLine().' in '.$e->getFile().')';
1428
  error_log($log_message);
1742
  'data' => $data,
1743
  'cksum' => md5($output),
1744
  'logs_exist' => $logs_exist,
1745
+ 'web_server_disk_space' => $this->web_server_disk_space(true),
1746
  ));
1747
  }
1748
 
1749
+ /**
1750
+ * Get the html of "Web-server disk space" line which resides above of the existing backup table
1751
+ *
1752
+ * @param Boolean $will_immediately_calculate_disk_space Whether disk space should be counted now or when user click Refresh link
1753
+ * @return String Web server disk space html to render
1754
+ */
1755
+ public function web_server_disk_space($will_immediately_calculate_disk_space = true) {
1756
+ global $updraftplus, $updraftplus_admin;
1757
+ if ($will_immediately_calculate_disk_space) {
1758
+ $disk_space_used = $updraftplus_admin->get_disk_space_used('updraft', 'numeric');
1759
+ if ($disk_space_used > apply_filters('updraftplus_display_usage_line_threshold_size', 104857600)) { // 104857600 = 100 MB = (100 * 1024 * 1024)
1760
+ $disk_space_text = UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($disk_space_used);
1761
+ $refresh_link_text = __('refresh', 'updraftplus');
1762
+ return $this->web_server_disk_space_html($disk_space_text, $refresh_link_text);
1763
+ } else {
1764
+ return '';
1765
+ }
1766
+ } else {
1767
+ $disk_space_text = '';
1768
+ $refresh_link_text = __('calculate', 'updraftplus');
1769
+ return $this->web_server_disk_space_html($disk_space_text, $refresh_link_text);
1770
+ }
1771
+ }
1772
+
1773
+ /**
1774
+ * Get the html of "Web-server disk space" line which resides above of the existing backup table
1775
+ *
1776
+ * @param String $disk_space_text The texts which represents disk space usage
1777
+ * @param String $refresh_link_text Refresh disk space link text
1778
+ * @return String Web server disk space html
1779
+ */
1780
+ private function web_server_disk_space_html($disk_space_text, $refresh_link_text) {
1781
+ return '<li class="updraft-server-disk-space" title="'.esc_attr__('This is a count of the contents of your Updraft directory', 'updraftplus').'"><strong>'.__('Web-server disk space in use by UpdraftPlus', 'updraftplus').':</strong> <span class="updraft_diskspaceused"><em>'.$disk_space_text.'</em></span> <a class="updraft_diskspaceused_update" href="#">'.$refresh_link_text.'</a></li>';
1782
+ }
1783
+
1784
  /**
1785
  * Get information on disk space used by an entity, or by UD's internal directory. Returns as a human-readable string.
1786
  *
1787
  * @param String $entity - the entity (e.g. 'plugins'; 'all' for all entities, or 'ud' for UD's internal directory)
1788
+ * @param String $format Return format - 'text' or 'numeric'
1789
+ * @return String|Integer If $format is text, It returns strings. Otherwise integer value.
1790
  */
1791
+ public function get_disk_space_used($entity, $format = 'text') {
1792
  global $updraftplus;
1793
+ if ('updraft' == $entity) return $this->recursive_directory_size($updraftplus->backups_dir_location(), array(), '', $format);
1794
 
1795
  $backupable_entities = $updraftplus->get_backupable_file_entities(true, false);
1796
 
1803
  $size = $this->recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, 'numeric');
1804
  if (is_numeric($size) && $size>0) $total_size += $size;
1805
  }
1806
+
1807
+ if ('numeric' == $format) {
1808
+ return $total_size;
1809
+ } else {
1810
+ return UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_size);
1811
+ }
1812
+
1813
  } elseif (!empty($backupable_entities[$entity])) {
1814
  // Might be an array
1815
  $basedir = $backupable_entities[$entity];
1816
  $dirs = apply_filters('updraftplus_dirlist_'.$entity, $basedir);
1817
+ return $this->recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, $format);
1818
  }
1819
 
1820
  // Default fallback
2323
  $this->include_template('wp-admin/settings/header.php');
2324
  }
2325
 
2326
+ /**
2327
+ * Output the settings page content. Will also run a restore if $_REQUEST so indicates.
2328
+ */
2329
  public function settings_output() {
2330
 
2331
  if (false == ($render = apply_filters('updraftplus_settings_page_render', true))) {
2386
  if ('db' != $v) $s_val = 2;
2387
  }
2388
  }
2389
+ $pval = $updraftplus->have_addons ? 1 : 0;
2390
 
2391
  echo '<strong>'.__('Actions', 'updraftplus').':</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&updraft_restore_success='.$s_val.'&pval='.$pval.'">'.__('Return to UpdraftPlus Configuration', 'updraftplus').'</a>';
2392
  return;
2393
+
2394
  } elseif (is_wp_error($backup_success)) {
2395
  echo '<p>';
2396
  $updraftplus->log_e('Restore failed...');
2397
  echo '</p>';
2398
  $updraftplus->log_wp_error($backup_success);
2399
+ $updraftplus->log('Restore failed');
2400
  $updraftplus->list_errors();
2401
  echo '<strong>'.__('Actions', 'updraftplus').':</strong> <a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus">'.__('Return to UpdraftPlus Configuration', 'updraftplus').'</a>';
2402
  return;
2529
  $backup_history = UpdraftPlus_Backup_History::get_history();
2530
  }
2531
 
2532
+ $tabflag = 'status';
2533
+ $main_tabs = apply_filters(
2534
+ 'updraftplus_main_tabs',
2535
+ array(
2536
+ 'status' => __('Current Status', 'updraftplus'),
2537
+ 'backups' => __('Existing Backups', 'updraftplus').' ('.count($backup_history).')',
2538
+ 'settings' => __('Settings', 'updraftplus'),
2539
+ 'expert' => __('Advanced Tools', 'updraftplus'),
2540
+ 'addons' => __('Premium / Extensions', 'updraftplus'),
2541
+ )
2542
+ );
2543
 
2544
  if (isset($_REQUEST['tab'])) {
2545
+ $request_tab = sanitize_text_field($_REQUEST['tab']);
2546
+ $valid_tabflags = array_keys($main_tabs);
2547
+ if (in_array($request_tab, $valid_tabflags)) {
2548
+ $tabflag = $request_tab;
2549
+ } else {
2550
+ $tabflag = 'status';
 
 
 
 
 
 
 
 
 
 
 
 
2551
  }
2552
  }
2553
+
2554
+ $this->include_template('wp-admin/settings/tab-bar.php', false, array('main_tabs' => $main_tabs, 'backup_history' => $backup_history, 'tabflag' => $tabflag));
2555
 
2556
  $updraft_dir = $updraftplus->backups_dir_location();
2557
  $backup_disabled = $updraftplus->really_is_writable($updraft_dir) ? '' : 'disabled="disabled"';
2563
 
2564
  <?php $this->include_template('wp-admin/settings/tab-status.php', false, array('tabflag' => $tabflag, 'backup_disabled' => $backup_disabled)); ?>
2565
 
2566
+ <div id="updraft-navtab-backups-content" <?php if ('backups' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('backups' != $tabflag) echo 'display:none;'; ?>">
2567
  <?php
2568
  $is_opera = (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/'));
2569
  $tmp_opts = array('include_opera_warning' => $is_opera);
2572
  $this->include_template('wp-admin/settings/upload-backups-modal.php');
2573
  ?>
2574
  </div>
2575
+
2576
+ <div id="updraft-navtab-settings-content" <?php if ('settings' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('settings' != $tabflag) echo 'display:none;'; ?>">
2577
  <h2 class="updraft_settings_sectionheading"><?php _e('Backup Contents And Schedule', 'updraftplus');?></h2>
2578
  <?php UpdraftPlus_Options::options_form_begin(); ?>
2579
  <?php $this->settings_formcontents(); ?>
2580
  </form>
2581
+ <?php
2582
+ $our_keys = UpdraftPlus_Options::get_updraft_option('updraft_central_localkeys');
2583
+ if (!is_array($our_keys)) $our_keys = array();
2584
+
2585
+ // Hide the UpdraftCentral Cloud wizard If the user already has a key created for either
2586
+ // updraftplus.com or self hosted version.
2587
+ if (empty($our_keys)) {
2588
+ ?>
2589
+ <div id="updraftcentral_cloud_connect_container" class="updraftcentral_cloud_connect hidden-in-updraftcentral">
2590
+ <?php
2591
+
2592
+ $email = '';
2593
+
2594
+ // Checking email from "Premium / Extensions" tab
2595
+ if (defined('UDADDONS2_SLUG')) {
2596
+ global $updraftplus_addons2;
2597
+
2598
+ if (is_a($updraftplus_addons2, 'UpdraftPlusAddons2') && is_callable(array($updraftplus_addons2, 'get_option'))) {
2599
+ $options = $updraftplus_addons2->get_option(UDADDONS2_SLUG.'_options');
2600
+
2601
+ if (!empty($options['email'])) {
2602
+ $email = htmlspecialchars($options['email']);
2603
+ }
2604
+ }
2605
+ }
2606
+
2607
+ // Check the vault's email if we fail to get the "email" from the "Premium / Extensions" tab
2608
+ if (empty($email)) {
2609
+ $settings = $updraftplus->update_remote_storage_options_format('updraftvault');
2610
+ if (!is_wp_error($settings)) {
2611
+ if (!empty($settings['settings'])) {
2612
+ foreach ($settings['settings'] as $instance_id => $storage_options) {
2613
+ if (!empty($storage_options['email'])) {
2614
+ $email = $storage_options['email'];
2615
+ break;
2616
+ }
2617
+ }
2618
+ }
2619
+ }
2620
+ }
2621
+
2622
+ // Checking any possible email we could find from the "updraft_email" option in case the
2623
+ // above two checks failed.
2624
+ if (empty($email)) {
2625
+ $possible_emails = $updraftplus->just_one_email(UpdraftPlus_Options::get_updraft_option('updraft_email'));
2626
+ if (!empty($possible_emails)) {
2627
+ // If we get an array from the 'just_one_email' result then we're going
2628
+ // to pull the very first entry and make use of that on the succeeding process.
2629
+ if (is_array($possible_emails)) $possible_emails = array_shift($possible_emails);
2630
+
2631
+ if (is_string($possible_emails)) {
2632
+ $emails = explode(',', $possible_emails);
2633
+ $email = trim($emails[0]);
2634
+ }
2635
+ }
2636
+ }
2637
+
2638
+ $this->include_template('wp-admin/settings/updraftcentral-connect.php', false, array('email' => $email));
2639
+ ?>
2640
+ </div>
2641
+ <?php
2642
+ }
2643
+ ?>
2644
  </div>
2645
 
2646
+ <div id="updraft-navtab-expert-content"<?php if ('expert' != $tabflag) echo ' class="updraft-hidden"'; ?> style="<?php if ('expert' != $tabflag) echo 'display:none;'; ?>">
2647
  <?php $this->settings_advanced_tools(); ?>
2648
  </div>
2649
 
2650
+ <div id="updraft-navtab-addons-content"<?php if ('addons' != $tabflag) echo ' class="updraft-hidden"'; ?> style="<?php if ('addons' != $tabflag) echo 'display:none;'; ?>">
2651
 
2652
  <?php
2653
  $tab_addons = $this->include_template('wp-admin/settings/tab-addons.php', true, array('tabflag' => $tabflag));
2659
  </div>
2660
 
2661
  <?php
2662
+ do_action('updraftplus_after_main_tab_content', $tabflag);
2663
  // settings_header() opens a div
2664
  echo '</div>';
2665
  }
2709
  /**
2710
  * This method will build the UpdraftPlus.com login form and echo it to the page.
2711
  *
2712
+ * @param string $option_page - the option page this form is being output to
2713
+ * @param boolean $tfa - indicates if we want to add the tfa UI
2714
  *
2715
  * @return void
2716
  */
2717
+ public function build_credentials_form($option_page, $tfa = false) {
2718
+ global $updraftplus;
2719
 
2720
  $enter_credentials_begin = UpdraftPlus_Options::options_form_begin('', false, array(), 'updraftplus_com_login');
2721
 
2731
 
2732
  $enter_credentials_end .= '</form>';
2733
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2734
  echo $enter_credentials_begin;
2735
 
2736
  // We have to duplicate settings_fields() in order to set our referer
2751
 
2752
  echo $nonce_field;
2753
 
2754
+ $referer = esc_attr(UpdraftPlus_Manipulation_Functions::wp_unslash($_SERVER['REQUEST_URI']));
2755
 
2756
  // This one is used on single site installs
2757
  if (false === strpos($referer, '?')) {
2760
  $referer .= '&tab=addons';
2761
  }
2762
 
2763
+ $options = apply_filters('updraftplus_com_login_options', array("email" => "", "password" => ""));
2764
+
2765
  echo '<input type="hidden" name="_wp_http_referer" value="'.$referer.'" />';
2766
  // End of duplication of settings-fields()
2767
 
2768
+ ?>
2769
+
2770
+ <h2> <?php _e('Connect with your UpdraftPlus.Com account', 'updraftplus'); ?></h2>
2771
+ <p class="updraftplus_com_login_status"></p>
2772
+
2773
+ <table class="form-table">
2774
+ <tbody>
2775
+ <tr class="non_tfa_fields">
2776
+ <th><?php _e('Email', 'updraftplus'); ?></th>
2777
+ <td>
2778
+ <label for="<?php echo $option_page; ?>_options_email">
2779
+ <input id="<?php echo $option_page; ?>_options_email" type="text" size="36" name="<?php echo $option_page; ?>_options[email]" value="<?php echo htmlspecialchars($options['email']); ?>" />
2780
+ <br/>
2781
+ <a href="https://updraftplus.com/my-account/"><?php _e("Not yet got an account (it's free)? Go get one!", 'updraftplus'); ?></a>
2782
+ </label>
2783
+ </td>
2784
+ </tr>
2785
+ <tr class="non_tfa_fields">
2786
+ <th><?php _e('Password', 'updraftplus'); ?></th>
2787
+ <td>
2788
+ <label for="<?php echo $option_page; ?>'_options_password">
2789
+ <input id="<?php echo $option_page; ?>_options_password" type="password" size="36" name="<?php echo $option_page; ?>_options[password]" value="<?php echo htmlspecialchars($options['password']); ?>" />
2790
+ <br/>
2791
+ <a href="https://updraftplus.com/my-account/?action=lostpassword"><?php _e('Forgotten your details?', 'updraftplus'); ?></a>
2792
+ </label>
2793
+ </td>
2794
+ </tr>
2795
+ <?php if ($tfa) { ?>
2796
+ <tr class="tfa_fields" style="display:none;">
2797
+ <th><?php _e('One Time Password (check your OTP app to get this password)', 'updraftplus'); ?></th>
2798
+ <td>
2799
+ <label for="<?php echo $option_page; ?>_options_two_factor_code">
2800
+ <input id="<?php echo $option_page; ?>_options_two_factor_code" type="text" size="10" name="<?php echo $option_page; ?>_options[two_factor_code]" />
2801
+ </label>
2802
+ </td>
2803
+ </tr>
2804
+ <?php } ?>
2805
+ </tbody>
2806
+ </table>
2807
+
2808
+ <?php
2809
+
2810
  echo $enter_credentials_end;
2811
  }
2812
 
3235
  if (!$wp_filesystem->delete($plugs.'-old', true)) {
3236
  $ret3 = false;
3237
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
3238
+ echo $updraftplus->log_permission_failure_message($wp_filesystem->wp_content_dir(), 'Delete '.$plugs.'-old');
3239
  } else {
3240
  $ret3 = true;
3241
  echo "<strong>".__('OK', 'updraftplus')."</strong><br>";
3271
  if (!$wp_filesystem->delete($dir.$name, true)) {
3272
  $ret = false;
3273
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
3274
+ echo $updraftplus->log_permission_failure_message($dir, 'Delete '.$dir.$name);
3275
  } else {
3276
  echo "<strong>".__('OK', 'updraftplus')."</strong><br>";
3277
  }
3281
  } else {
3282
  $ret = false;
3283
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
3284
+ echo $updraftplus->log_permission_failure_message($dir, 'Delete '.$dir.$name);
3285
  }
3286
  }
3287
  }
3508
  } else {
3509
  $dir_info .= __('Backup directory specified exists, but is <b>not</b> writable.', 'updraftplus');
3510
  }
3511
+ $dir_info .= '<span class="updraft-directory-not-writable-blurb"><span class="directory-permissions"><a class="updraft_create_backup_dir" href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraft_create_backup_dir&nonce='.wp_create_nonce('create_backup_dir').'">'.__('Follow this link to attempt to create the directory and set the permissions', 'updraftplus').'</a></span>, '.__('or, to reset this option', 'updraftplus').' <a href="#" class="updraft_backup_dir_reset">'.__('press here', 'updraftplus').'</a>. '.__('If that is unsuccessful check the permissions on your server or change it to another directory that is writable by your web server process.', 'updraftplus').'</span>';
3512
  }
3513
  return $dir_info;
3514
  }
3715
  if ('numeric' == $format) return $size;
3716
 
3717
  global $updraftplus;
3718
+ return UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($size);
3719
 
3720
  }
3721
 
3817
  $rawbackup .= $show_services;
3818
 
3819
  if (false !== $total_size) {
3820
+ $rawbackup .= '</p><strong>'.__('Total backup size:', 'updraftplus').'</strong> '.UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($total_size).'<p>';
3821
  }
3822
 
3823
 
4029
  if (!empty($jobdata) && 'finished' != $jobdata['jobstatus']) return '';
4030
 
4031
  // Check that the user has remote storage setup.
4032
+ $services = (array) $updraftplus->just_one($updraftplus->get_canonical_service_list());
4033
+ if (empty($services)) return '';
 
 
 
4034
 
4035
  $show_upload = false;
4036
  $not_uploaded = array();
4188
  $blog_name = $matches[2];
4189
  }
4190
 
4191
+ if (UpdraftPlus_Encryption::is_file_encrypted($db_backup_name)) $status = 'encrypted';
4192
 
4193
  if (is_array($db_info) && isset($db_info['status'])) {
4194
  $db_backups[$key]['status'] = $status;
4243
  }
4244
 
4245
  /**
4246
+ * Processes $_POST (keys: updraft_restore and updraft_restore_*) to build an array of entities to restore.
4247
+ * Can also edit $_POST['updraft_restore']
4248
  *
4249
+ * @param Array $backup_set - information on the backup to restore
4250
+ *
4251
+ * @return Array
4252
  */
4253
+ private function get_entities_to_restore($backup_set) {
4254
+
4255
+ $entities_to_restore = array();
4256
+ $foreign_known = apply_filters('updraftplus_accept_archivename', array());
 
4257
 
4258
+ foreach ($_POST['updraft_restore'] as $entity) {
4259
+ if (empty($backup_set['meta_foreign'])) {
4260
+ $entities_to_restore[$entity] = $entity;
4261
+ } else {
4262
+ if ('db' == $entity && !empty($foreign_known[$backup_set['meta_foreign']]) && !empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
4263
+ $entities_to_restore[$entity] = 'db';
4264
+ } else {
4265
+ $entities_to_restore[$entity] = 'wpcore';
4266
+ }
4267
+ }
4268
  }
4269
 
4270
+ foreach ($_POST as $key => $value) {
4271
+ if (0 === strpos($key, 'updraft_restore_')) {
4272
+ $nkey = substr($key, 16);
4273
+ if (!isset($entities_to_restore[$nkey])) {
4274
+ $_POST['updraft_restore'][] = $nkey;
4275
+ if (empty($backup_set['meta_foreign'])) {
4276
+ $entities_to_restore[$nkey] = $nkey;
4277
+ } else {
4278
+ if ('db' == $entity && !empty($foreign_known[$backup_set['meta_foreign']]['separatedb'])) {
4279
+ $entities_to_restore[$nkey] = 'db';
4280
+ } else {
4281
+ $entities_to_restore[$nkey] = 'wpcore';
4282
+ }
4283
+ }
4284
+ }
4285
+ }
4286
+ }
4287
+
4288
+ return $entities_to_restore;
4289
+ }
4290
+
4291
+ /**
4292
+ * Ensure that WP_Filesystem is instantiated and functional. Otherwise, outputs necessary HTML and dies.
4293
+ *
4294
+ * @param Array $continuation_data - continuation data
4295
+ * @param Integer $timestamp - backup timestamp
4296
+ *
4297
+ * @return Array|Null - restore options to use, if any
4298
+ */
4299
+ private function ensure_wp_filesystem_set_up($continuation_data, $timestamp) {
4300
+
4301
+ global $wp_filesystem;
4302
+
4303
+ $restore_options = null;
4304
+
4305
  // request_filesystem_credentials passes on fields just via hidden name/value pairs.
4306
  // Build array of parameters to be passed via this
4307
  $extra_fields = array();
4332
  foreach ($wp_filesystem->errors->get_error_messages() as $message) show_message($message);
4333
  exit;
4334
  }
4335
+
4336
+ return $restore_options;
4337
+ }
4338
+
4339
+ /**
4340
+ * Carry out the restore process
4341
+ *
4342
+ * @param Integer $timestamp Identifying the backup to be restored
4343
+ * @param Array|null $continuation_data For continuing a multi-stage restore (code believed to be incomplete)
4344
+ * @return Boolean|WP_Error WP_Error indicates a terminal failure; false indicates not-yet complete (not necessarily terminal); true indicates complete.
4345
+ */
4346
+ private function restore_backup($timestamp, $continuation_data = null) {
4347
+
4348
+ global $updraftplus;
4349
+
4350
+ $backup_set = UpdraftPlus_Backup_History::get_history($timestamp);
4351
+
4352
+ if (empty($backup_set)) {
4353
+ echo '<p>'.__('This backup does not exist in the backup history - restoration aborted. Timestamp:', 'updraftplus')." $timestamp</p><br>";
4354
+ return new WP_Error('does_not_exist', __('Backup does not exist in the backup history', 'updraftplus')." ($timestamp)");
4355
+ }
4356
 
4357
+ // Will print HTML and die() if necessary
4358
+ $restore_options = $this->ensure_wp_filesystem_set_up($continuation_data, $timestamp);
4359
+
4360
+ // The <div> is closed by self::post_restore_clean_up()
4361
+ echo '<h1>'.__('UpdraftPlus Restoration: Progress', 'updraftplus').'</h1><div id="updraft-restore-progress">';
4362
 
4363
+ // Set up job ID, time and logging
4364
  $updraftplus->backup_time_nonce();
4365
  $updraftplus->jobdata_set('job_type', 'restore');
4366
  $updraftplus->jobdata_set('job_time_ms', $updraftplus->job_time_ms);
4370
  // TODO: Automatic purging of old log files
4371
  // TODO: Provide option to auto-email the log file
4372
 
 
 
4373
  $this->show_admin_warning('<a target="_blank" href="?action=downloadlog&page=updraftplus&updraftplus_backup_nonce='.htmlspecialchars($updraftplus->nonce).'">'.__('Follow this link to download the log file for this restoration (needed for any support requests).', 'updraftplus').'</a>');
4374
 
 
 
 
 
 
 
4375
  // Now, need to turn any updraft_restore_<entity> fields (that came from a potential WP_Filesystem form) back into parts of the _POST array (which we want to use)
4376
  if (empty($_POST['updraft_restore']) || (!is_array($_POST['updraft_restore']))) $_POST['updraft_restore'] = array();
4377
 
4378
+ // N.B. This both processes, and edits, $_POST['updraft_restore']
4379
+ $entities_to_restore = $this->get_entities_to_restore($backup_set);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4380
 
4381
  if (0 == count($_POST['updraft_restore'])) {
4382
  echo '<p>'.__('ABORT: Could not find the information on which entities to restore.', 'updraftplus').'</p>';
4384
  return new WP_Error('missing_info', 'Backup information not found');
4385
  }
4386
 
4387
+ // This is used in painting the admin page after a successful restore
4388
  $this->entities_to_restore = $entities_to_restore;
4389
 
4390
+ // This will be removed by self::post_restore_clean_up()
4391
  set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
4392
 
4393
+ // $_POST['updraft_restore'] is typically something like: array('db', 'plugins', 'themes'), etc.
 
 
 
4394
 
4395
+ // If not options were supplied in $restore_options, then process things in $_POST to get them
4396
  if (empty($restore_options)) {
4397
+ // Gather the restore options into one place - code after here should read the options, and not the HTTP variables
4398
  $restore_options = array();
4399
  if (!empty($_POST['updraft_restorer_restore_options'])) {
4400
  parse_str(stripslashes($_POST['updraft_restorer_restore_options']), $restore_options);
4405
  $updraftplus->jobdata_set('restore_options', $restore_options);
4406
  }
4407
 
 
 
4408
  // If updraft_incremental_restore_point is equal to -1 then this is either not a incremental restore or we are going to restore up to the latest increment, so there is no need to prune the backup set of any unwanted backup archives.
4409
  if (isset($restore_options['updraft_incremental_restore_point']) && $restore_options['updraft_incremental_restore_point'] > 0) {
4410
  $restore_point = $restore_options['updraft_incremental_restore_point'];
4411
+ foreach ($backup_set['incremental_sets'] as $increment_timestamp => $entities) {
4412
+ if ($increment_timestamp > $restore_point) {
 
 
4413
  foreach ($entities as $entity => $backups) {
 
4414
  foreach ($backups as $key => $value) {
4415
  unset($backup_set[$entity][$key]);
4416
  }
4420
  }
4421
 
4422
  // Restore in the most helpful order
4423
+ uksort($backup_set, array('UpdraftPlus_Manipulation_Functions', 'sort_restoration_entities'));
4424
 
4425
+ // Now log. We first remove any encryption passphrase from the log data.
4426
  $copy_restore_options = $restore_options;
4427
  if (!empty($copy_restore_options['updraft_encryptionphrase'])) $copy_restore_options['updraft_encryptionphrase'] = '***';
4428
  $updraftplus->log("Restore job started. Entities to restore: ".implode(', ', array_flip($entities_to_restore)).'. Restore options: '.json_encode($copy_restore_options));
4429
 
4430
  $backup_set['timestamp'] = $timestamp;
4431
 
 
 
 
4432
  // We use a single object for each entity, because we want to store information about the backup set
4433
+ if (!class_exists('Updraft_Restorer')) include_once(UPDRAFTPLUS_DIR.'/restorer.php');
4434
+
4435
+ echo "<h2>".__('Final checks', 'updraftplus').'</h2>';
4436
 
4437
  global $updraftplus_restorer;
4438
 
4439
  $updraftplus_restorer = new Updraft_Restorer(new Updraft_Restorer_Skin, $backup_set, false, $restore_options);
4440
+
4441
+ add_action('updraftplus_restoration_title', array($this, 'restoration_title'));
4442
+
4443
+ $restore_result = $updraftplus_restorer->perform_restore($entities_to_restore, $restore_options, $continuation_data);
4444
+
4445
+ if (is_wp_error($restore_result)) {
4446
+ foreach ($restore_result->get_error_codes() as $code) {
4447
+ if ('already_exists' == $code) $this->print_delete_old_dirs_form(false);
4448
+ $data = $restore_result->get_error_data($code);
4449
+ if (!empty($data)) {
4450
+ $pdata = is_string($data) ? $data : serialize($data);
4451
+ $updraftplus->log(__('Error data:', 'updraftplus').' '.$pdata, 'warning-restore');
4452
+ if (false !== strpos($pdata, 'PCLZIP_ERR_BAD_FORMAT (-10)')) {
4453
+ echo '<a href="'.apply_filters('updraftplus_com_link', "https://updraftplus.com/faqs/error-message-pclzip_err_bad_format-10-invalid-archive-structure-mean/").'"><strong>'.__('Follow this link for more information', 'updraftplus').'</strong></a><br>';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4454
  }
4455
  }
4456
+
4457
  }
 
4458
  }
4459
+
4460
+ if (true === $restore_result) {
4461
+ $this->post_restore_clean_up(true);
4462
+ } else {
4463
+ $this->post_restore_clean_up(false);
4464
  }
4465
+
4466
+ return $restore_result;
4467
+
4468
+ }
4469
+
4470
+ /**
4471
+ * Called when the restore process wants to print a title
4472
+ *
4473
+ * @param String $title - title
4474
+ */
4475
+ public function restoration_title($title) {
4476
+ echo '<h2>'.$title.'</h2>';
4477
+ }
4478
+
4479
+ /**
4480
+ * Restore has been completed - clean some things up
4481
+ *
4482
+ * @param Boolean $successful - if the restore was successful or not. If not, then only a minimum of necessary clean-up things is done.
4483
+ * @param Boolean $browser_context - if true, then extra messages will be echo-ed
4484
+ *
4485
+ * @uses $GLOBALS['updraftplus_restorer']
4486
+ * @uses UpdraftPlus::log()
4487
+ */
4488
+ private function post_restore_clean_up($successful = true, $browser_context = true) {
4489
+
4490
+ global $updraftplus_restorer, $updraftplus;
4491
+
4492
+ if ($successful) {
4493
+ // All done - remove the intermediate marker
4494
+ delete_site_option('updraft_restore_in_progress');
4495
 
4496
+ foreach (array('template', 'stylesheet', 'template_root', 'stylesheet_root') as $opt) {
4497
+ add_filter('pre_option_'.$opt, array($this, 'option_filter_'.$opt));
 
 
 
 
 
 
 
4498
  }
 
4499
 
4500
+ // Clear any cached pages after the restore
4501
+ $updraftplus_restorer->clear_cache();
 
 
4502
 
4503
+ // Have seen a case where the current theme in the DB began with a capital, but not on disk - and this breaks migrating from Windows to a case-sensitive system
4504
+ $template = get_option('template');
4505
+ if (!empty($template) && WP_DEFAULT_THEME != $template && strtolower($template) != $template) {
4506
 
4507
+ $theme_root = get_theme_root($template);
4508
+ $theme_root2 = get_theme_root(strtolower($template));
4509
 
4510
+ if (!file_exists("$theme_root/$template/style.css") && file_exists("$theme_root/".strtolower($template)."/style.css")) {
4511
+ $updraftplus->log_e("Theme directory (%s) not found, but lower-case version exists; updating database option accordingly", $template);
4512
+ update_option('template', strtolower($template));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4513
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4514
 
4515
  }
 
 
 
 
 
 
 
 
 
 
 
 
4516
 
4517
+ if (!function_exists('validate_current_theme')) include_once(ABSPATH.WPINC.'/themes');
 
4518
 
4519
+ if (!validate_current_theme()) {
4520
+ if ($browser_context) echo '<strong>';
4521
+ $updraftplus->log_e("The current theme was not found; to prevent this stopping the site from loading, your theme has been reverted to the default theme");
4522
+ if ($browser_context) echo '</strong>';
 
 
 
 
 
 
 
 
4523
  }
 
4524
  }
4525
 
4526
+ if ($browser_context) echo '</div>'; // Close the updraft_restore_progress div
 
 
 
 
 
 
4527
 
4528
  restore_error_handler();
4529
 
 
4530
  }
4531
 
4532
  public function option_filter_template($val) {
4549
  return $updraftplus->option_filter_get('stylesheet_root');
4550
  }
4551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4552
  public function return_array($input) {
4553
  if (!is_array($input)) $input = array();
4554
  return $input;
4690
 
4691
  $return_array = array('saved' => true);
4692
 
4693
+ $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');
4694
 
4695
  // If database and files are on same schedule, override the db day/time settings
4696
  if (isset($settings['updraft_interval_database']) && isset($settings['updraft_interval_database']) && $settings['updraft_interval_database'] == $settings['updraft_interval'] && isset($settings['updraft_starttime_files'])) {
5075
  /**
5076
  * This will call any wp_action
5077
  *
5078
+ * @param Array|Null $data The array of data with the vaules for wpaction
5079
  * @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
5080
  * @return Array - results
5081
  */
5149
  wp_enqueue_script('jstree', UPDRAFTPLUS_URL.'/includes/jstree/jstree'.$min_or_not.'.js', array('jquery'), $jstree_enqueue_version);
5150
  wp_enqueue_style('jstree', UPDRAFTPLUS_URL.'/includes/jstree/themes/default/style'.$min_or_not.'.css', array(), $jstree_enqueue_version);
5151
  }
5152
+
5153
+ /**
5154
+ * Detects byte-order mark at the start of common files and change waning message texts
5155
+ *
5156
+ * @return string|boolean BOM warning text or false if not bom characters detected
5157
+ */
5158
+ public function get_bom_warning_text() {
5159
+ $files_to_check = array(
5160
+ ABSPATH.'wp-config.php',
5161
+ get_template_directory().DIRECTORY_SEPARATOR.'functions.php',
5162
+ );
5163
+ if (is_child_theme()) {
5164
+ $files_to_check[] = get_stylesheet_directory().DIRECTORY_SEPARATOR.'functions.php';
5165
+ }
5166
+ $corrupted_files = array();
5167
+ foreach ($files_to_check as $file) {
5168
+ if (false === ($fp = fopen($file, 'r'))) continue;
5169
+ if (false === ($file_data = fread($fp, 8192)));
5170
+ fclose($fp);
5171
+ $substr_file_data = array();
5172
+ for ($substr_length = 2; $substr_length <= 5; $substr_length++) {
5173
+ $substr_file_data[$substr_length] = substr($file_data, 0, $substr_length);
5174
+ }
5175
+ // Detect UTF-7, UTF-8, UTF-16 (BE), UTF-16 (LE), UTF-32 (BE) & UTF-32 (LE) Byte order marks (BOM)
5176
+ $bom_decimal_representations = array(
5177
+ array(43, 47, 118, 56), // UTF-7 (Hexadecimal: 2B 2F 76 38)
5178
+ array(43, 47, 118, 57), // UTF-7 (Hexadecimal: 2B 2F 76 39)
5179
+ array(43, 47, 118, 43), // UTF-7 (Hexadecimal: 2B 2F 76 2B)
5180
+ array(43, 47, 118, 47), // UTF-7 (Hexadecimal: 2B 2F 76 2F)
5181
+ array(43, 47, 118, 56, 45), // UTF-7 (Hexadecimal: 2B 2F 76 38 2D)
5182
+ array(239, 187, 191), // UTF-8 (Hexadecimal: 2B 2F 76 38 2D)
5183
+ array(254, 255), // UTF-16 (BE) (Hexadecimal: FE FF)
5184
+ array(255, 254), // UTF-16 (LE) (Hexadecimal: FF FE)
5185
+ array(0, 0, 254, 255), // UTF-32 (BE) (Hexadecimal: 00 00 FE FF)
5186
+ array(255, 254, 0, 0), // UTF-32 (LE) (Hexadecimal: FF FE 00 00)
5187
+ );
5188
+ foreach ($bom_decimal_representations as $bom_decimal_representation) {
5189
+ $no_of_chars = count($bom_decimal_representation);
5190
+ array_unshift($bom_decimal_representation, 'C*');
5191
+ $binary = call_user_func_array('pack', $bom_decimal_representation);
5192
+ if ($binary == $substr_file_data[$no_of_chars]) {
5193
+ $corrupted_files[] = $file;
5194
+ break;
5195
+ }
5196
+ }
5197
+ }
5198
+ if (empty($corrupted_files)) {
5199
+ return false;
5200
+ } else {
5201
+ $corrupted_files_count = count($corrupted_files);
5202
+ 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/").'">'.__('Follow this link for more information', 'updraftplus').'</a>';
5203
+ }
5204
+ }
5205
+
5206
+ /**
5207
+ * Gets an instance of the "UpdraftPlus_UpdraftCentral_Cloud" class which will be
5208
+ * used to login or register the user to the UpdraftCentral cloud
5209
+ *
5210
+ * @return object
5211
+ */
5212
+ public function get_updraftcentral_cloud() {
5213
+ if (!class_exists('UpdraftPlus_UpdraftCentral_Cloud')) include_once(UPDRAFTPLUS_DIR.'/includes/updraftcentral.php');
5214
+ return new UpdraftPlus_UpdraftCentral_Cloud();
5215
+ }
5216
+
5217
+ /**
5218
+ * Gets an instance of the "UpdraftPlus_Clone" class which will be
5219
+ * used to login the user to UpdraftPlus.com
5220
+ *
5221
+ * @return object
5222
+ */
5223
+ public function get_updraftplus_clone() {
5224
+ if (!class_exists('UpdraftPlus_Clone')) include_once(UPDRAFTPLUS_DIR.'/includes/updraftplus-clone.php');
5225
+ return new UpdraftPlus_Clone();
5226
+ }
5227
+
5228
+ /**
5229
+ * This function will build and return the UpdraftPlus tempoaray clone version select widget
5230
+ *
5231
+ * @return string - the UpdraftPlus tempoary clone version select widget
5232
+ */
5233
+ public function updraftplus_clone_versions() {
5234
+ $output = sprintf(__('%s version:', 'updraftplus'), 'PHP').' ';
5235
+ $output .= $this->output_select_data($this->php_versions, 'php');
5236
+ $output .= ' '.sprintf(__('%s version:', 'updraftplus'), 'WordPress').' ';
5237
+ $output .= $this->output_select_data($this->get_wordpress_versions(), 'wp');
5238
+ $output .= '<br><input type="checkbox" class="updraftplus_clone_admin_login_options" id="" name="updraftplus_clone_admin_login_options" value="1" checked="checked">';
5239
+ $output .= '<label for="updraftplus_clone_admin_login_options" class="updraftplus_clone_admin_login_options_label">'.__('Forbid logins from non-administrators on this clone', 'updraftplus').'</label><br>';
5240
+
5241
+ return $output;
5242
+ }
5243
+
5244
+ /**
5245
+ * This function will output a select input using the passed in values.
5246
+ *
5247
+ * @param array $data - the keys and values for the select
5248
+ * @param string $name - the name of the items in the select input
5249
+ *
5250
+ * @return string - the output of the select input
5251
+ */