UpdraftPlus WordPress Backup Plugin - Version 1.11.24

Version Description

  • 10/Feb/2016 =

  • FIX: Fixed further logic errors in the advanced backup retention options, potentially relevant if you had more than one extra rule

  • TWEAK: Saving of settings is now done over AJAX (i.e. without a page reload)

  • TWEAK: In-dashboard downloads now process the HTTP Range: header, allowing resumption of failed downloads via the browser

  • TWEAK: Tweak 'Existing Backups' table CSS, to allow more entities per row

  • TWEAK: Warn copy.com users of Barracuda ending the service - https://techlib.barracuda.com/CudaDrive/EOL

  • TWEAK: Rename the 'hidden' CSS class, to prevent clashes with other plugins/themes which load their CSS code onto UD's page (which they shouldn't be doing)

  • TWEAK: Fix newsletter sign-up link

  • TWEAK: Log and triple-click summary now mentions the total size of the backup (i.e. total of the compressed backup set)

  • TWEAK: Try to detect a very rare case of recoverable database read failure, and schedule a re-try

  • TWEAK: Suppress unnecessary warning message when Dropbox account info checking fails

  • TWEAK: Attempt to restart a large OneDrive upload in a particular case seen when OneDrive's end seems to get into confusion about state

  • TWEAK: Various bits of internal re-factoring to support future improvements

Download this release

Release Info

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

Code changes from version 1.11.23 to 1.11.24

admin.php CHANGED
@@ -15,6 +15,151 @@ class UpdraftPlus_Admin {
15
  $this->admin_init();
16
  }
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  private function admin_init() {
19
 
20
  add_action('core_upgrade_preamble', array($this, 'core_upgrade_preamble'));
@@ -33,6 +178,9 @@ class UpdraftPlus_Admin {
33
 
34
  add_action('wp_before_admin_bar_render', array($this, 'wp_before_admin_bar_render'));
35
 
 
 
 
36
  global $updraftplus, $wp_version, $pagenow;
37
  add_filter('updraftplus_dirlist_others', array($updraftplus, 'backup_others_dirlist'));
38
  add_filter('updraftplus_dirlist_uploads', array($updraftplus, 'backup_uploads_dirlist'));
@@ -60,88 +208,15 @@ class UpdraftPlus_Admin {
60
  add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead') );
61
  }
62
  }
63
-
64
- if ('googledrive' === $service || (is_array($service) && in_array('googledrive', $service))) {
65
- $opts = UpdraftPlus_Options::get_updraft_option('updraft_googledrive');
66
- if (empty($opts)) {
67
- $clientid = UpdraftPlus_Options::get_updraft_option('updraft_googledrive_clientid', '');
68
- $token = UpdraftPlus_Options::get_updraft_option('updraft_googledrive_token', '');
69
- } else {
70
- $clientid = $opts['clientid'];
71
- $token = (empty($opts['token'])) ? '' : $opts['token'];
72
- }
73
- if (!empty($clientid) && empty($token)) add_action('all_admin_notices', array($this,'show_admin_warning_googledrive'));
74
- }
75
- if ('googlecloud' === $service || (is_array($service) && in_array('googlecloud', $service))) {
76
- $opts = UpdraftPlus_Options::get_updraft_option('updraft_googlecloud');
77
- if (!empty($opts)) {
78
- $clientid = $opts['clientid'];
79
- $token = (empty($opts['token'])) ? '' : $opts['token'];
80
- }
81
- if (!empty($clientid) && empty($token)) add_action('all_admin_notices', array($this,'show_admin_warning_googlecloud'));
82
- }
83
- if ('dropbox' === $service || (is_array($service) && in_array('dropbox', $service))) {
84
- $opts = UpdraftPlus_Options::get_updraft_option('updraft_dropbox');
85
- if (empty($opts['tk_request_token'])) {
86
- add_action('all_admin_notices', array($this,'show_admin_warning_dropbox') );
87
- }
88
- }
89
- if ('bitcasa' === $service || (is_array($service) && in_array('bitcasa', $service))) {
90
- $opts = UpdraftPlus_Options::get_updraft_option('updraft_bitcasa');
91
- if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['token'])) add_action('all_admin_notices', array($this,'show_admin_warning_bitcasa') );
92
- }
93
- if ('copycom' === $service || (is_array($service) && in_array('copycom', $service))) {
94
- $opts = UpdraftPlus_Options::get_updraft_option('updraft_copycom');
95
- if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['token'])) add_action('all_admin_notices', array($this,'show_admin_warning_copycom') );
96
- }
97
- if ('onedrive' === $service || (is_array($service) && in_array('onedrive', $service))) {
98
- $opts = UpdraftPlus_Options::get_updraft_option('updraft_onedrive');
99
- if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['refresh_token'])) add_action('all_admin_notices', array($this,'show_admin_warning_onedrive') );
100
- }
101
-
102
- if ('updraftvault' === $service || (is_array($service) && in_array('updraftvault', $service))) {
103
- $vault_settings = UpdraftPlus_Options::get_updraft_option('updraft_updraftvault');
104
- $connected = (is_array($vault_settings) && !empty($vault_settings['token']) && !empty($vault_settings['email'])) ? true : false;
105
- if (!$connected) add_action('all_admin_notices', array($this,'show_admin_warning_updraftvault') );
106
- }
107
-
108
- if ($this->disk_space_check(1048576*35) === false) add_action('all_admin_notices', array($this, 'show_admin_warning_diskspace'));
109
  }
110
 
111
  // Next, the actions that only come on the UpdraftPlus page
112
  if ($pagenow != UpdraftPlus_Options::admin_page() || empty($_REQUEST['page']) || 'updraftplus' != $_REQUEST['page']) return;
113
-
114
- if (UpdraftPlus_Options::user_can_manage() && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON == true) {
115
- add_action('all_admin_notices', array($this, 'show_admin_warning_disabledcron'));
116
- }
117
-
118
- if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
119
- @ini_set('display_errors',1);
120
- @error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
121
- add_action('all_admin_notices', array($this, 'show_admin_debug_warning'));
122
- }
123
-
124
- if (null === UpdraftPlus_Options::get_updraft_option('updraft_interval')) {
125
- add_action('all_admin_notices', array($this, 'show_admin_nosettings_warning'));
126
- $this->no_settings_warning = true;
127
- }
128
-
129
- # Avoid false positives, by attempting to raise the limit (as happens when we actually do a backup)
130
- @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);
131
- $max_execution_time = (int)@ini_get('max_execution_time');
132
- if ($max_execution_time>0 && $max_execution_time<20) {
133
- add_action('all_admin_notices', array($this, 'show_admin_warning_execution_time'));
134
- }
135
-
136
- // LiteSpeed has a generic problem with terminating cron jobs
137
- if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false) {
138
- if (!is_file(ABSPATH.'.htaccess') || !preg_match('/noabort/i', file_get_contents(ABSPATH.'.htaccess'))) {
139
- add_action('all_admin_notices', array($this, 'show_admin_warning_litespeed'));
140
- }
141
- }
142
-
143
- if (version_compare($wp_version, '3.2', '<')) add_action('all_admin_notices', array($this, 'show_admin_warning_wordpressversion'));
144
-
145
  add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'), 99999);
146
 
147
  }
@@ -316,7 +391,7 @@ class UpdraftPlus_Admin {
316
  <a href="https://updraftplus.com/"><img class="udp-logo" alt="UpdraftPlus" src="<?php echo UPDRAFTPLUS_URL.'/images/ud-logo-150.png' ?>"></a>
317
 
318
  <?php
319
- echo '<p><strong>'.__('Free Newsletter', 'updraftplus').'</strong> <br>'.__('UpdraftPlus news, high-quality training materials for WordPress developers and site-owners, and general WordPress news. You can de-subscribe at any time.', 'updraftplus').' <a href="http://try.updraftplus.com/newslettersignup/">'.__('Follow this link to sign up.', 'updraftplus').'</a></p>';
320
 
321
  echo '<p><strong>'.__('UpdraftPlus Premium', 'updraftplus').'</strong> <br>'.__('For personal support, the ability to copy sites, more storage destinations, encrypted backups for security, multiple backup destinations, better reporting, no adverts and plenty more, take a look at the premium version of UpdraftPlus - the world’s most popular backup plugin.', 'updraftplus').' <a href="https://updraftplus.com/comparison-updraftplus-free-updraftplus-premium/">'.__('Compare with the free version', 'updraftplus').'</a> / <a href="https://updraftplus.com/shop/updraftplus-premium/">'.__('Go to the shop.', 'updraftplus').'</a></p>';
322
 
@@ -343,21 +418,28 @@ class UpdraftPlus_Admin {
343
  } else {
344
  wp_enqueue_script('updraftplus-admin-ui', UPDRAFTPLUS_URL.'/includes/updraft-admin-ui.js', array('jquery', 'jquery-ui-dialog', 'plupload-all'), $enqueue_version);
345
  }
 
346
  }
347
 
348
  // This is also called directly from the auto-backup add-on
349
  public function admin_enqueue_scripts() {
350
 
 
 
351
  // Defeat other plugins/themes which dump their jQuery UI CSS onto our settings page
352
  wp_deregister_style('jquery-ui');
353
  wp_enqueue_style('jquery-ui', UPDRAFTPLUS_URL.'/includes/jquery-ui.custom.css', array(), '1.11.4');
354
- wp_enqueue_style('updraft-admin-css', UPDRAFTPLUS_URL.'/css/admin.css');
 
 
 
355
  // add_filter('style_loader_tag', array($this, 'style_loader_tag'), 10, 2);
356
 
357
- global $wp_locale;
358
  $this->ensure_sufficient_jquery_and_enqueue();
359
-
360
- $selectric_file = (defined('SCRIPT_DEBUG') && SCRIPT_DEBUG) ? 'jquery.selectric.js' : 'jquery.selectric.min.js';
 
 
361
  wp_enqueue_script('selectric', UPDRAFTPLUS_URL."/includes/selectric/$selectric_file", array('jquery'), '1.9.3');
362
  wp_enqueue_style('selectric', UPDRAFTPLUS_URL.'/includes/selectric/selectric.css', array(), '1.9.3');
363
 
@@ -401,7 +483,7 @@ class UpdraftPlus_Admin {
401
  'emptyresponse' => __('Error: the server sent an empty response.', 'updraftplus'),
402
  'warnings' => __('Warnings:','updraftplus'),
403
  'errors' => __('Errors:','updraftplus'),
404
- 'jsonnotunderstood' => __('Error: the server sent us a response (JSON) which we did not understand.', 'updraftplus'),
405
  'errordata' => __('Error data:', 'updraftplus'),
406
  'error' => __('Error:','updraftplus'),
407
  'errornocolon' => __('Error','updraftplus'),
@@ -437,6 +519,7 @@ class UpdraftPlus_Admin {
437
  'downloadlogfile' => __('Download log file', 'updraftplus'),
438
  'automaticbackupbeforeupdate' => __('Automatic backup before update', 'updraftplus'),
439
  'unsavedsettings' => __('You have made changes to your settings, and not saved.', 'updraftplus'),
 
440
  'connect' => __('Connect', 'updraftplus'),
441
  'connecting' => __('Connecting...', 'updraftplus'),
442
  'disconnect' => __('Disconnect', 'updraftplus'),
@@ -453,6 +536,7 @@ class UpdraftPlus_Admin {
453
  'key' => __('Key', 'updraftplus'),
454
  'nokeynamegiven' => sprintf(__("Failure: No %s was given.",'updraftplus'), __('key name','updraftplus')),
455
  'deleting' => __('Deleting...', 'updraftplus'),
 
456
  'testingconnection' => __('Testing connection...', 'updraftplus'),
457
  'send' => __('Send', 'updraftplus'),
458
  'migratemodalheight' => class_exists('UpdraftPlus_Addons_Migrator') ? 555 : 300,
@@ -461,6 +545,7 @@ class UpdraftPlus_Admin {
461
  'unsavedsettingsbackup' => __('You have made changes to your settings, and not saved.', 'updraftplus')."\n".__('Your backup will use your old settings until you save your changes.','updraftplus'),
462
  'dayselector' => $day_selector,
463
  'mdayselector' => $mday_selector,
 
464
  'day' => __('day', 'updraftplus'),
465
  'inthemonth' => __('in the month', 'updraftplus'),
466
  'days' => __('day(s)', 'updraftplus'),
@@ -553,6 +638,7 @@ class UpdraftPlus_Admin {
553
 
554
  ?><script type="text/javascript">
555
  var updraft_credentialtest_nonce='<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>';
 
556
  var updraft_siteurl = '<?php echo esc_js(site_url('', 'relative'));?>';
557
  var updraft_plupload_config=<?php echo json_encode($plupload_init); ?>;
558
  var updraft_download_nonce='<?php echo wp_create_nonce('updraftplus_download');?>';
@@ -678,6 +764,12 @@ class UpdraftPlus_Admin {
678
  echo '<div class="updraftmessage '.$class.'">'."<p>$message</p></div>";
679
  }
680
 
 
 
 
 
 
 
681
  public function show_admin_nosettings_warning() {
682
  $this->show_admin_warning('<strong>'.__('Welcome to UpdraftPlus!', 'updraftplus').'</strong> '.__('To make a backup, just press the Backup Now button.', 'updraftplus').' <a href="#" id="updraft-navtab-settings2">'.__('To change any of the default settings of what is backed up, to configure scheduled backups, to send your backups to remote storage (recommended), and more, go to the settings tab.', 'updraftplus').'</a>', 'updated notice is-dismissible');
683
  }
@@ -759,26 +851,39 @@ class UpdraftPlus_Admin {
759
 
760
  public function updraft_download_backup() {
761
 
762
- @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);
763
 
764
- global $updraftplus;
765
- if (!isset($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'], 'updraftplus_download')) die;
766
- if (!isset($_REQUEST['timestamp']) || !is_numeric($_REQUEST['timestamp']) || !isset($_REQUEST['type'])) exit;
767
 
768
- $findex = (isset($_REQUEST['findex'])) ? $_REQUEST['findex'] : 0;
769
- if (empty($findex)) $findex=0;
770
 
771
- $backupable_entities = $updraftplus->get_backupable_file_entities(true);
772
- $type_match = false;
773
- foreach ($backupable_entities as $type => $info) {
774
- if ($_REQUEST['type'] == $type) $type_match = true;
775
- }
776
-
777
- if (!$type_match && 'db' != substr($_REQUEST['type'], 0, 2)) exit;
 
 
 
778
 
779
- // Get the information on what is wanted
780
- $type = $_REQUEST['type'];
781
- $timestamp = $_REQUEST['timestamp'];
 
 
 
 
 
 
 
 
 
 
 
 
782
 
783
  // We already know that no possible entities have an MD5 clash (even after 2 characters)
784
  // Also, there's nothing enforcing a requirement that nonces are hexadecimal
@@ -804,27 +909,26 @@ class UpdraftPlus_Admin {
804
  // Where it should end up being downloaded to
805
  $fullpath = $updraftplus->backups_dir_location().'/'.$file;
806
 
807
- if (isset($_GET['stage']) && '2' == $_GET['stage']) {
808
  $updraftplus->spool_file($type, $fullpath);
 
809
  die;
810
  }
811
 
812
- if (isset($_POST['stage']) && 'delete' == $_POST['stage']) {
813
  @unlink($fullpath);
814
- echo 'deleted';
815
- $updraftplus->log('The file has been deleted');
816
- die;
817
  }
818
 
819
  // TODO: FIXME: Failed downloads may leave log files forever (though they are small)
820
- // Note that log() assumes that the data is in _POST, not _GET
821
  if ($debug_mode) $updraftplus->logfile_open($updraftplus->nonce);
822
 
823
  set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
824
 
825
  $updraftplus->log("Requested to obtain file: timestamp=$timestamp, type=$type, index=$findex");
826
 
827
- $itext = (empty($findex)) ? '' : $findex;
828
  $known_size = isset($backup_history[$timestamp][$type.$itext.'-size']) ? $backup_history[$timestamp][$type.$itext.'-size'] : 0;
829
 
830
  $services = (isset($backup_history[$timestamp]['service'])) ? $backup_history[$timestamp]['service'] : false;
@@ -836,14 +940,14 @@ class UpdraftPlus_Admin {
836
 
837
  $needs_downloading = false;
838
 
839
- if(!file_exists($fullpath)) {
840
  //if the file doesn't exist and they're using one of the cloud options, fetch it down from the cloud.
841
  $needs_downloading = true;
842
  $updraftplus->log('File does not yet exist locally - needs downloading');
843
- } elseif ($known_size>0 && filesize($fullpath) < $known_size) {
844
  $updraftplus->log("The file was found locally (".filesize($fullpath).") but did not match the size in the backup history ($known_size) - will resume downloading");
845
  $needs_downloading = true;
846
- } elseif ($known_size>0) {
847
  $updraftplus->log('The file was found locally and matched the recorded size from the backup history ('.round($known_size/1024,1).' Kb)');
848
  } else {
849
  $updraftplus->log('No file size was found recorded in the backup history. We will assume the local one is complete.');
@@ -854,7 +958,17 @@ class UpdraftPlus_Admin {
854
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, "downloading:$known_size:$fullpath");
855
 
856
  if ($needs_downloading) {
857
- $updraftplus->close_browser_connection();
 
 
 
 
 
 
 
 
 
 
858
  $is_downloaded = false;
859
  add_action('http_request_args', array($updraftplus, 'modify_http_options'));
860
  foreach ($services as $service) {
@@ -873,16 +987,21 @@ class UpdraftPlus_Admin {
873
  remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
874
  }
875
 
876
- // Now, spool the thing to the browser
877
- if(is_file($fullpath) && is_readable($fullpath)) {
878
 
879
  // That message is then picked up by the AJAX listener
880
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'downloaded:'.filesize($fullpath).":$fullpath");
881
 
 
 
882
  } else {
 
883
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'failed');
884
  $updraftplus->jobdata_set('dlerrors_'.$timestamp.'_'.$type.'_'.$findex, $updraftplus->errors);
885
  $updraftplus->log('Remote fetch failed. File '.$fullpath.' did not exist or was unreadable. If you delete local backups then remote retrieval may have failed.');
 
 
886
  }
887
 
888
  restore_error_handler();
@@ -890,7 +1009,8 @@ class UpdraftPlus_Admin {
890
  @fclose($updraftplus->logfile_handle);
891
  if (!$debug_mode) @unlink($updraftplus->logfile_name);
892
 
893
- exit;
 
894
 
895
  }
896
 
@@ -1251,119 +1371,7 @@ class UpdraftPlus_Admin {
1251
 
1252
  } elseif (isset($_POST['backup_timestamp']) && 'deleteset' == $_REQUEST['subaction']) {
1253
 
1254
- $backups = $updraftplus->get_backup_history();
1255
- $timestamps = (string)$_POST['backup_timestamp'];
1256
-
1257
- $timestamps = explode(',', $timestamps);
1258
- $delete_remote = (empty($_POST['delete_remote'])) ? false : true;
1259
-
1260
- // You need a nonce before you can set job data. And we certainly don't yet have one.
1261
- $updraftplus->backup_time_nonce();
1262
- // Set the job type before logging, as there can be different logging destinations
1263
- $updraftplus->jobdata_set('job_type', 'delete');
1264
- $updraftplus->jobdata_set('job_time_ms', $updraftplus->job_time_ms);
1265
-
1266
- if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
1267
- $updraftplus->logfile_open($updraftplus->nonce);
1268
- set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
1269
- }
1270
-
1271
- $updraft_dir = $updraftplus->backups_dir_location();
1272
- $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
1273
-
1274
- $local_deleted = 0;
1275
- $remote_deleted = 0;
1276
- $sets_removed = 0;
1277
-
1278
- foreach ($timestamps as $i => $timestamp) {
1279
-
1280
- if (!isset($backups[$timestamp])) {
1281
- echo json_encode(array('result' => 'error', 'message' => __('Backup set not found', 'updraftplus')));
1282
- die;
1283
- }
1284
-
1285
- $nonce = isset($backups[$timestamp]['nonce']) ? $backups[$timestamp]['nonce'] : '';
1286
-
1287
- $delete_from_service = array();
1288
-
1289
- if ($delete_remote) {
1290
- // Locate backup set
1291
- if (isset($backups[$timestamp]['service'])) {
1292
- $services = is_string($backups[$timestamp]['service']) ? array($backups[$timestamp]['service']) : $backups[$timestamp]['service'];
1293
- if (is_array($services)) {
1294
- foreach ($services as $service) {
1295
- if ($service && $service != 'none' && $service != 'email') $delete_from_service[] = $service;
1296
- }
1297
- }
1298
- }
1299
- }
1300
-
1301
- $files_to_delete = array();
1302
- foreach ($backupable_entities as $key => $ent) {
1303
- if (isset($backups[$timestamp][$key])) {
1304
- $files_to_delete[$key] = $backups[$timestamp][$key];
1305
- }
1306
- }
1307
- // Delete DB
1308
- if (isset($backups[$timestamp]['db'])) $files_to_delete['db'] = $backups[$timestamp]['db'];
1309
-
1310
- // Also delete the log
1311
- if ($nonce && !UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
1312
- $files_to_delete['log'] = "log.$nonce.txt";
1313
- }
1314
-
1315
- unset($backups[$timestamp]);
1316
- $sets_removed++;
1317
- UpdraftPlus_Options::update_updraft_option('updraft_backup_history', $backups);
1318
-
1319
- add_action('http_request_args', array($updraftplus, 'modify_http_options'));
1320
- foreach ($files_to_delete as $key => $files) {
1321
- # Local deletion
1322
- if (is_string($files)) $files=array($files);
1323
- foreach ($files as $file) {
1324
- if (is_file($updraft_dir.'/'.$file)) {
1325
- if (@unlink($updraft_dir.'/'.$file)) $local_deleted++;
1326
- }
1327
- }
1328
- if ('log' != $key && count($delete_from_service) > 0) {
1329
- foreach ($delete_from_service as $service) {
1330
- if ('email' == $service) continue;
1331
- if (file_exists(UPDRAFTPLUS_DIR."/methods/$service.php")) require_once(UPDRAFTPLUS_DIR."/methods/$service.php");
1332
- $objname = "UpdraftPlus_BackupModule_".$service;
1333
- $deleted = -1;
1334
- if (class_exists($objname)) {
1335
- # TODO: Re-use the object (i.e. prevent repeated connection setup/teardown)
1336
- $remote_obj = new $objname;
1337
- $deleted = $remote_obj->delete($files);
1338
- }
1339
- if ($deleted === -1) {
1340
- //echo __('Did not know how to delete from this cloud service.', 'updraftplus');
1341
- } elseif ($deleted !== false) {
1342
- $remote_deleted = $remote_deleted + count($files);
1343
- } else {
1344
- // Do nothing
1345
- }
1346
- }
1347
- }
1348
- }
1349
- remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
1350
- }
1351
-
1352
-
1353
- $message = sprintf(__('Backup sets removed: %d', 'updraftplus'),$sets_removed)."\n";
1354
-
1355
- $message .= sprintf(__('Local archives deleted: %d', 'updraftplus'),$local_deleted)."\n";
1356
- $message .= sprintf(__('Remote archives deleted: %d', 'updraftplus'),$remote_deleted)."\n";
1357
-
1358
- $updraftplus->log("Local archives deleted: ".$local_deleted);
1359
- $updraftplus->log("Remote archives deleted: ".$remote_deleted);
1360
-
1361
- print json_encode(array('result' => 'success', 'message' => $message));
1362
-
1363
- if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
1364
- restore_error_handler();
1365
- }
1366
-
1367
 
1368
  } elseif ('rawbackuphistory' == $_REQUEST['subaction']) {
1369
 
@@ -1467,15 +1475,6 @@ class UpdraftPlus_Admin {
1467
  $history_status = $this->get_history_status($rescan, $remotescan);
1468
  echo @json_encode($history_status);
1469
 
1470
- // Legacy code
1471
- // } elseif (isset($_GET['subaction']) && 'downloadstatus' == $_GET['subaction'] && isset($_GET['timestamp']) && isset($_GET['type'])) {
1472
- //
1473
- // $findex = (isset($_GET['findex'])) ? $_GET['findex'] : '0';
1474
- // if (empty($findex)) $findex = '0';
1475
- // $updraftplus->nonce = $_GET['timestamp'];
1476
- //
1477
- // echo json_encode($this->download_status($_GET['timestamp'], $_GET['type'], $findex));
1478
- //
1479
  } elseif (isset($_POST['subaction']) && $_POST['subaction'] == 'credentials_test') {
1480
  $method = (preg_match("/^[a-z0-9]+$/", $_POST['method'])) ? $_POST['method'] : "";
1481
 
@@ -1500,6 +1499,126 @@ class UpdraftPlus_Admin {
1500
  die;
1501
 
1502
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1503
 
1504
  public function get_history_status($rescan, $remotescan) {
1505
 
@@ -1541,7 +1660,7 @@ class UpdraftPlus_Admin {
1541
  $size = $this->recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, 'numeric');
1542
  if (is_numeric($size) && $size>0) $total_size += $size;
1543
  }
1544
- return $this->convert_numeric_size_to_text($total_size);
1545
  } elseif (!empty($backupable_entities[$entity])) {
1546
  # Might be an array
1547
  $basedir = $backupable_entities[$entity];
@@ -1581,28 +1700,36 @@ class UpdraftPlus_Admin {
1581
 
1582
  }
1583
 
1584
- public function get_activejobs_list($request) {
1585
-
 
 
1586
  global $updraftplus;
1587
  $download_status = array();
1588
- if (!empty($request['downloaders'])) {
1589
- foreach(explode(':', $request['downloaders']) as $downloader) {
1590
- # prefix, timestamp, entity, index
1591
- if (preg_match('/^([^,]+),(\d+),([-a-z]+|db[0-9]+),(\d+)$/', $downloader, $matches)) {
1592
- $findex = (empty($matches[4])) ? '0' : $matches[4];
1593
- $updraftplus->nonce = dechex($matches[2]).$findex.substr(md5($matches[3]), 0, 3);
1594
- $updraftplus->jobdata_reset();
1595
- $status = $this->download_status($matches[2], $matches[3], $matches[4]);
1596
- if (is_array($status)) {
1597
- $status['base'] = $matches[1];
1598
- $status['timestamp'] = $matches[2];
1599
- $status['what'] = $matches[3];
1600
- $status['findex'] = $findex;
1601
- $download_status[] = $status;
1602
- }
1603
  }
1604
  }
1605
  }
 
 
 
 
 
 
 
 
1606
 
1607
  if (!empty($request['oneshot'])) {
1608
  $job_id = get_site_option('updraft_oneshotnonce', false);
@@ -1749,7 +1876,8 @@ class UpdraftPlus_Admin {
1749
  $response = array( 'm' => $updraftplus->jobdata_get('dlmessage_'.$timestamp.'_'.$type.'_'.$findex).'<br>' );
1750
  if ($file = $updraftplus->jobdata_get('dlfile_'.$timestamp.'_'.$type.'_'.$findex)) {
1751
  if ('failed' == $file) {
1752
- $response['e'] = __('Download failed','updraftplus').'<br>';
 
1753
  $errs = $updraftplus->jobdata_get('dlerrors_'.$timestamp.'_'.$type.'_'.$findex);
1754
  if (is_array($errs) && !empty($errs)) {
1755
  $response['e'] .= '<ul class="disc">';
@@ -2037,7 +2165,7 @@ class UpdraftPlus_Admin {
2037
  passed back in as GET parameters.
2038
  */
2039
 
2040
- if(isset($_REQUEST['action']) && (($_REQUEST['action'] == 'updraft_restore' && isset($_REQUEST['backup_timestamp'])) || ('updraft_restore_continue' == $_REQUEST['action'] && !empty($_REQUEST['restoreid'])))) {
2041
 
2042
  $is_continuation = ('updraft_restore_continue' == $_REQUEST['action']) ? true : false;
2043
 
@@ -2121,7 +2249,7 @@ class UpdraftPlus_Admin {
2121
  return;
2122
  }
2123
 
2124
- if(isset($_GET['error'])) {
2125
  // This is used by Microsoft OneDrive authorisation failures (May 15). I am not sure what may have been using the 'error' GET parameter otherwise - but it is harmless.
2126
  if (!empty($_GET['error_description'])) {
2127
  $this->show_admin_warning(htmlspecialchars($_GET['error_description']).' ('.htmlspecialchars($_GET['error']).')', 'error');
@@ -2130,11 +2258,11 @@ class UpdraftPlus_Admin {
2130
  }
2131
  }
2132
 
2133
- if(isset($_GET['message'])) $this->show_admin_warning(htmlspecialchars($_GET['message']));
2134
 
2135
- if(isset($_GET['action']) && $_GET['action'] == 'updraft_create_backup_dir' && isset($_GET['nonce']) && wp_verify_nonce($_GET['nonce'], 'create_backup_dir')) {
2136
  $created = $this->create_backup_dir();
2137
- if(is_wp_error($created)) {
2138
  echo '<p>'.__('Backup directory could not be created', 'updraftplus').'...<br/>';
2139
  echo '<ul class="disc">';
2140
  foreach ($created->get_error_messages() as $key => $msg) {
@@ -2148,9 +2276,9 @@ class UpdraftPlus_Admin {
2148
  return;
2149
  }
2150
 
2151
- echo '<div id="updraft_backup_started" class="updated hidden"></div>';
2152
 
2153
- if(isset($_POST['action']) && 'updraft_backup_debug_all' == $_POST['action']) {
2154
  $updraftplus->boot_backup(true,true);
2155
  } elseif (isset($_POST['action']) && 'updraft_backup_debug_db' == $_POST['action']) {
2156
  $updraftplus->boot_backup(false, true, false, true);
@@ -2210,13 +2338,13 @@ class UpdraftPlus_Admin {
2210
  $ws_advert = $updraftplus->wordshell_random_advert(1);
2211
  if ($ws_advert && empty($success_advert) && empty($this->no_settings_warning)) { echo '<div class="updated ws_advert" style="clear:left;">'.$ws_advert.'</div>'; }
2212
 
2213
- if(!$updraftplus->memory_check(64)) {?>
2214
  <div class="updated memory-limit"><?php _e("Your PHP memory limit (set by your web hosting company) is very low. UpdraftPlus attempted to raise it but was unsuccessful. This plugin may struggle with a memory limit of less than 64 Mb - especially if you have very large files uploaded (though on the other hand, many sites will be successful with a 32Mb limit - your experience may vary).",'updraftplus');?> <?php _e('Current limit is:','updraftplus');?> <?php echo $updraftplus->memory_check_current(); ?> Mb</div>
2215
  <?php
2216
  }
2217
 
2218
 
2219
- if(!empty($updraftplus->errors)) {
2220
  echo '<div class="error updraft_list_errors">';
2221
  $updraftplus->list_errors();
2222
  echo '</div>';
@@ -2245,11 +2373,11 @@ class UpdraftPlus_Admin {
2245
  }
2246
 
2247
  ?>
2248
- <a class="nav-tab <?php if(1 == $tabflag) echo 'nav-tab-active'; ?>" id="updraft-navtab-status" href="#updraft-navtab-status-content" ><?php _e('Current Status', 'updraftplus');?></a>
2249
- <a class="nav-tab <?php if(2 == $tabflag) echo 'nav-tab-active'; ?>" id="updraft-navtab-backups" href="#updraft-navtab-backups-contents" ><?php echo __('Existing Backups', 'updraftplus').' ('.count($backup_history).')';?></a>
2250
- <a class="nav-tab <?php if(3 == $tabflag) echo 'nav-tab-active'; ?>" id="updraft-navtab-settings" href="#updraft-navtab-settings-content"><?php _e('Settings', 'updraftplus');?></a>
2251
- <a class="nav-tab<?php if(4 == $tabflag) echo ' nav-tab-active'; ?>" id="updraft-navtab-expert" href="#updraft-navtab-expert-content"><?php _e('Advanced Tools', 'updraftplus');?></a>
2252
- <a class="nav-tab<?php if(5 == $tabflag) echo ' nav-tab-active'; ?>" id="updraft-navtab-addons" href="#updraft-navtab-addons-content"><?php _e('Premium / Extensions', 'updraftplus');?></a>
2253
  <?php //do_action('updraftplus_settings_afternavtabs'); ?>
2254
  </h2>
2255
 
@@ -2262,7 +2390,7 @@ class UpdraftPlus_Admin {
2262
  <pre id="updraft-poplog-content"></pre>
2263
  </div>
2264
 
2265
- <div id="updraft-navtab-status-content" class="<?php if(1 != $tabflag) echo 'hidden'; ?>">
2266
 
2267
  <div id="updraft-insert-admin-warning"></div>
2268
 
@@ -2284,13 +2412,13 @@ class UpdraftPlus_Admin {
2284
  $this->show_admin_warning($unwritable_mess, "error");
2285
  }
2286
  ?>
2287
- <button type="button" <?php echo $backup_disabled ?> class="button-primary updraft-bigbutton" <?php if ($backup_disabled) echo 'title="'.esc_attr(__('This button is disabled because your backup directory is not writable (see the settings).', 'updraftplus')).'" ';?> onclick="updraft_backup_dialog_open();"><?php _e('Backup Now', 'updraftplus');?></button>
2288
 
2289
- <button type="button" class="button-primary updraft-bigbutton" onclick="updraft_openrestorepanel();">
2290
  <?php _e('Restore','updraftplus');?>
2291
  </button>
2292
 
2293
- <button type="button" class="button-primary updraft-bigbutton" onclick="updraft_migrate_dialog_open();"><?php _e('Clone/Migrate','updraftplus');?></button>
2294
 
2295
  </td>
2296
  </tr>
@@ -2362,7 +2490,7 @@ class UpdraftPlus_Admin {
2362
  </tr>
2363
  </table>
2364
 
2365
- <br style="clear:both" />
2366
 
2367
  <?php $this->render_active_jobs_and_log_table(); ?>
2368
 
@@ -2389,9 +2517,24 @@ class UpdraftPlus_Admin {
2389
  <?php echo $this->backupnow_modal_contents(); ?>
2390
  </div>
2391
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2392
  </div>
2393
 
2394
- <div id="updraft-navtab-backups-content" <?php if (2 != $tabflag) echo 'class="hidden"'; ?>>
 
 
2395
  <?php
2396
  $is_opera = (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/'));
2397
  $tmp_opts = array('include_opera_warning' => $is_opera);
@@ -2400,18 +2543,18 @@ class UpdraftPlus_Admin {
2400
  ?>
2401
  </div>
2402
 
2403
- <div id="updraft-navtab-settings-content" <?php if (3 != $tabflag) echo 'class="hidden"'; ?>>
2404
  <h2 class="updraft_settings_sectionheading"><?php _e('Backup Contents And Schedule','updraftplus');?></h2>
2405
  <?php UpdraftPlus_Options::options_form_begin(); ?>
2406
  <?php $this->settings_formcontents($last_backup_html); ?>
2407
  </form>
2408
  </div>
2409
 
2410
- <div id="updraft-navtab-expert-content"<?php if (4 != $tabflag) echo ' class="hidden"'; ?>>
2411
  <?php $this->settings_expertsettings($backup_disabled); ?>
2412
  </div>
2413
 
2414
- <div id="updraft-navtab-addons-content"<?php if (5 != $tabflag) echo ' class="hidden"'; ?>>
2415
 
2416
  <?php
2417
  $tick = UPDRAFTPLUS_URL.'/images/updraft_tick.png';
@@ -2631,21 +2774,10 @@ class UpdraftPlus_Admin {
2631
 
2632
  $ret .= '<input type="checkbox" id="backupnow_includefiles" checked="checked"> <label for="backupnow_includefiles">'.__("Include any files in the backup", 'updraftplus').'</label> (<a href="#" id="backupnow_includefiles_showmoreoptions">...</a>)<br>';
2633
 
2634
- $ret .= '<div id="backupnow_includefiles_moreoptions" class="hidden"><em>'.__('Your saved settings also affect what is backed up - e.g. files excluded.', 'updraftplus').'</em><br>'.$this->files_selector_widgetry('backupnow_files_', false, 'sometimes').'</div>';
2635
 
2636
- global $updraftplus;
2637
-
2638
- $service = $updraftplus->just_one(UpdraftPlus_Options::get_updraft_option('updraft_service'));
2639
- if (is_string($service)) $service = array($service);
2640
- if (!is_array($service)) $service = array('none');
2641
-
2642
- $no_remote_configured = (empty($service) || array('none') === $service || array('') === $service) ? true : false;
2643
 
2644
- if ($no_remote_configured) {
2645
- $ret .= '<input type="checkbox" disabled="disabled" id="backupnow_includecloud"> <label for="backupnow_includecloud"><em>'.sprintf(__("Backup won't be sent to any remote storage - none has been saved in the %s", 'updraftplus'), '<a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&tab=settings" id="updraft_backupnow_gotosettings">'.__('settings', 'updraftplus')).'</a>. '.__('Not got any remote storage?', 'updraftplus').' <a href="https://updraftplus.com/support/updraftplus-vault-faqs/">'.__("Check out UpdraftPlus Vault.", 'updraftplus').'</a></em></label>';
2646
- } else {
2647
- $ret .= '<input type="checkbox" id="backupnow_includecloud" checked="checked"> <label for="backupnow_includecloud">'.__("Send this backup to remote storage", 'updraftplus').'</label>';
2648
- }
2649
  $ret .= '</p>';
2650
 
2651
  $ret .= apply_filters('updraft_backupnow_modal_afteroptions', '', '');
@@ -2679,13 +2811,13 @@ class UpdraftPlus_Admin {
2679
  ?>
2680
  <td colspan="2" class="last-message"><strong><?php _e('Last log message','updraftplus');?>:</strong><br>
2681
  <span id="updraft_lastlogcontainer"><?php echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', __('(Nothing yet logged)','updraftplus'))); ?></span><br>
2682
- <a href="?page=updraftplus&action=downloadlatestmodlog&wpnonce=<?php echo wp_create_nonce('updraftplus_download') ?>" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('');"><?php _e('Download most recently modified log file','updraftplus');?></a>
2683
  </td>
2684
  <?php } else { ?>
2685
  <th><?php _e('Last log message','updraftplus');?>:</th>
2686
  <td>
2687
  <span id="updraft_lastlogcontainer"><?php echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', __('(Nothing yet logged)','updraftplus'))); ?></span><br>
2688
- <a href="?page=updraftplus&action=downloadlatestmodlog&wpnonce=<?php echo wp_create_nonce('updraftplus_download') ?>" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('');"><?php _e('Download most recently modified log file','updraftplus');?></a>
2689
  </td>
2690
  <?php } ?>
2691
  </tr>
@@ -2738,7 +2870,7 @@ class UpdraftPlus_Admin {
2738
  <div class="download-backups form-table">
2739
  <?php /* echo '<h2>'.__('Existing Backups: Downloading And Restoring', 'updraftplus').'</h2>'; */ ?>
2740
  <?php if (!empty($options['include_whitespace_warning'])) { ?>
2741
- <p class="ud-whitespace-warning hidden">
2742
  <?php echo '<strong>'.__('Warning','updraftplus').':</strong> '.__('Your WordPress installation has a problem with outputting extra whitespace. This can corrupt backups that you download from here.','updraftplus').' <a href="https://updraftplus.com/problems-with-extra-white-space/">'.__('Please consult this FAQ for help on what to do about it.', 'updraftplus').'</a>';?>
2743
  </p>
2744
  <?php } ?>
@@ -2800,7 +2932,7 @@ class UpdraftPlus_Admin {
2800
  if ($return_result) ob_start();
2801
  ?>
2802
 
2803
- <div id="ud_massactions" class="hidden">
2804
  <strong><?php _e('Actions upon selected backups', 'updraftplus');?></strong> <br>
2805
  <div class="updraftplus-remove" style="float: left;"><a href="#" onclick="updraft_deleteallselected(); return false;"><?php _e('Delete', 'updraftplus');?></a></div>
2806
  <div class="updraft-viewlogdiv"><a href="#" onclick="jQuery('#updraft-navtab-backups-content .updraft_existing_backups .updraft_existing_backups_row').addClass('backuprowselected'); return false;"><?php _e('Select all', 'updraftplus');?></a></div>
@@ -2815,10 +2947,10 @@ class UpdraftPlus_Admin {
2815
  <div id="updraft-delete-modal" title="<?php _e('Delete backup set', 'updraftplus');?>">
2816
  <form id="updraft_delete_form" method="post">
2817
  <p id="updraft_delete_question_singular">
2818
- <?php echo sprintf(__('Are you sure that you wish to remove %s from UpdraftPlus?', 'updraftplus'), 'this backup set'); ?>
2819
  </p>
2820
- <p id="updraft_delete_question_plural" class="hidden">
2821
- <?php echo sprintf(__('Are you sure that you wish to remove %s from UpdraftPlus?', 'updraftplus'), 'these backup sets'); ?>
2822
  </p>
2823
  <fieldset>
2824
  <input type="hidden" name="nonce" value="<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>">
@@ -2827,7 +2959,7 @@ class UpdraftPlus_Admin {
2827
  <input type="hidden" name="backup_timestamp" value="0" id="updraft_delete_timestamp">
2828
  <input type="hidden" name="backup_nonce" value="0" id="updraft_delete_nonce">
2829
  <div id="updraft-delete-remote-section"><input checked="checked" type="checkbox" name="delete_remote" id="updraft_delete_remote" value="1"> <label for="updraft_delete_remote"><?php _e('Also delete from remote storage', 'updraftplus');?></label><br>
2830
- <p id="updraft-delete-waitwarning" class="hidden"><em><?php _e('Deleting... please allow time for the communications with the remote storage to complete.', 'updraftplus');?></em></p>
2831
  </div>
2832
  </fieldset>
2833
  </form>
@@ -2857,7 +2989,7 @@ class UpdraftPlus_Admin {
2857
  <?php
2858
 
2859
  # The 'off' check is for badly configured setups - http://wordpress.org/support/topic/plugin-wp-super-cache-warning-php-safe-mode-enabled-but-safe-mode-is-off
2860
- if($updraftplus->detect_safe_mode()) {
2861
  echo "<p><em>".__("Your web server has PHP's so-called safe_mode active.", 'updraftplus').' '.__('This makes time-outs much more likely. You are recommended to turn safe_mode off, or to restore only one entity at a time, <a href="https://updraftplus.com/faqs/i-want-to-restore-but-have-either-cannot-or-have-failed-to-do-so-from-the-wp-admin-console/">or to restore manually</a>.', 'updraftplus')."</em></p><br/>";
2862
  }
2863
 
@@ -2878,7 +3010,7 @@ class UpdraftPlus_Admin {
2878
  ?>
2879
  <div><input id="updraft_restore_db" type="checkbox" name="updraft_restore[]" value="db"> <label for="updraft_restore_db"><?php _e('Database','updraftplus'); ?></label><br>
2880
 
2881
- <div id="updraft_restorer_dboptions" class="hidden"><h4><?php echo sprintf(__('%s restoration options:','updraftplus'),__('Database','updraftplus')); ?></h4>
2882
 
2883
  <?php
2884
 
@@ -3033,7 +3165,7 @@ class UpdraftPlus_Admin {
3033
  </tr>
3034
  </tbody>
3035
  </table>
3036
- <h3><?php _e('Wipe settings','updraftplus');?></h3>
3037
  <p class="max-width-600"><?php echo __('This button will delete all UpdraftPlus settings and progress information for in-progress backups (but not any of your existing backups from your cloud storage).', 'updraftplus').' '.__('You will then need to enter all your settings again. You can also do this before deactivating/deinstalling UpdraftPlus if you wish.','updraftplus');?></p>
3038
  <form method="post" action="<?php echo esc_url(add_query_arg(array('error' => false, 'updraft_restore_success' => false, 'action' => false, 'page' => 'updraftplus'))); ?>">
3039
  <input type="hidden" name="action" value="updraft_wipesettings" />
@@ -3292,7 +3424,7 @@ class UpdraftPlus_Admin {
3292
  private function delete_old_dirs_go($show_return = true) {
3293
  echo ($show_return) ? '<h1>UpdraftPlus - '.__('Remove old directories', 'updraftplus').'</h1>' : '<h2>'.__('Remove old directories', 'updraftplus').'</h2>';
3294
 
3295
- if($this->delete_old_dirs()) {
3296
  echo '<p>'.__('Old directories successfully removed.','updraftplus').'</p><br/>';
3297
  } else {
3298
  echo '<p>',__('Old directory removal failed for some reason. You may want to do this manually.','updraftplus').'</p><br/>';
@@ -3324,7 +3456,7 @@ class UpdraftPlus_Admin {
3324
  $plugs = untrailingslashit($wp_filesystem->wp_plugins_dir());
3325
  if ($wp_filesystem->is_dir($plugs.'-old')) {
3326
  print "<strong>".__('Delete','updraftplus').": </strong>plugins-old: ";
3327
- if(!$wp_filesystem->delete($plugs.'-old', true)) {
3328
  $ret3 = false;
3329
  print "<strong>".__('Failed', 'updraftplus')."</strong><br>";
3330
  } else {
@@ -3359,7 +3491,7 @@ class UpdraftPlus_Admin {
3359
  print "<strong>".__('Delete','updraftplus').": </strong>".htmlspecialchars($name).": ";
3360
 
3361
  if ($wpfs) {
3362
- if(!$wp_filesystem->delete($dir.$name, true)) {
3363
  $ret = false;
3364
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
3365
  } else {
@@ -3529,6 +3661,21 @@ class UpdraftPlus_Admin {
3529
  'monthly' => __("Monthly", 'updraftplus')
3530
  ));
3531
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3532
 
3533
  private function settings_formcontents($last_backup_html) {
3534
 
@@ -3708,7 +3855,7 @@ class UpdraftPlus_Admin {
3708
 
3709
  <a href="#" onclick="jQuery('#updraftplus_db_decrypt').val(jQuery('#updraft_encryptionphrase').val()); jQuery('#updraft-manualdecrypt-modal').slideToggle(); return false;"><?php _e('You can manually decrypt an encrypted database here.','updraftplus');?></a>
3710
 
3711
- <div id="updraft-manualdecrypt-modal" class="hidden">
3712
  <p><h3><?php _e("Manually decrypt a database backup file" ,'updraftplus');?></h3></p>
3713
 
3714
  <?php
@@ -3830,54 +3977,46 @@ class UpdraftPlus_Admin {
3830
  if ($split_every_mb < UPDRAFTPLUS_SPLIT_MIN) $split_every_mb = UPDRAFTPLUS_SPLIT_MIN;
3831
  ?>
3832
 
3833
- <tr class="expertmode hidden">
3834
  <th><?php _e('Debug mode','updraftplus');?>:</th>
3835
  <td><input type="checkbox" id="updraft_debug_mode" name="updraft_debug_mode" value="1" <?php echo $debug_mode; ?> /> <br><label for="updraft_debug_mode"><?php _e('Check this to receive more information and emails on the backup process - useful if something is going wrong.','updraftplus');?> <?php _e('This will also cause debugging output from all plugins to be shown upon this screen - please do not be surprised to see these.', 'updraftplus');?></label></td>
3836
  </tr>
3837
 
3838
- <tr class="expertmode hidden">
3839
  <th><?php _e('Split archives every:','updraftplus');?></th>
3840
  <td><input type="text" name="updraft_split_every" id="updraft_split_every" value="<?php echo $split_every_mb ?>" size="5" /> Mb<br><?php echo sprintf(__('UpdraftPlus will split up backup archives when they exceed this file size. The default value is %s megabytes. Be careful to leave some margin if your web-server has a hard size limit (e.g. the 2 Gb / 2048 Mb limit on some 32-bit servers/file systems).','updraftplus'), 400); ?></td>
3841
  </tr>
3842
 
3843
- <tr class="deletelocal expertmode hidden">
3844
  <th><?php _e('Delete local backup','updraftplus');?>:</th>
3845
  <td><input type="checkbox" id="updraft_delete_local" name="updraft_delete_local" value="1" <?php if ($delete_local) echo 'checked="checked"'; ?>> <br><label for="updraft_delete_local"><?php _e('Check this to delete any superfluous backup files from your server after the backup run finishes (i.e. if you uncheck, then any files despatched remotely will also remain locally, and any files being kept locally will not be subject to the retention limits).','updraftplus');?></label></td>
3846
  </tr>
3847
 
3848
- <tr class="expertmode backupdirrow hidden">
3849
  <th><?php _e('Backup directory','updraftplus');?>:</th>
3850
  <td><input type="text" name="updraft_dir" id="updraft_dir" style="width:525px" value="<?php echo htmlspecialchars($this->prune_updraft_dir_prefix($updraft_dir)); ?>" /></td>
3851
  </tr>
3852
- <tr class="expertmode backupdirrow hidden">
3853
- <td></td><td><?php
3854
-
3855
- if($really_is_writable) {
3856
- $dir_info = '<span style="color:green;">'.__('Backup directory specified is writable, which is good.','updraftplus').'</span>';
3857
- } else {
3858
- $dir_info = '<span style="color:red;">';
3859
- if (!is_dir($updraft_dir)) {
3860
- $dir_info .= __('Backup directory specified does <b>not</b> exist.','updraftplus');
3861
- } else {
3862
- $dir_info .= __('Backup directory specified exists, but is <b>not</b> writable.','updraftplus');
3863
- }
3864
- $dir_info .= ' <span class="directory-permissions"><a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraft_create_backup_dir&nonce='.wp_create_nonce('create_backup_dir').'">'.__('Click here to attempt to create the directory and set the permissions','updraftplus').'</a></span>, '.__('or, to reset this option','updraftplus').' <a href="#" onclick="jQuery(\'#updraft_dir\').val(\'updraft\'); return false;">'.__('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>';
3865
- }
3866
-
3867
- echo $dir_info.' '.__("This is where UpdraftPlus will write the zip files it creates initially. This directory must be writable by your web server. It is relative to your content directory (which by default is called wp-content).", 'updraftplus').' '.__("<b>Do not</b> place it inside your uploads or plugins directory, as that will cause recursion (backups of backups of backups of...).",'updraftplus');?></td>
3868
  </tr>
3869
 
3870
- <tr class="expertmode hidden">
3871
  <th><?php _e('Use the server\'s SSL certificates','updraftplus');?>:</th>
3872
  <td><input type="checkbox" id="updraft_ssl_useservercerts" name="updraft_ssl_useservercerts" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_useservercerts"><?php _e('By default UpdraftPlus uses its own store of SSL certificates to verify the identity of remote sites (i.e. to make sure it is talking to the real Dropbox, Amazon S3, etc., and not an attacker). We keep these up to date. However, if you get an SSL error, then choosing this option (which causes UpdraftPlus to use your web server\'s collection instead) may help.','updraftplus');?></label></td>
3873
  </tr>
3874
 
3875
- <tr class="expertmode hidden">
3876
  <th><?php _e('Do not verify SSL certificates','updraftplus');?>:</th>
3877
  <td><input type="checkbox" id="updraft_ssl_disableverify" name="updraft_ssl_disableverify" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_disableverify"><?php _e('Choosing this option lowers your security by stopping UpdraftPlus from verifying the identity of encrypted sites that it connects to (e.g. Dropbox, Google Drive). It means that UpdraftPlus will be using SSL only for encryption of traffic, and not for authentication.','updraftplus');?> <?php _e('Note that not all cloud backup methods are necessarily using SSL authentication.', 'updraftplus');?></label></td>
3878
  </tr>
3879
 
3880
- <tr class="expertmode hidden">
3881
  <th><?php _e('Disable SSL entirely where possible', 'updraftplus');?>:</th>
3882
  <td><input type="checkbox" id="updraft_ssl_nossl" name="updraft_ssl_nossl" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_nossl')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_nossl"><?php _e('Choosing this option lowers your security by stopping UpdraftPlus from using SSL for authentication and encrypted transport at all, where possible. Note that some cloud storage providers do not allow this (e.g. Dropbox), so with those providers this setting will have no effect.','updraftplus');?> <a href="https://updraftplus.com/faqs/i-get-ssl-certificate-errors-when-backing-up-andor-restoring/"><?php _e('See this FAQ also.', 'updraftplus');?></a></label></td>
3883
  </tr>
@@ -3903,7 +4042,7 @@ class UpdraftPlus_Admin {
3903
  <td></td>
3904
  <td>
3905
  <input type="hidden" name="action" value="update" />
3906
- <input type="submit" class="button-primary" value="<?php _e('Save Changes','updraftplus');?>" />
3907
  </td>
3908
  </tr>
3909
  </table>
@@ -3928,7 +4067,7 @@ class UpdraftPlus_Admin {
3928
  if ($show_exclusion_options) {
3929
  $include_exclude = UpdraftPlus_Options::get_updraft_option('updraft_include_'.$key.'_exclude', ('others' == $key) ? UPDRAFT_DEFAULT_OTHERS_EXCLUDE : UPDRAFT_DEFAULT_UPLOADS_EXCLUDE);
3930
 
3931
- $display = ($included) ? '' : 'class="hidden"';
3932
 
3933
  $ret .= "<div id=\"".$prefix."updraft_include_".$key."_exclude\" $display>";
3934
 
@@ -4026,46 +4165,18 @@ class UpdraftPlus_Admin {
4026
 
4027
  }
4028
 
4029
- // foreach ($basedirs as $ind => $basedir) {
4030
- //
4031
- // $directories = $directorieses[$ind];
4032
- // if (!is_array($directories)) $directories=array($directories);
4033
- //
4034
- // foreach ($directories as $dir) {
4035
- // error_log($dir);
4036
- // if (is_file($dir)) {
4037
- // $size += @filesize($dir);
4038
- // } else {
4039
- // $suffix = ('' != $basedir) ? ((0 === strpos($dir, $basedir.'/')) ? substr($dir, 1+strlen($basedir)) : '') : '';
4040
- // $size += $this->recursive_directory_size_raw($basedir, $exclude, $suffix);
4041
- // }
4042
- // }
4043
- //
4044
- // }
4045
-
4046
  if ('numeric' == $format) return $size;
4047
 
4048
- return $this->convert_numeric_size_to_text($size);
4049
-
4050
- }
4051
 
4052
- private function convert_numeric_size_to_text($size) {
4053
- if ($size > 1073741824) {
4054
- return round($size / 1073741824, 1).' Gb';
4055
- } elseif ($size > 1048576) {
4056
- return round($size / 1048576, 1).' Mb';
4057
- } elseif ($size > 1024) {
4058
- return round($size / 1024, 1).' Kb';
4059
- } else {
4060
- return round($size, 1).' b';
4061
- }
4062
  }
4063
 
4064
  private function recursive_directory_size_raw($prefix_directory, &$exclude = array(), $suffix_directory = '') {
4065
 
4066
  $directory = $prefix_directory.('' == $suffix_directory ? '' : '/'.$suffix_directory);
4067
  $size = 0;
4068
- if(substr($directory, -1) == '/') $directory = substr($directory,0,-1);
4069
 
4070
  if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) return -1;
4071
  if (file_exists($directory.'/.donotbackup')) return 0;
@@ -4079,11 +4190,11 @@ class UpdraftPlus_Admin {
4079
  continue;
4080
  }
4081
  $path = $directory.'/'.$file;
4082
- if(is_file($path)) {
4083
  $size += filesize($path);
4084
- } elseif(is_dir($path)) {
4085
  $handlesize = $this->recursive_directory_size_raw($prefix_directory, $exclude, $suffix_directory.('' == $suffix_directory ? '' : '/').$file);
4086
- if($handlesize >= 0) { $size += $handlesize; }# else { return -1; }
4087
  }
4088
  }
4089
  }
@@ -4128,10 +4239,17 @@ class UpdraftPlus_Admin {
4128
  // }
4129
  }
4130
 
4131
- foreach ($backup as $ekey => $val) {
 
4132
  if ('db' == strtolower(substr($ekey, 0, 2)) && '-size' != substr($ekey, -5, 5)) {
4133
  $rawbackup .= $updraftplus->printfile(__('Database', 'updraftplus'), $backup, $ekey, array('sha1'), $jd, true);
4134
  }
 
 
 
 
 
 
4135
  }
4136
 
4137
  $services = empty($backup['service']) ? array('none') : $backup['service'];
@@ -4153,6 +4271,12 @@ class UpdraftPlus_Admin {
4153
 
4154
  $rawbackup .= $show_services;
4155
 
 
 
 
 
 
 
4156
  $rawbackup .= '</p><hr><p><pre>'.print_r($backup, true).'</p></pre>';
4157
 
4158
  if (!empty($jd) && is_array($jd)) {
@@ -4177,7 +4301,6 @@ class UpdraftPlus_Admin {
4177
  if (!is_array($accept)) $accept = array();
4178
 
4179
  $ret = '<table class="existing-backups-table">';
4180
- $nonce_field = wp_nonce_field('updraftplus_download', '_wpnonce', true, false);
4181
 
4182
  //".__('Actions', 'updraftplus')."
4183
  $ret .= "<thead>
@@ -4250,7 +4373,7 @@ ENDHERE;
4250
  $db = is_array($backup['db']) ? $backup['db'][0] : $backup['db'];
4251
  if ($updraftplus->is_db_encrypted($db)) $entities .= '/dbcrypted=1/';
4252
 
4253
- $ret .= $this->download_db_button('db', $key, $esc_pretty_date, $nonce_field, $backup, $accept);
4254
  } else {
4255
  // $ret .= sprintf(_x('(No %s)','Message shown when no such object is available','updraftplus'), __('database', 'updraftplus'));
4256
  }
@@ -4258,7 +4381,7 @@ ENDHERE;
4258
  # External databases
4259
  foreach ($backup as $bkey => $binfo) {
4260
  if ('db' == $bkey || 'db' != substr($bkey, 0, 2) || '-size' == substr($bkey, -5, 5)) continue;
4261
- $ret .= $this->download_db_button($bkey, $key, $esc_pretty_date, $nonce_field, $backup);
4262
  }
4263
 
4264
  } else {
@@ -4270,7 +4393,7 @@ ENDHERE;
4270
  $entities .= '/meta_foreign=2/';
4271
  }
4272
 
4273
- $download_buttons = $this->download_buttons($backup, $key, $accept, $entities, $esc_pretty_date, $nonce_field);
4274
 
4275
  $ret .= $download_buttons;
4276
 
@@ -4278,9 +4401,7 @@ ENDHERE;
4278
 
4279
  // No logs expected for foreign backups
4280
  if (empty($backup['meta_foreign'])) {
4281
- // $ret .= '<td>';
4282
- // $ret .= $this->log_button($backup);
4283
- // $ret .= "</td>";
4284
  }
4285
  }
4286
 
@@ -4302,7 +4423,7 @@ ENDHERE;
4302
  return $ret;
4303
  }
4304
 
4305
- private function download_db_button($bkey, $key, $esc_pretty_date, $nonce_field, $backup, $accept = array()) {
4306
 
4307
  if (!empty($backup['meta_foreign']) && isset($accept[$backup['meta_foreign']])) {
4308
  $desc_source = $accept[$backup['meta_foreign']]['desc'];
@@ -4318,23 +4439,13 @@ ENDHERE;
4318
  $dbt = __('External database','updraftplus').' ('.substr($bkey, 2).')';
4319
  }
4320
 
4321
- $ret .= <<<ENDHERE
4322
- <div style="float:left; clear:none;">
4323
- <form class="uddownloadform_${bkey}_${key}_0" action="admin-ajax.php" onsubmit="return updraft_downloader('uddlstatus_', $key, '$bkey', '.ud_downloadstatus', '0', '$esc_pretty_date', true)" method="post">
4324
- $nonce_field
4325
- <input type="hidden" name="action" value="updraft_download_backup" />
4326
- <input type="hidden" name="type" value="$bkey" />
4327
- <input type="hidden" name="timestamp" value="$key" />
4328
- <input type="submit" class="updraft-backupentitybutton" value="$dbt" />
4329
- </form>
4330
- </div>
4331
- ENDHERE;
4332
-
4333
  return $ret;
4334
  }
4335
 
4336
  // Go through each of the file entities
4337
- private function download_buttons($backup, $key, $accept, &$entities, $esc_pretty_date, $nonce_field) {
4338
  global $updraftplus;
4339
  $ret = '';
4340
  $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
@@ -4398,7 +4509,7 @@ ENDHERE;
4398
  $ide .= __('Press here to download', 'updraftplus').' '.strtolower($info['description']);
4399
  $pdescrip = ($findex > 0) ? $sdescrip.' ('.($findex+1).')' : $sdescrip;
4400
  if (!$first_printed) {
4401
- $ret .= '<div class="hidden">';
4402
  }
4403
  if (count($backup[$type]) >0) {
4404
  $ide .= ' '.sprintf(__('(%d archive(s) in set).', 'updraftplus'), $howmanyinset);
@@ -4413,7 +4524,7 @@ ENDHERE;
4413
  $first_entity = false;
4414
  }
4415
 
4416
- $ret .= $this->download_button($type, $key, $findex, $info, $nonce_field, $ide, $pdescrip, $esc_pretty_date, $set_contents);
4417
 
4418
  if (!$first_printed) {
4419
  $ret .= '</div>';
@@ -4443,50 +4554,53 @@ ENDHERE;
4443
  return $ret;
4444
  }
4445
 
4446
- private function download_button($type, $key, $findex, $info, $nonce_field, $ide, $pdescrip, $esc_pretty_date, $set_contents) {
4447
- $ret = <<<ENDHERE
4448
- <div style="float:left; clear: none;">
4449
- <form class="uddownloadform_${type}_${key}_${findex}" action="admin-ajax.php" onsubmit="return updraft_downloader('uddlstatus_', '$key', '$type', '.ud_downloadstatus', '$set_contents', '$esc_pretty_date', true)" method="post">
4450
- $nonce_field
4451
- <input type="hidden" name="action" value="updraft_download_backup" />
4452
- <input type="hidden" name="type" value="$type" />
4453
- <input type="hidden" name="timestamp" value="$key" />
4454
- <input type="hidden" name="findex" value="$findex" />
4455
- <input type="submit" class="updraft-backupentitybutton" title="$ide" value="$pdescrip" />
4456
- </form>
4457
- </div>
4458
- ENDHERE;
 
 
 
 
 
 
 
 
 
 
 
4459
  return $ret;
4460
  }
4461
 
4462
- private function restore_button($backup, $key, $pretty_date, $entities) {
4463
- $ret = <<<ENDHERE
4464
- <div class="restore-button">
4465
- <form method="post" action="">
4466
- <input type="hidden" name="backup_timestamp" value="$key">
4467
- <input type="hidden" name="action" value="updraft_restore" />
4468
- ENDHERE;
4469
- if ($entities) {
4470
- $show_data = $pretty_date;
4471
- if (isset($backup['native']) && false == $backup['native']) {
4472
- $show_data .= ' '.__('(backup set imported from remote location)', 'updraftplus');
4473
- }
4474
- # jQuery('#updraft_restore_label_wpcore').html('".esc_js($wpcore_restore_descrip)."');
4475
- $ret .= '<button id="restore-'.$key.'" title="'.__('After pressing this button, you will be given the option to choose which components you wish to restore','updraftplus').'" type="button" style="float:left; clear:none;" class="button-primary choose-components-button" onclick="'."updraft_restore_setoptions('$entities');
4476
- jQuery('#updraft_restore_timestamp').val('$key'); jQuery('.updraft_restore_date').html('".esc_js($show_data)."'); ";
4477
 
4478
- $ret .= "updraft_restore_stage = 1; jQuery('#updraft-migrate-modal').dialog('close'); jQuery('#updraft-restore-modal').dialog('open'); jQuery('#updraft-restore-modal-stage1').show();jQuery('#updraft-restore-modal-stage2').hide(); jQuery('#updraft-restore-modal-stage2a').html(''); updraft_activejobs_update(true);\">".__('Restore', 'updraftplus').'</button>';
 
 
 
4479
  }
4480
- $ret .= "</form></div>\n";
 
 
 
4481
  return $ret;
4482
  }
4483
 
4484
  private function delete_button($key, $nonce, $backup) {
4485
  $sval = ((isset($backup['service']) && $backup['service'] != 'email' && $backup['service'] != 'none')) ? '1' : '0';
4486
- // return '<div class="updraftplus-remove" style="float: left; clear:none; "padding-top:2px;padding-bottom:2px;font-size:16px !important; min-height:26px;text-align:center; font-weight:bold; border-radius: 2px;"><a style="text-decoration:none;" href="javascript:updraft_delete('.$key.', '.$nonce.', '.$sval.');" title="'.esc_attr(__('Delete this backup set', 'updraftplus')).'">'.__('Delete', 'updraftplus').'</a></div>';
4487
- // return '<div class="updraftplus-remove" style="float: left; clear:none; width: 27px; height: 27px; padding-top:0px; padding-bottom: 4px;font-size: 26px; text-align:center; font-weight:bold; border-radius: 7px;"><a style="text-decoration:none;" href="javascript:updraft_delete('.$key.', '.$nonce.', '.$sval.');" title="'.esc_attr(__('Delete this backup set', 'updraftplus')).'">×</a></div>';
4488
- // return '<div class="updraftplus-remove" style="float: left; clear:none; width: 20px; height: 20px; padding-top:0px; padding-bottom: 2px;font-size: 19px; text-align:center; font-weight:bold; border-radius: 4px;"><a style="text-decoration:none;" href="javascript:'."updraft_delete('$key', '$nonce', $sval);".'" title="'.esc_attr(__('Delete this backup set', 'updraftplus')).'">×</a></div>';
4489
- return '<div class="updraftplus-remove" style="float: left; clear: none;" data-hasremote="'.$sval.'"><a class="no-decoration" href="javascript:'."updraft_delete('$key', '$nonce', $sval);".'" title="'.esc_attr(__('Delete this backup set', 'updraftplus')).'">'.__('Delete', 'updraftplus').'</a></div>';
4490
  }
4491
 
4492
  private function log_button($backup) {
@@ -4495,16 +4609,22 @@ ENDHERE;
4495
  $ret = '';
4496
  if (isset($backup['nonce']) && preg_match("/^[0-9a-f]{12}$/",$backup['nonce']) && is_readable($updraft_dir.'/log.'.$backup['nonce'].'.txt')) {
4497
  $nval = $backup['nonce'];
4498
- $lt = esc_attr(__('View Log','updraftplus'));
4499
- $url = UpdraftPlus_Options::admin_page();
 
4500
  $ret .= <<<ENDHERE
4501
  <div style="clear:none;" class="updraft-viewlogdiv">
4502
- <form action="$url" method="get">
4503
- <input type="hidden" name="action" value="downloadlog" />
4504
- <input type="hidden" name="page" value="updraftplus" />
4505
- <input type="hidden" name="updraftplus_backup_nonce" value="$nval" />
4506
- <input type="submit" value="$lt" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('$nval');" />
4507
- </form>
 
 
 
 
 
4508
  </div>
4509
  ENDHERE;
4510
  return $ret;
@@ -4715,7 +4835,7 @@ ENDHERE;
4715
 
4716
  add_action('http_request_args', array($updraftplus, 'modify_http_options'));
4717
  foreach ($service as $serv) {
4718
- if(!is_readable($fullpath)) {
4719
  $sd = (empty($updraftplus->backup_methods[$serv])) ? $serv : $updraftplus->backup_methods[$serv];
4720
  echo __("File is not locally present - needs retrieving from remote storage",'updraftplus')." ($sd)";
4721
  $this->download_file($file, $serv);
@@ -4943,5 +5063,142 @@ ENDHERE;
4943
  if (!is_array($input)) $input = array();
4944
  return $input;
4945
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4946
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4947
  }
15
  $this->admin_init();
16
  }
17
 
18
+ private function setup_all_admin_notices_global($service){
19
+ if ('googledrive' === $service || (is_array($service) && in_array('googledrive', $service))) {
20
+ $opts = UpdraftPlus_Options::get_updraft_option('updraft_googledrive');
21
+ if (empty($opts)) {
22
+ $clientid = UpdraftPlus_Options::get_updraft_option('updraft_googledrive_clientid', '');
23
+ $token = UpdraftPlus_Options::get_updraft_option('updraft_googledrive_token', '');
24
+ } else {
25
+ $clientid = $opts['clientid'];
26
+ $token = (empty($opts['token'])) ? '' : $opts['token'];
27
+ }
28
+ if (!empty($clientid) && empty($token)) add_action('all_admin_notices', array($this,'show_admin_warning_googledrive'));
29
+ }
30
+ if ('googlecloud' === $service || (is_array($service) && in_array('googlecloud', $service))) {
31
+ $opts = UpdraftPlus_Options::get_updraft_option('updraft_googlecloud');
32
+ if (!empty($opts)) {
33
+ $clientid = $opts['clientid'];
34
+ $token = (empty($opts['token'])) ? '' : $opts['token'];
35
+ }
36
+ if (!empty($clientid) && empty($token)) add_action('all_admin_notices', array($this,'show_admin_warning_googlecloud'));
37
+ }
38
+ if ('dropbox' === $service || (is_array($service) && in_array('dropbox', $service))) {
39
+ $opts = UpdraftPlus_Options::get_updraft_option('updraft_dropbox');
40
+ if (empty($opts['tk_request_token'])) {
41
+ add_action('all_admin_notices', array($this,'show_admin_warning_dropbox') );
42
+ }
43
+ }
44
+ if ('bitcasa' === $service || (is_array($service) && in_array('bitcasa', $service))) {
45
+ $opts = UpdraftPlus_Options::get_updraft_option('updraft_bitcasa');
46
+ if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['token'])) add_action('all_admin_notices', array($this,'show_admin_warning_bitcasa') );
47
+ }
48
+ if ('copycom' === $service || (is_array($service) && in_array('copycom', $service))) {
49
+ $opts = UpdraftPlus_Options::get_updraft_option('updraft_copycom');
50
+ if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['token'])) add_action('all_admin_notices', array($this,'show_admin_warning_copycom') );
51
+ }
52
+ if ('onedrive' === $service || (is_array($service) && in_array('onedrive', $service))) {
53
+ $opts = UpdraftPlus_Options::get_updraft_option('updraft_onedrive');
54
+ if (!empty($opts['clientid']) && !empty($opts['secret']) && empty($opts['refresh_token'])) add_action('all_admin_notices', array($this,'show_admin_warning_onedrive') );
55
+ }
56
+
57
+ if ('updraftvault' === $service || (is_array($service) && in_array('updraftvault', $service))) {
58
+ $vault_settings = UpdraftPlus_Options::get_updraft_option('updraft_updraftvault');
59
+ $connected = (is_array($vault_settings) && !empty($vault_settings['token']) && !empty($vault_settings['email'])) ? true : false;
60
+ if (!$connected) add_action('all_admin_notices', array($this,'show_admin_warning_updraftvault') );
61
+ }
62
+
63
+ if ($this->disk_space_check(1048576*35) === false) add_action('all_admin_notices', array($this, 'show_admin_warning_diskspace'));
64
+ }
65
+
66
+ private function setup_all_admin_notices_udonly($service, $override = false){
67
+ global $wp_version;
68
+
69
+ if (UpdraftPlus_Options::user_can_manage() && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON == true) {
70
+ add_action('all_admin_notices', array($this, 'show_admin_warning_disabledcron'));
71
+ }
72
+
73
+ if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
74
+ @ini_set('display_errors',1);
75
+ @error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
76
+ add_action('all_admin_notices', array($this, 'show_admin_debug_warning'));
77
+ }
78
+
79
+ if (null === UpdraftPlus_Options::get_updraft_option('updraft_interval')) {
80
+ add_action('all_admin_notices', array($this, 'show_admin_nosettings_warning'));
81
+ $this->no_settings_warning = true;
82
+ }
83
+
84
+ # Avoid false positives, by attempting to raise the limit (as happens when we actually do a backup)
85
+ @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);
86
+ $max_execution_time = (int)@ini_get('max_execution_time');
87
+ if ($max_execution_time>0 && $max_execution_time<20) {
88
+ add_action('all_admin_notices', array($this, 'show_admin_warning_execution_time'));
89
+ }
90
+
91
+ // LiteSpeed has a generic problem with terminating cron jobs
92
+ if (isset($_SERVER['SERVER_SOFTWARE']) && strpos($_SERVER['SERVER_SOFTWARE'], 'LiteSpeed') !== false) {
93
+ if (!is_file(ABSPATH.'.htaccess') || !preg_match('/noabort/i', file_get_contents(ABSPATH.'.htaccess'))) {
94
+ add_action('all_admin_notices', array($this, 'show_admin_warning_litespeed'));
95
+ }
96
+ }
97
+
98
+ if (version_compare($wp_version, '3.2', '<')) add_action('all_admin_notices', array($this, 'show_admin_warning_wordpressversion'));
99
+ }
100
+
101
+ /*
102
+ private function reset_all_updraft_admin_notices() {
103
+
104
+ $actions_to_remove = array('show_admin_warning_googledrive', 'show_admin_warning_googlecloud', 'show_admin_warning_dropbox', 'show_admin_warning_bitcasa', 'show_admin_warning_copycom', 'show_admin_warning_onedrive', 'show_admin_warning_updraftvault', 'show_admin_warning_diskspace', 'show_admin_warning_disabledcron', 'show_admin_debug_warning', 'show_admin_warning_execution_time', 'show_admin_warning_litespeed', 'show_admin_warning_wordpressversion');
105
+
106
+ foreach ($actions_to_remove as $action) {
107
+ remove_action('all_admin_notices', $action);
108
+ }
109
+
110
+ }
111
+ */
112
+
113
+ //Used to output the information for the next scheduled backup
114
+ //**// moved to function for the ajax saves
115
+ private function next_scheduled_backups_output() {
116
+ // UNIX timestamp
117
+ $next_scheduled_backup = wp_next_scheduled('updraft_backup');
118
+ if ($next_scheduled_backup) {
119
+ // Convert to GMT
120
+ $next_scheduled_backup_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup);
121
+ // Convert to blog time zone
122
+ $next_scheduled_backup = get_date_from_gmt($next_scheduled_backup_gmt, 'D, F j, Y H:i');
123
+ } else {
124
+ $next_scheduled_backup = __('Nothing currently scheduled', 'updraftplus');
125
+ $files_not_scheduled = true;
126
+ }
127
+
128
+ $next_scheduled_backup_database = wp_next_scheduled('updraft_backup_database');
129
+ if (UpdraftPlus_Options::get_updraft_option('updraft_interval_database',UpdraftPlus_Options::get_updraft_option('updraft_interval')) == UpdraftPlus_Options::get_updraft_option('updraft_interval')) {
130
+ if (isset($files_not_scheduled)) {
131
+ $next_scheduled_backup_database = $next_scheduled_backup;
132
+ $database_not_scheduled = true;
133
+ } else {
134
+ $next_scheduled_backup_database = __("At the same time as the files backup", 'updraftplus');
135
+ }
136
+ } else {
137
+ if ($next_scheduled_backup_database) {
138
+ // Convert to GMT
139
+ $next_scheduled_backup_database_gmt = gmdate('Y-m-d H:i:s', $next_scheduled_backup_database);
140
+ // Convert to blog time zone
141
+ $next_scheduled_backup_database = get_date_from_gmt($next_scheduled_backup_database_gmt, 'D, F j, Y H:i');
142
+ } else {
143
+ $next_scheduled_backup_database = __('Nothing currently scheduled', 'updraftplus');
144
+ $database_not_scheduled = true;
145
+ }
146
+ }
147
+ $current_time = get_date_from_gmt(gmdate('Y-m-d H:i:s'), 'D, F j, Y H:i');
148
+ ?>
149
+ <tr>
150
+ <?php if (isset($files_not_scheduled) && isset($database_not_scheduled)) { ?>
151
+ <td colspan="2" class="not-scheduled"><?php _e('Nothing currently scheduled','updraftplus'); ?></td>
152
+ <?php } else { ?>
153
+ <td class="updraft_scheduled"><?php _e('Files','updraftplus'); ?>:</td><td class="updraft_all-files"><?php echo $next_scheduled_backup; ?></td>
154
+ </tr><tr>
155
+ <td class="updraft_scheduled"><?php _e('Database','updraftplus');?>: </td><td class="updraft_all-files"><?php echo $next_scheduled_backup_database; ?></td>
156
+ </tr><tr>
157
+ <td class="updraft_scheduled"><?php _e('Time now','updraftplus');?>: </td><td class="updraft_all-files"><?php echo $current_time; ?></td>
158
+ <?php
159
+ }
160
+ }
161
+
162
+
163
  private function admin_init() {
164
 
165
  add_action('core_upgrade_preamble', array($this, 'core_upgrade_preamble'));
178
 
179
  add_action('wp_before_admin_bar_render', array($this, 'wp_before_admin_bar_render'));
180
 
181
+ // Add a new Ajax action for saving settings
182
+ add_action('wp_ajax_updraft_savesettings', array($this, 'updraft_ajax_savesettings'));
183
+
184
  global $updraftplus, $wp_version, $pagenow;
185
  add_filter('updraftplus_dirlist_others', array($updraftplus, 'backup_others_dirlist'));
186
  add_filter('updraftplus_dirlist_uploads', array($updraftplus, 'backup_uploads_dirlist'));
208
  add_action('all_admin_notices', array($this, 'show_admin_notice_upgradead') );
209
  }
210
  }
211
+
212
+ //Moved out for use with Ajax saving
213
+ $this->setup_all_admin_notices_global($service);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  }
215
 
216
  // Next, the actions that only come on the UpdraftPlus page
217
  if ($pagenow != UpdraftPlus_Options::admin_page() || empty($_REQUEST['page']) || 'updraftplus' != $_REQUEST['page']) return;
218
+ $this->setup_all_admin_notices_udonly($service);
219
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'), 99999);
221
 
222
  }
391
  <a href="https://updraftplus.com/"><img class="udp-logo" alt="UpdraftPlus" src="<?php echo UPDRAFTPLUS_URL.'/images/ud-logo-150.png' ?>"></a>
392
 
393
  <?php
394
+ echo '<p><strong>'.__('Free Newsletter', 'updraftplus').'</strong> <br>'.__('UpdraftPlus news, high-quality training materials for WordPress developers and site-owners, and general WordPress news. You can de-subscribe at any time.', 'updraftplus').' <a href="https://updraftplus.com/newsletter-signup">'.__('Follow this link to sign up.', 'updraftplus').'</a></p>';
395
 
396
  echo '<p><strong>'.__('UpdraftPlus Premium', 'updraftplus').'</strong> <br>'.__('For personal support, the ability to copy sites, more storage destinations, encrypted backups for security, multiple backup destinations, better reporting, no adverts and plenty more, take a look at the premium version of UpdraftPlus - the world’s most popular backup plugin.', 'updraftplus').' <a href="https://updraftplus.com/comparison-updraftplus-free-updraftplus-premium/">'.__('Compare with the free version', 'updraftplus').'</a> / <a href="https://updraftplus.com/shop/updraftplus-premium/">'.__('Go to the shop.', 'updraftplus').'</a></p>';
397
 
418
  } else {
419
  wp_enqueue_script('updraftplus-admin-ui', UPDRAFTPLUS_URL.'/includes/updraft-admin-ui.js', array('jquery', 'jquery-ui-dialog', 'plupload-all'), $enqueue_version);
420
  }
421
+
422
  }
423
 
424
  // This is also called directly from the auto-backup add-on
425
  public function admin_enqueue_scripts() {
426
 
427
+ global $updraftplus, $wp_locale;
428
+
429
  // Defeat other plugins/themes which dump their jQuery UI CSS onto our settings page
430
  wp_deregister_style('jquery-ui');
431
  wp_enqueue_style('jquery-ui', UPDRAFTPLUS_URL.'/includes/jquery-ui.custom.css', array(), '1.11.4');
432
+
433
+ $our_version = @constant('SCRIPT_DEBUG') ? $updraftplus->version.'.'.time() : $updraftplus->version;
434
+
435
+ wp_enqueue_style('updraft-admin-css', UPDRAFTPLUS_URL.'/css/admin.css', array(), $our_version);
436
  // add_filter('style_loader_tag', array($this, 'style_loader_tag'), 10, 2);
437
 
 
438
  $this->ensure_sufficient_jquery_and_enqueue();
439
+
440
+ wp_enqueue_script('jquery-blockui', UPDRAFTPLUS_URL.'/includes/jquery.blockUI.js', array('jquery'), '2.70.0');
441
+
442
+ $selectric_file = @constant('SCRIPT_DEBUG') ? 'jquery.selectric.js' : 'jquery.selectric.min.js';
443
  wp_enqueue_script('selectric', UPDRAFTPLUS_URL."/includes/selectric/$selectric_file", array('jquery'), '1.9.3');
444
  wp_enqueue_style('selectric', UPDRAFTPLUS_URL.'/includes/selectric/selectric.css', array(), '1.9.3');
445
 
483
  'emptyresponse' => __('Error: the server sent an empty response.', 'updraftplus'),
484
  'warnings' => __('Warnings:','updraftplus'),
485
  'errors' => __('Errors:','updraftplus'),
486
+ 'jsonnotunderstood' => __('Error: the server sent us a response which we did not understand.', 'updraftplus'),
487
  'errordata' => __('Error data:', 'updraftplus'),
488
  'error' => __('Error:','updraftplus'),
489
  'errornocolon' => __('Error','updraftplus'),
519
  'downloadlogfile' => __('Download log file', 'updraftplus'),
520
  'automaticbackupbeforeupdate' => __('Automatic backup before update', 'updraftplus'),
521
  'unsavedsettings' => __('You have made changes to your settings, and not saved.', 'updraftplus'),
522
+ 'saving' => __('Saving...', 'updraftplus'),
523
  'connect' => __('Connect', 'updraftplus'),
524
  'connecting' => __('Connecting...', 'updraftplus'),
525
  'disconnect' => __('Disconnect', 'updraftplus'),
536
  'key' => __('Key', 'updraftplus'),
537
  'nokeynamegiven' => sprintf(__("Failure: No %s was given.",'updraftplus'), __('key name','updraftplus')),
538
  'deleting' => __('Deleting...', 'updraftplus'),
539
+ 'delete_response_not_understood' => __("We requested to delete the file, but could not understand the server's response", 'updraftplus'),
540
  'testingconnection' => __('Testing connection...', 'updraftplus'),
541
  'send' => __('Send', 'updraftplus'),
542
  'migratemodalheight' => class_exists('UpdraftPlus_Addons_Migrator') ? 555 : 300,
545
  'unsavedsettingsbackup' => __('You have made changes to your settings, and not saved.', 'updraftplus')."\n".__('Your backup will use your old settings until you save your changes.','updraftplus'),
546
  'dayselector' => $day_selector,
547
  'mdayselector' => $mday_selector,
548
+ 'ud_url' => UPDRAFTPLUS_URL,
549
  'day' => __('day', 'updraftplus'),
550
  'inthemonth' => __('in the month', 'updraftplus'),
551
  'days' => __('day(s)', 'updraftplus'),
638
 
639
  ?><script type="text/javascript">
640
  var updraft_credentialtest_nonce='<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>';
641
+ var updraftplus_settings_nonce='<?php echo wp_create_nonce('updraftplus-settings-nonce');?>';
642
  var updraft_siteurl = '<?php echo esc_js(site_url('', 'relative'));?>';
643
  var updraft_plupload_config=<?php echo json_encode($plupload_init); ?>;
644
  var updraft_download_nonce='<?php echo wp_create_nonce('updraftplus_download');?>';
764
  echo '<div class="updraftmessage '.$class.'">'."<p>$message</p></div>";
765
  }
766
 
767
+ //
768
+ public function show_admin_warning_unwritable(){
769
+ $unwritable_mess = htmlspecialchars(__("The 'Backup Now' button is disabled as your backup directory is not writable (go to the 'Settings' tab and find the relevant option).", 'updraftplus'));
770
+ $this->show_admin_warning($unwritable_mess, "error");
771
+ }
772
+
773
  public function show_admin_nosettings_warning() {
774
  $this->show_admin_warning('<strong>'.__('Welcome to UpdraftPlus!', 'updraftplus').'</strong> '.__('To make a backup, just press the Backup Now button.', 'updraftplus').' <a href="#" id="updraft-navtab-settings2">'.__('To change any of the default settings of what is backed up, to configure scheduled backups, to send your backups to remote storage (recommended), and more, go to the settings tab.', 'updraftplus').'</a>', 'updated notice is-dismissible');
775
  }
851
 
852
  public function updraft_download_backup() {
853
 
854
+ if (empty($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'], 'updraftplus_download')) die;
855
 
856
+ if (empty($_REQUEST['timestamp']) || !is_numeric($_REQUEST['timestamp']) || empty($_REQUEST['type'])) exit;
 
 
857
 
858
+ $findex = empty($_REQUEST['findex']) ? 0 : (int)$_REQUEST['findex'];
859
+ $stage = empty($_REQUEST['stage']) ? '' : $_REQUEST['stage'];
860
 
861
+ // This call may not actually return, depending upon what mode it is called in
862
+ echo json_encode($this->do_updraft_download_backup($findex, $_REQUEST['type'], $_REQUEST['timestamp'], $stage));
863
+
864
+ die();
865
+ }
866
+
867
+ // This function may die(), depending on the request being made
868
+ public function do_updraft_download_backup($findex, $type, $timestamp, $stage, $close_connection_callable = false) {
869
+
870
+ @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);
871
 
872
+ global $updraftplus;
873
+
874
+ // This is a bit ugly; these variables get placed back into $_POST (where they may possibly have come from), so that UpdraftPlus::log() can detect exactly where to log the download status.
875
+ $_POST['findex'] = $findex;
876
+ $_POST['type'] = $type;
877
+ $_POST['timestamp'] = $timestamp;
878
+
879
+ // Check that it is a known entity type; if not, die
880
+ if ('db' != substr($type, 0, 2)) {
881
+ $backupable_entities = $updraftplus->get_backupable_file_entities(true);
882
+ foreach ($backupable_entities as $t => $info) {
883
+ if ($type == $t) $type_match = true;
884
+ }
885
+ if (empty($type_match)) return array('result' => 'error', 'code' => 'no_such_type');
886
+ }
887
 
888
  // We already know that no possible entities have an MD5 clash (even after 2 characters)
889
  // Also, there's nothing enforcing a requirement that nonces are hexadecimal
909
  // Where it should end up being downloaded to
910
  $fullpath = $updraftplus->backups_dir_location().'/'.$file;
911
 
912
+ if (2 == $stage) {
913
  $updraftplus->spool_file($type, $fullpath);
914
+ // Do not return - we do not want the caller to add any output
915
  die;
916
  }
917
 
918
+ if ('delete' == $stage) {
919
  @unlink($fullpath);
920
+ $updraftplus->log("The file has been deleted ($file)");
921
+ return array('result' => 'deleted');
 
922
  }
923
 
924
  // TODO: FIXME: Failed downloads may leave log files forever (though they are small)
 
925
  if ($debug_mode) $updraftplus->logfile_open($updraftplus->nonce);
926
 
927
  set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
928
 
929
  $updraftplus->log("Requested to obtain file: timestamp=$timestamp, type=$type, index=$findex");
930
 
931
+ $itext = empty($findex) ? '' : $findex;
932
  $known_size = isset($backup_history[$timestamp][$type.$itext.'-size']) ? $backup_history[$timestamp][$type.$itext.'-size'] : 0;
933
 
934
  $services = (isset($backup_history[$timestamp]['service'])) ? $backup_history[$timestamp]['service'] : false;
940
 
941
  $needs_downloading = false;
942
 
943
+ if (!file_exists($fullpath)) {
944
  //if the file doesn't exist and they're using one of the cloud options, fetch it down from the cloud.
945
  $needs_downloading = true;
946
  $updraftplus->log('File does not yet exist locally - needs downloading');
947
+ } elseif ($known_size > 0 && filesize($fullpath) < $known_size) {
948
  $updraftplus->log("The file was found locally (".filesize($fullpath).") but did not match the size in the backup history ($known_size) - will resume downloading");
949
  $needs_downloading = true;
950
+ } elseif ($known_size > 0) {
951
  $updraftplus->log('The file was found locally and matched the recorded size from the backup history ('.round($known_size/1024,1).' Kb)');
952
  } else {
953
  $updraftplus->log('No file size was found recorded in the backup history. We will assume the local one is complete.');
958
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, "downloading:$known_size:$fullpath");
959
 
960
  if ($needs_downloading) {
961
+
962
+ $msg = array(
963
+ 'result' => 'needs_download'
964
+ );
965
+
966
+ if ($close_connection_callable && is_callable($close_connection_callable)) {
967
+ call_user_func($close_connection_callable, $msg);
968
+ } else {
969
+ $updraftplus->close_browser_connection(json_encode($msg));
970
+ }
971
+
972
  $is_downloaded = false;
973
  add_action('http_request_args', array($updraftplus, 'modify_http_options'));
974
  foreach ($services as $service) {
987
  remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
988
  }
989
 
990
+ // Now, be ready to spool the thing to the browser
991
+ if (is_file($fullpath) && is_readable($fullpath)) {
992
 
993
  // That message is then picked up by the AJAX listener
994
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'downloaded:'.filesize($fullpath).":$fullpath");
995
 
996
+ $result = 'downloaded';
997
+
998
  } else {
999
+
1000
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'failed');
1001
  $updraftplus->jobdata_set('dlerrors_'.$timestamp.'_'.$type.'_'.$findex, $updraftplus->errors);
1002
  $updraftplus->log('Remote fetch failed. File '.$fullpath.' did not exist or was unreadable. If you delete local backups then remote retrieval may have failed.');
1003
+
1004
+ $result = 'download_failed';
1005
  }
1006
 
1007
  restore_error_handler();
1009
  @fclose($updraftplus->logfile_handle);
1010
  if (!$debug_mode) @unlink($updraftplus->logfile_name);
1011
 
1012
+ // The browser connection was possibly already closed, but not necessarily
1013
+ return array('result' => $result);
1014
 
1015
  }
1016
 
1371
 
1372
  } elseif (isset($_POST['backup_timestamp']) && 'deleteset' == $_REQUEST['subaction']) {
1373
 
1374
+ echo json_encode($this->delete_set($_POST));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1375
 
1376
  } elseif ('rawbackuphistory' == $_REQUEST['subaction']) {
1377
 
1475
  $history_status = $this->get_history_status($rescan, $remotescan);
1476
  echo @json_encode($history_status);
1477
 
 
 
 
 
 
 
 
 
 
1478
  } elseif (isset($_POST['subaction']) && $_POST['subaction'] == 'credentials_test') {
1479
  $method = (preg_match("/^[a-z0-9]+$/", $_POST['method'])) ? $_POST['method'] : "";
1480
 
1499
  die;
1500
 
1501
  }
1502
+
1503
+ // Relevant options (array keys): backup_timestamp, delete_remote,
1504
+ public function delete_set($opts) {
1505
+
1506
+ global $updraftplus;
1507
+
1508
+ $backups = $updraftplus->get_backup_history();
1509
+ $timestamps = (string)$opts['backup_timestamp'];
1510
+
1511
+ $timestamps = explode(',', $timestamps);
1512
+ $delete_remote = empty($opts['delete_remote']) ? false : true;
1513
+
1514
+ // You need a nonce before you can set job data. And we certainly don't yet have one.
1515
+ $updraftplus->backup_time_nonce();
1516
+ // Set the job type before logging, as there can be different logging destinations
1517
+ $updraftplus->jobdata_set('job_type', 'delete');
1518
+ $updraftplus->jobdata_set('job_time_ms', $updraftplus->job_time_ms);
1519
+
1520
+ if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
1521
+ $updraftplus->logfile_open($updraftplus->nonce);
1522
+ set_error_handler(array($updraftplus, 'php_error'), E_ALL & ~E_STRICT);
1523
+ }
1524
+
1525
+ $updraft_dir = $updraftplus->backups_dir_location();
1526
+ $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
1527
+
1528
+ $local_deleted = 0;
1529
+ $remote_deleted = 0;
1530
+ $sets_removed = 0;
1531
+
1532
+ foreach ($timestamps as $i => $timestamp) {
1533
+
1534
+ if (!isset($backups[$timestamp])) {
1535
+ echo json_encode(array('result' => 'error', 'message' => __('Backup set not found', 'updraftplus')));
1536
+ die;
1537
+ }
1538
+
1539
+ $nonce = isset($backups[$timestamp]['nonce']) ? $backups[$timestamp]['nonce'] : '';
1540
+
1541
+ $delete_from_service = array();
1542
+
1543
+ if ($delete_remote) {
1544
+ // Locate backup set
1545
+ if (isset($backups[$timestamp]['service'])) {
1546
+ $services = is_string($backups[$timestamp]['service']) ? array($backups[$timestamp]['service']) : $backups[$timestamp]['service'];
1547
+ if (is_array($services)) {
1548
+ foreach ($services as $service) {
1549
+ if ($service && $service != 'none' && $service != 'email') $delete_from_service[] = $service;
1550
+ }
1551
+ }
1552
+ }
1553
+ }
1554
+
1555
+ $files_to_delete = array();
1556
+ foreach ($backupable_entities as $key => $ent) {
1557
+ if (isset($backups[$timestamp][$key])) {
1558
+ $files_to_delete[$key] = $backups[$timestamp][$key];
1559
+ }
1560
+ }
1561
+ // Delete DB
1562
+ if (isset($backups[$timestamp]['db'])) $files_to_delete['db'] = $backups[$timestamp]['db'];
1563
+
1564
+ // Also delete the log
1565
+ if ($nonce && !UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
1566
+ $files_to_delete['log'] = "log.$nonce.txt";
1567
+ }
1568
+
1569
+ unset($backups[$timestamp]);
1570
+ $sets_removed++;
1571
+ UpdraftPlus_Options::update_updraft_option('updraft_backup_history', $backups);
1572
+
1573
+ add_action('http_request_args', array($updraftplus, 'modify_http_options'));
1574
+ foreach ($files_to_delete as $key => $files) {
1575
+ # Local deletion
1576
+ if (is_string($files)) $files=array($files);
1577
+ foreach ($files as $file) {
1578
+ if (is_file($updraft_dir.'/'.$file)) {
1579
+ if (@unlink($updraft_dir.'/'.$file)) $local_deleted++;
1580
+ }
1581
+ }
1582
+ if ('log' != $key && count($delete_from_service) > 0) {
1583
+ foreach ($delete_from_service as $service) {
1584
+ if ('email' == $service) continue;
1585
+ if (file_exists(UPDRAFTPLUS_DIR."/methods/$service.php")) require_once(UPDRAFTPLUS_DIR."/methods/$service.php");
1586
+ $objname = "UpdraftPlus_BackupModule_".$service;
1587
+ $deleted = -1;
1588
+ if (class_exists($objname)) {
1589
+ # TODO: Re-use the object (i.e. prevent repeated connection setup/teardown)
1590
+ $remote_obj = new $objname;
1591
+ $deleted = $remote_obj->delete($files);
1592
+ }
1593
+ if ($deleted === -1) {
1594
+ //echo __('Did not know how to delete from this cloud service.', 'updraftplus');
1595
+ } elseif ($deleted !== false) {
1596
+ $remote_deleted = $remote_deleted + count($files);
1597
+ } else {
1598
+ // Do nothing
1599
+ }
1600
+ }
1601
+ }
1602
+ }
1603
+ remove_action('http_request_args', array($updraftplus, 'modify_http_options'));
1604
+ }
1605
+
1606
+
1607
+ $message = sprintf(__('Backup sets removed: %d', 'updraftplus'),$sets_removed)."\n";
1608
+
1609
+ $message .= sprintf(__('Local archives deleted: %d', 'updraftplus'),$local_deleted)."\n";
1610
+ $message .= sprintf(__('Remote archives deleted: %d', 'updraftplus'),$remote_deleted)."\n";
1611
+
1612
+ $updraftplus->log("Local archives deleted: ".$local_deleted);
1613
+ $updraftplus->log("Remote archives deleted: ".$remote_deleted);
1614
+
1615
+ if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
1616
+ restore_error_handler();
1617
+ }
1618
+
1619
+ return array('result' => 'success', 'message' => $message, 'removed' => array('sets' => $sets_removed, 'local' => $local_deleted, 'remote' => $remote_deleted));
1620
+
1621
+ }
1622
 
1623
  public function get_history_status($rescan, $remotescan) {
1624
 
1660
  $size = $this->recursive_directory_size($dirs, $updraftplus->get_exclude($entity), $basedir, 'numeric');
1661
  if (is_numeric($size) && $size>0) $total_size += $size;
1662
  }
1663
+ return $updraftplus->convert_numeric_size_to_text($total_size);
1664
  } elseif (!empty($backupable_entities[$entity])) {
1665
  # Might be an array
1666
  $basedir = $backupable_entities[$entity];
1700
 
1701
  }
1702
 
1703
+ // Input: an array of items
1704
+ // Each item is in the format: <base>,<timestamp>,<type>(,<findex>)
1705
+ // The 'base' is not for us: we just pass it straight back
1706
+ public function get_download_statuses($downloaders) {
1707
  global $updraftplus;
1708
  $download_status = array();
1709
+ foreach ($downloaders as $downloader) {
1710
+ # prefix, timestamp, entity, index
1711
+ if (preg_match('/^([^,]+),(\d+),([-a-z]+|db[0-9]+),(\d+)$/', $downloader, $matches)) {
1712
+ $findex = (empty($matches[4])) ? '0' : $matches[4];
1713
+ $updraftplus->nonce = dechex($matches[2]).$findex.substr(md5($matches[3]), 0, 3);
1714
+ $updraftplus->jobdata_reset();
1715
+ $status = $this->download_status($matches[2], $matches[3], $matches[4]);
1716
+ if (is_array($status)) {
1717
+ $status['base'] = $matches[1];
1718
+ $status['timestamp'] = $matches[2];
1719
+ $status['what'] = $matches[3];
1720
+ $status['findex'] = $findex;
1721
+ $download_status[] = $status;
 
 
1722
  }
1723
  }
1724
  }
1725
+ return $download_status;
1726
+ }
1727
+
1728
+ public function get_activejobs_list($request) {
1729
+
1730
+ global $updraftplus;
1731
+
1732
+ $download_status = empty($request['downloaders']) ? array(): $this->get_download_statuses(explode(':', $request['downloaders']));
1733
 
1734
  if (!empty($request['oneshot'])) {
1735
  $job_id = get_site_option('updraft_oneshotnonce', false);
1876
  $response = array( 'm' => $updraftplus->jobdata_get('dlmessage_'.$timestamp.'_'.$type.'_'.$findex).'<br>' );
1877
  if ($file = $updraftplus->jobdata_get('dlfile_'.$timestamp.'_'.$type.'_'.$findex)) {
1878
  if ('failed' == $file) {
1879
+ $response['e'] = __('Download failed', 'updraftplus').'<br>';
1880
+ $response['failed'] = true;
1881
  $errs = $updraftplus->jobdata_get('dlerrors_'.$timestamp.'_'.$type.'_'.$findex);
1882
  if (is_array($errs) && !empty($errs)) {
1883
  $response['e'] .= '<ul class="disc">';
2165
  passed back in as GET parameters.
2166
  */
2167
 
2168
+ if (isset($_REQUEST['action']) && (($_REQUEST['action'] == 'updraft_restore' && isset($_REQUEST['backup_timestamp'])) || ('updraft_restore_continue' == $_REQUEST['action'] && !empty($_REQUEST['restoreid'])))) {
2169
 
2170
  $is_continuation = ('updraft_restore_continue' == $_REQUEST['action']) ? true : false;
2171
 
2249
  return;
2250
  }
2251
 
2252
+ if (isset($_GET['error'])) {
2253
  // This is used by Microsoft OneDrive authorisation failures (May 15). I am not sure what may have been using the 'error' GET parameter otherwise - but it is harmless.
2254
  if (!empty($_GET['error_description'])) {
2255
  $this->show_admin_warning(htmlspecialchars($_GET['error_description']).' ('.htmlspecialchars($_GET['error']).')', 'error');
2258
  }
2259
  }
2260
 
2261
+ if (isset($_GET['message'])) $this->show_admin_warning(htmlspecialchars($_GET['message']));
2262
 
2263
+ if (isset($_GET['action']) && $_GET['action'] == 'updraft_create_backup_dir' && isset($_GET['nonce']) && wp_verify_nonce($_GET['nonce'], 'create_backup_dir')) {
2264
  $created = $this->create_backup_dir();
2265
+ if (is_wp_error($created)) {
2266
  echo '<p>'.__('Backup directory could not be created', 'updraftplus').'...<br/>';
2267
  echo '<ul class="disc">';
2268
  foreach ($created->get_error_messages() as $key => $msg) {
2276
  return;
2277
  }
2278
 
2279
+ echo '<div id="updraft_backup_started" class="updated updraft-hidden"></div>';
2280
 
2281
+ if (isset($_POST['action']) && 'updraft_backup_debug_all' == $_POST['action']) {
2282
  $updraftplus->boot_backup(true,true);
2283
  } elseif (isset($_POST['action']) && 'updraft_backup_debug_db' == $_POST['action']) {
2284
  $updraftplus->boot_backup(false, true, false, true);
2338
  $ws_advert = $updraftplus->wordshell_random_advert(1);
2339
  if ($ws_advert && empty($success_advert) && empty($this->no_settings_warning)) { echo '<div class="updated ws_advert" style="clear:left;">'.$ws_advert.'</div>'; }
2340
 
2341
+ if (!$updraftplus->memory_check(64)) {?>
2342
  <div class="updated memory-limit"><?php _e("Your PHP memory limit (set by your web hosting company) is very low. UpdraftPlus attempted to raise it but was unsuccessful. This plugin may struggle with a memory limit of less than 64 Mb - especially if you have very large files uploaded (though on the other hand, many sites will be successful with a 32Mb limit - your experience may vary).",'updraftplus');?> <?php _e('Current limit is:','updraftplus');?> <?php echo $updraftplus->memory_check_current(); ?> Mb</div>
2343
  <?php
2344
  }
2345
 
2346
 
2347
+ if (!empty($updraftplus->errors)) {
2348
  echo '<div class="error updraft_list_errors">';
2349
  $updraftplus->list_errors();
2350
  echo '</div>';
2373
  }
2374
 
2375
  ?>
2376
+ <a class="nav-tab <?php if (1 == $tabflag) echo 'nav-tab-active'; ?>" id="updraft-navtab-status" href="#updraft-navtab-status-content" ><?php _e('Current Status', 'updraftplus');?> </span></a>
2377
+ <a class="nav-tab <?php if (2 == $tabflag) echo 'nav-tab-active'; ?>" id="updraft-navtab-backups" href="#updraft-navtab-backups-contents" ><?php echo __('Existing Backups', 'updraftplus').' ('.count($backup_history).')';?> </span></a>
2378
+ <a class="nav-tab <?php if (3 == $tabflag) echo 'nav-tab-active'; ?>" id="updraft-navtab-settings" href="#updraft-navtab-settings-content"><?php _e('Settings', 'updraftplus');?> </span></a>
2379
+ <a class="nav-tab<?php if (4 == $tabflag) echo ' nav-tab-active'; ?>" id="updraft-navtab-expert" href="#updraft-navtab-expert-content"><?php _e('Advanced Tools', 'updraftplus');?> </span></a>
2380
+ <a class="nav-tab<?php if (5 == $tabflag) echo ' nav-tab-active'; ?>" id="updraft-navtab-addons" href="#updraft-navtab-addons-content"><?php _e('Premium / Extensions', 'updraftplus');?> </span></a>
2381
  <?php //do_action('updraftplus_settings_afternavtabs'); ?>
2382
  </h2>
2383
 
2390
  <pre id="updraft-poplog-content"></pre>
2391
  </div>
2392
 
2393
+ <div id="updraft-navtab-status-content" class="<?php if (1 != $tabflag) echo 'updraft-hidden'; ?>">
2394
 
2395
  <div id="updraft-insert-admin-warning"></div>
2396
 
2412
  $this->show_admin_warning($unwritable_mess, "error");
2413
  }
2414
  ?>
2415
+ <button id="updraft-backupnow-button" type="button" <?php echo $backup_disabled ?> class="updraft-bigbutton button-primary" <?php if ($backup_disabled) echo 'title="'.esc_attr(__('This button is disabled because your backup directory is not writable (see the settings).', 'updraftplus')).'" ';?> onclick="updraft_backup_dialog_open();"><?php _e('Backup Now', 'updraftplus');?></button>
2416
 
2417
+ <button type="button" class="updraft-bigbutton button-primary" onclick="updraft_openrestorepanel();">
2418
  <?php _e('Restore','updraftplus');?>
2419
  </button>
2420
 
2421
+ <button type="button" class="updraft-bigbutton button-primary" onclick="updraft_migrate_dialog_open();"><?php _e('Clone/Migrate','updraftplus');?></button>
2422
 
2423
  </td>
2424
  </tr>
2490
  </tr>
2491
  </table>
2492
 
2493
+ <br style="clear:both;" />
2494
 
2495
  <?php $this->render_active_jobs_and_log_table(); ?>
2496
 
2517
  <?php echo $this->backupnow_modal_contents(); ?>
2518
  </div>
2519
 
2520
+ <?php
2521
+ if (is_multisite() && !file_exists(UPDRAFTPLUS_DIR.'/addons/multisite.php')) {
2522
+ ?>
2523
+ <h2>UpdraftPlus <?php _e('Multisite','updraftplus');?></h2>
2524
+ <table>
2525
+ <tr>
2526
+ <td>
2527
+ <p class="multisite-advert-width"><?php echo __('Do you need WordPress Multisite support?','updraftplus').' <a href="https://updraftplus.com/shop/updraftplus-premium/">'. __('Please check out UpdraftPlus Premium, or the stand-alone Multisite add-on.','updraftplus');?></a>.</p>
2528
+ </td>
2529
+ </tr>
2530
+ </table>
2531
+ <?php } ?>
2532
+
2533
  </div>
2534
 
2535
+
2536
+
2537
+ <div id="updraft-navtab-backups-content" <?php if (2 != $tabflag) echo 'class="updraft-hidden"'; ?>>
2538
  <?php
2539
  $is_opera = (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/'));
2540
  $tmp_opts = array('include_opera_warning' => $is_opera);
2543
  ?>
2544
  </div>
2545
 
2546
+ <div id="updraft-navtab-settings-content" <?php if (3 != $tabflag) echo 'class="updraft-hidden"'; ?>>
2547
  <h2 class="updraft_settings_sectionheading"><?php _e('Backup Contents And Schedule','updraftplus');?></h2>
2548
  <?php UpdraftPlus_Options::options_form_begin(); ?>
2549
  <?php $this->settings_formcontents($last_backup_html); ?>
2550
  </form>
2551
  </div>
2552
 
2553
+ <div id="updraft-navtab-expert-content"<?php if (4 != $tabflag) echo ' class="updraft-hidden"'; ?>>
2554
  <?php $this->settings_expertsettings($backup_disabled); ?>
2555
  </div>
2556
 
2557
+ <div id="updraft-navtab-addons-content"<?php if (5 != $tabflag) echo ' class="updraft-hidden"'; ?>>
2558
 
2559
  <?php
2560
  $tick = UPDRAFTPLUS_URL.'/images/updraft_tick.png';
2774
 
2775
  $ret .= '<input type="checkbox" id="backupnow_includefiles" checked="checked"> <label for="backupnow_includefiles">'.__("Include any files in the backup", 'updraftplus').'</label> (<a href="#" id="backupnow_includefiles_showmoreoptions">...</a>)<br>';
2776
 
2777
+ $ret .= '<div id="backupnow_includefiles_moreoptions" class="updraft-hidden"><em>'.__('Your saved settings also affect what is backed up - e.g. files excluded.', 'updraftplus').'</em><br>'.$this->files_selector_widgetry('backupnow_files_', false, 'sometimes').'</div>';
2778
 
2779
+ $ret .= '<span id="backupnow_remote_container">'.$this->backup_now_remote_message().'</span>';
 
 
 
 
 
 
2780
 
 
 
 
 
 
2781
  $ret .= '</p>';
2782
 
2783
  $ret .= apply_filters('updraft_backupnow_modal_afteroptions', '', '');
2811
  ?>
2812
  <td colspan="2" class="last-message"><strong><?php _e('Last log message','updraftplus');?>:</strong><br>
2813
  <span id="updraft_lastlogcontainer"><?php echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', __('(Nothing yet logged)','updraftplus'))); ?></span><br>
2814
+ <a href="?page=updraftplus&amp;action=downloadlatestmodlog&amp;wpnonce=<?php echo wp_create_nonce('updraftplus_download') ?>" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('');"><?php _e('Download most recently modified log file','updraftplus');?></a>
2815
  </td>
2816
  <?php } else { ?>
2817
  <th><?php _e('Last log message','updraftplus');?>:</th>
2818
  <td>
2819
  <span id="updraft_lastlogcontainer"><?php echo htmlspecialchars(UpdraftPlus_Options::get_updraft_option('updraft_lastmessage', __('(Nothing yet logged)','updraftplus'))); ?></span><br>
2820
+ <a href="?page=updraftplus&amp;action=downloadlatestmodlog&amp;wpnonce=<?php echo wp_create_nonce('updraftplus_download') ?>" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('');"><?php _e('Download most recently modified log file','updraftplus');?></a>
2821
  </td>
2822
  <?php } ?>
2823
  </tr>
2870
  <div class="download-backups form-table">
2871
  <?php /* echo '<h2>'.__('Existing Backups: Downloading And Restoring', 'updraftplus').'</h2>'; */ ?>
2872
  <?php if (!empty($options['include_whitespace_warning'])) { ?>
2873
+ <p class="ud-whitespace-warning updraft-hidden">
2874
  <?php echo '<strong>'.__('Warning','updraftplus').':</strong> '.__('Your WordPress installation has a problem with outputting extra whitespace. This can corrupt backups that you download from here.','updraftplus').' <a href="https://updraftplus.com/problems-with-extra-white-space/">'.__('Please consult this FAQ for help on what to do about it.', 'updraftplus').'</a>';?>
2875
  </p>
2876
  <?php } ?>
2932
  if ($return_result) ob_start();
2933
  ?>
2934
 
2935
+ <div id="ud_massactions" class="updraft-hidden">
2936
  <strong><?php _e('Actions upon selected backups', 'updraftplus');?></strong> <br>
2937
  <div class="updraftplus-remove" style="float: left;"><a href="#" onclick="updraft_deleteallselected(); return false;"><?php _e('Delete', 'updraftplus');?></a></div>
2938
  <div class="updraft-viewlogdiv"><a href="#" onclick="jQuery('#updraft-navtab-backups-content .updraft_existing_backups .updraft_existing_backups_row').addClass('backuprowselected'); return false;"><?php _e('Select all', 'updraftplus');?></a></div>
2947
  <div id="updraft-delete-modal" title="<?php _e('Delete backup set', 'updraftplus');?>">
2948
  <form id="updraft_delete_form" method="post">
2949
  <p id="updraft_delete_question_singular">
2950
+ <?php echo sprintf(__('Are you sure that you wish to remove %s from UpdraftPlus?', 'updraftplus'), __('this backup set', 'updraftplus')); ?>
2951
  </p>
2952
+ <p id="updraft_delete_question_plural" class="updraft-hidden">
2953
+ <?php echo sprintf(__('Are you sure that you wish to remove %s from UpdraftPlus?', 'updraftplus'), __('these backup sets', 'updraftplus')); ?>
2954
  </p>
2955
  <fieldset>
2956
  <input type="hidden" name="nonce" value="<?php echo wp_create_nonce('updraftplus-credentialtest-nonce');?>">
2959
  <input type="hidden" name="backup_timestamp" value="0" id="updraft_delete_timestamp">
2960
  <input type="hidden" name="backup_nonce" value="0" id="updraft_delete_nonce">
2961
  <div id="updraft-delete-remote-section"><input checked="checked" type="checkbox" name="delete_remote" id="updraft_delete_remote" value="1"> <label for="updraft_delete_remote"><?php _e('Also delete from remote storage', 'updraftplus');?></label><br>
2962
+ <p id="updraft-delete-waitwarning" class="updraft-hidden"><em><?php _e('Deleting... please allow time for the communications with the remote storage to complete.', 'updraftplus');?></em></p>
2963
  </div>
2964
  </fieldset>
2965
  </form>
2989
  <?php
2990
 
2991
  # The 'off' check is for badly configured setups - http://wordpress.org/support/topic/plugin-wp-super-cache-warning-php-safe-mode-enabled-but-safe-mode-is-off
2992
+ if ($updraftplus->detect_safe_mode()) {
2993
  echo "<p><em>".__("Your web server has PHP's so-called safe_mode active.", 'updraftplus').' '.__('This makes time-outs much more likely. You are recommended to turn safe_mode off, or to restore only one entity at a time, <a href="https://updraftplus.com/faqs/i-want-to-restore-but-have-either-cannot-or-have-failed-to-do-so-from-the-wp-admin-console/">or to restore manually</a>.', 'updraftplus')."</em></p><br/>";
2994
  }
2995
 
3010
  ?>
3011
  <div><input id="updraft_restore_db" type="checkbox" name="updraft_restore[]" value="db"> <label for="updraft_restore_db"><?php _e('Database','updraftplus'); ?></label><br>
3012
 
3013
+ <div id="updraft_restorer_dboptions" class="updraft-hidden"><h4><?php echo sprintf(__('%s restoration options:','updraftplus'),__('Database','updraftplus')); ?></h4>
3014
 
3015
  <?php
3016
 
3165
  </tr>
3166
  </tbody>
3167
  </table>
3168
+ <h3><?php _e('Wipe settings', 'updraftplus');?></h3>
3169
  <p class="max-width-600"><?php echo __('This button will delete all UpdraftPlus settings and progress information for in-progress backups (but not any of your existing backups from your cloud storage).', 'updraftplus').' '.__('You will then need to enter all your settings again. You can also do this before deactivating/deinstalling UpdraftPlus if you wish.','updraftplus');?></p>
3170
  <form method="post" action="<?php echo esc_url(add_query_arg(array('error' => false, 'updraft_restore_success' => false, 'action' => false, 'page' => 'updraftplus'))); ?>">
3171
  <input type="hidden" name="action" value="updraft_wipesettings" />
3424
  private function delete_old_dirs_go($show_return = true) {
3425
  echo ($show_return) ? '<h1>UpdraftPlus - '.__('Remove old directories', 'updraftplus').'</h1>' : '<h2>'.__('Remove old directories', 'updraftplus').'</h2>';
3426
 
3427
+ if ($this->delete_old_dirs()) {
3428
  echo '<p>'.__('Old directories successfully removed.','updraftplus').'</p><br/>';
3429
  } else {
3430
  echo '<p>',__('Old directory removal failed for some reason. You may want to do this manually.','updraftplus').'</p><br/>';
3456
  $plugs = untrailingslashit($wp_filesystem->wp_plugins_dir());
3457
  if ($wp_filesystem->is_dir($plugs.'-old')) {
3458
  print "<strong>".__('Delete','updraftplus').": </strong>plugins-old: ";
3459
+ if (!$wp_filesystem->delete($plugs.'-old', true)) {
3460
  $ret3 = false;
3461
  print "<strong>".__('Failed', 'updraftplus')."</strong><br>";
3462
  } else {
3491
  print "<strong>".__('Delete','updraftplus').": </strong>".htmlspecialchars($name).": ";
3492
 
3493
  if ($wpfs) {
3494
+ if (!$wp_filesystem->delete($dir.$name, true)) {
3495
  $ret = false;
3496
  echo "<strong>".__('Failed', 'updraftplus')."</strong><br>";
3497
  } else {
3661
  'monthly' => __("Monthly", 'updraftplus')
3662
  ));
3663
  }
3664
+
3665
+ private function really_writable_message($really_is_writable, $updraft_dir){
3666
+ if ($really_is_writable) {
3667
+ $dir_info = '<span style="color:green;">'.__('Backup directory specified is writable, which is good.','updraftplus').'</span>';
3668
+ } else {
3669
+ $dir_info = '<span style="color:red;">';
3670
+ if (!is_dir($updraft_dir)) {
3671
+ $dir_info .= __('Backup directory specified does <b>not</b> exist.','updraftplus');
3672
+ } else {
3673
+ $dir_info .= __('Backup directory specified exists, but is <b>not</b> writable.','updraftplus');
3674
+ }
3675
+ $dir_info .= ' <span class="directory-permissions"><a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&action=updraft_create_backup_dir&nonce='.wp_create_nonce('create_backup_dir').'">'.__('Click here to attempt to create the directory and set the permissions','updraftplus').'</a></span>, '.__('or, to reset this option','updraftplus').' <a href="#" onclick="jQuery(\'#updraft_dir\').val(\'updraft\'); return false;">'.__('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>';
3676
+ }
3677
+ return $dir_info;
3678
+ }
3679
 
3680
  private function settings_formcontents($last_backup_html) {
3681
 
3855
 
3856
  <a href="#" onclick="jQuery('#updraftplus_db_decrypt').val(jQuery('#updraft_encryptionphrase').val()); jQuery('#updraft-manualdecrypt-modal').slideToggle(); return false;"><?php _e('You can manually decrypt an encrypted database here.','updraftplus');?></a>
3857
 
3858
+ <div id="updraft-manualdecrypt-modal" class="updraft-hidden">
3859
  <p><h3><?php _e("Manually decrypt a database backup file" ,'updraftplus');?></h3></p>
3860
 
3861
  <?php
3977
  if ($split_every_mb < UPDRAFTPLUS_SPLIT_MIN) $split_every_mb = UPDRAFTPLUS_SPLIT_MIN;
3978
  ?>
3979
 
3980
+ <tr class="expertmode updraft-hidden">
3981
  <th><?php _e('Debug mode','updraftplus');?>:</th>
3982
  <td><input type="checkbox" id="updraft_debug_mode" name="updraft_debug_mode" value="1" <?php echo $debug_mode; ?> /> <br><label for="updraft_debug_mode"><?php _e('Check this to receive more information and emails on the backup process - useful if something is going wrong.','updraftplus');?> <?php _e('This will also cause debugging output from all plugins to be shown upon this screen - please do not be surprised to see these.', 'updraftplus');?></label></td>
3983
  </tr>
3984
 
3985
+ <tr class="expertmode updraft-hidden">
3986
  <th><?php _e('Split archives every:','updraftplus');?></th>
3987
  <td><input type="text" name="updraft_split_every" id="updraft_split_every" value="<?php echo $split_every_mb ?>" size="5" /> Mb<br><?php echo sprintf(__('UpdraftPlus will split up backup archives when they exceed this file size. The default value is %s megabytes. Be careful to leave some margin if your web-server has a hard size limit (e.g. the 2 Gb / 2048 Mb limit on some 32-bit servers/file systems).','updraftplus'), 400); ?></td>
3988
  </tr>
3989
 
3990
+ <tr class="deletelocal expertmode updraft-hidden">
3991
  <th><?php _e('Delete local backup','updraftplus');?>:</th>
3992
  <td><input type="checkbox" id="updraft_delete_local" name="updraft_delete_local" value="1" <?php if ($delete_local) echo 'checked="checked"'; ?>> <br><label for="updraft_delete_local"><?php _e('Check this to delete any superfluous backup files from your server after the backup run finishes (i.e. if you uncheck, then any files despatched remotely will also remain locally, and any files being kept locally will not be subject to the retention limits).','updraftplus');?></label></td>
3993
  </tr>
3994
 
3995
+ <tr class="expertmode backupdirrow updraft-hidden">
3996
  <th><?php _e('Backup directory','updraftplus');?>:</th>
3997
  <td><input type="text" name="updraft_dir" id="updraft_dir" style="width:525px" value="<?php echo htmlspecialchars($this->prune_updraft_dir_prefix($updraft_dir)); ?>" /></td>
3998
  </tr>
3999
+ <tr class="expertmode backupdirrow updraft-hidden">
4000
+ <td></td><td>
4001
+ <span id="updraft_writable_mess">
4002
+ <?php
4003
+ //moved into function for ajax save
4004
+ $dir_info = $this->really_writable_message($really_is_writable, $updraft_dir);
4005
+ echo $dir_info.'</span> '.__("This is where UpdraftPlus will write the zip files it creates initially. This directory must be writable by your web server. It is relative to your content directory (which by default is called wp-content).", 'updraftplus').' '.__("<b>Do not</b> place it inside your uploads or plugins directory, as that will cause recursion (backups of backups of backups of...).",'updraftplus');?></td>
4006
+
 
 
 
 
 
 
 
 
4007
  </tr>
4008
 
4009
+ <tr class="expertmode updraft-hidden">
4010
  <th><?php _e('Use the server\'s SSL certificates','updraftplus');?>:</th>
4011
  <td><input type="checkbox" id="updraft_ssl_useservercerts" name="updraft_ssl_useservercerts" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_useservercerts')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_useservercerts"><?php _e('By default UpdraftPlus uses its own store of SSL certificates to verify the identity of remote sites (i.e. to make sure it is talking to the real Dropbox, Amazon S3, etc., and not an attacker). We keep these up to date. However, if you get an SSL error, then choosing this option (which causes UpdraftPlus to use your web server\'s collection instead) may help.','updraftplus');?></label></td>
4012
  </tr>
4013
 
4014
+ <tr class="expertmode updraft-hidden">
4015
  <th><?php _e('Do not verify SSL certificates','updraftplus');?>:</th>
4016
  <td><input type="checkbox" id="updraft_ssl_disableverify" name="updraft_ssl_disableverify" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_disableverify')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_disableverify"><?php _e('Choosing this option lowers your security by stopping UpdraftPlus from verifying the identity of encrypted sites that it connects to (e.g. Dropbox, Google Drive). It means that UpdraftPlus will be using SSL only for encryption of traffic, and not for authentication.','updraftplus');?> <?php _e('Note that not all cloud backup methods are necessarily using SSL authentication.', 'updraftplus');?></label></td>
4017
  </tr>
4018
 
4019
+ <tr class="expertmode updraft-hidden">
4020
  <th><?php _e('Disable SSL entirely where possible', 'updraftplus');?>:</th>
4021
  <td><input type="checkbox" id="updraft_ssl_nossl" name="updraft_ssl_nossl" value="1" <?php if (UpdraftPlus_Options::get_updraft_option('updraft_ssl_nossl')) echo 'checked="checked"'; ?>> <br><label for="updraft_ssl_nossl"><?php _e('Choosing this option lowers your security by stopping UpdraftPlus from using SSL for authentication and encrypted transport at all, where possible. Note that some cloud storage providers do not allow this (e.g. Dropbox), so with those providers this setting will have no effect.','updraftplus');?> <a href="https://updraftplus.com/faqs/i-get-ssl-certificate-errors-when-backing-up-andor-restoring/"><?php _e('See this FAQ also.', 'updraftplus');?></a></label></td>
4022
  </tr>
4042
  <td></td>
4043
  <td>
4044
  <input type="hidden" name="action" value="update" />
4045
+ <input type="submit" class="button-primary" id="updraftplus-settings-save" value="<?php _e('Save Changes','updraftplus');?>" />
4046
  </td>
4047
  </tr>
4048
  </table>
4067
  if ($show_exclusion_options) {
4068
  $include_exclude = UpdraftPlus_Options::get_updraft_option('updraft_include_'.$key.'_exclude', ('others' == $key) ? UPDRAFT_DEFAULT_OTHERS_EXCLUDE : UPDRAFT_DEFAULT_UPLOADS_EXCLUDE);
4069
 
4070
+ $display = ($included) ? '' : 'class="updraft-hidden"';
4071
 
4072
  $ret .= "<div id=\"".$prefix."updraft_include_".$key."_exclude\" $display>";
4073
 
4165
 
4166
  }
4167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4168
  if ('numeric' == $format) return $size;
4169
 
4170
+ global $updraftplus;
4171
+ return $updraftplus->convert_numeric_size_to_text($size);
 
4172
 
 
 
 
 
 
 
 
 
 
 
4173
  }
4174
 
4175
  private function recursive_directory_size_raw($prefix_directory, &$exclude = array(), $suffix_directory = '') {
4176
 
4177
  $directory = $prefix_directory.('' == $suffix_directory ? '' : '/'.$suffix_directory);
4178
  $size = 0;
4179
+ if (substr($directory, -1) == '/') $directory = substr($directory,0,-1);
4180
 
4181
  if (!file_exists($directory) || !is_dir($directory) || !is_readable($directory)) return -1;
4182
  if (file_exists($directory.'/.donotbackup')) return 0;
4190
  continue;
4191
  }
4192
  $path = $directory.'/'.$file;
4193
+ if (is_file($path)) {
4194
  $size += filesize($path);
4195
+ } elseif (is_dir($path)) {
4196
  $handlesize = $this->recursive_directory_size_raw($prefix_directory, $exclude, $suffix_directory.('' == $suffix_directory ? '' : '/').$file);
4197
+ if ($handlesize >= 0) { $size += $handlesize; }# else { return -1; }
4198
  }
4199
  }
4200
  }
4239
  // }
4240
  }
4241
 
4242
+ $total_size = 0;
4243
+ foreach ($backup as $ekey => $files) {
4244
  if ('db' == strtolower(substr($ekey, 0, 2)) && '-size' != substr($ekey, -5, 5)) {
4245
  $rawbackup .= $updraftplus->printfile(__('Database', 'updraftplus'), $backup, $ekey, array('sha1'), $jd, true);
4246
  }
4247
+ if (!isset($backupable_entities[$ekey]) && ('db' != substr($ekey, 0, 2) || '-size' == substr($ekey, -5, 5))) continue;
4248
+ if (is_string($files)) $files = array($files);
4249
+ foreach ($files as $findex => $file) {
4250
+ $size_key = (0 == $findex) ? $ekey.'-size' : $ekey.$findex.'-size';
4251
+ $total_size = (false === $total_size || !isset($backup[$size_key]) || !is_numeric($backup[$size_key])) ? false : $total_size + $backup[$size_key];
4252
+ }
4253
  }
4254
 
4255
  $services = empty($backup['service']) ? array('none') : $backup['service'];
4271
 
4272
  $rawbackup .= $show_services;
4273
 
4274
+ if ($total_size !== false) {
4275
+ $rawbackup .= '</p><strong>'.__('Total backup size:', 'updraftplus').'</strong> '.$updraftplus->convert_numeric_size_to_text($total_size).'<p>';
4276
+ }
4277
+
4278
+
4279
+
4280
  $rawbackup .= '</p><hr><p><pre>'.print_r($backup, true).'</p></pre>';
4281
 
4282
  if (!empty($jd) && is_array($jd)) {
4301
  if (!is_array($accept)) $accept = array();
4302
 
4303
  $ret = '<table class="existing-backups-table">';
 
4304
 
4305
  //".__('Actions', 'updraftplus')."
4306
  $ret .= "<thead>
4373
  $db = is_array($backup['db']) ? $backup['db'][0] : $backup['db'];
4374
  if ($updraftplus->is_db_encrypted($db)) $entities .= '/dbcrypted=1/';
4375
 
4376
+ $ret .= $this->download_db_button('db', $key, $esc_pretty_date, $backup, $accept);
4377
  } else {
4378
  // $ret .= sprintf(_x('(No %s)','Message shown when no such object is available','updraftplus'), __('database', 'updraftplus'));
4379
  }
4381
  # External databases
4382
  foreach ($backup as $bkey => $binfo) {
4383
  if ('db' == $bkey || 'db' != substr($bkey, 0, 2) || '-size' == substr($bkey, -5, 5)) continue;
4384
+ $ret .= $this->download_db_button($bkey, $key, $esc_pretty_date, $backup);
4385
  }
4386
 
4387
  } else {
4393
  $entities .= '/meta_foreign=2/';
4394
  }
4395
 
4396
+ $download_buttons = $this->download_buttons($backup, $key, $accept, $entities, $esc_pretty_date);
4397
 
4398
  $ret .= $download_buttons;
4399
 
4401
 
4402
  // No logs expected for foreign backups
4403
  if (empty($backup['meta_foreign'])) {
4404
+ // $ret .= '<td>'.$this->log_button($backup)."</td>";
 
 
4405
  }
4406
  }
4407
 
4423
  return $ret;
4424
  }
4425
 
4426
+ private function download_db_button($bkey, $key, $esc_pretty_date, $backup, $accept = array()) {
4427
 
4428
  if (!empty($backup['meta_foreign']) && isset($accept[$backup['meta_foreign']])) {
4429
  $desc_source = $accept[$backup['meta_foreign']]['desc'];
4439
  $dbt = __('External database','updraftplus').' ('.substr($bkey, 2).')';
4440
  }
4441
 
4442
+ $ret .= $this->download_button($bkey, $key, 0, null, '', $dbt, $esc_pretty_date, '0');
4443
+
 
 
 
 
 
 
 
 
 
 
4444
  return $ret;
4445
  }
4446
 
4447
  // Go through each of the file entities
4448
+ private function download_buttons($backup, $key, $accept, &$entities, $esc_pretty_date) {
4449
  global $updraftplus;
4450
  $ret = '';
4451
  $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
4509
  $ide .= __('Press here to download', 'updraftplus').' '.strtolower($info['description']);
4510
  $pdescrip = ($findex > 0) ? $sdescrip.' ('.($findex+1).')' : $sdescrip;
4511
  if (!$first_printed) {
4512
+ $ret .= '<div class="updraft-hidden">';
4513
  }
4514
  if (count($backup[$type]) >0) {
4515
  $ide .= ' '.sprintf(__('(%d archive(s) in set).', 'updraftplus'), $howmanyinset);
4524
  $first_entity = false;
4525
  }
4526
 
4527
+ $ret .= $this->download_button($type, $key, $findex, $info, $ide, $pdescrip, $esc_pretty_date, $set_contents);
4528
 
4529
  if (!$first_printed) {
4530
  $ret .= '</div>';
4554
  return $ret;
4555
  }
4556
 
4557
+ private function download_button($type, $backup_timestamp, $findex, $info, $ide, $pdescrip, $esc_pretty_date, $set_contents) {
4558
+
4559
+ $ret = '';
4560
+
4561
+ $wp_nonce = wp_create_nonce('updraftplus_download');
4562
+
4563
+ // updraft_downloader(base, backup_timestamp, what, whicharea, set_contents, prettydate, async)
4564
+ $ret .= '<button data-wp_nonce="'.esc_attr($wp_nonce).'" data-backup_timestamp="'.esc_attr($backup_timestamp).'" data-what="'.esc_attr($type).'" data-set_contents="'.esc_attr($set_contents).'" data-prettydate="'.esc_attr($esc_pretty_date).'" type="button" class="updraft_download_button '."uddownloadform_${type}_${backup_timestamp}_${findex}".'" title="'.$ide.'">'.$pdescrip.'</button>';
4565
+ // onclick="'."return updraft_downloader('uddlstatus_', '$backup_timestamp', '$type', '.ud_downloadstatus', '$set_contents', '$esc_pretty_date', true)".'"
4566
+
4567
+
4568
+ // Pre 1.11.24
4569
+ // $nonce_field = wp_nonce_field('updraftplus_download', '_wpnonce', true, false);
4570
+ // $ret .= <<<ENDHERE
4571
+ // <form class="uddownloadform_${type}_${backup_timestamp}_${findex}" action="admin-ajax.php" onsubmit="return updraft_downloader('uddlstatus_', '$backup_timestamp', '$type', '.ud_downloadstatus', '$set_contents', '$esc_pretty_date', true)" method="post">
4572
+ // $nonce_field
4573
+ // <input type="hidden" name="action" value="updraft_download_backup" />
4574
+ // <input type="hidden" name="type" value="$type" />
4575
+ // <input type="hidden" name="timestamp" value="$backup_timestamp" />
4576
+ // <input type="hidden" name="findex" value="$findex" />
4577
+ // <input type="submit" class="updraft-backupentitybutton" title="$ide" value="$pdescrip" />
4578
+ // </form>
4579
+ // </div>
4580
+ // ENDHERE;
4581
  return $ret;
4582
  }
4583
 
4584
+ private function restore_button($backup, $key, $pretty_date, $entities = '') {
4585
+ $ret = '<div class="restore-button">';
 
 
 
 
 
 
 
 
 
 
 
 
 
4586
 
4587
+ if ($entities) {
4588
+ $show_data = $pretty_date;
4589
+ if (isset($backup['native']) && false == $backup['native']) {
4590
+ $show_data .= ' '.__('(backup set imported from remote location)', 'updraftplus');
4591
  }
4592
+
4593
+ $ret .= '<button data-showdata="'.esc_attr($show_data).'" data-backup_timestamp="'.$key.'" data-entities="'.esc_attr($entities).'" title="'.__('After pressing this button, you will be given the option to choose which components you wish to restore','updraftplus').'" type="button" style="float:left; clear:none;" class="button-primary choose-components-button">'.__('Restore', 'updraftplus').'</button>';
4594
+ }
4595
+ $ret .= "</div>\n";
4596
  return $ret;
4597
  }
4598
 
4599
  private function delete_button($key, $nonce, $backup) {
4600
  $sval = ((isset($backup['service']) && $backup['service'] != 'email' && $backup['service'] != 'none')) ? '1' : '0';
4601
+ return '<div class="updraftplus-remove" style="float: left; clear: none;" data-hasremote="'.$sval.'">
4602
+ <a data-hasremote="'.$sval.'" data-nonce="'.$nonce.'" data-key="'.$key.'" class="no-decoration updraft-delete-link" href="#" title="'.esc_attr(__('Delete this backup set', 'updraftplus')).'">'.__('Delete', 'updraftplus').'</a>
4603
+ </div>';
 
4604
  }
4605
 
4606
  private function log_button($backup) {
4609
  $ret = '';
4610
  if (isset($backup['nonce']) && preg_match("/^[0-9a-f]{12}$/",$backup['nonce']) && is_readable($updraft_dir.'/log.'.$backup['nonce'].'.txt')) {
4611
  $nval = $backup['nonce'];
4612
+ // $lt = esc_attr(__('View Log','updraftplus'));
4613
+ $lt = __('View Log','updraftplus');
4614
+ $url = esc_attr(UpdraftPlus_Options::admin_page()."?page=updraftplus&action=downloadlog&amp;updraftplus_backup_nonce=$nval");
4615
  $ret .= <<<ENDHERE
4616
  <div style="clear:none;" class="updraft-viewlogdiv">
4617
+ <a class="no-decoration updraft-log-link" href="$url" data-jobid="$nval">
4618
+ $lt
4619
+ </a>
4620
+ <!--
4621
+ <form action="$url" method="get">
4622
+ <input type="hidden" name="action" value="downloadlog" />
4623
+ <input type="hidden" name="page" value="updraftplus" />
4624
+ <input type="hidden" name="updraftplus_backup_nonce" value="$nval" />
4625
+ <input type="submit" value="$lt" class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('$nval');" />
4626
+ </form>
4627
+ -->
4628
  </div>
4629
  ENDHERE;
4630
  return $ret;
4835
 
4836
  add_action('http_request_args', array($updraftplus, 'modify_http_options'));
4837
  foreach ($service as $serv) {
4838
+ if (!is_readable($fullpath)) {
4839
  $sd = (empty($updraftplus->backup_methods[$serv])) ? $serv : $updraftplus->backup_methods[$serv];
4840
  echo __("File is not locally present - needs retrieving from remote storage",'updraftplus')." ($sd)";
4841
  $this->download_file($file, $serv);
5063
  if (!is_array($input)) $input = array();
5064
  return $input;
5065
  }
5066
+
5067
+ public function updraft_ajax_savesettings() {
5068
+ global $updraftplus;
5069
+
5070
+ if (empty($_POST) || empty($_POST['subaction']) || 'savesettings' != $_POST['subaction'] || !isset($_POST['nonce']) || !is_user_logged_in() || !UpdraftPlus_Options::user_can_manage() || !wp_verify_nonce($_POST['nonce'], 'updraftplus-settings-nonce')) die('Security check');
5071
+
5072
+ if (empty($_POST['settings']) || !is_string($_POST['settings'])) die('Invalid data');
5073
+
5074
+ parse_str($_POST['settings'], $posted_settings);
5075
+ // We now have $posted_settings as an array
5076
+
5077
+ echo json_encode($this->save_settings($posted_settings));
5078
+
5079
+ die;
5080
+ }
5081
+
5082
+ private function backup_now_remote_message() {
5083
+ global $updraftplus;
5084
+
5085
+ $service = $updraftplus->just_one(UpdraftPlus_Options::get_updraft_option('updraft_service'));
5086
+ if (is_string($service)) $service = array($service);
5087
+ if (!is_array($service)) $service = array();
5088
 
5089
+ $no_remote_configured = (empty($service) || array('none') === $service || array('') === $service) ? true : false;
5090
+
5091
+ if ($no_remote_configured) {
5092
+ return '<input type="checkbox" disabled="disabled" id="backupnow_includecloud"> <label for="backupnow_includecloud"><em>'.sprintf(__("Backup won't be sent to any remote storage - none has been saved in the %s", 'updraftplus'), '<a href="'.UpdraftPlus_Options::admin_page_url().'?page=updraftplus&amp;tab=settings" id="updraft_backupnow_gotosettings">'.__('settings', 'updraftplus')).'</a>. '.__('Not got any remote storage?', 'updraftplus').' <a href="https://updraftplus.com/support/updraftplus-vault-faqs/">'.__("Check out UpdraftPlus Vault.", 'updraftplus').'</a></em></label>';
5093
+ } else {
5094
+ return '<input type="checkbox" id="backupnow_includecloud" checked="checked"> <label for="backupnow_includecloud">'.__("Send this backup to remote storage", 'updraftplus').'</label>';
5095
+ }
5096
+ }
5097
+
5098
+
5099
+
5100
+ public function save_settings($settings) {
5101
+
5102
+ global $updraftplus;
5103
+
5104
+ $return_array = array('saved' => true, 'changed' => array());
5105
+
5106
+ $add_to_post_keys = array('updraft_interval', 'updraft_interval_database', 'updraft_starttime_files', 'updraft_starttime_db', 'updraft_startday_files', 'updraft_startday_db');
5107
+
5108
+ //If database and files are on same schedule, override the db day/time settings
5109
+ if (isset($settings['updraft_interval_database']) && isset($settings['updraft_interval_database']) && $settings['updraft_interval_database'] == $settings['updraft_interval'] && isset($settings['updraft_starttime_files'])) {
5110
+ $settings['updraft_starttime_db'] = $settings['updraft_starttime_files'];
5111
+ $settings['updraft_startday_db'] = $settings['updraft_startday_files'];
5112
+ }
5113
+ foreach ($add_to_post_keys as $key) {
5114
+ // For add-ons that look at $_POST to find saved settings, add the relevant keys to $_POST so that they find them there
5115
+ if (isset($settings[$key])) {
5116
+ $_POST[$key] = $settings[$key];
5117
+ }
5118
+ }
5119
+
5120
+ // Wipe the extra retention rules, as they are not saved correctly if the last one is deleted
5121
+ UpdraftPlus_Options::update_updraft_option('updraft_retain_extrarules', array());
5122
+ UpdraftPlus_Options::update_updraft_option('updraft_email', array());
5123
+ UpdraftPlus_Options::update_updraft_option('updraft_report_warningsonly', array());
5124
+ UpdraftPlus_Options::update_updraft_option('updraft_report_wholebackup', array());
5125
+ UpdraftPlus_Options::update_updraft_option('updraft_extradbs', array());
5126
+ UpdraftPlus_Options::update_updraft_option('updraft_include_more_path', array());
5127
+
5128
+ $relevant_keys = $updraftplus->get_settings_keys();
5129
+
5130
+ foreach ($settings as $key => $value) {
5131
+ // $exclude_keys = array('option_page', 'action', '_wpnonce', '_wp_http_referer');
5132
+
5133
+ // if (!in_array($key, $exclude_keys)) {
5134
+ if (in_array($key, $relevant_keys)) {
5135
+ if ($key == "updraft_service" && is_array($value)){
5136
+ foreach ($value as $subkey => $subvalue){
5137
+ if ($subvalue == '0') unset($value[$subkey]);
5138
+ }
5139
+ }
5140
+
5141
+ $updated = UpdraftPlus_Options::update_updraft_option($key, $value);
5142
+
5143
+ // Add information on what has changed to array to loop through to update links etc.
5144
+ if ($updated){
5145
+ $return_array['changed'][$key] = $value;
5146
+ } elseif ($key == 'updraft_interval'){ //To schedule a database when the interval is not changed.
5147
+ $updraftplus->schedule_backup($value);
5148
+ } elseif ($key == 'updraft_interval_database'){
5149
+ $updraftplus->schedule_backup_database($value);
5150
+ }
5151
+ } else {
5152
+ // When last active, it was catching: option_page, action, _wpnonce, _wp_http_referer, updraft_s3_endpoint, updraft_dreamobjects_endpoint. The latter two are empty; probably don't need to be in the page at all.
5153
+ //error_log("Non-UD key when saving from POSTed data: ".$key);
5154
+ }
5155
+ }
5156
+
5157
+ // Checking for various possible messages
5158
+ $updraft_dir = $updraftplus->backups_dir_location();
5159
+ $really_is_writable = $updraftplus->really_is_writable($updraft_dir);
5160
+ $dir_info = $this->really_writable_message($really_is_writable, $updraft_dir);
5161
+ $button_title = esc_attr(__('This button is disabled because your backup directory is not writable (see the settings).', 'updraftplus'));
5162
+
5163
+ $return_array['backup_now_message'] = $this->backup_now_remote_message();
5164
+
5165
+ $return_array['backup_dir'] = array('writable' => $really_is_writable, 'message' => $dir_info, 'button_title' => $button_title);
5166
+
5167
+ //Because of the single AJAX call, we need to remove the existing UD messages from the 'all_admin_notices' action
5168
+ remove_all_actions('all_admin_notices');
5169
+
5170
+ //Moving from 2 to 1 ajax call
5171
+ ob_start();
5172
+
5173
+ $service = UpdraftPlus_Options::get_updraft_option('updraft_service');
5174
+
5175
+ $this->setup_all_admin_notices_global($service);
5176
+ $this->setup_all_admin_notices_udonly($service);
5177
+
5178
+ do_action('all_admin_notices');
5179
+
5180
+ if (!$really_is_writable){ //Check if writable
5181
+ $this->show_admin_warning_unwritable();
5182
+ }
5183
+
5184
+ if ($return_array['saved'] == true){ //
5185
+ $this->show_admin_warning(__('Your settings have been saved.', 'updraftplus'), 'updated fade');
5186
+ }
5187
+
5188
+ $messages_output = ob_get_contents();
5189
+
5190
+ ob_clean();
5191
+
5192
+ // Backup schedule output
5193
+ $this->next_scheduled_backups_output();
5194
+
5195
+ $scheduled_output = ob_get_clean();
5196
+
5197
+ $return_array['messages'] = $messages_output;
5198
+ $return_array['scheduled'] = $scheduled_output;
5199
+
5200
+ return $return_array;
5201
+
5202
+ }
5203
+
5204
  }
backup.php CHANGED
@@ -391,6 +391,15 @@ class UpdraftPlus_Backup {
391
 
392
  }
393
 
 
 
 
 
 
 
 
 
 
394
  // $services *must* be an array
395
  public function prune_retained_backups($services) {
396
 
@@ -422,11 +431,11 @@ class UpdraftPlus_Backup {
422
 
423
  // Number of backups to retain - files
424
  $updraft_retain = UpdraftPlus_Options::get_updraft_option('updraft_retain', 2);
425
- $updraft_retain = (is_numeric($updraft_retain)) ? $updraft_retain : 1;
426
 
427
  // Number of backups to retain - db
428
  $updraft_retain_db = UpdraftPlus_Options::get_updraft_option('updraft_retain_db', $updraft_retain);
429
- $updraft_retain_db = (is_numeric($updraft_retain_db)) ? $updraft_retain_db : 1;
430
 
431
  $updraftplus->log("Retain: beginning examination of existing backup sets; user setting: retain_files=$updraft_retain, retain_db=$updraft_retain_db");
432
 
@@ -434,7 +443,20 @@ class UpdraftPlus_Backup {
434
  $backup_history = $updraftplus->get_backup_history();
435
  $db_backups_found = 0;
436
  $file_backups_found = 0;
437
- $updraftplus->log("Number of backup sets in history: ".count($backup_history));
 
 
 
 
 
 
 
 
 
 
 
 
 
438
 
439
  $backupable_entities = $updraftplus->get_backupable_file_entities(true);
440
 
@@ -445,117 +467,64 @@ class UpdraftPlus_Backup {
445
  $file_entities_backups_found[$entity] = 0;
446
  }
447
 
448
- // The array returned by UpdraftPlus::get_backup_history() is already sorted, with most-recent first
449
- foreach ($backup_history as $backup_datestamp => $backup_to_examine) {
450
-
451
- $files_to_prune = array();
452
-
453
- // $backup_to_examine is an array of file names, keyed on db/plugins/themes/uploads
454
- // The new backup_history array is saved afterwards, so remember to unset the ones that are to be deleted
455
- $updraftplus->log(sprintf("Examining backup set with datestamp: %s (%s)", $backup_datestamp, gmdate('M d Y H:i:s', $backup_datestamp)));
456
-
457
- if (isset($backup_to_examine['native']) && false == $backup_to_examine['native']) {
458
- $updraftplus->log("This backup set ($backup_datestamp) was imported from a remote location, so will not be counted or pruned. Skipping.");
459
- continue;
460
- }
461
-
462
- // Auto-backups are only counted or deleted once we have reached the retain limit - before that, they are skipped
463
- $is_autobackup = (isset($backup_to_examine['autobackup']) && true == $backup_to_examine['autobackup']);
464
-
465
- $remote_sent = (!empty($backup_to_examine['service']) && ((is_array($backup_to_examine['service']) && in_array('remotesend', $backup_to_examine['service'])) || 'remotesend' === $backup_to_examine['service'])) ? true : false;
466
-
467
- $any_deleted_via_filter_yet = false;
468
-
469
- # Databases
470
- foreach ($backup_to_examine as $key => $data) {
471
- if ('db' != strtolower(substr($key, 0, 2)) || '-size' == substr($key, -5, 5)) continue;
472
 
473
- if (empty($database_backups_found[$key])) $database_backups_found[$key] = 0;
474
-
475
- if (!empty($backup_to_examine['nonce']) && $backup_to_examine['nonce'] == $updraftplus->nonce) {
476
- $updraftplus->log("This backup set ($backup_datestamp) is the backup set just made, so will not be deleted.");
477
- $database_backups_found[$key]++;
478
- continue;
479
- }
480
-
481
- if ($is_autobackup) {
482
- if ($any_deleted_via_filter_yet) {
483
- $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
484
- $prune_it = true;
485
- } elseif ($database_backups_found[$key] < $updraft_retain_db) {
486
- $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, and we have not yet reached any retain limits, so it will not be counted or pruned. Skipping.");
487
- continue;
488
- } else {
489
- $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, and we have already reached retain limits, so it will be pruned.");
490
- $prune_it = true;
491
- }
492
- } else {
493
- $prune_it = false;
494
- }
495
 
496
- if ($remote_sent) {
497
- $prune_it = true;
498
- $updraftplus->log("$backup_datestamp: $key: was sent to remote site; will remove from local record (only)");
499
- }
500
-
501
- // All non-auto backups must be run through this filter (in date order) regardless of the current state of $prune_it - so that filters are able to track state.
502
- $prune_it_before_filter = $prune_it;
503
 
504
- if (!$is_autobackup) $prune_it = apply_filters('updraftplus_prune_or_not', $prune_it, 'db', $backup_datestamp, $database_backups_found[$key], $key, $data, $updraft_retain_db);
 
 
 
 
 
 
505
 
506
- // Apply the final retention limit list (do not increase the 'retained' counter before seeing if the backup is being pruned for some other reason)
507
- if (!$prune_it && !$is_autobackup) {
508
 
509
- if ($database_backups_found[$key] + 1 > $updraft_retain_db) {
510
- $prune_it = true;
 
511
 
512
- $fname = (is_string($data)) ? $data : $data[0];
513
- $updraftplus->log("$backup_datestamp: $key: this set includes a database (".$fname."); db count is now ".$database_backups_found[$key]);
 
 
 
514
 
515
- $updraftplus->log("$backup_datestamp: $key: over retain limit ($updraft_retain_db); will delete this database");
516
- }
517
-
518
- }
519
-
520
- if ($prune_it) {
521
- if (!$prune_it_before_filter) $any_deleted_via_filter_yet = true;
522
-
523
- if (!empty($data)) {
524
- $size_key = $key.'-size';
525
- $size = isset($backup_to_examine[$size_key]) ? $backup_to_examine[$size_key] : null;
526
- foreach ($services as $service => $sd) {
527
- $this->prune_file($service, $data, $sd[0], $sd[1], array($size));
528
- }
529
- }
530
- unset($backup_to_examine[$key]);
531
- $updraftplus->record_still_alive();
532
- } elseif (!$is_autobackup) {
533
- $database_backups_found[$key]++;
534
- }
535
 
536
- }
537
 
538
- $any_deleted_via_filter_yet = false;
539
 
540
- $file_sizes = array();
 
 
541
 
542
- # Files
543
- foreach ($backupable_entities as $entity => $info) {
544
- if (!empty($backup_to_examine[$entity])) {
545
-
546
- // This should only be able to happen if you import backups with a future timestamp
547
- if (!empty($backup_to_examine['nonce']) && $backup_to_examine['nonce'] == $updraftplus->nonce) {
548
- $updraftplus->log("This backup set ($backup_datestamp) is the backup set just made, so will not be deleted, despite being over the retain limit.");
549
- $file_entities_backups_found[$entity]++;
550
  continue;
551
  }
552
-
553
-
554
  if ($is_autobackup) {
555
  if ($any_deleted_via_filter_yet) {
556
  $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
557
  $prune_it = true;
558
- } elseif ($file_entities_backups_found[$entity] < $updraft_retain) {
559
  $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, and we have not yet reached any retain limits, so it will not be counted or pruned. Skipping.");
560
  continue;
561
  } else {
@@ -568,89 +537,188 @@ class UpdraftPlus_Backup {
568
 
569
  if ($remote_sent) {
570
  $prune_it = true;
 
571
  }
572
-
573
  // All non-auto backups must be run through this filter (in date order) regardless of the current state of $prune_it - so that filters are able to track state.
574
  $prune_it_before_filter = $prune_it;
575
- if (!$is_autobackup) $prune_it = apply_filters('updraftplus_prune_or_not', $prune_it, 'files', $backup_datestamp, $file_entities_backups_found[$entity], $entity, $data, $updraft_retain);
576
 
577
- // The "more than maximum to keep?" counter should not be increased until we actually know that the set is being kept. Before verison 1.11.22, we checked this before running the filter, which resulted in the counter being increased for sets that got pruned via the filter (i.e. not kept) - and too many backups were thus deleted
 
 
578
  if (!$prune_it && !$is_autobackup) {
579
- if ($file_entities_backups_found[$entity] >= $updraft_retain) {
580
- $updraftplus->log("$entity: $backup_datestamp: over retain limit ($updraft_retain); will delete this file entity");
581
  $prune_it = true;
 
 
 
 
 
582
  }
 
583
  }
584
 
585
  if ($prune_it) {
586
  if (!$prune_it_before_filter) $any_deleted_via_filter_yet = true;
587
- $prune_this = $backup_to_examine[$entity];
588
- if (is_string($prune_this)) $prune_this = array($prune_this);
589
 
590
- foreach ($prune_this as $k => $prune_file) {
591
- if ($remote_sent) {
592
- $updraftplus->log("$entity: $backup_datestamp: was sent to remote site; will remove from local record (only)");
 
 
593
  }
594
- $size_key = (0 == $k) ? $entity.'-size' : $entity.$k.'-size';
595
- $size = (isset($backup_to_examine[$size_key])) ? $backup_to_examine[$size_key] : null;
596
- $files_to_prune[] = $prune_file;
597
- $file_sizes[] = $size;
598
  }
599
- unset($backup_to_examine[$entity]);
600
-
601
  } elseif (!$is_autobackup) {
602
- $file_entities_backups_found[$entity]++;
603
  }
604
- }
605
- }
606
 
607
- // Sending an empty array is not itself a problem - except that the remote storage method may not check that before setting up a connection, which can waste time: especially if this is done every time around the loop.
608
- if (!empty($files_to_prune)) {
609
- # Actually delete the files
610
- foreach ($services as $service => $sd) {
611
- $this->prune_file($service, $files_to_prune, $sd[0], $sd[1], $file_sizes);
612
- $updraftplus->record_still_alive();
 
 
613
  }
614
  }
 
615
 
616
- // Get new result, post-deletion; anything left in this set?
617
- $contains_files = 0;
618
- foreach ($backupable_entities as $entity => $info) {
619
- if (isset($backup_to_examine[$entity])) {
620
- $contains_files = 1;
621
- break;
622
- }
623
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
624
 
625
- $contains_db = 0;
626
- foreach ($backup_to_examine as $key => $data) {
627
- if ('db' == strtolower(substr($key, 0, 2)) && '-size' != substr($key, -5, 5)) {
628
- $contains_db = 1;
629
- break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
  }
631
- }
632
 
633
- // Delete backup set completely if empty, o/w just remove DB
634
- // We search on the four keys which represent data, allowing other keys to be used to track other things
635
- if (!$contains_files && !$contains_db) {
636
- $updraftplus->log("$backup_datestamp: this backup set is now empty; will remove from history");
637
- unset($backup_history[$backup_datestamp]);
638
- if (isset($backup_to_examine['nonce'])) {
639
- $fullpath = $this->updraft_dir.'/log.'.$backup_to_examine['nonce'].'.txt';
640
- if (is_file($fullpath)) {
641
- $updraftplus->log("$backup_datestamp: deleting log file (log.".$backup_to_examine['nonce'].".txt)");
642
- @unlink($fullpath);
643
- } else {
644
- $updraftplus->log("$backup_datestamp: corresponding log file not found - must have already been deleted");
645
  }
 
 
 
 
 
 
646
  } else {
647
- $updraftplus->log("$backup_datestamp: no nonce record found in the backup set, so cannot delete any remaining log file");
 
648
  }
649
- } else {
650
- $updraftplus->log("$backup_datestamp: this backup set remains non-empty ($contains_files/$contains_db); will retain in history");
651
- $backup_history[$backup_datestamp] = $backup_to_examine;
652
  }
653
- # Loop over backup sets
 
654
  }
655
 
656
  $updraftplus->log("Retain: saving new backup history (sets now: ".count($backup_history).") and finishing retain operation");
@@ -660,6 +728,51 @@ class UpdraftPlus_Backup {
660
 
661
  }
662
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
663
  # $dofiles: An array of files (or a single string for one file)
664
  private function prune_file($service, $dofiles, $method_object = null, $object_passback = null, $file_sizes = array()) {
665
  global $updraftplus;
@@ -1188,7 +1301,7 @@ class UpdraftPlus_Backup {
1188
  - When the writing finishes, it is renamed to ($final_filename).table
1189
  - When all tables are finished, they are concatenated into the final file
1190
  */
1191
- # dbinfo is only used when whichdb != 'wp'; and the keys should be: user, pass, name, host, prefix
1192
  public function backup_db($already_done = 'begun', $whichdb = 'wp', $dbinfo = array()) {
1193
 
1194
  global $updraftplus, $wpdb;
391
 
392
  }
393
 
394
+ private function group_backups($backup_history) {
395
+ return array(array('sets' => $backup_history, 'process_order' => 'keep_newest'));
396
+ // $groups = array();
397
+ // foreach ($backup_history as $k => $v) {
398
+ // $groups[] = array('sets' => array($k => $v));
399
+ // }
400
+ // return $groups;
401
+ }
402
+
403
  // $services *must* be an array
404
  public function prune_retained_backups($services) {
405
 
431
 
432
  // Number of backups to retain - files
433
  $updraft_retain = UpdraftPlus_Options::get_updraft_option('updraft_retain', 2);
434
+ $updraft_retain = is_numeric($updraft_retain) ? $updraft_retain : 1;
435
 
436
  // Number of backups to retain - db
437
  $updraft_retain_db = UpdraftPlus_Options::get_updraft_option('updraft_retain_db', $updraft_retain);
438
+ $updraft_retain_db = is_numeric($updraft_retain_db) ? $updraft_retain_db : 1;
439
 
440
  $updraftplus->log("Retain: beginning examination of existing backup sets; user setting: retain_files=$updraft_retain, retain_db=$updraft_retain_db");
441
 
443
  $backup_history = $updraftplus->get_backup_history();
444
  $db_backups_found = 0;
445
  $file_backups_found = 0;
446
+
447
+ $ignored_because_imported = array();
448
+
449
+ // Remove non-native (imported) backups, which are neither counted nor pruned. It's neater to do these in advance, and log only one line.
450
+ $functional_backup_history = $backup_history;
451
+ foreach ($functional_backup_history as $backup_time => $backup_to_examine) {
452
+ if (isset($backup_to_examine['native']) && false == $backup_to_examine['native']) {
453
+ $ignored_because_imported[] = $backup_time;
454
+ unset($functional_backup_history[$backup_time]);
455
+ }
456
+ }
457
+ if (!empty($ignored_because_imported)) {
458
+ $updraftplus->log("These backup set(s) were imported from a remote location, so will not be counted or pruned. Skipping: ".implode(', ', $ignored_because_imported));
459
+ }
460
 
461
  $backupable_entities = $updraftplus->get_backupable_file_entities(true);
462
 
467
  $file_entities_backups_found[$entity] = 0;
468
  }
469
 
470
+ if (false === ($backup_db_groups = apply_filters('updraftplus_group_backups_for_pruning', false, $functional_backup_history, 'db'))) {
471
+ $backup_db_groups = $this->group_backups($functional_backup_history);
472
+ }
473
+ $updraftplus->log("Number of backup sets in history: ".count($backup_history)."; groups (db): ".count($backup_db_groups));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
 
475
+ foreach ($backup_db_groups as $group_id => $group) {
476
+
477
+ // The array returned by UpdraftPlus::get_backup_history() is already sorted, with most-recent first
478
+ // foreach ($backup_history as $backup_datestamp => $backup_to_examine) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
479
 
480
+ if (empty($group['sets']) || !is_array($group['sets'])) continue;
481
+ $sets = $group['sets'];
 
 
 
 
 
482
 
483
+ // Sort the groups into the desired "keep this first" order
484
+ $process_order = (!empty($group['process_order']) && 'keep_oldest' == $group['process_order']) ? 'keep_oldest' : 'keep_newest';
485
+ if ('keep_oldest' == $process_order) ksort($sets);
486
+
487
+ $rule = !empty($group['rule']) ? $group['rule'] : array('after-howmany' => 0, 'after-period' => 0, 'every-period' => 1, 'every-howmany' => 1);
488
+
489
+ foreach ($sets as $backup_datestamp => $backup_to_examine) {
490
 
491
+ $files_to_prune = array();
492
+ $nonce = empty($backup_to_examine['nonce']) ? '???' : $backup_to_examine['nonce'];
493
 
494
+ // $backup_to_examine is an array of file names, keyed on db/plugins/themes/uploads
495
+ // The new backup_history array is saved afterwards, so remember to unset the ones that are to be deleted
496
+ $updraftplus->log(sprintf("Examining (for databases) backup set with group_id=$group_id, nonce=%s, datestamp=%s (%s)", $nonce, $backup_datestamp, gmdate('M d Y H:i:s', $backup_datestamp)));
497
 
498
+ // This was already done earlier
499
+ // if (isset($backup_to_examine['native']) && false == $backup_to_examine['native']) {
500
+ // $updraftplus->log("This backup set was imported from a remote location, so will not be counted or pruned. Skipping.");
501
+ // continue;
502
+ // }
503
 
504
+ // Auto-backups are only counted or deleted once we have reached the retain limit - before that, they are skipped
505
+ $is_autobackup = !empty($backup_to_examine['autobackup']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
 
507
+ $remote_sent = (!empty($backup_to_examine['service']) && ((is_array($backup_to_examine['service']) && in_array('remotesend', $backup_to_examine['service'])) || 'remotesend' === $backup_to_examine['service'])) ? true : false;
508
 
509
+ $any_deleted_via_filter_yet = false;
510
 
511
+ // Databases
512
+ foreach ($backup_to_examine as $key => $data) {
513
+ if ('db' != strtolower(substr($key, 0, 2)) || '-size' == substr($key, -5, 5)) continue;
514
 
515
+ if (empty($database_backups_found[$key])) $database_backups_found[$key] = 0;
516
+
517
+ if ($nonce == $updraftplus->nonce) {
518
+ $updraftplus->log("This backup set is the backup set just made, so will not be deleted.");
519
+ $database_backups_found[$key]++;
 
 
 
520
  continue;
521
  }
522
+
 
523
  if ($is_autobackup) {
524
  if ($any_deleted_via_filter_yet) {
525
  $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
526
  $prune_it = true;
527
+ } elseif ($database_backups_found[$key] < $updraft_retain_db) {
528
  $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, and we have not yet reached any retain limits, so it will not be counted or pruned. Skipping.");
529
  continue;
530
  } else {
537
 
538
  if ($remote_sent) {
539
  $prune_it = true;
540
+ $updraftplus->log("$backup_datestamp: $key: was sent to remote site; will remove from local record (only)");
541
  }
542
+
543
  // All non-auto backups must be run through this filter (in date order) regardless of the current state of $prune_it - so that filters are able to track state.
544
  $prune_it_before_filter = $prune_it;
 
545
 
546
+ if (!$is_autobackup) $prune_it = apply_filters('updraftplus_prune_or_not', $prune_it, 'db', $backup_datestamp, $key, $database_backups_found[$key], $rule, $group_id);
547
+
548
+ // Apply the final retention limit list (do not increase the 'retained' counter before seeing if the backup is being pruned for some other reason)
549
  if (!$prune_it && !$is_autobackup) {
550
+
551
+ if ($database_backups_found[$key] + 1 > $updraft_retain_db) {
552
  $prune_it = true;
553
+
554
+ $fname = (is_string($data)) ? $data : $data[0];
555
+ $updraftplus->log("$backup_datestamp: $key: this set includes a database (".$fname."); db count is now ".$database_backups_found[$key]);
556
+
557
+ $updraftplus->log("$backup_datestamp: $key: over retain limit ($updraft_retain_db); will delete this database");
558
  }
559
+
560
  }
561
 
562
  if ($prune_it) {
563
  if (!$prune_it_before_filter) $any_deleted_via_filter_yet = true;
 
 
564
 
565
+ if (!empty($data)) {
566
+ $size_key = $key.'-size';
567
+ $size = isset($backup_to_examine[$size_key]) ? $backup_to_examine[$size_key] : null;
568
+ foreach ($services as $service => $sd) {
569
+ $this->prune_file($service, $data, $sd[0], $sd[1], array($size));
570
  }
 
 
 
 
571
  }
572
+ unset($backup_to_examine[$key]);
573
+ $updraftplus->record_still_alive();
574
  } elseif (!$is_autobackup) {
575
+ $database_backups_found[$key]++;
576
  }
 
 
577
 
578
+ $backup_to_examine = $this->remove_backup_set_if_empty($backup_to_examine, $backup_datestamp, $backupable_entities, $backup_history);
579
+ if (empty($backup_to_examine)) {
580
+ unset($functional_backup_history[$backup_datestamp]);
581
+ unset($backup_history[$backup_datestamp]);
582
+ } else {
583
+ $functional_backup_history[$backup_datestamp] = $backup_to_examine;
584
+ $backup_history[$backup_datestamp] = $backup_to_examine;
585
+ }
586
  }
587
  }
588
+ }
589
 
590
+ if (false === ($backup_files_groups = apply_filters('updraftplus_group_backups_for_pruning', false, $functional_backup_history, 'files'))) {
591
+ $backup_files_groups = $this->group_backups($functional_backup_history);
592
+ }
593
+
594
+ $updraftplus->log("Number of backup sets in history: ".count($backup_history)."; groups (files): ".count($backup_files_groups));
595
+
596
+ // Now again - this time for the files
597
+ foreach ($backup_files_groups as $group_id => $group) {
598
+
599
+ // The array returned by UpdraftPlus::get_backup_history() is already sorted, with most-recent first
600
+ // foreach ($backup_history as $backup_datestamp => $backup_to_examine) {
601
+
602
+ if (empty($group['sets']) || !is_array($group['sets'])) continue;
603
+ $sets = $group['sets'];
604
+
605
+ // Sort the groups into the desired "keep this first" order
606
+ $process_order = (!empty($group['process_order']) && 'keep_oldest' == $group['process_order']) ? 'keep_oldest' : 'keep_newest';
607
+ // Youngest - i.e. smallest epoch - first
608
+ if ('keep_oldest' == $process_order) ksort($sets);
609
+
610
+ $rule = !empty($group['rule']) ? $group['rule'] : array('after-howmany' => 0, 'after-period' => 0, 'every-period' => 1, 'every-howmany' => 1);
611
+
612
+ foreach ($sets as $backup_datestamp => $backup_to_examine) {
613
+
614
+ $files_to_prune = array();
615
+ $nonce = empty($backup_to_examine['nonce']) ? '???' : $backup_to_examine['nonce'];
616
+
617
+ // $backup_to_examine is an array of file names, keyed on db/plugins/themes/uploads
618
+ // The new backup_history array is saved afterwards, so remember to unset the ones that are to be deleted
619
+ $updraftplus->log(sprintf("Examining (for files) backup set with nonce=%s, datestamp=%s (%s)", $nonce, $backup_datestamp, gmdate('M d Y H:i:s', $backup_datestamp)));
620
+
621
+ // This was already done earlier
622
+ // if (isset($backup_to_examine['native']) && false == $backup_to_examine['native']) {
623
+ // $updraftplus->log("This backup set was imported from a remote location, so will not be counted or pruned. Skipping.");
624
+ // continue;
625
+ // }
626
+
627
+ // Auto-backups are only counted or deleted once we have reached the retain limit - before that, they are skipped
628
+ $is_autobackup = !empty($backup_to_examine['autobackup']);
629
+
630
+ $remote_sent = (!empty($backup_to_examine['service']) && ((is_array($backup_to_examine['service']) && in_array('remotesend', $backup_to_examine['service'])) || 'remotesend' === $backup_to_examine['service'])) ? true : false;
631
+
632
+ $any_deleted_via_filter_yet = false;
633
+
634
+ $file_sizes = array();
635
 
636
+ // Files
637
+ foreach ($backupable_entities as $entity => $info) {
638
+ if (!empty($backup_to_examine[$entity])) {
639
+
640
+ // This should only be able to happen if you import backups with a future timestamp
641
+ if ($nonce == $updraftplus->nonce) {
642
+ $updraftplus->log("This backup set is the backup set just made, so will not be deleted, despite being over the retain limit.");
643
+ $file_entities_backups_found[$entity]++;
644
+ continue;
645
+ }
646
+
647
+ if ($is_autobackup) {
648
+ if ($any_deleted_via_filter_yet) {
649
+ $updraftplus->log("This backup set was an automatic backup, but we have previously deleted a backup due to a limit, so it will be pruned (but not counted towards numerical limits).");
650
+ $prune_it = true;
651
+ } elseif ($file_entities_backups_found[$entity] < $updraft_retain) {
652
+ $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, and we have not yet reached any retain limits, so it will not be counted or pruned. Skipping.");
653
+ continue;
654
+ } else {
655
+ $updraftplus->log("This backup set ($backup_datestamp) was an automatic backup, and we have already reached retain limits, so it will be pruned.");
656
+ $prune_it = true;
657
+ }
658
+ } else {
659
+ $prune_it = false;
660
+ }
661
+
662
+ if ($remote_sent) {
663
+ $prune_it = true;
664
+ }
665
+
666
+ // All non-auto backups must be run through this filter (in date order) regardless of the current state of $prune_it - so that filters are able to track state.
667
+ $prune_it_before_filter = $prune_it;
668
+ if (!$is_autobackup) $prune_it = apply_filters('updraftplus_prune_or_not', $prune_it, 'files', $backup_datestamp, $entity, $file_entities_backups_found[$entity], $rule, $group_id);
669
+
670
+ // The "more than maximum to keep?" counter should not be increased until we actually know that the set is being kept. Before verison 1.11.22, we checked this before running the filter, which resulted in the counter being increased for sets that got pruned via the filter (i.e. not kept) - and too many backups were thus deleted
671
+ if (!$prune_it && !$is_autobackup) {
672
+ if ($file_entities_backups_found[$entity] >= $updraft_retain) {
673
+ $updraftplus->log("$entity: over retain limit ($updraft_retain); will delete this file entity");
674
+ $prune_it = true;
675
+ }
676
+ }
677
+
678
+ if ($prune_it) {
679
+ if (!$prune_it_before_filter) $any_deleted_via_filter_yet = true;
680
+ $prune_this = $backup_to_examine[$entity];
681
+ if (is_string($prune_this)) $prune_this = array($prune_this);
682
+
683
+ foreach ($prune_this as $k => $prune_file) {
684
+ if ($remote_sent) {
685
+ $updraftplus->log("$entity: $backup_datestamp: was sent to remote site; will remove from local record (only)");
686
+ }
687
+ $size_key = (0 == $k) ? $entity.'-size' : $entity.$k.'-size';
688
+ $size = (isset($backup_to_examine[$size_key])) ? $backup_to_examine[$size_key] : null;
689
+ $files_to_prune[] = $prune_file;
690
+ $file_sizes[] = $size;
691
+ }
692
+ unset($backup_to_examine[$entity]);
693
+
694
+ } elseif (!$is_autobackup) {
695
+ $file_entities_backups_found[$entity]++;
696
+ }
697
+ }
698
  }
 
699
 
700
+ // Sending an empty array is not itself a problem - except that the remote storage method may not check that before setting up a connection, which can waste time: especially if this is done every time around the loop.
701
+ if (!empty($files_to_prune)) {
702
+ # Actually delete the files
703
+ foreach ($services as $service => $sd) {
704
+ $this->prune_file($service, $files_to_prune, $sd[0], $sd[1], $file_sizes);
705
+ $updraftplus->record_still_alive();
 
 
 
 
 
 
706
  }
707
+ }
708
+
709
+ $backup_to_examine = $this->remove_backup_set_if_empty($backup_to_examine, $backup_datestamp, $backupable_entities, $backup_history);
710
+ if (empty($backup_to_examine)) {
711
+ // unset($functional_backup_history[$backup_datestamp]);
712
+ unset($backup_history[$backup_datestamp]);
713
  } else {
714
+ // $functional_backup_history[$backup_datestamp] = $backup_to_examine;
715
+ $backup_history[$backup_datestamp] = $backup_to_examine;
716
  }
717
+
718
+ // Loop over backup sets
 
719
  }
720
+
721
+ // Look over backup groups
722
  }
723
 
724
  $updraftplus->log("Retain: saving new backup history (sets now: ".count($backup_history).") and finishing retain operation");
728
 
729
  }
730
 
731
+ private function remove_backup_set_if_empty($backup_to_examine, $backup_datestamp, $backupable_entities, $backup_history) {
732
+
733
+ global $updraftplus;
734
+
735
+ // Get new result, post-deletion; anything left in this set?
736
+ $contains_files = 0;
737
+ foreach ($backupable_entities as $entity => $info) {
738
+ if (isset($backup_to_examine[$entity])) {
739
+ $contains_files = 1;
740
+ break;
741
+ }
742
+ }
743
+
744
+ $contains_db = 0;
745
+ foreach ($backup_to_examine as $key => $data) {
746
+ if ('db' == strtolower(substr($key, 0, 2)) && '-size' != substr($key, -5, 5)) {
747
+ $contains_db = 1;
748
+ break;
749
+ }
750
+ }
751
+
752
+ // Delete backup set completely if empty, o/w just remove DB
753
+ // We search on the four keys which represent data, allowing other keys to be used to track other things
754
+ if (!$contains_files && !$contains_db) {
755
+ $updraftplus->log("This backup set is now empty; will remove from history");
756
+ if (isset($backup_to_examine['nonce'])) {
757
+ $fullpath = $this->updraft_dir."/log.".$backup_to_examine['nonce'].".txt";
758
+ if (is_file($fullpath)) {
759
+ $updraftplus->log("Deleting log file (log.".$backup_to_examine['nonce'].".txt)");
760
+ @unlink($fullpath);
761
+ } else {
762
+ $updraftplus->log("Corresponding log file (log.".$backup_to_examine['nonce'].".txt) not found - must have already been deleted");
763
+ }
764
+ } else {
765
+ $updraftplus->log("No nonce record found in the backup set, so cannot delete any remaining log file");
766
+ }
767
+ // unset($backup_history[$backup_datestamp]);
768
+ return false;
769
+ } else {
770
+ $updraftplus->log("This backup set remains non-empty (f=$contains_files/d=$contains_db); will retain in history");
771
+ return $backup_to_examine;
772
+ }
773
+
774
+ }
775
+
776
  # $dofiles: An array of files (or a single string for one file)
777
  private function prune_file($service, $dofiles, $method_object = null, $object_passback = null, $file_sizes = array()) {
778
  global $updraftplus;
1301
  - When the writing finishes, it is renamed to ($final_filename).table
1302
  - When all tables are finished, they are concatenated into the final file
1303
  */
1304
+ // dbinfo is only used when whichdb != 'wp'; and the keys should be: user, pass, name, host, prefix
1305
  public function backup_db($already_done = 'begun', $whichdb = 'wp', $dbinfo = array()) {
1306
 
1307
  global $updraftplus, $wpdb;
class-updraftplus.php CHANGED
@@ -155,7 +155,7 @@ class UpdraftPlus {
155
  $sent_key = wp_remote_post(
156
  $post_it,
157
  array(
158
- 'timeout' => 15,
159
  'body' => array(
160
  'key' => $ud_rpc->get_key_remote()
161
  )
@@ -1385,7 +1385,7 @@ class UpdraftPlus {
1385
  if (0 == error_reporting()) return true;
1386
  $logline = $this->php_error_to_logline($errno, $errstr, $errfile, $errline);
1387
  $this->log($logline, 'notice', 'php_event');
1388
- # Pass it up the chain
1389
  return $this->error_reporting_stop_when_logged;
1390
  }
1391
 
@@ -1413,11 +1413,13 @@ class UpdraftPlus {
1413
 
1414
  $this->nonce = $bnonce;
1415
  $this->backup_time = $this->jobdata_get('backup_time');
1416
-
1417
  $this->job_time_ms = $this->jobdata_get('job_time_ms');
 
1418
  # Get the warnings before opening the log file, as opening the log file may generate new ones (which then leads to $this->errors having duplicate entries when they are copied over below)
1419
  $warnings = $this->jobdata_get('warnings');
 
1420
  $this->logfile_open($bnonce);
 
1421
  // Import existing warnings. The purpose of this is so that when save_backup_history() is called, it has a complete set - because job data expires quickly, whilst the warnings of the last backup run need to persist
1422
  if (is_array($warnings)) {
1423
  foreach ($warnings as $warning) {
@@ -1429,6 +1431,7 @@ class UpdraftPlus {
1429
  if (!is_array($runs_started)) $runs_started=array();
1430
  $time_passed = $this->jobdata_get('run_times');
1431
  if (!is_array($time_passed)) $time_passed = array();
 
1432
  foreach ($time_passed as $run => $passed) {
1433
  if (isset($runs_started[$run]) && $runs_started[$run] + $time_passed[$run] + 30 > $time_now) {
1434
  // We don't want to increase the resumption if WP has started two copies of the same resumption off
@@ -1451,11 +1454,25 @@ class UpdraftPlus {
1451
  } else {
1452
  $this->no_checkin_last_time = true;
1453
  }
1454
-
1455
 
1456
- # This is just a simple test to catch restorations of old backup sets where the backup includes a resumption of the backup job
1457
- if ($time_now - $this->backup_time > 172800 && true == apply_filters('updraftplus_check_obsolete_backup', true, $time_now)) {
1458
- $this->log("This backup task is either complete or began over 2 days ago: ending ($time_now, ".$this->backup_time.")");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1459
  die;
1460
  }
1461
 
@@ -1656,8 +1673,6 @@ class UpdraftPlus {
1656
  $this->log("Unrecognised data when trying to ascertain if the database ($whichdb) was backed up (".serialize($backup_database).")");
1657
  }
1658
 
1659
- // Save this to our history so we can track backups for the retain feature
1660
- $this->log("Saving backup history");
1661
  // This is done before cloud despatch, because we want a record of what *should* be in the backup. Whether it actually makes it there or not is not yet known.
1662
  $this->save_backup_history($our_files);
1663
 
@@ -1682,12 +1697,18 @@ class UpdraftPlus {
1682
 
1683
  $checksums = array('sha1' => array());
1684
 
1685
- # Queue files for upload
 
 
1686
  foreach ($our_files as $key => $files) {
1687
  // Only continue if the stored info was about a dump
1688
  if (!isset($backupable_entities[$key]) && ('db' != substr($key, 0, 2) || '-size' == substr($key, -5, 5))) continue;
1689
  if (is_string($files)) $files = array($files);
1690
  foreach ($files as $findex => $file) {
 
 
 
 
1691
  $sha = $this->jobdata_get('sha1-'.$key.$findex);
1692
  if ($sha) $checksums['sha1'][$key.$findex] = $sha;
1693
  $sha = $this->jobdata_get('sha1-'.$key.$findex.'.crypt');
@@ -1709,7 +1730,9 @@ class UpdraftPlus {
1709
  }
1710
  $our_files['checksums'] = $checksums;
1711
 
1712
- # Save again (now that we have checksums)
 
 
1713
  $this->save_backup_history($our_files);
1714
  do_action('updraft_final_backup_history', $our_files);
1715
 
@@ -1754,6 +1777,18 @@ class UpdraftPlus {
1754
 
1755
  }
1756
 
 
 
 
 
 
 
 
 
 
 
 
 
1757
  public function max_time_passed($time_passed, $upto, $first_run) {
1758
  $max_time = 0;
1759
  $timings_string = "";
@@ -1795,7 +1830,7 @@ class UpdraftPlus {
1795
  }
1796
 
1797
  public function jobdata_set($key, $value) {
1798
- if (!is_array($this->jobdata)) {
1799
  $this->jobdata = empty($this->nonce) ? array() : get_site_option("updraft_jobdata_".$this->nonce);
1800
  if (!is_array($this->jobdata)) $this->jobdata = array();
1801
  }
@@ -1822,11 +1857,11 @@ class UpdraftPlus {
1822
  }
1823
 
1824
  public function jobdata_get($key, $default = null) {
1825
- if (!is_array($this->jobdata)) {
1826
  $this->jobdata = empty($this->nonce) ? array() : get_site_option("updraft_jobdata_".$this->nonce, array());
1827
  if (!is_array($this->jobdata)) return $default;
1828
  }
1829
- return (isset($this->jobdata[$key])) ? $this->jobdata[$key] : $default;
1830
  }
1831
 
1832
  public function jobdata_reset() {
@@ -2093,7 +2128,7 @@ class UpdraftPlus {
2093
  if (!is_string($val)) continue;
2094
  if (preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-[\-a-z]+([0-9]+)?+(\.(zip|gz|gz\.crypt))?$/i', $val, $matches)) {
2095
  $nonce = $matches[2];
2096
- if (isset($bdata['service']) && ($bdata['service'] === 'none' || (is_array($bdata['service']) && array('none') === $bdata['service'])) && !is_file($updraft_dir.'/'.$val)) {
2097
  # File without remote storage is no longer present
2098
  } else {
2099
  $found_file = true;
@@ -2856,8 +2891,8 @@ class UpdraftPlus {
2856
  public function get_backup_history($timestamp = false) {
2857
  $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
2858
  // The line below actually *introduces* a race condition
2859
- // global $wpdb;
2860
- // $backup_history = @unserialize($wpdb->get_var($wpdb->prepare("SELECT option_value from $wpdb->options WHERE option_name='updraft_backup_history'")));
2861
  if (is_array($backup_history)) {
2862
  krsort($backup_history); //reverse sort so earliest backup is last on the array. Then we can array_pop.
2863
  } else {
@@ -3080,7 +3115,7 @@ class UpdraftPlus {
3080
  if (!is_array($opts)) $opts = array();
3081
  if (!is_array($dropbox)) return $opts;
3082
  foreach ($dropbox as $key => $value) { $opts[$key] = $value; }
3083
- if (preg_match('#^https?://(www.)dropbox\.com/home/Apps/UpdraftPlus([^/]*)/(.*)$#i', $opts['folder'], $matches)) $opts['folder'] = $matches[3];
3084
  return $opts;
3085
  }
3086
 
@@ -3165,7 +3200,6 @@ class UpdraftPlus {
3165
 
3166
  }
3167
  }
3168
- return true;
3169
  }
3170
 
3171
  public function get_mime_type_from_filename($filename, $allow_gzip = true) {
@@ -3185,28 +3219,62 @@ class UpdraftPlus {
3185
  }
3186
  }
3187
 
3188
- public function spool_file($type, $fullpath, $encryption = "") {
3189
  @set_time_limit(900);
3190
 
3191
  if (file_exists($fullpath)) {
3192
 
3193
- header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
3194
- header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
3195
-
3196
  $spooled = false;
3197
- if ('.crypt' == substr($fullpath, -6, 6)) $spooled = $this->spool_crypted_file($fullpath, $encryption);
 
 
 
 
 
3198
 
3199
- if (!$spooled) {
 
 
3200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3201
  header("Content-Length: ".filesize($fullpath));
3202
-
3203
- header('Content-type: '.$this->get_mime_type_from_filename($fullpath, false));
3204
-
3205
  header("Content-Disposition: attachment; filename=\"".basename($fullpath)."\";");
3206
- # Prevent the file being read into memory
3207
- @ob_end_flush();
3208
  readfile($fullpath);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3209
  }
 
3210
  } else {
3211
  echo __('File not found', 'updraftplus');
3212
  }
@@ -3659,7 +3727,7 @@ CREATE TABLE $wpdb->signups (
3659
  }
3660
 
3661
  # TODO: Remove legacy storage setting keys from here
3662
- // These are used in 3 places (May 2015 - of course, you should re-scan the code to check if relying on this): showing current settings on the debug modal, wiping all current settings, and getting a settings bundle to restore when migrating
3663
  public function get_settings_keys() {
3664
  // N.B. updraft_backup_history is not included here, as we don't want that wiped
3665
  return array('updraft_autobackup_default', 'updraft_dropbox', 'updraft_googledrive', 'updraftplus_tmp_googledrive_access_token', 'updraftplus_dismissedautobackup', 'updraftplus_dismissedexpiry', 'updraftplus_dismisseddashnotice', 'updraft_interval', 'updraft_interval_increments', 'updraft_interval_database', 'updraft_retain', 'updraft_retain_db', 'updraft_encryptionphrase', 'updraft_service', 'updraft_dropbox_appkey', 'updraft_dropbox_secret', 'updraft_googledrive_clientid', 'updraft_googledrive_secret', 'updraft_googledrive_remotepath', 'updraft_ftp', 'updraft_ftp_login', 'updraft_ftp_pass', 'updraft_ftp_remote_path', 'updraft_server_address', 'updraft_dir', 'updraft_email', 'updraft_delete_local', 'updraft_debug_mode', 'updraft_include_plugins', 'updraft_include_themes', 'updraft_include_uploads', 'updraft_include_others', 'updraft_include_wpcore', 'updraft_include_wpcore_exclude', 'updraft_include_more', 'updraft_include_blogs', 'updraft_include_mu-plugins',
155
  $sent_key = wp_remote_post(
156
  $post_it,
157
  array(
158
+ 'timeout' => 45,
159
  'body' => array(
160
  'key' => $ud_rpc->get_key_remote()
161
  )
1385
  if (0 == error_reporting()) return true;
1386
  $logline = $this->php_error_to_logline($errno, $errstr, $errfile, $errline);
1387
  $this->log($logline, 'notice', 'php_event');
1388
+ // Pass it up the chain
1389
  return $this->error_reporting_stop_when_logged;
1390
  }
1391
 
1413
 
1414
  $this->nonce = $bnonce;
1415
  $this->backup_time = $this->jobdata_get('backup_time');
 
1416
  $this->job_time_ms = $this->jobdata_get('job_time_ms');
1417
+
1418
  # Get the warnings before opening the log file, as opening the log file may generate new ones (which then leads to $this->errors having duplicate entries when they are copied over below)
1419
  $warnings = $this->jobdata_get('warnings');
1420
+
1421
  $this->logfile_open($bnonce);
1422
+
1423
  // Import existing warnings. The purpose of this is so that when save_backup_history() is called, it has a complete set - because job data expires quickly, whilst the warnings of the last backup run need to persist
1424
  if (is_array($warnings)) {
1425
  foreach ($warnings as $warning) {
1431
  if (!is_array($runs_started)) $runs_started=array();
1432
  $time_passed = $this->jobdata_get('run_times');
1433
  if (!is_array($time_passed)) $time_passed = array();
1434
+
1435
  foreach ($time_passed as $run => $passed) {
1436
  if (isset($runs_started[$run]) && $runs_started[$run] + $time_passed[$run] + 30 > $time_now) {
1437
  // We don't want to increase the resumption if WP has started two copies of the same resumption off
1454
  } else {
1455
  $this->no_checkin_last_time = true;
1456
  }
 
1457
 
1458
+ // This is just a simple test to catch restorations of old backup sets where the backup includes a resumption of the backup job
1459
+ if ($time_now - $this->backup_time > 172800 && true == apply_filters('updraftplus_check_obsolete_backup', true, $time_now, $this)) {
1460
+
1461
+ // We have seen cases where the get_site_option() call that self::get_jobdata() relies on returns nothing, even though the data was there in the database. This appears to be sometimes reproducible for the people who get it, but stops being reproducible if they change their backup times - which suggests that they're having failures at times of extreme load. We can attempt to detect this case, and reschedule, instead of aborting.
1462
+ if (empty($this->backup_time) && empty($this->backup_is_already_complete) && !empty($this->logfile_name) && is_readable($this->logfile_name)) {
1463
+ $first_log_bit = file_get_contents($this->logfile_name, false, null, 0, 250);
1464
+ if (preg_match('/\(0\) Opened log file at time: (.*) on /', $first_log_bit, $matches)) {
1465
+ $first_opened = strtotime($matches[1]);
1466
+ // The value of 1000 seconds here is somewhat arbitrary; but allows for the problem to occur in ~ the first 15 minutes. In practice, the problem is extremely rare; if this does not catch it, we can tweak the algorithm.
1467
+ if (time() - $first_opened < 1000) {
1468
+ $this->log("This backup task (".$this->nonce.") failed to load its job data (possible database server malfunction), but appears to be only recently started: scheduling a fresh resumption in order to try again, and then ending this resumption ($time_now, ".$this->backup_time.") (existing jobdata keys: ".implode(', ', array_keys($this->jobdata)).")");
1469
+ $this->reschedule(120);
1470
+ die;
1471
+ }
1472
+ }
1473
+ }
1474
+
1475
+ $this->log("This backup task (".$this->nonce.") is either complete or began over 2 days ago: ending ($time_now, ".$this->backup_time.") (existing jobdata keys: ".implode(', ', array_keys($this->jobdata)).")");
1476
  die;
1477
  }
1478
 
1673
  $this->log("Unrecognised data when trying to ascertain if the database ($whichdb) was backed up (".serialize($backup_database).")");
1674
  }
1675
 
 
 
1676
  // This is done before cloud despatch, because we want a record of what *should* be in the backup. Whether it actually makes it there or not is not yet known.
1677
  $this->save_backup_history($our_files);
1678
 
1697
 
1698
  $checksums = array('sha1' => array());
1699
 
1700
+ $total_size = 0;
1701
+
1702
+ // Queue files for upload
1703
  foreach ($our_files as $key => $files) {
1704
  // Only continue if the stored info was about a dump
1705
  if (!isset($backupable_entities[$key]) && ('db' != substr($key, 0, 2) || '-size' == substr($key, -5, 5))) continue;
1706
  if (is_string($files)) $files = array($files);
1707
  foreach ($files as $findex => $file) {
1708
+
1709
+ $size_key = (0 == $findex) ? $key.'-size' : $key.$findex.'-size';
1710
+ $total_size = (false === $total_size || !isset($our_files[$size_key]) || !is_numeric($our_files[$size_key])) ? false : $total_size + $our_files[$size_key];
1711
+
1712
  $sha = $this->jobdata_get('sha1-'.$key.$findex);
1713
  if ($sha) $checksums['sha1'][$key.$findex] = $sha;
1714
  $sha = $this->jobdata_get('sha1-'.$key.$findex.'.crypt');
1730
  }
1731
  $our_files['checksums'] = $checksums;
1732
 
1733
+ // Save again (now that we have checksums)
1734
+ $size_description = (false === $total_size) ? 'Unknown' : $this->convert_numeric_size_to_text($total_size);
1735
+ $this->log("Saving backup history. Total backup size: $size_description");
1736
  $this->save_backup_history($our_files);
1737
  do_action('updraft_final_backup_history', $our_files);
1738
 
1777
 
1778
  }
1779
 
1780
+ public function convert_numeric_size_to_text($size) {
1781
+ if ($size > 1073741824) {
1782
+ return round($size / 1073741824, 1).' Gb';
1783
+ } elseif ($size > 1048576) {
1784
+ return round($size / 1048576, 1).' Mb';
1785
+ } elseif ($size > 1024) {
1786
+ return round($size / 1024, 1).' Kb';
1787
+ } else {
1788
+ return round($size, 1).' b';
1789
+ }
1790
+ }
1791
+
1792
  public function max_time_passed($time_passed, $upto, $first_run) {
1793
  $max_time = 0;
1794
  $timings_string = "";
1830
  }
1831
 
1832
  public function jobdata_set($key, $value) {
1833
+ if (empty($this->jobdata)) {
1834
  $this->jobdata = empty($this->nonce) ? array() : get_site_option("updraft_jobdata_".$this->nonce);
1835
  if (!is_array($this->jobdata)) $this->jobdata = array();
1836
  }
1857
  }
1858
 
1859
  public function jobdata_get($key, $default = null) {
1860
+ if (empty($this->jobdata)) {
1861
  $this->jobdata = empty($this->nonce) ? array() : get_site_option("updraft_jobdata_".$this->nonce, array());
1862
  if (!is_array($this->jobdata)) return $default;
1863
  }
1864
+ return isset($this->jobdata[$key]) ? $this->jobdata[$key] : $default;
1865
  }
1866
 
1867
  public function jobdata_reset() {
2128
  if (!is_string($val)) continue;
2129
  if (preg_match('/^backup_([\-0-9]{15})_.*_([0-9a-f]{12})-[\-a-z]+([0-9]+)?+(\.(zip|gz|gz\.crypt))?$/i', $val, $matches)) {
2130
  $nonce = $matches[2];
2131
+ if (isset($bdata['service']) && ($bdata['service'] === 'none' || (is_array($bdata['service']) && (array('none') === $bdata['service'] || (1 == count($bdata['service']) && isset($bdata['service'][0]) && empty($bdata['service'][0]))))) && !is_file($updraft_dir.'/'.$val)) {
2132
  # File without remote storage is no longer present
2133
  } else {
2134
  $found_file = true;
2891
  public function get_backup_history($timestamp = false) {
2892
  $backup_history = UpdraftPlus_Options::get_updraft_option('updraft_backup_history');
2893
  // The line below actually *introduces* a race condition
2894
+ // global $wpdb;
2895
+ // $backup_history = @unserialize($wpdb->get_var($wpdb->prepare("SELECT option_value from $wpdb->options WHERE option_name='updraft_backup_history'")));
2896
  if (is_array($backup_history)) {
2897
  krsort($backup_history); //reverse sort so earliest backup is last on the array. Then we can array_pop.
2898
  } else {
3115
  if (!is_array($opts)) $opts = array();
3116
  if (!is_array($dropbox)) return $opts;
3117
  foreach ($dropbox as $key => $value) { $opts[$key] = $value; }
3118
+ if (!empty($opts['folder']) && preg_match('#^https?://(www.)dropbox\.com/home/Apps/UpdraftPlus([^/]*)/(.*)$#i', $opts['folder'], $matches)) $opts['folder'] = $matches[3];
3119
  return $opts;
3120
  }
3121
 
3200
 
3201
  }
3202
  }
 
3203
  }
3204
 
3205
  public function get_mime_type_from_filename($filename, $allow_gzip = true) {
3219
  }
3220
  }
3221
 
3222
+ public function spool_file($type, $fullpath, $encryption = '') {
3223
  @set_time_limit(900);
3224
 
3225
  if (file_exists($fullpath)) {
3226
 
3227
+ // Prevent any debug output
3228
+ @ini_set('display_errors', '0');
3229
+
3230
  $spooled = false;
3231
+ if ('.crypt' == substr($fullpath, -6, 6)) {
3232
+ header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
3233
+ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
3234
+ $this->spool_crypted_file($fullpath, (string)$encryption);
3235
+ return;
3236
+ }
3237
 
3238
+ $content_type = $this->get_mime_type_from_filename($fullpath, false);
3239
+
3240
+ require_once(UPDRAFTPLUS_DIR.'/includes/class-partialfileservlet.php');
3241
 
3242
+ //Prevent the file being read into memory
3243
+ @ob_end_flush();
3244
+
3245
+ if (isset($_SERVER['HTTP_RANGE'])) {
3246
+ $range_header = trim($_SERVER['HTTP_RANGE']);
3247
+ } elseif (function_exists('apache_request_headers')) {
3248
+ foreach (apache_request_headers() as $name => $value) {
3249
+ if (strtoupper($name) === 'RANGE') {
3250
+ $range_header = trim($value);
3251
+ }
3252
+ }
3253
+ }
3254
+
3255
+ if (empty($range_header)) {
3256
  header("Content-Length: ".filesize($fullpath));
3257
+ header("Content-type: $content_type");
 
 
3258
  header("Content-Disposition: attachment; filename=\"".basename($fullpath)."\";");
 
 
3259
  readfile($fullpath);
3260
+ return;
3261
+ }
3262
+
3263
+ try {
3264
+ $range_header = UpdraftPlus_RangeHeader::createFromHeaderString($range_header);
3265
+ $servlet = new UpdraftPlus_PartialFileServlet($range_header);
3266
+ $servlet->sendFile($fullpath, $content_type);
3267
+ } catch (UpdraftPlus_InvalidRangeHeaderException $e) {
3268
+ header("HTTP/1.1 400 Bad Request");
3269
+ error_log("UpdraftPlus: UpdraftPlus_InvalidRangeHeaderException: ".$e->getMessage());
3270
+ } catch (UpdraftPlus_UnsatisfiableRangeException $e) {
3271
+ header("HTTP/1.1 416 Range Not Satisfiable");
3272
+ } catch (UpdraftPlus_NonExistentFileException $e) {
3273
+ header("HTTP/1.1 404 Not Found");
3274
+ } catch (UpdraftPlus_UnreadableFileException $e) {
3275
+ header("HTTP/1.1 500 Internal Server Error");
3276
  }
3277
+
3278
  } else {
3279
  echo __('File not found', 'updraftplus');
3280
  }
3727
  }
3728
 
3729
  # TODO: Remove legacy storage setting keys from here
3730
+ // These are used in 4 places (Feb 2016 - of course, you should re-scan the code to check if relying on this): showing current settings on the debug modal, wiping all current settings, getting a settings bundle to restore when migrating, and for relevant keys in POST-ed data when saving settings over AJAX
3731
  public function get_settings_keys() {
3732
  // N.B. updraft_backup_history is not included here, as we don't want that wiped
3733
  return array('updraft_autobackup_default', 'updraft_dropbox', 'updraft_googledrive', 'updraftplus_tmp_googledrive_access_token', 'updraftplus_dismissedautobackup', 'updraftplus_dismissedexpiry', 'updraftplus_dismisseddashnotice', 'updraft_interval', 'updraft_interval_increments', 'updraft_interval_database', 'updraft_retain', 'updraft_retain_db', 'updraft_encryptionphrase', 'updraft_service', 'updraft_dropbox_appkey', 'updraft_dropbox_secret', 'updraft_googledrive_clientid', 'updraft_googledrive_secret', 'updraft_googledrive_remotepath', 'updraft_ftp', 'updraft_ftp_login', 'updraft_ftp_pass', 'updraft_ftp_remote_path', 'updraft_server_address', 'updraft_dir', 'updraft_email', 'updraft_delete_local', 'updraft_debug_mode', 'updraft_include_plugins', 'updraft_include_themes', 'updraft_include_uploads', 'updraft_include_others', 'updraft_include_wpcore', 'updraft_include_wpcore_exclude', 'updraft_include_more', 'updraft_include_blogs', 'updraft_include_mu-plugins',
css/admin.css CHANGED
@@ -8,6 +8,10 @@
8
  .width-900 {
9
  width: 900px;
10
  }
 
 
 
 
11
 
12
  /* End widths and sizing */
13
 
@@ -15,30 +19,214 @@
15
  .no-decoration {
16
  text-decoration: none;
17
  }
18
- /* End font styling */
19
 
20
- /* End common elements/classes */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
 
 
 
 
22
  .autobackup {
23
  padding: 6px;
24
- margin: 8px, 0px;
25
  }
26
 
27
  ul .disc {
28
  list-style: disc inside;
29
  }
30
 
31
- .hidden {
32
  display:none;
33
  }
34
 
35
- /* Alignment */
36
- .center-align-td {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
 
 
39
 
40
  /* End of common elements */
41
 
 
 
 
 
 
 
 
42
  h3 .thank-you {
43
  margin-top: 0px;
44
  }
@@ -67,7 +255,11 @@ a .udp-logo {
67
 
68
  /* Taken straight from admin.php */
69
 
70
- #updraft-navtab-backups-content#updraft-navtab-backups-content .updraft_existing_backups .updraft_existing_backups_row.backuprowselected {
 
 
 
 
71
  background-color: #ccc;
72
  }
73
 
@@ -88,7 +280,7 @@ a .udp-logo {
88
  margin-left: 8px;
89
  }
90
  .updraft-bigbutton {
91
- padding: 2px 0px;
92
  margin-right: 14px !important;
93
  font-size:22px !important;
94
  min-height: 32px;
@@ -97,7 +289,7 @@ a .udp-logo {
97
 
98
  .updraft_debugrow th {
99
  float: right;
100
- text-align: right !important;
101
  font-weight: bold;
102
  padding-right: 8px;
103
  min-width: 140px;
@@ -105,6 +297,7 @@ a .udp-logo {
105
 
106
  .updraft_debugrow td {
107
  min-width: 300px;
 
108
  }
109
  .updraftplus-morefiles-row-delete {
110
  cursor: pointer;
@@ -153,6 +346,7 @@ a .udp-logo {
153
  margin:0px;
154
  padding: 3px 4px;
155
  font-size: 16px;
 
156
  }
157
  .updraft-viewlogdiv:hover {
158
  background-color: #000000;
@@ -344,17 +538,31 @@ a .udp-logo {
344
  padding: 8px;
345
  }
346
 
347
- /* .nav-tab {
348
  border-radius: 20px 20px 0 0;
 
 
 
349
  }
350
 
351
- .nav-tab-active {
 
 
 
 
352
  color: #df6926;
 
 
 
353
  }
354
 
 
 
 
 
355
  .nav-tab-wrapper {
356
- margin: 14px, 0px;
357
- } */
358
 
359
  #updraft-poplog-content {
360
  white-space: pre-wrap;
@@ -366,21 +574,22 @@ a .udp-logo {
366
  margin: 0 10px 0 0;
367
  }
368
 
369
- .next-backup .not-scheduled {
370
- vertical-align: top;
371
- margin: 0px;
372
- padding: 0px;
373
  }
374
 
375
  .next-backup .updraft_scheduled {
376
  width: 124px;
377
- vertical-align:top;
378
  margin: 0px;
379
  padding: 0px;
380
  }
381
 
382
- .next-backup .updraft_scheduled, .next-backup .updraft_all-files {
383
- color:blue; margin: 0px; padding: 0px;
 
 
384
  }
385
 
386
  .multisite-advert-width {
@@ -413,7 +622,7 @@ input #backupnow_includefiles_moreoptions {
413
  padding: 6px 10px;
414
  }
415
 
416
- .form-table #updraft_activejobsrow .minimum-height {
417
  min-height: 100px;
418
  }
419
 
@@ -430,7 +639,16 @@ input #backupnow_includefiles_moreoptions {
430
  margin-top: 8px;
431
  }
432
 
433
- #updraft-navtab-backups-content .ud-whitespace-warning {
 
 
 
 
 
 
 
 
 
434
  background-color: pink;
435
  padding: 8px;
436
  margin: 4px;
@@ -450,16 +668,21 @@ input #backupnow_includefiles_moreoptions {
450
  margin-left: 100px;
451
  }
452
 
453
- #updraft-plupload-modal p.upload {
454
  max-width: 610px;
455
  }
456
 
457
- #updraft-navtab-backups-content #plupload-upload-ui {
458
  width: 70%;
459
  }
460
 
 
 
 
 
 
461
  #ud_massactions {
462
- padding: 10px;
463
  position: fixed;
464
  right: 25%;
465
  top: 25%;
@@ -565,6 +788,7 @@ input #backupnow_includefiles_moreoptions {
565
 
566
  .delete-old-directories {
567
  padding: 8px;
 
568
  }
569
 
570
  .active-jobs {
@@ -654,7 +878,7 @@ input #backupnow_includefiles_moreoptions {
654
 
655
  .updraft_existingbackup_date {
656
  width: 22%;
657
- max-width: 140px !important;
658
  }
659
 
660
  .existing-backups-table {
@@ -667,19 +891,19 @@ input #backupnow_includefiles_moreoptions {
667
  margin-bottom: 4px;
668
  }
669
 
670
- .download-backups .backup-date {
671
  width: 172px;
672
  padding: 0;
673
  padding-left: 15px;
674
  }
675
 
676
- .download-backups .backup-data {
677
  width: 426px;
678
  padding: 0;
679
  padding-left: 15px;
680
  }
681
 
682
- .download-backups .updraft_backup_actions {
683
  width: 272px;
684
  padding: 0 0 10px 15px;
685
  }
@@ -749,13 +973,6 @@ input #backupnow_includefiles_moreoptions {
749
  border-radius: 4px;
750
  }
751
 
752
- .choose-components-button {
753
- padding-top: 2px;
754
- padding-bottom: 2px;
755
- font-size: 16px !important;
756
- height: 28px;
757
- }
758
-
759
  .before-restore-button {
760
  padding: 1px;
761
  margin: 0px;
@@ -777,49 +994,352 @@ input #backupnow_includefiles_moreoptions {
777
  background-color: #aaaaaa;
778
  }
779
 
780
- /* Main Buttons */
781
- .main-dashboard-buttons {
782
- border-width: 4px!important;
783
- border-radius: 12px;
784
- letter-spacing: 0px;
785
- font-size: 17px;
786
- font-weight: bold;
787
- text-transform: uppercase;
788
- padding-left: 0.7em;
789
- padding-right: 2em;
790
- padding: 0.3em 1em;
791
- line-height: 1.7em !important;
792
- background: transparent;
793
- position: relative;
794
- border: 2px solid;
795
- trasnsition: all 0.2s;
796
- vertical-align: baseline;
797
- box-sizing: border-box;
798
- text-align: justify;
799
- line-height: 1.3em;
800
- margin-left: .3em;
801
- text-transform: none;
802
- line-height: 1;
803
- -webkit-font-smoothing: antialiased;
804
- text-decoration: none;
805
- }
806
 
807
- .button-restore {
808
- border-color: RGB(98, 158, 192);
809
- color: RGB(98, 158, 192);
810
- }
811
 
812
- .button-restore:hover, .button-migrate:hover, .button-backup:hover {
813
- border-color: #df6926;
814
- color: #df6926;
815
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
816
 
817
- .button-migrate {
818
- color: rgb(238, 169, 32);
819
- border-color: rgb(238, 169, 32);
820
- }
821
 
822
- .button-backup {
823
- border-color: #84CA1B;
824
- color: #84CA1B;
825
- }
8
  .width-900 {
9
  width: 900px;
10
  }
11
+
12
+ .width-80 {
13
+ width: 80%;
14
+ }
15
 
16
  /* End widths and sizing */
17
 
19
  .no-decoration {
20
  text-decoration: none;
21
  }
 
22
 
23
+ .bold {
24
+ font-weight: bold;
25
+ }
26
+ /* End font styling */
27
+
28
+ /* Alignment */
29
+ .center-align-td {
30
+ text-align: center;
31
+ }
32
+ /* End of Alignment */
33
+
34
+ /* Padding */
35
+ .remove-padding {
36
+ padding: 0 !important;
37
+ }
38
+ /* End of padding */
39
 
40
+ .updraft-text-center {
41
+ text-align: center;
42
+ }
43
+
44
  .autobackup {
45
  padding: 6px;
46
+ margin: 8px 0px;
47
  }
48
 
49
  ul .disc {
50
  list-style: disc inside;
51
  }
52
 
53
+ .updraft-hidden {
54
  display:none;
55
  }
56
 
57
+ .dashicons-log-fix {
58
+ display: inherit;
59
+ }
60
+
61
+ /* Input boxes */
62
+
63
+ input {
64
+ border-radius: 4px;
65
+ line-height: 1.42;
66
+ border: 1px solid #ccc;
67
+ height: 27px;
68
+ padding: 2px 6px;
69
+ color: #555;
70
+ }
71
+
72
+ input[type="text"] {
73
+ font-size: 14px;
74
+ }
75
+
76
+ input[type="number"] {
77
+ height: 31px;
78
+ }
79
+
80
+ select {
81
+ border-radius: 4px;
82
+ }
83
+
84
+ /* End input boxes */
85
+
86
+
87
+ /* Main Buttons */
88
+ .main-dashboard-buttons {
89
+ border-width: 4px;
90
+ border-radius: 12px;
91
+ letter-spacing: 0px;
92
+ font-size: 17px;
93
+ font-weight: bold;
94
+ padding-left: 0.7em;
95
+ padding-right: 2em;
96
+ padding: 0.3em 1em;
97
+ line-height: 1.7em;
98
+ background: transparent;
99
+ position: relative;
100
+ border: 2px solid;
101
+ transition: all 0.2s;
102
+ vertical-align: baseline;
103
+ box-sizing: border-box;
104
  text-align: center;
105
+ line-height: 1.3em;
106
+ margin-left: .3em;
107
+ text-transform: none;
108
+ line-height: 1;
109
+ text-decoration: none;
110
+ }
111
+
112
+ .button-restore {
113
+ border-color: RGB(98, 158, 192);
114
+ color: RGB(98, 158, 192);
115
+ }
116
+
117
+ .dashboard-main-sizing {
118
+ border-width: 4px;
119
+ width: 190px;
120
+ line-height: 1.7em;
121
+ }
122
+
123
+ .button-restore:hover, .button-migrate:hover, .button-backup:hover,
124
+ .button-view-log:hover, .button-mass-selectors:hover,
125
+ .button-delete:hover, .button-entity-backup:hover, .udp-button-primary:hover {
126
+ border-color: #df6926;
127
+ color: #df6926;
128
+ }
129
+
130
+ .button-migrate {
131
+ color: rgb(238, 169, 32);
132
+ border-color: rgb(238, 169, 32);
133
+ }
134
+
135
+ .button-backup {
136
+ border-color: #84CA1B;
137
+ color: #84CA1B;
138
+ }
139
+
140
+ .existing-backups-buttons {
141
+ font-size: 11px;
142
+ line-height: 1.4em;
143
+ border-width: 3px;
144
+ }
145
+
146
+ .existing-backups-restore-buttons {
147
+ font-size: 11px;
148
+ line-height: 1.4em;
149
+ border-width: 3px;
150
+ }
151
+
152
+ .button-delete {
153
+ color: #E23900;
154
+ border-color: #E23900;
155
+ font-size: 14px;
156
+ line-height: 1.4em;
157
+ border-width: 2px;
158
+ margin-right: 10px;
159
+ }
160
+
161
+ .button-view-log, .button-mass-selectors {
162
+ color: darkgrey;
163
+ border-color: darkgrey;
164
+ font-size: 14px;
165
+ line-height: 1.4em;
166
+ border-width: 2px;
167
+ margin-top: -1px;
168
+ }
169
+
170
+ .button-view-log {
171
+ width: 120px;
172
+ }
173
+
174
+ .button-existing-restore {
175
+ font-size: 14px;
176
+ line-height: 1.4em;
177
+ border-width: 2px;
178
+ width: 110px;
179
+ }
180
+
181
+ .main-restore {
182
+ margin-right: 3%;
183
+ margin-left: 3%;
184
+ }
185
+
186
+ .button-entity-backup {
187
+ color: #555555;
188
+ border-color: #555555;
189
+ font-size: 11px;
190
+ line-height: 1.4em;
191
+ border-width: 2px;
192
+ margin-right: 5px;
193
+ }
194
+
195
+ .button-select-all {
196
+ width: 122px;
197
+ }
198
+
199
+ .button-deselect {
200
+ width: 92px;
201
+ }
202
+
203
+ #ud_massactions > .display-flex > .mass-selectors-margins {
204
+ margin-right: -4px;
205
+ }
206
+
207
+ .udp-button-primary {
208
+ border-width: 4px;
209
+ color: #0073AA;
210
+ border-color: #0073AA;
211
+ font-size: 14px;
212
+ height: 40px;
213
+ }
214
+
215
+ #ud_massactions .button-delete {
216
+ margin-right: 0px;
217
  }
218
+
219
+ /* End Main Buttons */
220
 
221
  /* End of common elements */
222
 
223
+ .udp-logo-70 {
224
+ width: 70px;
225
+ height: 70px;
226
+ float: left;
227
+ padding-right: 25px;
228
+ }
229
+
230
  h3 .thank-you {
231
  margin-top: 0px;
232
  }
255
 
256
  /* Taken straight from admin.php */
257
 
258
+ #updraft-navtab-settings-content table.form-table p {
259
+ max-width: 700px;
260
+ }
261
+
262
+ #updraft-navtab-backups-content .updraft_existing_backups .updraft_existing_backups_row.backuprowselected {
263
  background-color: #ccc;
264
  }
265
 
280
  margin-left: 8px;
281
  }
282
  .updraft-bigbutton {
283
+ padding: 2px 0px !important;
284
  margin-right: 14px !important;
285
  font-size:22px !important;
286
  min-height: 32px;
289
 
290
  .updraft_debugrow th {
291
  float: right;
292
+ text-align: right;
293
  font-weight: bold;
294
  padding-right: 8px;
295
  min-width: 140px;
297
 
298
  .updraft_debugrow td {
299
  min-width: 300px;
300
+ vertical-align: bottom;
301
  }
302
  .updraftplus-morefiles-row-delete {
303
  cursor: pointer;
346
  margin:0px;
347
  padding: 3px 4px;
348
  font-size: 16px;
349
+ line-height: 26px;
350
  }
351
  .updraft-viewlogdiv:hover {
352
  background-color: #000000;
538
  padding: 8px;
539
  }
540
 
541
+ /*.nav-tab {
542
  border-radius: 20px 20px 0 0;
543
+ border-color: grey;
544
+ border-width: 2px;
545
+ margin-top: 34px;
546
  }
547
 
548
+ .nav-tab:hover {
549
+ border-bottom: 0;
550
+ }
551
+
552
+ .nav-tab-active, .nav-tab-active:active {
553
  color: #df6926;
554
+ border-color: #D3D3D3;
555
+ border-width: 1px;
556
+ border-bottom: 0;
557
  }
558
 
559
+ .nav-tab-active:focus {
560
+ color: #df6926;
561
+ }*/
562
+
563
  .nav-tab-wrapper {
564
+ margin: 14px 0px;
565
+ }
566
 
567
  #updraft-poplog-content {
568
  white-space: pre-wrap;
574
  margin: 0 10px 0 0;
575
  }
576
 
577
+ .not-scheduled {
578
+ vertical-align: top !important;
579
+ margin: 0px !important;
580
+ padding: 0px !important;
581
  }
582
 
583
  .next-backup .updraft_scheduled {
584
  width: 124px;
 
585
  margin: 0px;
586
  padding: 0px;
587
  }
588
 
589
+ .next-backup .updraft_scheduled .updraft_all-files {
590
+ color: blue;
591
+ margin: 0px;
592
+ padding: 0px;
593
  }
594
 
595
  .multisite-advert-width {
622
  padding: 6px 10px;
623
  }
624
 
625
+ .form-table #updraft_activejobsrow .minimum-height{
626
  min-height: 100px;
627
  }
628
 
639
  margin-top: 8px;
640
  }
641
 
642
+ .download-backups .updraft_download_button {
643
+ margin-right: 6px;
644
+ margin-top: 4px;
645
+ }
646
+
647
+ .download-backups .choose-components-button {
648
+ font-size: 16px;
649
+ }
650
+
651
+ .download-backups .ud-whitespace-warning {
652
  background-color: pink;
653
  padding: 8px;
654
  margin: 4px;
668
  margin-left: 100px;
669
  }
670
 
671
+ .download-backups .upload {
672
  max-width: 610px;
673
  }
674
 
675
+ .download-backups #plupload-upload-ui {
676
  width: 70%;
677
  }
678
 
679
+ .ud_downloadstatus {
680
+ padding: 10px;
681
+ background: #f1f1f1;
682
+ }
683
+
684
  #ud_massactions {
685
+ padding: 14px;
686
  position: fixed;
687
  right: 25%;
688
  top: 25%;
788
 
789
  .delete-old-directories {
790
  padding: 8px;
791
+ padding-bottom: 12px;
792
  }
793
 
794
  .active-jobs {
878
 
879
  .updraft_existingbackup_date {
880
  width: 22%;
881
+ max-width: 140px;
882
  }
883
 
884
  .existing-backups-table {
891
  margin-bottom: 4px;
892
  }
893
 
894
+ .form-table .backup-date {
895
  width: 172px;
896
  padding: 0;
897
  padding-left: 15px;
898
  }
899
 
900
+ .form-table .backup-data {
901
  width: 426px;
902
  padding: 0;
903
  padding-left: 15px;
904
  }
905
 
906
+ .form-table .updraft_backup_actions {
907
  width: 272px;
908
  padding: 0 0 10px 15px;
909
  }
973
  border-radius: 4px;
974
  }
975
 
 
 
 
 
 
 
 
976
  .before-restore-button {
977
  padding: 1px;
978
  margin: 0px;
994
  background-color: #aaaaaa;
995
  }
996
 
997
+ .last-backup-job {
998
+ padding-top: 3% !important;
999
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1000
 
1001
+ .line-height-03 {
1002
+ line-height: 0.3 !important;
1003
+ }
 
1004
 
1005
+ .line-height-13 {
1006
+ line-height: 1.3 !important;
1007
+ }
1008
+
1009
+ .line-height-23 {
1010
+ line-height: 2.3 !important;
1011
+ }
1012
+
1013
+ #updraft_diskspaceused {
1014
+ color: #df6926;
1015
+ }
1016
+
1017
+ .updraft_premium_description_list {
1018
+ text-align: left;
1019
+ }
1020
+
1021
+ #updraft_delete_old_dirs_pagediv {
1022
+ padding-bottom: 10px;
1023
+ }
1024
+
1025
+ /*#updraft_lastlogmessagerow > td, #updraft_last_backup > td {
1026
+ padding: 0;
1027
+ }*/
1028
+
1029
+ .job-id {
1030
+ margin: 0 auto;
1031
+ width: 20%;
1032
+ }
1033
+
1034
+ .updraft_all-files {
1035
+ color: #df6926;
1036
+ }
1037
+
1038
+ /* Time + scheduling add-on*/
1039
+ .fix-time {
1040
+ width: 70px;
1041
+ }
1042
+
1043
+ .retain-files {
1044
+ width: 70px;
1045
+ }
1046
+
1047
+ .number-input {
1048
+ min-width: 50px;
1049
+ max-width: 70px;
1050
+ }
1051
+
1052
+ .additional-rule-width {
1053
+ min-width: 60px;
1054
+ max-width: 70px;
1055
+ }
1056
+
1057
+ /* Add-ons */
1058
+ /* Want to fix the WordPress icons so that they fit inline with the text, and don't push everything out of place. */
1059
+
1060
+ .dashicons {
1061
+ line-height: inherit;
1062
+ font-size: inherit;
1063
+ }
1064
+
1065
+ .addon-logo-150 {
1066
+ margin-left: 30px;
1067
+ margin-top: 33px;
1068
+ height: 125px;
1069
+ width: 150px;
1070
+ }
1071
+
1072
+ .margin-bottom-50 {
1073
+ margin-bottom: 50px;
1074
+ }
1075
+
1076
+ .premium-container {
1077
+ width: 80%;
1078
+ }
1079
+
1080
+ /* Main Header */
1081
+
1082
+ .main-header {
1083
+ background-color: #df6926;
1084
+ height: 200px;
1085
+ width: 100%;
1086
+ }
1087
+
1088
+ .button-add-to-cart {
1089
+ color: white;
1090
+ border-color: white;
1091
+ float: none;
1092
+ margin-right: 17px;
1093
+ }
1094
+
1095
+ .button-add-to-cart:hover, .button-add-to-cart:focus, .button-add-to-cart:active {
1096
+ border-color: #A0A5AA;
1097
+ color: #A0A5AA;
1098
+ }
1099
+
1100
+ .addon-title {
1101
+ margin-top: 25px;
1102
+ }
1103
+
1104
+ .addon-text {
1105
+ margin-top: 75px;
1106
+ }
1107
+
1108
+ .image-main-div {
1109
+ width: 25%;
1110
+ float: left;
1111
+ }
1112
+
1113
+ .text-main-div {
1114
+ width: 60%;
1115
+ float: left;
1116
+ text-align: center;
1117
+ color: white;
1118
+ margin-top: 16px;
1119
+ }
1120
+
1121
+ .text-main-div-title {
1122
+ font-weight: bold !important;
1123
+ color: white;
1124
+ text-align: center;
1125
+ }
1126
+
1127
+ .text-main-div-paragraph {
1128
+ color: white;
1129
+ }
1130
+
1131
+ /* End main header */
1132
+
1133
+ /* Vault icons */
1134
+
1135
+ .updraftplus-vault-cta {
1136
+ width: 100%;
1137
+ text-align: center;
1138
+ margin-bottom: 50px;
1139
+ }
1140
+
1141
+ .updraftplus-vault-cta h1 {
1142
+ font-weight: bold;
1143
+ }
1144
+
1145
+ .updraftvault-buy {
1146
+ width: 225px;
1147
+ height: 225px;
1148
+ border: 2px solid #777777;
1149
+ display: inline-table;
1150
+ margin: 0 auto;
1151
+ margin-right: 50px;
1152
+ position: relative;
1153
+ }
1154
+
1155
+ .updraftplus-vault-cta > .vault-options > .center-vault {
1156
+ width: 275px;
1157
+ height: 275px;
1158
+ }
1159
+
1160
+ .updraftplus-vault-cta > .vault-options > .center-vault > a {
1161
+ right: 21%;
1162
+ font-size: 16px;
1163
+ border-width: 4px !important;
1164
+ }
1165
+
1166
+
1167
+ .updraftplus-vault-cta > .vault-options > .center-vault > p {
1168
+ font-size: 16px;
1169
+ }
1170
+
1171
+ .updraftvault-buy .button-purchase {
1172
+ right: 24%;
1173
+ margin-left: 0;
1174
+ line-height: 1.7em;
1175
+ }
1176
+
1177
+ .updraftvault-buy hr {
1178
+ height: 2px;
1179
+ background-color: #777777;
1180
+ margin-top: 18px;
1181
+ }
1182
+
1183
+ .right {
1184
+ margin-right: 0px;
1185
+ }
1186
+
1187
+ .updraftvault-buy .addon-logo-100 {
1188
+ height: 100px;
1189
+ width: 125px;
1190
+ margin-top: 7px;
1191
+ }
1192
+
1193
+ .updraftvault-buy .addon-logo-large {
1194
+ margin-top: 7px;
1195
+ }
1196
+
1197
+ .updraftvault-buy .button-buy-vault {
1198
+ font-size: 12px;
1199
+ color: #df6926;
1200
+ border-color: #df6926;
1201
+ border-width: 2px !important;
1202
+ position: absolute;
1203
+ right: 29%;
1204
+ bottom: 2%;
1205
+ }
1206
+
1207
+ .premium-addon-div .button-purchase {
1208
+ line-height: 1.7em;
1209
+ }
1210
+
1211
+ .updraftvault-buy .button-buy-vault:hover {
1212
+ border-color: darkgrey;
1213
+ color: darkgrey;
1214
+ }
1215
+
1216
+ /* End Vault icons */
1217
+
1218
+ /* Premium addons */
1219
+
1220
+ .premium-addons {
1221
+ margin-top: 80px;
1222
+ width: 100%;
1223
+ margin: 0 auto;
1224
+ display: table;
1225
+ }
1226
+
1227
+ .addon-list {
1228
+ /* margin-left: 32px; */
1229
+ display: table;
1230
+ text-align: center;
1231
+ }
1232
+
1233
+ .premium-addons h1 {
1234
+ text-align: center;
1235
+ font-weight: bold;
1236
+ }
1237
+
1238
+ .premium-addons p {
1239
+ text-align: center;
1240
+ }
1241
+
1242
+ .premium-addons .premium-addon-div {
1243
+ width: 200px;
1244
+ height: 250px;
1245
+ border: 2px solid #777777;
1246
+ display: inline-table;
1247
+ margin: 0 auto;
1248
+ margin-right: 25px;
1249
+ margin-top: 25px;
1250
+ text-align: center;
1251
+ position: relative;
1252
+ }
1253
+
1254
+ .premium-addons .premium-addon-div p {
1255
+ margin-left: 2px;
1256
+ margin-right: 2px;
1257
+ }
1258
+
1259
+ .premium-addons .premium-addon-div img {
1260
+ width: auto;
1261
+ height: 50px;
1262
+ margin-top: 7px;
1263
+ }
1264
+
1265
+ .premium-addons .premium-addon-div .hr-alignment {
1266
+ margin-top: 44px;
1267
+ }
1268
+
1269
+ .premium-addons .premium-addon-div .dropbox-logo {
1270
+ height: 39px;
1271
+ width: 150px;
1272
+ }
1273
+
1274
+ .premium-addons .premium-addon-div .azure-logo, .premium-addons .premium-addon-div .onedrive-logo {
1275
+ width: 75%;
1276
+ height: 24px;
1277
+ }
1278
+ .button-purchase {
1279
+ font-size: 12px;
1280
+ color: #df6926;
1281
+ border-color: #df6926;
1282
+ border-width: 2px !important;
1283
+ position: absolute;
1284
+ right: 25%;
1285
+ bottom: 2%;
1286
+ }
1287
+
1288
+ .button-purchase:hover {
1289
+ color: darkgrey;
1290
+ border-color: darkgrey;
1291
+ }
1292
+
1293
+ .premium-addons .premium-addon-div hr {
1294
+ height: 2px;
1295
+ background-color: #777777;
1296
+ margin-top: 18px;
1297
+ }
1298
+
1299
+ .premium-addon-div p {
1300
+ font-style: italic;
1301
+ }
1302
+
1303
+ .addon-list > .premium-addon-div > .onedrive-fix,
1304
+ .addon-list > .premium-addon-div > .azure-logo {
1305
+ margin-top: 33px;
1306
+ }
1307
+
1308
+ .addon-list > .premium-addon-div > .dropbox-fix {
1309
+ margin-top: 18px;
1310
+ }
1311
+
1312
+ /* End premium addons */
1313
+
1314
+
1315
+ /* Forgotton something (that is the name of the div rather than a mental note!) */
1316
+
1317
+ .premium-forgotton-something {
1318
+ margin-top: 5%;
1319
+ }
1320
+
1321
+ .premium-forgotton-something h1 {
1322
+ text-align: center;
1323
+ font-weight: bold;
1324
+ }
1325
+
1326
+ .premium-forgotton-something p {
1327
+ text-align: center;
1328
+ font-weight: normal;
1329
+ }
1330
+
1331
+ .premium-forgotton-something .button-faq {
1332
+ color: #df6926;
1333
+ border-color: #df6926;
1334
+ margin: 0 auto;
1335
+ display: table;
1336
+ }
1337
+
1338
+ .premium-forgotton-something .button-faq:hover {
1339
+ color: #777777;
1340
+ border-color: #777777;
1341
+ }
1342
+
1343
+ /* End of forgotton something */
1344
 
 
 
 
 
1345
 
 
 
 
 
images/udlogo-rotating.gif ADDED
Binary file
includes/class-partialfileservlet.php ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // https://stackoverflow.com/questions/157318/resumable-downloads-when-using-php-to-send-the-file
4
+ // User: DaveRandom
5
+
6
+ if (!class_exists('UpdraftPlus_NonExistentFileException')):
7
+ class UpdraftPlus_NonExistentFileException extends RuntimeException {}
8
+ endif;
9
+
10
+ if (!class_exists('UpdraftPlus_UnreadableFileException')):
11
+ class UpdraftPlus_UnreadableFileException extends RuntimeException {}
12
+ endif;
13
+
14
+ if (!class_exists('UpdraftPlus_UnsatisfiableRangeException')):
15
+ class UpdraftPlus_UnsatisfiableRangeException extends RuntimeException {}
16
+ endif;
17
+
18
+ if (!class_exists('UpdraftPlus_InvalidRangeHeaderException')):
19
+ class UpdraftPlus_InvalidRangeHeaderException extends RuntimeException {}
20
+ endif;
21
+
22
+ class UpdraftPlus_RangeHeader
23
+ {
24
+ /**
25
+ * The first byte in the file to send (0-indexed), a null value indicates the last
26
+ * $end bytes
27
+ *
28
+ * @var int|null
29
+ */
30
+ private $firstByte;
31
+
32
+ /**
33
+ * The last byte in the file to send (0-indexed), a null value indicates $start to
34
+ * EOF
35
+ *
36
+ * @var int|null
37
+ */
38
+ private $lastByte;
39
+
40
+ /**
41
+ * Create a new instance from a Range header string
42
+ *
43
+ * @param string $header
44
+ * @return UpdraftPlus_RangeHeader
45
+ */
46
+ public static function createFromHeaderString($header)
47
+ {
48
+ if ($header === null) {
49
+ return null;
50
+ }
51
+ error_log("header=$header");
52
+ if (!preg_match('/^\s*([A-Za-z]+)\s*=\s*(\d*)\s*-\s*(\d*)\s*(?:,|$)/', $header, $info)) {
53
+ throw new UpdraftPlus_InvalidRangeHeaderException('Invalid header format');
54
+ } else if (strtolower($info[1]) !== 'bytes') {
55
+ error_log_v($info);
56
+ throw new UpdraftPlus_InvalidRangeHeaderException('Unknown range unit: ' . $info[1]);
57
+ }
58
+
59
+ return new self(
60
+ $info[2] === '' ? null : $info[2],
61
+ $info[3] === '' ? null : $info[3]
62
+ );
63
+ }
64
+
65
+ /**
66
+ * @param int|null $firstByte
67
+ * @param int|null $lastByte
68
+ * @throws UpdraftPlus_InvalidRangeHeaderException
69
+ */
70
+ public function __construct($firstByte, $lastByte)
71
+ {
72
+ $this->firstByte = $firstByte === null ? $firstByte : (int)$firstByte;
73
+ $this->lastByte = $lastByte === null ? $lastByte : (int)$lastByte;
74
+
75
+ if ($this->firstByte === null && $this->lastByte === null) {
76
+ throw new UpdraftPlus_InvalidRangeHeaderException(
77
+ 'Both start and end position specifiers empty'
78
+ );
79
+ } else if ($this->firstByte < 0 || $this->lastByte < 0) {
80
+ throw new UpdraftPlus_InvalidRangeHeaderException(
81
+ 'Position specifiers cannot be negative'
82
+ );
83
+ } else if ($this->lastByte !== null && $this->lastByte < $this->firstByte) {
84
+ throw new UpdraftPlus_InvalidRangeHeaderException(
85
+ 'Last byte cannot be less than first byte'
86
+ );
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Get the start position when this range is applied to a file of the specified size
92
+ *
93
+ * @param int $fileSize
94
+ * @return int
95
+ * @throws UpdraftPlus_UnsatisfiableRangeException
96
+ */
97
+ public function getStartPosition($fileSize)
98
+ {
99
+ $size = (int)$fileSize;
100
+
101
+ if ($this->firstByte === null) {
102
+ return ($size - 1) - $this->lastByte;
103
+ }
104
+
105
+ if ($size <= $this->firstByte) {
106
+ throw new UpdraftPlus_UnsatisfiableRangeException(
107
+ 'Start position is after the end of the file'
108
+ );
109
+ }
110
+
111
+ return $this->firstByte;
112
+ }
113
+
114
+ /**
115
+ * Get the end position when this range is applied to a file of the specified size
116
+ *
117
+ * @param int $fileSize
118
+ * @return int
119
+ * @throws UpdraftPlus_UnsatisfiableRangeException
120
+ */
121
+ public function getEndPosition($fileSize)
122
+ {
123
+ $size = (int)$fileSize;
124
+
125
+ if ($this->lastByte === null) {
126
+ return $size - 1;
127
+ }
128
+
129
+ if ($size <= $this->lastByte) {
130
+ throw new UpdraftPlus_UnsatisfiableRangeException(
131
+ 'End position is after the end of the file'
132
+ );
133
+ }
134
+
135
+ return $this->lastByte;
136
+ }
137
+
138
+ /**
139
+ * Get the length when this range is applied to a file of the specified size
140
+ *
141
+ * @param int $fileSize
142
+ * @return int
143
+ * @throws UpdraftPlus_UnsatisfiableRangeException
144
+ */
145
+ public function getLength($fileSize)
146
+ {
147
+ $size = (int)$fileSize;
148
+
149
+ return $this->getEndPosition($size) - $this->getStartPosition($size) + 1;
150
+ }
151
+
152
+ /**
153
+ * Get a Content-Range header corresponding to this Range and the specified file
154
+ * size
155
+ *
156
+ * @param int $fileSize
157
+ * @return string
158
+ */
159
+ public function getContentRangeHeader($fileSize)
160
+ {
161
+ return 'bytes ' . $this->getStartPosition($fileSize) . '-'
162
+ . $this->getEndPosition($fileSize) . '/' . $fileSize;
163
+ }
164
+ }
165
+
166
+ class UpdraftPlus_PartialFileServlet
167
+ {
168
+ /**
169
+ * The range header on which the data transmission will be based
170
+ *
171
+ * @var UpdraftPlus_RangeHeader|null
172
+ */
173
+ private $range;
174
+
175
+ /**
176
+ * @param UpdraftPlus_RangeHeader $range Range header on which the transmission will be based
177
+ */
178
+ public function __construct($range = null)
179
+ {
180
+ $this->range = $range;
181
+ }
182
+
183
+ /**
184
+ * Send part of the data in a seekable stream resource to the output buffer
185
+ *
186
+ * @param resource $fp Stream resource to read data from
187
+ * @param int $start Position in the stream to start reading
188
+ * @param int $length Number of bytes to read
189
+ * @param int $chunkSize Maximum bytes to read from the file in a single operation
190
+ */
191
+ private function sendDataRange($fp, $start, $length, $chunkSize = 2097152)
192
+ {
193
+ if ($start > 0) {
194
+ fseek($fp, $start, SEEK_SET);
195
+ }
196
+
197
+ while ($length) {
198
+ $read = ($length > $chunkSize) ? $chunkSize : $length;
199
+ $length -= $read;
200
+ echo fread($fp, $read);
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Send the headers that are included regardless of whether a range was requested
206
+ *
207
+ * @param string $fileName
208
+ * @param int $contentLength
209
+ * @param string $contentType
210
+ */
211
+ private function sendDownloadHeaders($fileName, $contentLength, $contentType)
212
+ {
213
+ header('Content-Type: ' . $contentType);
214
+ header('Content-Length: ' . $contentLength);
215
+ header('Content-Disposition: attachment; filename="' . $fileName . '"');
216
+ header('Accept-Ranges: bytes');
217
+ }
218
+
219
+ /**
220
+ * Send data from a file based on the current Range header
221
+ *
222
+ * @param string $path Local file system path to serve
223
+ * @param string $contentType MIME type of the data stream
224
+ */
225
+ public function sendFile($path, $contentType = 'application/octet-stream')
226
+ {
227
+ // Make sure the file exists and is a file, otherwise we are wasting our time
228
+ $localPath = realpath($path);
229
+ if ($localPath === false || !is_file($localPath)) {
230
+ throw new UpdraftPlus_NonExistentFileException(
231
+ $path . ' does not exist or is not a file'
232
+ );
233
+ }
234
+
235
+ // Make sure we can open the file for reading
236
+ if (!$fp = fopen($localPath, 'r')) {
237
+ throw new UpdraftPlus_UnreadableFileException(
238
+ 'Failed to open ' . $localPath . ' for reading'
239
+ );
240
+ }
241
+
242
+ $fileSize = filesize($localPath);
243
+
244
+ if ($this->range == null) {
245
+ // No range requested, just send the whole file
246
+ header('HTTP/1.1 200 OK');
247
+ $this->sendDownloadHeaders(basename($localPath), $fileSize, $contentType);
248
+
249
+ fpassthru($fp);
250
+ } else {
251
+ // Send the request range
252
+ header('HTTP/1.1 206 Partial Content');
253
+ header('Content-Range: ' . $this->range->getContentRangeHeader($fileSize));
254
+ $this->sendDownloadHeaders(
255
+ basename($localPath),
256
+ $this->range->getLength($fileSize),
257
+ $contentType
258
+ );
259
+
260
+ $this->sendDataRange(
261
+ $fp,
262
+ $this->range->getStartPosition($fileSize),
263
+ $this->range->getLength($fileSize)
264
+ );
265
+ }
266
+
267
+ fclose($fp);
268
+ }
269
+ }
includes/jquery.blockUI.js ADDED
@@ -0,0 +1,619 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery blockUI plugin
3
+ * Version 2.70.0-2014.11.23
4
+ * Requires jQuery v1.7 or later
5
+ *
6
+ * Examples at: http://malsup.com/jquery/block/
7
+ * Copyright (c) 2007-2013 M. Alsup
8
+ * Dual licensed under the MIT and GPL licenses:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ * http://www.gnu.org/licenses/gpl.html
11
+ *
12
+ * Thanks to Amir-Hossein Sobhi for some excellent contributions!
13
+ */
14
+ ;(function() {
15
+ /*jshint eqeqeq:false curly:false latedef:false */
16
+ "use strict";
17
+
18
+ function setup($) {
19
+ $.fn._fadeIn = $.fn.fadeIn;
20
+
21
+ var noOp = $.noop || function() {};
22
+
23
+ // this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
24
+ // confusing userAgent strings on Vista)
25
+ var msie = /MSIE/.test(navigator.userAgent);
26
+ var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
27
+ var mode = document.documentMode || 0;
28
+ var setExpr = $.isFunction( document.createElement('div').style.setExpression );
29
+
30
+ // global $ methods for blocking/unblocking the entire page
31
+ $.blockUI = function(opts) { install(window, opts); };
32
+ $.unblockUI = function(opts) { remove(window, opts); };
33
+
34
+ // convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
35
+ $.growlUI = function(title, message, timeout, onClose) {
36
+ var $m = $('<div class="growlUI"></div>');
37
+ if (title) $m.append('<h1>'+title+'</h1>');
38
+ if (message) $m.append('<h2>'+message+'</h2>');
39
+ if (timeout === undefined) timeout = 3000;
40
+
41
+ // Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
42
+ var callBlock = function(opts) {
43
+ opts = opts || {};
44
+
45
+ $.blockUI({
46
+ message: $m,
47
+ fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
48
+ fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
49
+ timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
50
+ centerY: false,
51
+ showOverlay: false,
52
+ onUnblock: onClose,
53
+ css: $.blockUI.defaults.growlCSS
54
+ });
55
+ };
56
+
57
+ callBlock();
58
+ var nonmousedOpacity = $m.css('opacity');
59
+ $m.mouseover(function() {
60
+ callBlock({
61
+ fadeIn: 0,
62
+ timeout: 30000
63
+ });
64
+
65
+ var displayBlock = $('.blockMsg');
66
+ displayBlock.stop(); // cancel fadeout if it has started
67
+ displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
68
+ }).mouseout(function() {
69
+ $('.blockMsg').fadeOut(1000);
70
+ });
71
+ // End konapun additions
72
+ };
73
+
74
+ // plugin method for blocking element content
75
+ $.fn.block = function(opts) {
76
+ if ( this[0] === window ) {
77
+ $.blockUI( opts );
78
+ return this;
79
+ }
80
+ var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
81
+ this.each(function() {
82
+ var $el = $(this);
83
+ if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
84
+ return;
85
+ $el.unblock({ fadeOut: 0 });
86
+ });
87
+
88
+ return this.each(function() {
89
+ if ($.css(this,'position') == 'static') {
90
+ this.style.position = 'relative';
91
+ $(this).data('blockUI.static', true);
92
+ }
93
+ this.style.zoom = 1; // force 'hasLayout' in ie
94
+ install(this, opts);
95
+ });
96
+ };
97
+
98
+ // plugin method for unblocking element content
99
+ $.fn.unblock = function(opts) {
100
+ if ( this[0] === window ) {
101
+ $.unblockUI( opts );
102
+ return this;
103
+ }
104
+ return this.each(function() {
105
+ remove(this, opts);
106
+ });
107
+ };
108
+
109
+ $.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
110
+
111
+ // override these in your code to change the default behavior and style
112
+ $.blockUI.defaults = {
113
+ // message displayed when blocking (use null for no message)
114
+ message: '<h1>Please wait...</h1>',
115
+
116
+ title: null, // title string; only used when theme == true
117
+ draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
118
+
119
+ theme: false, // set to true to use with jQuery UI themes
120
+
121
+ // styles for the message when blocking; if you wish to disable
122
+ // these and use an external stylesheet then do this in your code:
123
+ // $.blockUI.defaults.css = {};
124
+ css: {
125
+ padding: 0,
126
+ margin: 0,
127
+ width: '30%',
128
+ top: '40%',
129
+ left: '35%',
130
+ textAlign: 'center',
131
+ color: '#000',
132
+ border: '3px solid #aaa',
133
+ backgroundColor:'#fff',
134
+ cursor: 'wait'
135
+ },
136
+
137
+ // minimal style set used when themes are used
138
+ themedCSS: {
139
+ width: '30%',
140
+ top: '40%',
141
+ left: '35%'
142
+ },
143
+
144
+ // styles for the overlay
145
+ overlayCSS: {
146
+ backgroundColor: '#000',
147
+ opacity: 0.6,
148
+ cursor: 'wait'
149
+ },
150
+
151
+ // style to replace wait cursor before unblocking to correct issue
152
+ // of lingering wait cursor
153
+ cursorReset: 'default',
154
+
155
+ // styles applied when using $.growlUI
156
+ growlCSS: {
157
+ width: '350px',
158
+ top: '10px',
159
+ left: '',
160
+ right: '10px',
161
+ border: 'none',
162
+ padding: '5px',
163
+ opacity: 0.6,
164
+ cursor: 'default',
165
+ color: '#fff',
166
+ backgroundColor: '#000',
167
+ '-webkit-border-radius':'10px',
168
+ '-moz-border-radius': '10px',
169
+ 'border-radius': '10px'
170
+ },
171
+
172
+ // IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
173
+ // (hat tip to Jorge H. N. de Vasconcelos)
174
+ /*jshint scripturl:true */
175
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
176
+
177
+ // force usage of iframe in non-IE browsers (handy for blocking applets)
178
+ forceIframe: false,
179
+
180
+ // z-index for the blocking overlay
181
+ baseZ: 1000,
182
+
183
+ // set these to true to have the message automatically centered
184
+ centerX: true, // <-- only effects element blocking (page block controlled via css above)
185
+ centerY: true,
186
+
187
+ // allow body element to be stetched in ie6; this makes blocking look better
188
+ // on "short" pages. disable if you wish to prevent changes to the body height
189
+ allowBodyStretch: true,
190
+
191
+ // enable if you want key and mouse events to be disabled for content that is blocked
192
+ bindEvents: true,
193
+
194
+ // be default blockUI will supress tab navigation from leaving blocking content
195
+ // (if bindEvents is true)
196
+ constrainTabKey: true,
197
+
198
+ // fadeIn time in millis; set to 0 to disable fadeIn on block
199
+ fadeIn: 200,
200
+
201
+ // fadeOut time in millis; set to 0 to disable fadeOut on unblock
202
+ fadeOut: 400,
203
+
204
+ // time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
205
+ timeout: 0,
206
+
207
+ // disable if you don't want to show the overlay
208
+ showOverlay: true,
209
+
210
+ // if true, focus will be placed in the first available input field when
211
+ // page blocking
212
+ focusInput: true,
213
+
214
+ // elements that can receive focus
215
+ focusableElements: ':input:enabled:visible',
216
+
217
+ // suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
218
+ // no longer needed in 2012
219
+ // applyPlatformOpacityRules: true,
220
+
221
+ // callback method invoked when fadeIn has completed and blocking message is visible
222
+ onBlock: null,
223
+
224
+ // callback method invoked when unblocking has completed; the callback is
225
+ // passed the element that has been unblocked (which is the window object for page
226
+ // blocks) and the options that were passed to the unblock call:
227
+ // onUnblock(element, options)
228
+ onUnblock: null,
229
+
230
+ // callback method invoked when the overlay area is clicked.
231
+ // setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
232
+ onOverlayClick: null,
233
+
234
+ // don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
235
+ quirksmodeOffsetHack: 4,
236
+
237
+ // class name of the message block
238
+ blockMsgClass: 'blockMsg',
239
+
240
+ // if it is already blocked, then ignore it (don't unblock and reblock)
241
+ ignoreIfBlocked: false
242
+ };
243
+
244
+ // private data and functions follow...
245
+
246
+ var pageBlock = null;
247
+ var pageBlockEls = [];
248
+
249
+ function install(el, opts) {
250
+ var css, themedCSS;
251
+ var full = (el == window);
252
+ var msg = (opts && opts.message !== undefined ? opts.message : undefined);
253
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
254
+
255
+ if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
256
+ return;
257
+
258
+ opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
259
+ css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
260
+ if (opts.onOverlayClick)
261
+ opts.overlayCSS.cursor = 'pointer';
262
+
263
+ themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
264
+ msg = msg === undefined ? opts.message : msg;
265
+
266
+ // remove the current block (if there is one)
267
+ if (full && pageBlock)
268
+ remove(window, {fadeOut:0});
269
+
270
+ // if an existing element is being used as the blocking content then we capture
271
+ // its current place in the DOM (and current display style) so we can restore
272
+ // it when we unblock
273
+ if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
274
+ var node = msg.jquery ? msg[0] : msg;
275
+ var data = {};
276
+ $(el).data('blockUI.history', data);
277
+ data.el = node;
278
+ data.parent = node.parentNode;
279
+ data.display = node.style.display;
280
+ data.position = node.style.position;
281
+ if (data.parent)
282
+ data.parent.removeChild(node);
283
+ }
284
+
285
+ $(el).data('blockUI.onUnblock', opts.onUnblock);
286
+ var z = opts.baseZ;
287
+
288
+ // blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
289
+ // layer1 is the iframe layer which is used to supress bleed through of underlying content
290
+ // layer2 is the overlay layer which has opacity and a wait cursor (by default)
291
+ // layer3 is the message content that is displayed while blocking
292
+ var lyr1, lyr2, lyr3, s;
293
+ if (msie || opts.forceIframe)
294
+ lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
295
+ else
296
+ lyr1 = $('<div class="blockUI" style="display:none"></div>');
297
+
298
+ if (opts.theme)
299
+ lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
300
+ else
301
+ lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
302
+
303
+ if (opts.theme && full) {
304
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
305
+ if ( opts.title ) {
306
+ s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
307
+ }
308
+ s += '<div class="ui-widget-content ui-dialog-content"></div>';
309
+ s += '</div>';
310
+ }
311
+ else if (opts.theme) {
312
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
313
+ if ( opts.title ) {
314
+ s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
315
+ }
316
+ s += '<div class="ui-widget-content ui-dialog-content"></div>';
317
+ s += '</div>';
318
+ }
319
+ else if (full) {
320
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
321
+ }
322
+ else {
323
+ s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
324
+ }
325
+ lyr3 = $(s);
326
+
327
+ // if we have a message, style it
328
+ if (msg) {
329
+ if (opts.theme) {
330
+ lyr3.css(themedCSS);
331
+ lyr3.addClass('ui-widget-content');
332
+ }
333
+ else
334
+ lyr3.css(css);
335
+ }
336
+
337
+ // style the overlay
338
+ if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
339
+ lyr2.css(opts.overlayCSS);
340
+ lyr2.css('position', full ? 'fixed' : 'absolute');
341
+
342
+ // make iframe layer transparent in IE
343
+ if (msie || opts.forceIframe)
344
+ lyr1.css('opacity',0.0);
345
+
346
+ //$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
347
+ var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
348
+ $.each(layers, function() {
349
+ this.appendTo($par);
350
+ });
351
+
352
+ if (opts.theme && opts.draggable && $.fn.draggable) {
353
+ lyr3.draggable({
354
+ handle: '.ui-dialog-titlebar',
355
+ cancel: 'li'
356
+ });
357
+ }
358
+
359
+ // ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
360
+ var expr = setExpr && (!$.support.boxModel || $('object,embed', full ? null : el).length > 0);
361
+ if (ie6 || expr) {
362
+ // give body 100% height
363
+ if (full && opts.allowBodyStretch && $.support.boxModel)
364
+ $('html,body').css('height','100%');
365
+
366
+ // fix ie6 issue when blocked element has a border width
367
+ if ((ie6 || !$.support.boxModel) && !full) {
368
+ var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
369
+ var fixT = t ? '(0 - '+t+')' : 0;
370
+ var fixL = l ? '(0 - '+l+')' : 0;
371
+ }
372
+
373
+ // simulate fixed position
374
+ $.each(layers, function(i,o) {
375
+ var s = o[0].style;
376
+ s.position = 'absolute';
377
+ if (i < 2) {
378
+ if (full)
379
+ s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.support.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"');
380
+ else
381
+ s.setExpression('height','this.parentNode.offsetHeight + "px"');
382
+ if (full)
383
+ s.setExpression('width','jQuery.support.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"');
384
+ else
385
+ s.setExpression('width','this.parentNode.offsetWidth + "px"');
386
+ if (fixL) s.setExpression('left', fixL);
387
+ if (fixT) s.setExpression('top', fixT);
388
+ }
389
+ else if (opts.centerY) {
390
+ if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
391
+ s.marginTop = 0;
392
+ }
393
+ else if (!opts.centerY && full) {
394
+ var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
395
+ var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
396
+ s.setExpression('top',expression);
397
+ }
398
+ });
399
+ }
400
+
401
+ // show the message
402
+ if (msg) {
403
+ if (opts.theme)
404
+ lyr3.find('.ui-widget-content').append(msg);
405
+ else
406
+ lyr3.append(msg);
407
+ if (msg.jquery || msg.nodeType)
408
+ $(msg).show();
409
+ }
410
+
411
+ if ((msie || opts.forceIframe) && opts.showOverlay)
412
+ lyr1.show(); // opacity is zero
413
+ if (opts.fadeIn) {
414
+ var cb = opts.onBlock ? opts.onBlock : noOp;
415
+ var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
416
+ var cb2 = msg ? cb : noOp;
417
+ if (opts.showOverlay)
418
+ lyr2._fadeIn(opts.fadeIn, cb1);
419
+ if (msg)
420
+ lyr3._fadeIn(opts.fadeIn, cb2);
421
+ }
422
+ else {
423
+ if (opts.showOverlay)
424
+ lyr2.show();
425
+ if (msg)
426
+ lyr3.show();
427
+ if (opts.onBlock)
428
+ opts.onBlock.bind(lyr3)();
429
+ }
430
+
431
+ // bind key and mouse events
432
+ bind(1, el, opts);
433
+
434
+ if (full) {
435
+ pageBlock = lyr3[0];
436
+ pageBlockEls = $(opts.focusableElements,pageBlock);
437
+ if (opts.focusInput)
438
+ setTimeout(focus, 20);
439
+ }
440
+ else
441
+ center(lyr3[0], opts.centerX, opts.centerY);
442
+
443
+ if (opts.timeout) {
444
+ // auto-unblock
445
+ var to = setTimeout(function() {
446
+ if (full)
447
+ $.unblockUI(opts);
448
+ else
449
+ $(el).unblock(opts);
450
+ }, opts.timeout);
451
+ $(el).data('blockUI.timeout', to);
452
+ }
453
+ }
454
+
455
+ // remove the block
456
+ function remove(el, opts) {
457
+ var count;
458
+ var full = (el == window);
459
+ var $el = $(el);
460
+ var data = $el.data('blockUI.history');
461
+ var to = $el.data('blockUI.timeout');
462
+ if (to) {
463
+ clearTimeout(to);
464
+ $el.removeData('blockUI.timeout');
465
+ }
466
+ opts = $.extend({}, $.blockUI.defaults, opts || {});
467
+ bind(0, el, opts); // unbind events
468
+
469
+ if (opts.onUnblock === null) {
470
+ opts.onUnblock = $el.data('blockUI.onUnblock');
471
+ $el.removeData('blockUI.onUnblock');
472
+ }
473
+
474
+ var els;
475
+ if (full) // crazy selector to handle odd field errors in ie6/7
476
+ els = $('body').children().filter('.blockUI').add('body > .blockUI');
477
+ else
478
+ els = $el.find('>.blockUI');
479
+
480
+ // fix cursor issue
481
+ if ( opts.cursorReset ) {
482
+ if ( els.length > 1 )
483
+ els[1].style.cursor = opts.cursorReset;
484
+ if ( els.length > 2 )
485
+ els[2].style.cursor = opts.cursorReset;
486
+ }
487
+
488
+ if (full)
489
+ pageBlock = pageBlockEls = null;
490
+
491
+ if (opts.fadeOut) {
492
+ count = els.length;
493
+ els.stop().fadeOut(opts.fadeOut, function() {
494
+ if ( --count === 0)
495
+ reset(els,data,opts,el);
496
+ });
497
+ }
498
+ else
499
+ reset(els, data, opts, el);
500
+ }
501
+
502
+ // move blocking element back into the DOM where it started
503
+ function reset(els,data,opts,el) {
504
+ var $el = $(el);
505
+ if ( $el.data('blockUI.isBlocked') )
506
+ return;
507
+
508
+ els.each(function(i,o) {
509
+ // remove via DOM calls so we don't lose event handlers
510
+ if (this.parentNode)
511
+ this.parentNode.removeChild(this);
512
+ });
513
+
514
+ if (data && data.el) {
515
+ data.el.style.display = data.display;
516
+ data.el.style.position = data.position;
517
+ data.el.style.cursor = 'default'; // #59
518
+ if (data.parent)
519
+ data.parent.appendChild(data.el);
520
+ $el.removeData('blockUI.history');
521
+ }
522
+
523
+ if ($el.data('blockUI.static')) {
524
+ $el.css('position', 'static'); // #22
525
+ }
526
+
527
+ if (typeof opts.onUnblock == 'function')
528
+ opts.onUnblock(el,opts);
529
+
530
+ // fix issue in Safari 6 where block artifacts remain until reflow
531
+ var body = $(document.body), w = body.width(), cssW = body[0].style.width;
532
+ body.width(w-1).width(w);
533
+ body[0].style.width = cssW;
534
+ }
535
+
536
+ // bind/unbind the handler
537
+ function bind(b, el, opts) {
538
+ var full = el == window, $el = $(el);
539
+
540
+ // don't bother unbinding if there is nothing to unbind
541
+ if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
542
+ return;
543
+
544
+ $el.data('blockUI.isBlocked', b);
545
+
546
+ // don't bind events when overlay is not in use or if bindEvents is false
547
+ if (!full || !opts.bindEvents || (b && !opts.showOverlay))
548
+ return;
549
+
550
+ // bind anchors and inputs for mouse and key events
551
+ var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
552
+ if (b)
553
+ $(document).bind(events, opts, handler);
554
+ else
555
+ $(document).unbind(events, handler);
556
+
557
+ // former impl...
558
+ // var $e = $('a,:input');
559
+ // b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
560
+ }
561
+
562
+ // event handler to suppress keyboard/mouse events when blocking
563
+ function handler(e) {
564
+ // allow tab navigation (conditionally)
565
+ if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
566
+ if (pageBlock && e.data.constrainTabKey) {
567
+ var els = pageBlockEls;
568
+ var fwd = !e.shiftKey && e.target === els[els.length-1];
569
+ var back = e.shiftKey && e.target === els[0];
570
+ if (fwd || back) {
571
+ setTimeout(function(){focus(back);},10);
572
+ return false;
573
+ }
574
+ }
575
+ }
576
+ var opts = e.data;
577
+ var target = $(e.target);
578
+ if (target.hasClass('blockOverlay') && opts.onOverlayClick)
579
+ opts.onOverlayClick(e);
580
+
581
+ // allow events within the message content
582
+ if (target.parents('div.' + opts.blockMsgClass).length > 0)
583
+ return true;
584
+
585
+ // allow events for content that is not being blocked
586
+ return target.parents().children().filter('div.blockUI').length === 0;
587
+ }
588
+
589
+ function focus(back) {
590
+ if (!pageBlockEls)
591
+ return;
592
+ var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
593
+ if (e)
594
+ e.focus();
595
+ }
596
+
597
+ function center(el, x, y) {
598
+ var p = el.parentNode, s = el.style;
599
+ var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
600
+ var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
601
+ if (x) s.left = l > 0 ? (l+'px') : '0';
602
+ if (y) s.top = t > 0 ? (t+'px') : '0';
603
+ }
604
+
605
+ function sz(el, p) {
606
+ return parseInt($.css(el,p),10)||0;
607
+ }
608
+
609
+ }
610
+
611
+
612
+ /*global define:true */
613
+ if (typeof define === 'function' && define.amd && define.amd.jQuery) {
614
+ define(['jquery'], setup);
615
+ } else {
616
+ setup(jQuery);
617
+ }
618
+
619
+ })();
includes/updraft-admin-ui.js CHANGED
@@ -639,8 +639,19 @@ function updraftplus_deletefromserver(timestamp, type, findex) {
639
  _wpnonce: updraft_download_nonce
640
  };
641
  jQuery.post(ajaxurl, pdata, function(response) {
 
642
  if (response != 'deleted') {
643
- alert('We requested to delete the file, but could not understand the server\'s response '+response);
 
 
 
 
 
 
 
 
 
 
644
  }
645
  });
646
  }
@@ -648,33 +659,46 @@ function updraftplus_downloadstage2(timestamp, type, findex) {
648
  location.href=ajaxurl+'?_wpnonce='+updraft_download_nonce+'&timestamp='+timestamp+'&type='+type+'&stage=2&findex='+findex+'&action=updraft_download_backup';
649
  }
650
 
651
- function updraft_downloader(base, nonce, what, whicharea, set_contents, prettydate, async) {
652
- if (typeof set_contents !== "string") set_contents=set_contents.toString();
 
 
653
  var set_contents = set_contents.split(',');
 
654
  for (var i=0; i<set_contents.length; i++) {
655
  // Create somewhere for the status to be found
656
- var stid = base+nonce+'_'+what+'_'+set_contents[i];
657
  var stid_selector = '.'+stid;
658
  var show_index = parseInt(set_contents[i]); show_index++;
659
  var itext = (set_contents[i] == 0) ? '' : ' ('+show_index+')';
660
  if (!jQuery(stid_selector).length) {
661
- var prdate = (prettydate) ? prettydate : nonce;
662
- jQuery(whicharea).append('<div style="clear:left; border: 1px solid; padding: 8px; margin-top: 4px; max-width:840px;" class="'+stid+' updraftplus_downloader"><button onclick="jQuery(this).parent().fadeOut().remove();" type="button" style="float:right; margin-bottom: 8px;">X</button><strong>'+updraftlion.download+' '+what+itext+' ('+prdate+')</strong>:<div class="raw">'+updraftlion.begunlooking+'</div><div class="file '+stid+'_st"><div class="dlfileprogress" style="width: 0;"></div></div>');
663
- jQuery(stid_selector).data('downloaderfor', { base: base, nonce: nonce, what: what, index: i });
664
- // Legacy: set up watcher
665
- //(function(base, nonce, what, i) {
666
- // setTimeout(function(){updraft_downloader_status(base, nonce, what, i);}, 300);
667
- //})(base, nonce, what, set_contents[i]);
668
  setTimeout(function() {updraft_activejobs_update(true);}, 1500);
669
  }
670
  jQuery(stid_selector).data('lasttimebegan', (new Date).getTime());
 
671
  // Now send the actual request to kick it all off
 
 
 
 
 
 
 
 
 
 
 
 
 
672
  jQuery.ajax({
673
  url: ajaxurl,
674
  timeout: 10000,
675
  type: 'POST',
676
  async: async,
677
- data: jQuery('#updraft-navtab-backups-content .uddownloadform_'+what+'_'+nonce+'_'+set_contents[i]).serialize()
678
  });
679
  }
680
  // We don't want the form to submit as that replaces the document
@@ -810,8 +834,8 @@ return;
810
  // });
811
  }
812
 
813
- function updraft_downloader_status_update(base, nonce, what, findex, resp, response) {
814
- var stid = base+nonce+'_'+what+'_'+findex;
815
  var stid_selector = '.'+stid;
816
  var cancel_repeat = 0;
817
  if (resp.e != null) {
@@ -830,13 +854,25 @@ function updraft_downloader_status_update(base, nonce, what, findex, resp, respo
830
  // Remember that this is in milliseconds
831
  var sincelastrestart = timenow - lasttimebegan;
832
  if (resp.a > 90 && sincelastrestart > 60000) {
833
- console.log(nonce+" "+what+" "+findex+": restarting download: file_age="+resp.a+", sincelastrestart_ms="+sincelastrestart);
834
  jQuery(stid_selector).data('lasttimebegan', (new Date).getTime());
 
 
 
 
 
 
 
 
 
 
 
835
  jQuery.ajax({
836
  url: ajaxurl,
837
  timeout: 10000,
838
  type: 'POST',
839
- data: jQuery('#updraft-navtab-backups-content .uddownloadform_'+what+'_'+nonce+'_'+findex).serialize()
 
840
  });
841
  jQuery(stid_selector).data('lasttimebegan', (new Date).getTime());
842
  }
@@ -849,7 +885,7 @@ function updraft_downloader_status_update(base, nonce, what, findex, resp, respo
849
  } else if (resp.p < 100 || base != 'uddlstatus_') {
850
  jQuery(stid_selector+' .raw').html(resp.m);
851
  } else {
852
- jQuery(stid_selector+' .raw').html(updraftlion.fileready+' '+ updraftlion.youshould+' <button type="button" onclick="updraftplus_downloadstage2(\''+nonce+'\', \''+what+'\', \''+findex+'\')\">'+updraftlion.downloadtocomputer+'</button> '+updraftlion.andthen+' <button id="uddownloaddelete_'+nonce+'_'+what+'" type="button" onclick="updraftplus_deletefromserver(\''+nonce+'\', \''+what+'\', \''+findex+'\')\">'+updraftlion.deletefromserver+'</button>');
853
  }
854
  }
855
  // dlstatus_lastlog = response;
@@ -906,7 +942,7 @@ jQuery(document).ready(function($){
906
  if (jQuery.ui && jQuery.ui.dialog && jQuery.ui.dialog.prototype._allowInteraction) {
907
  var ui_dialog_interaction = jQuery.ui.dialog.prototype._allowInteraction;
908
  jQuery.ui.dialog.prototype._allowInteraction = function(e) {
909
- if ($(e.target).closest('.select2-dropdown').length) return true;
910
  return ui_dialog_interaction.apply(this, arguments);
911
  };
912
  }
@@ -1523,17 +1559,17 @@ jQuery(document).ready(function($){
1523
 
1524
  // checks if browser supports drag and drop upload, makes some css adjustments if necessary
1525
  uploader.bind('Init', function(up){
1526
- var uploaddiv = $('#plupload-upload-ui');
1527
 
1528
  if (up.features.dragdrop){
1529
  uploaddiv.addClass('drag-drop');
1530
- $('#drag-drop-area')
1531
  .bind('dragover.wp-uploader', function(){ uploaddiv.addClass('drag-over'); })
1532
  .bind('dragleave.wp-uploader, drop.wp-uploader', function(){ uploaddiv.removeClass('drag-over'); });
1533
 
1534
  } else {
1535
  uploaddiv.removeClass('drag-drop');
1536
- $('#drag-drop-area').unbind('.wp-uploader');
1537
  }
1538
  });
1539
 
@@ -1565,7 +1601,7 @@ jQuery(document).ready(function($){
1565
  }
1566
 
1567
  // a file was added, you may want to update your DOM here...
1568
- $('#filelist').append(
1569
  '<div class="file" id="' + file.id + '"><b>' +
1570
  file.name + '</b> (<span>' + plupload.formatSize(0) + '</span>/' + plupload.formatSize(file.size) + ') ' +
1571
  '<div class="fileprogress"></div></div>');
@@ -1576,8 +1612,8 @@ jQuery(document).ready(function($){
1576
  });
1577
 
1578
  uploader.bind('UploadProgress', function(up, file) {
1579
- $('#' + file.id + " .fileprogress").width(file.percent + "%");
1580
- $('#' + file.id + " span").html(plupload.formatSize(parseInt(file.size * file.percent / 100)));
1581
  });
1582
 
1583
  uploader.bind('Error', function(up, error) {
@@ -1617,20 +1653,20 @@ jQuery(document).ready(function($){
1617
  }
1618
 
1619
  // Functions in the debugging console
1620
- $('#updraftplus_httpget_go').click(function(e) {
1621
  e.preventDefault();
1622
  updraftplus_httpget_go(0);
1623
  });
1624
 
1625
- $('#updraftplus_httpget_gocurl').click(function(e) {
1626
  e.preventDefault();
1627
  updraftplus_httpget_go(1);
1628
  });
1629
 
1630
- $('#updraftplus_callwpaction_go').click(function(e) {
1631
  e.preventDefault();
1632
- params = { action: 'updraft_ajax', subaction: 'callwpaction', nonce: updraft_credentialtest_nonce, wpaction: $('#updraftplus_callwpaction').val() };
1633
- $.get(ajaxurl, params, function(response) {
1634
  try {
1635
  resp = jQuery.parseJSON(response);
1636
  if (resp.e) {
@@ -1638,7 +1674,7 @@ jQuery(document).ready(function($){
1638
  } else if (resp.s) {
1639
  // Silence
1640
  } else if (resp.r) {
1641
- $('#updraftplus_callwpaction_results').html(resp.r);
1642
  } else {
1643
  console.log(response);
1644
  alert(updraftlion.jsonnotunderstood);
@@ -1652,16 +1688,16 @@ jQuery(document).ready(function($){
1652
  });
1653
 
1654
  function updraftplus_httpget_go(curl) {
1655
- params = { action: 'updraft_ajax', subaction: 'httpget', nonce: updraft_credentialtest_nonce, uri: $('#updraftplus_httpget_uri').val() };
1656
  params.curl = curl;
1657
- $.get(ajaxurl, params, function(response) {
1658
  try {
1659
  resp = jQuery.parseJSON(response);
1660
  if (resp.e) {
1661
  alert(resp.e);
1662
  }
1663
  if (resp.r) {
1664
- $('#updraftplus_httpget_results').html('<pre>'+resp.r+'</pre>');
1665
  } else {
1666
  console.log(response);
1667
  //alert(updraftlion.jsonnotunderstood);
@@ -1675,9 +1711,9 @@ jQuery(document).ready(function($){
1675
  });
1676
  }
1677
 
1678
- $('#updraft_activejobs_table').on('click', '.updraft_jobinfo_delete', function(e) {
1679
  e.preventDefault();
1680
- var job_id = $(this).data('jobid');
1681
  if (job_id) {
1682
  updraft_activejobs_delete(job_id);
1683
  } else {
@@ -1685,9 +1721,9 @@ jQuery(document).ready(function($){
1685
  }
1686
  });
1687
 
1688
- $('#updraft_activejobs_table').on('click', '.updraft-log-link', function(e) {
1689
  e.preventDefault();
1690
- var job_id = $(this).data('jobid');
1691
  if (job_id) {
1692
  updraft_popuplog(job_id);
1693
  } else {
@@ -1695,7 +1731,78 @@ jQuery(document).ready(function($){
1695
  }
1696
  });
1697
 
1698
- // ,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1699
  jQuery('#updraft-navtab-backups-content .updraft_existing_backups').on('tripleclick', '.updraft_existingbackup_date', { threshold: 500 }, function(e) {
1700
  e.preventDefault();
1701
  var data = jQuery(this).data('rawbackup');
@@ -1732,16 +1839,16 @@ jQuery(document).ready(function($){
1732
 
1733
  // checks if browser supports drag and drop upload, makes some css adjustments if necessary
1734
  uploader.bind('Init', function(up){
1735
- var uploaddiv = $('#plupload-upload-ui2');
1736
 
1737
  if (up.features.dragdrop){
1738
  uploaddiv.addClass('drag-drop');
1739
- $('#drag-drop-area2')
1740
  .bind('dragover.wp-uploader', function(){ uploaddiv.addClass('drag-over'); })
1741
  .bind('dragleave.wp-uploader, drop.wp-uploader', function(){ uploaddiv.removeClass('drag-over'); });
1742
  } else {
1743
  uploaddiv.removeClass('drag-drop');
1744
- $('#drag-drop-area2').unbind('.wp-uploader');
1745
  }
1746
  });
1747
 
@@ -1760,7 +1867,7 @@ jQuery(document).ready(function($){
1760
  }
1761
 
1762
  // a file was added, you may want to update your DOM here...
1763
- $('#filelist2').append(
1764
  '<div class="file" id="' + file.id + '"><b>' +
1765
  file.name + '</b> (<span>' + plupload.formatSize(0) + '</span>/' + plupload.formatSize(file.size) + ') ' +
1766
  '<div class="fileprogress"></div></div>');
@@ -1771,8 +1878,8 @@ jQuery(document).ready(function($){
1771
  });
1772
 
1773
  uploader.bind('UploadProgress', function(up, file) {
1774
- $('#' + file.id + " .fileprogress").width(file.percent + "%");
1775
- $('#' + file.id + " span").html(plupload.formatSize(parseInt(file.size * file.percent / 100)));
1776
  });
1777
 
1778
  uploader.bind('Error', function(up, error) {
@@ -1788,8 +1895,8 @@ jQuery(document).ready(function($){
1788
  alert(updraftlion.uploaderror+" "+response.response.substring(6));
1789
  } else if (response.response.substring(0,3) == 'OK:') {
1790
  bkey = response.response.substring(3);
1791
- $('#' + file.id + " .fileprogress").hide();
1792
- $('#' + file.id).append(updraftlion.uploaded+' <a href="?page=updraftplus&action=downloadfile&updraftplus_file='+bkey+'&decrypt_key='+encodeURIComponent($('#updraftplus_db_decrypt').val())+'">'+updraftlion.followlink+'</a> '+updraftlion.thiskey+' '+$('#updraftplus_db_decrypt').val().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"));
1793
  } else {
1794
  alert(updraftlion.unknownresp+' '+response.response);
1795
  }
@@ -1804,6 +1911,91 @@ jQuery(document).ready(function($){
1804
 
1805
  });
1806
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1807
  // https://github.com/richadams/jquery-tripleclick/
1808
  // @author Rich Adams <rich@richadams.me>
1809
  // Implements a triple-click event. Click (or touch) three times within 1s on the element to trigger.
639
  _wpnonce: updraft_download_nonce
640
  };
641
  jQuery.post(ajaxurl, pdata, function(response) {
642
+ // Legacy - a simple string (since 1.11.24 - Feb 2016)
643
  if (response != 'deleted') {
644
+ try {
645
+ var resp = jQuery.parseJSON(response);
646
+ if (!resp.hasOwnProperty('result') || resp.result != 'deleted') {
647
+ alert(updraftlion.delete_response_not_understood+' : '+response);
648
+ console.log(response);
649
+ }
650
+ } catch (e) {
651
+ alert(updraftlion.delete_response_not_understood+' : '+response);
652
+ console.log(e);
653
+ console.log(response);
654
+ }
655
  }
656
  });
657
  }
659
  location.href=ajaxurl+'?_wpnonce='+updraft_download_nonce+'&timestamp='+timestamp+'&type='+type+'&stage=2&findex='+findex+'&action=updraft_download_backup';
660
  }
661
 
662
+ function updraft_downloader(base, backup_timestamp, what, whicharea, set_contents, prettydate, async) {
663
+
664
+ if (typeof set_contents !== "string") set_contents = set_contents.toString();
665
+
666
  var set_contents = set_contents.split(',');
667
+
668
  for (var i=0; i<set_contents.length; i++) {
669
  // Create somewhere for the status to be found
670
+ var stid = base+backup_timestamp+'_'+what+'_'+set_contents[i];
671
  var stid_selector = '.'+stid;
672
  var show_index = parseInt(set_contents[i]); show_index++;
673
  var itext = (set_contents[i] == 0) ? '' : ' ('+show_index+')';
674
  if (!jQuery(stid_selector).length) {
675
+ var prdate = (prettydate) ? prettydate : backup_timestamp;
676
+ jQuery(whicharea).append('<div style="clear:left; border: 1px solid; padding: 8px; margin-top: 4px; max-width:840px;" class="'+stid+' updraftplus_downloader"><button onclick="jQuery(this).parent().fadeOut().remove();" type="button" style="float:right; margin-bottom: 8px;">X</button><strong>'+updraftlion.download+' '+what+itext+' ('+prdate+')</strong>:<div class="raw">'+updraftlion.begunlooking+'</div><div class="file '+stid+'_st"><div class="dlfileprogress" style="width: 0;"></div></div></div>');
677
+ jQuery(stid_selector).data('downloaderfor', { base: base, nonce: backup_timestamp, what: what, index: i });
 
 
 
 
678
  setTimeout(function() {updraft_activejobs_update(true);}, 1500);
679
  }
680
  jQuery(stid_selector).data('lasttimebegan', (new Date).getTime());
681
+
682
  // Now send the actual request to kick it all off
683
+ async = async ? true : false;
684
+
685
+ // Old-style, from when it was a form
686
+ // var data = jQuery('#updraft-navtab-backups-content .uddownloadform_'+what+'_'+backup_timestamp+'_'+set_contents[i]).serialize();
687
+
688
+ var data = {
689
+ _wpnonce: jQuery('#updraft-navtab-backups-content .uddownloadform_'+what+'_'+backup_timestamp+'_'+set_contents[i]).data('wp_nonce').toString(),
690
+ action: 'updraft_download_backup',
691
+ type: what,
692
+ timestamp: backup_timestamp,
693
+ findex: set_contents[i]
694
+ };
695
+
696
  jQuery.ajax({
697
  url: ajaxurl,
698
  timeout: 10000,
699
  type: 'POST',
700
  async: async,
701
+ data: data,
702
  });
703
  }
704
  // We don't want the form to submit as that replaces the document
834
  // });
835
  }
836
 
837
+ function updraft_downloader_status_update(base, backup_timestamp, what, findex, resp, response) {
838
+ var stid = base+backup_timestamp+'_'+what+'_'+findex;
839
  var stid_selector = '.'+stid;
840
  var cancel_repeat = 0;
841
  if (resp.e != null) {
854
  // Remember that this is in milliseconds
855
  var sincelastrestart = timenow - lasttimebegan;
856
  if (resp.a > 90 && sincelastrestart > 60000) {
857
+ console.log(backup_timestamp+" "+what+" "+findex+": restarting download: file_age="+resp.a+", sincelastrestart_ms="+sincelastrestart);
858
  jQuery(stid_selector).data('lasttimebegan', (new Date).getTime());
859
+
860
+ var $original_button = jQuery('#updraft-navtab-backups-content .uddownloadform_'+what+'_'+backup_timestamp+'_'+findex);
861
+
862
+ var data = {
863
+ _wpnonce: $original_button.data('wp_nonce').toString(),
864
+ action: 'updraft_download_backup',
865
+ type: what,
866
+ timestamp: backup_timestamp,
867
+ findex: findex
868
+ };
869
+
870
  jQuery.ajax({
871
  url: ajaxurl,
872
  timeout: 10000,
873
  type: 'POST',
874
+ data: data
875
+ // data: jQuery('#updraft-navtab-backups-content .uddownloadform_'+what+'_'+backup_timestamp+'_'+findex).serialize()
876
  });
877
  jQuery(stid_selector).data('lasttimebegan', (new Date).getTime());
878
  }
885
  } else if (resp.p < 100 || base != 'uddlstatus_') {
886
  jQuery(stid_selector+' .raw').html(resp.m);
887
  } else {
888
+ jQuery(stid_selector+' .raw').html(updraftlion.fileready+' '+ updraftlion.youshould+' <button type="button" onclick="updraftplus_downloadstage2(\''+backup_timestamp+'\', \''+what+'\', \''+findex+'\')\">'+updraftlion.downloadtocomputer+'</button> '+updraftlion.andthen+' <button id="uddownloaddelete_'+backup_timestamp+'_'+what+'" type="button" onclick="updraftplus_deletefromserver(\''+backup_timestamp+'\', \''+what+'\', \''+findex+'\')\">'+updraftlion.deletefromserver+'</button>');
889
  }
890
  }
891
  // dlstatus_lastlog = response;
942
  if (jQuery.ui && jQuery.ui.dialog && jQuery.ui.dialog.prototype._allowInteraction) {
943
  var ui_dialog_interaction = jQuery.ui.dialog.prototype._allowInteraction;
944
  jQuery.ui.dialog.prototype._allowInteraction = function(e) {
945
+ if (jQuery(e.target).closest('.select2-dropdown').length) return true;
946
  return ui_dialog_interaction.apply(this, arguments);
947
  };
948
  }
1559
 
1560
  // checks if browser supports drag and drop upload, makes some css adjustments if necessary
1561
  uploader.bind('Init', function(up){
1562
+ var uploaddiv = jQuery('#plupload-upload-ui');
1563
 
1564
  if (up.features.dragdrop){
1565
  uploaddiv.addClass('drag-drop');
1566
+ jQuery('#drag-drop-area')
1567
  .bind('dragover.wp-uploader', function(){ uploaddiv.addClass('drag-over'); })
1568
  .bind('dragleave.wp-uploader, drop.wp-uploader', function(){ uploaddiv.removeClass('drag-over'); });
1569
 
1570
  } else {
1571
  uploaddiv.removeClass('drag-drop');
1572
+ jQuery('#drag-drop-area').unbind('.wp-uploader');
1573
  }
1574
  });
1575
 
1601
  }
1602
 
1603
  // a file was added, you may want to update your DOM here...
1604
+ jQuery('#filelist').append(
1605
  '<div class="file" id="' + file.id + '"><b>' +
1606
  file.name + '</b> (<span>' + plupload.formatSize(0) + '</span>/' + plupload.formatSize(file.size) + ') ' +
1607
  '<div class="fileprogress"></div></div>');
1612
  });
1613
 
1614
  uploader.bind('UploadProgress', function(up, file) {
1615
+ jQuery('#' + file.id + " .fileprogress").width(file.percent + "%");
1616
+ jQuery('#' + file.id + " span").html(plupload.formatSize(parseInt(file.size * file.percent / 100)));
1617
  });
1618
 
1619
  uploader.bind('Error', function(up, error) {
1653
  }
1654
 
1655
  // Functions in the debugging console
1656
+ jQuery('#updraftplus_httpget_go').click(function(e) {
1657
  e.preventDefault();
1658
  updraftplus_httpget_go(0);
1659
  });
1660
 
1661
+ jQuery('#updraftplus_httpget_gocurl').click(function(e) {
1662
  e.preventDefault();
1663
  updraftplus_httpget_go(1);
1664
  });
1665
 
1666
+ jQuery('#updraftplus_callwpaction_go').click(function(e) {
1667
  e.preventDefault();
1668
+ params = { action: 'updraft_ajax', subaction: 'callwpaction', nonce: updraft_credentialtest_nonce, wpaction: jQuery('#updraftplus_callwpaction').val() };
1669
+ jQuery.get(ajaxurl, params, function(response) {
1670
  try {
1671
  resp = jQuery.parseJSON(response);
1672
  if (resp.e) {
1674
  } else if (resp.s) {
1675
  // Silence
1676
  } else if (resp.r) {
1677
+ jQuery('#updraftplus_callwpaction_results').html(resp.r);
1678
  } else {
1679
  console.log(response);
1680
  alert(updraftlion.jsonnotunderstood);
1688
  });
1689
 
1690
  function updraftplus_httpget_go(curl) {
1691
+ params = { action: 'updraft_ajax', subaction: 'httpget', nonce: updraft_credentialtest_nonce, uri: jQuery('#updraftplus_httpget_uri').val() };
1692
  params.curl = curl;
1693
+ jQuery.get(ajaxurl, params, function(response) {
1694
  try {
1695
  resp = jQuery.parseJSON(response);
1696
  if (resp.e) {
1697
  alert(resp.e);
1698
  }
1699
  if (resp.r) {
1700
+ jQuery('#updraftplus_httpget_results').html('<pre>'+resp.r+'</pre>');
1701
  } else {
1702
  console.log(response);
1703
  //alert(updraftlion.jsonnotunderstood);
1711
  });
1712
  }
1713
 
1714
+ jQuery('#updraft_activejobs_table').on('click', '.updraft_jobinfo_delete', function(e) {
1715
  e.preventDefault();
1716
+ var job_id = jQuery(this).data('jobid');
1717
  if (job_id) {
1718
  updraft_activejobs_delete(job_id);
1719
  } else {
1721
  }
1722
  });
1723
 
1724
+ jQuery('#updraft_activejobs_table, #updraft-navtab-backups-content .updraft_existing_backups').on('click', '.updraft-log-link', function(e) {
1725
  e.preventDefault();
1726
+ var job_id = jQuery(this).data('jobid');
1727
  if (job_id) {
1728
  updraft_popuplog(job_id);
1729
  } else {
1731
  }
1732
  });
1733
 
1734
+ function updraft_restore_setup(entities, key, show_data) {
1735
+ updraft_restore_setoptions(entities);
1736
+ jQuery('#updraft_restore_timestamp').val(key);
1737
+ jQuery('.updraft_restore_date').html(show_data);
1738
+
1739
+ updraft_restore_stage = 1;
1740
+
1741
+ jQuery('#updraft-migrate-modal').dialog('close');
1742
+ jQuery('#updraft-restore-modal').dialog('open');
1743
+ jQuery('#updraft-restore-modal-stage1').show();
1744
+ jQuery('#updraft-restore-modal-stage2').hide();
1745
+ jQuery('#updraft-restore-modal-stage2a').html('');
1746
+
1747
+ updraft_activejobs_update(true);
1748
+ }
1749
+
1750
+ jQuery('#updraft-navtab-backups-content .updraft_existing_backups').on('click', 'button.choose-components-button', function(e) {
1751
+ var entities = jQuery(this).data('entities');
1752
+ var backup_timestamp = jQuery(this).data('backup_timestamp');
1753
+ var show_data = jQuery(this).data('showdata');
1754
+ updraft_restore_setup(entities, backup_timestamp, show_data);
1755
+ });
1756
+
1757
+ /**
1758
+ * Get the value of a named URL parameter - https://stackoverflow.com/questions/4548487/jquery-read-query-string
1759
+ *
1760
+ * @param {string} name - URL parameter to return the value of
1761
+ * @returns {string}
1762
+ */
1763
+ function get_parameter_by_name(name) {
1764
+ name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
1765
+ var regexS = "[\\?&]"+name+"=([^&#]*)";
1766
+ var regex = new RegExp( regexS );
1767
+ var results = regex.exec( window.location.href );
1768
+ if( results == null ) {
1769
+ return "";
1770
+ } else {
1771
+ return decodeURIComponent(results[1].replace(/\+/g, " "));
1772
+ }
1773
+ }
1774
+
1775
+ if (get_parameter_by_name('udaction') == 'initiate_restore') {
1776
+ var entities = get_parameter_by_name('entities');
1777
+ var backup_timestamp = get_parameter_by_name('backup_timestamp');
1778
+ var show_data = get_parameter_by_name('showdata');
1779
+ updraft_restore_setup(entities, backup_timestamp, show_data);
1780
+ }
1781
+
1782
+ jQuery('#updraft-navtab-backups-content .updraft_existing_backups').on('click', '.updraft-delete-link', function(e) {
1783
+ e.preventDefault();
1784
+ var hasremote = jQuery(this).data('hasremote').toString();
1785
+ var nonce = jQuery(this).data('nonce').toString();
1786
+ var key = jQuery(this).data('key').toString();
1787
+ if (nonce) {
1788
+ updraft_delete(key, nonce, hasremote);
1789
+ } else {
1790
+ console.log("UpdraftPlus: A delete link was clicked, but the Job ID could not be found");
1791
+ }
1792
+ });
1793
+
1794
+ jQuery('#updraft-navtab-backups-content .updraft_existing_backups').on('click', 'button.updraft_download_button', function(e) {
1795
+ e.preventDefault();
1796
+ var base = 'uddlstatus_';
1797
+ var backup_timestamp = jQuery(this).data('backup_timestamp');
1798
+ var what = jQuery(this).data('what');
1799
+ var whicharea = '.ud_downloadstatus';
1800
+ var set_contents = jQuery(this).data('set_contents');
1801
+ var prettydate = jQuery(this).data('prettydate');
1802
+ var async = true;
1803
+ updraft_downloader(base, backup_timestamp, what, whicharea, set_contents, prettydate, async);
1804
+ });
1805
+
1806
  jQuery('#updraft-navtab-backups-content .updraft_existing_backups').on('tripleclick', '.updraft_existingbackup_date', { threshold: 500 }, function(e) {
1807
  e.preventDefault();
1808
  var data = jQuery(this).data('rawbackup');
1839
 
1840
  // checks if browser supports drag and drop upload, makes some css adjustments if necessary
1841
  uploader.bind('Init', function(up){
1842
+ var uploaddiv = jQuery('#plupload-upload-ui2');
1843
 
1844
  if (up.features.dragdrop){
1845
  uploaddiv.addClass('drag-drop');
1846
+ jQuery('#drag-drop-area2')
1847
  .bind('dragover.wp-uploader', function(){ uploaddiv.addClass('drag-over'); })
1848
  .bind('dragleave.wp-uploader, drop.wp-uploader', function(){ uploaddiv.removeClass('drag-over'); });
1849
  } else {
1850
  uploaddiv.removeClass('drag-drop');
1851
+ jQuery('#drag-drop-area2').unbind('.wp-uploader');
1852
  }
1853
  });
1854
 
1867
  }
1868
 
1869
  // a file was added, you may want to update your DOM here...
1870
+ jQuery('#filelist2').append(
1871
  '<div class="file" id="' + file.id + '"><b>' +
1872
  file.name + '</b> (<span>' + plupload.formatSize(0) + '</span>/' + plupload.formatSize(file.size) + ') ' +
1873
  '<div class="fileprogress"></div></div>');
1878
  });
1879
 
1880
  uploader.bind('UploadProgress', function(up, file) {
1881
+ jQuery('#' + file.id + " .fileprogress").width(file.percent + "%");
1882
+ jQuery('#' + file.id + " span").html(plupload.formatSize(parseInt(file.size * file.percent / 100)));
1883
  });
1884
 
1885
  uploader.bind('Error', function(up, error) {
1895
  alert(updraftlion.uploaderror+" "+response.response.substring(6));
1896
  } else if (response.response.substring(0,3) == 'OK:') {
1897
  bkey = response.response.substring(3);
1898
+ jQuery('#' + file.id + " .fileprogress").hide();
1899
+ jQuery('#' + file.id).append(updraftlion.uploaded+' <a href="?page=updraftplus&action=downloadfile&updraftplus_file='+bkey+'&decrypt_key='+encodeURIComponent(jQuery('#updraftplus_db_decrypt').val())+'">'+updraftlion.followlink+'</a> '+updraftlion.thiskey+' '+jQuery('#updraftplus_db_decrypt').val().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"));
1900
  } else {
1901
  alert(updraftlion.unknownresp+' '+response.response);
1902
  }
1911
 
1912
  });
1913
 
1914
+ // Save settings via AJAX
1915
+ jQuery(document).ready(function($){
1916
+
1917
+ // Pre-load the image so that it doesn't jerk when first used
1918
+ var my_image = new Image();
1919
+ my_image.src = updraftlion.ud_url+'/images/udlogo-rotating.gif';
1920
+
1921
+ $('#updraftplus-settings-save').click(function(e) {
1922
+ e.preventDefault();
1923
+ $.blockUI({ message: '<div style="margin: 8px; font-size:150%;"><img src="'+updraftlion.ud_url+'/images/udlogo-rotating.gif" height="80" width="80" style="padding-bottom:10px;"><br>'+updraftlion.saving+'</div>'});
1924
+
1925
+ //Gather data
1926
+ var form_data = $("#updraft-navtab-settings-content form input, #updraft-navtab-settings-content form textarea, #updraft-navtab-settings-content form select").serialize();
1927
+
1928
+ //include unchecked checkboxes. user filter to only include unchecked boxes.
1929
+ $.each($('#updraft-navtab-settings-content form input[type=checkbox]')
1930
+ .filter(function(idx){
1931
+ return $(this).prop('checked') == false
1932
+ }),
1933
+ function(idx, el){
1934
+ //attach matched element names to the form_data with chosen value.
1935
+ var empty_val = '0';
1936
+ form_data += '&' + $(el).attr('name') + '=' + empty_val;
1937
+ }
1938
+ );
1939
+
1940
+ // POST the settings back to the AJAX handler
1941
+ $.post(ajaxurl, {
1942
+ action: 'updraft_savesettings',
1943
+ subaction: 'savesettings',
1944
+ settings: form_data,
1945
+ nonce: updraftplus_settings_nonce
1946
+ }, function(response) {
1947
+ // Add page updates etc based on response
1948
+
1949
+ try {
1950
+ var resp = jQuery.parseJSON(response);
1951
+
1952
+ var messages = resp.changed.updraft_service;
1953
+ var debug = resp.changed.updraft_debug_mode;
1954
+
1955
+ // If backup dir is not writable, change the text, and grey out the 'Backup Now' button
1956
+ var backup_dir_writable = resp.backup_dir.writable;
1957
+ var backup_dir_message = resp.backup_dir.message;
1958
+ var backup_button_title = resp.backup_dir.button_title;
1959
+ } catch (e) {
1960
+ console.log(e);
1961
+ console.log(response);
1962
+ alert(updraftlion.jsonnotunderstood);
1963
+ $.unblockUI();
1964
+ return;
1965
+ }
1966
+
1967
+ $('#updraft_writable_mess').html(backup_dir_message);
1968
+
1969
+ if (backup_dir_writable == false){
1970
+ $('#updraft-backupnow-button').attr('disabled', 'disabled');
1971
+ $('#updraft-backupnow-button').attr('title', backup_button_title);
1972
+ $('.backupdirrow').css('display', 'table-row');
1973
+ } else {
1974
+ $('#updraft-backupnow-button').removeAttr('disabled');
1975
+ $('#updraft-backupnow-button').removeAttr('title');
1976
+ //$('.backupdirrow').hide();
1977
+ }
1978
+
1979
+ if (resp.hasOwnProperty('backup_now_message')) { $('#backupnow_remote_container').html(resp.backup_now_message); }
1980
+
1981
+ // Move from 2 to 1
1982
+ $('.updraftmessage').remove();
1983
+
1984
+ $('#updraft_backup_started').before(resp.messages);
1985
+
1986
+ $('#next-backup-table-inner').html(resp.scheduled);
1987
+
1988
+ $('#updraft-wrap .fade').delay(6000).fadeOut(2000);
1989
+ $('html, body').animate({
1990
+ scrollTop: $("#updraft-wrap").offset().top
1991
+ }, 1000);
1992
+
1993
+ $.unblockUI();
1994
+
1995
+ });
1996
+ });
1997
+ });
1998
+
1999
  // https://github.com/richadams/jquery-tripleclick/
2000
  // @author Rich Adams <rich@richadams.me>
2001
  // Implements a triple-click event. Click (or touch) three times within 1s on the element to trigger.
methods/dropbox.php CHANGED
@@ -127,7 +127,7 @@ class UpdraftPlus_BackupModule_dropbox {
127
  $updraftplus->log($message);
128
  } catch (Exception $e) {
129
  $updraftplus->log("Dropbox error: exception (".get_class($e).") occurred whilst getting account info: ".$e->getMessage());
130
- $updraftplus->log(sprintf(__("%s error: %s", 'updraftplus'), 'Dropbox', $e->getMessage()).' ('.$e->getCode().')', 'warning', md5($e->getMessage()));
131
  }
132
 
133
  $file_success = 1;
@@ -230,7 +230,7 @@ class UpdraftPlus_BackupModule_dropbox {
230
 
231
  $opts = $this->get_opts();
232
 
233
- if (empty($opts['tk_access_token'])) return new WP_Error('no_settings', __('No settings were found', 'updraftplus'));
234
 
235
  global $updraftplus;
236
  try {
127
  $updraftplus->log($message);
128
  } catch (Exception $e) {
129
  $updraftplus->log("Dropbox error: exception (".get_class($e).") occurred whilst getting account info: ".$e->getMessage());
130
+ //$updraftplus->log(sprintf(__("%s error: %s", 'updraftplus'), 'Dropbox', $e->getMessage()).' ('.$e->getCode().')', 'warning', md5($e->getMessage()));
131
  }
132
 
133
  $file_success = 1;
230
 
231
  $opts = $this->get_opts();
232
 
233
+ if (empty($opts['tk_access_token'])) return new WP_Error('no_settings', __('No settings were found', 'updraftplus').' (dropbox)');
234
 
235
  global $updraftplus;
236
  try {
options.php CHANGED
@@ -29,7 +29,7 @@ class UpdraftPlus_Options {
29
 
30
  // The apparently unused parameter is used in the alternative class in the Multisite add-on
31
  public static function update_updraft_option($option, $value, $use_cache = true) {
32
- update_option($option, $value);
33
  }
34
 
35
  public static function delete_updraft_option($option) {
29
 
30
  // The apparently unused parameter is used in the alternative class in the Multisite add-on
31
  public static function update_updraft_option($option, $value, $use_cache = true) {
32
+ return update_option($option, $value);
33
  }
34
 
35
  public static function delete_updraft_option($option) {
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: Backup with UpdraftPlus, DavidAnderson, DNutbourne, lcahill
3
  Tags: backup, backups, restore, amazon backup, s3 backup, dropbox backup, google drive backup, rackspace cloud files, rackspace backup, dreamhost, dreamobjects backup, ftp backup, webdav backup, google cloud storage, onedrive, microsoft one drive, microsoft azure, azure, back up, multisite, restoration, sftp backup, ftps, scp backup, migrate, duplicate, copy, mysql backup, database backup, db backups, website backup, wordpress backup, full backup, openstack backup, sicherung
4
  Requires at least: 3.2
5
  Tested up to: 4.4
6
- Stable tag: 1.11.23
7
  Author URI: https://updraftplus.com
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
@@ -14,9 +14,9 @@ Backup and restoration made easy. Complete backups; manual or scheduled (backup
14
 
15
  <a href="https://updraftplus.com">UpdraftPlus</a> simplifies backups (and restoration). Backup into the cloud (Amazon S3 (or compatible), Dropbox, Google Drive, Rackspace Cloud, DreamObjects, FTP, Openstack Swift, UpdraftPlus Vault and email) and restore with a single click. Backups of files and database can have separate schedules. The paid version also backs up to Microsoft OneDrive, Microsoft Azure, Copy.Com, Google Cloud Storage, SFTP, SCP, and WebDAV.
16
 
17
- <strong>Top-quality:</strong> UpdraftPlus is the <a href="http://rankwp.com/plugins/updraftplus">highest-ranking backup plugin on wordpress.org</a> (ranks in the top 40 out of over 30,000 WordPress plugins for quality on rankwp.com).
18
 
19
- <strong>Over 600,000 currently active installs:</strong> widely tested and reliable (over 3.8 million downloads). The #1 most installed scheduled backup plugin, according to wordpress.org. Many millions of backups completed!
20
 
21
  * Supports WordPress backups to UpdraftPlus Vault, Amazon S3 (or compatible), Dropbox, Rackspace Cloud Files, Google Drive, Google Cloud Storage, DreamHost DreamObjects, FTP, OpenStack (Swift) and email. Also (via a paid add-on) backup to Microsoft OneDrive, Microsoft Azure, Google Cloud Storage, Copy.Com, FTP over SSL, SFTP, SCP, and WebDAV (and compatible services, e.g. Yandex, Cubby, OwnCloud). Examples of S3-compatible providers: Cloudian, Connectria, Constant, Eucalyptus, Nifty, Nimbula, Cloudn.
22
  * Quick restore (both file and database backups)
@@ -118,7 +118,22 @@ Thanks for asking; yes, we've got a few. Check out this profile page - https://p
118
 
119
  The <a href="https://updraftplus.com/news/">UpdraftPlus backup blog</a> is the best place to learn in more detail about any important changes.
120
 
121
- N.B. Paid versions of UpdraftPlus Backup / Restore have a version number which is 1 higher in the first digit, and has an extra component on the end, but the changelog below still applies. i.e. changes listed for 1.11.23 of the free version correspond to changes made in 2.11.23.x of the paid version.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  = 1.11.23 - 26/Jan/2016 =
124
 
@@ -1729,7 +1744,7 @@ improvements
1729
 
1730
  == License ==
1731
 
1732
- Copyright 2011-15 David Anderson
1733
 
1734
  This program is free software; you can redistribute it and/or modify
1735
  it under the terms of the GNU General Public License as published by
@@ -1751,4 +1766,4 @@ We recognise and thank the following for code and/or libraries used and/or modif
1751
 
1752
 
1753
  == Upgrade Notice ==
1754
- * 1.11.23: Various tweaks and fixes, and foundation-laying internal improvements.
3
  Tags: backup, backups, restore, amazon backup, s3 backup, dropbox backup, google drive backup, rackspace cloud files, rackspace backup, dreamhost, dreamobjects backup, ftp backup, webdav backup, google cloud storage, onedrive, microsoft one drive, microsoft azure, azure, back up, multisite, restoration, sftp backup, ftps, scp backup, migrate, duplicate, copy, mysql backup, database backup, db backups, website backup, wordpress backup, full backup, openstack backup, sicherung
4
  Requires at least: 3.2
5
  Tested up to: 4.4
6
+ Stable tag: 1.11.24
7
  Author URI: https://updraftplus.com
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
14
 
15
  <a href="https://updraftplus.com">UpdraftPlus</a> simplifies backups (and restoration). Backup into the cloud (Amazon S3 (or compatible), Dropbox, Google Drive, Rackspace Cloud, DreamObjects, FTP, Openstack Swift, UpdraftPlus Vault and email) and restore with a single click. Backups of files and database can have separate schedules. The paid version also backs up to Microsoft OneDrive, Microsoft Azure, Copy.Com, Google Cloud Storage, SFTP, SCP, and WebDAV.
16
 
17
+ <strong>Top-quality:</strong> UpdraftPlus is the highest-ranking backup plugin on wordpress.org, with <strong>over 600,000 currently active installs</strong>. Widely tested and reliable, this is the world's #1 most popular and mostly highly rated scheduled backup plugin. Millions of backups completed!
18
 
19
+ [vimeo https://vimeo.com/154870690]
20
 
21
  * Supports WordPress backups to UpdraftPlus Vault, Amazon S3 (or compatible), Dropbox, Rackspace Cloud Files, Google Drive, Google Cloud Storage, DreamHost DreamObjects, FTP, OpenStack (Swift) and email. Also (via a paid add-on) backup to Microsoft OneDrive, Microsoft Azure, Google Cloud Storage, Copy.Com, FTP over SSL, SFTP, SCP, and WebDAV (and compatible services, e.g. Yandex, Cubby, OwnCloud). Examples of S3-compatible providers: Cloudian, Connectria, Constant, Eucalyptus, Nifty, Nimbula, Cloudn.
22
  * Quick restore (both file and database backups)
118
 
119
  The <a href="https://updraftplus.com/news/">UpdraftPlus backup blog</a> is the best place to learn in more detail about any important changes.
120
 
121
+ N.B. Paid versions of UpdraftPlus Backup / Restore have a version number which is 1 higher in the first digit, and has an extra component on the end, but the changelog below still applies. i.e. changes listed for 1.11.24 of the free version correspond to changes made in 2.11.24.x of the paid version.
122
+
123
+ = 1.11.24 - 10/Feb/2016 =
124
+
125
+ * FIX: Fixed further logic errors in the advanced backup retention options, potentially relevant if you had more than one extra rule
126
+ * TWEAK: Saving of settings is now done over AJAX (i.e. without a page reload)
127
+ * TWEAK: In-dashboard downloads now process the HTTP Range: header, allowing resumption of failed downloads via the browser
128
+ * TWEAK: Tweak 'Existing Backups' table CSS, to allow more entities per row
129
+ * TWEAK: Warn copy.com users of Barracuda ending the service - https://techlib.barracuda.com/CudaDrive/EOL
130
+ * TWEAK: Rename the 'hidden' CSS class, to prevent clashes with other plugins/themes which load their CSS code onto UD's page (which they shouldn't be doing)
131
+ * TWEAK: Fix newsletter sign-up link
132
+ * TWEAK: Log and triple-click summary now mentions the total size of the backup (i.e. total of the compressed backup set)
133
+ * TWEAK: Try to detect a very rare case of recoverable database read failure, and schedule a re-try
134
+ * TWEAK: Suppress unnecessary warning message when Dropbox account info checking fails
135
+ * TWEAK: Attempt to restart a large OneDrive upload in a particular case seen when OneDrive's end seems to get into confusion about state
136
+ * TWEAK: Various bits of internal re-factoring to support future improvements
137
 
138
  = 1.11.23 - 26/Jan/2016 =
139
 
1744
 
1745
  == License ==
1746
 
1747
+ Copyright 2011-16 David Anderson
1748
 
1749
  This program is free software; you can redistribute it and/or modify
1750
  it under the terms of the GNU General Public License as published by
1766
 
1767
 
1768
  == Upgrade Notice ==
1769
+ * 1.11.24: Various tweaks and small improvements, and foundation-laying internal improvements.
updraftplus.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: UpdraftPlus - Backup/Restore
4
  Plugin URI: https://updraftplus.com
5
  Description: Backup and restore: take backups locally, or backup to Amazon S3, Dropbox, Google Drive, Rackspace, (S)FTP, WebDAV & email, on automatic schedules.
6
  Author: UpdraftPlus.Com, DavidAnderson
7
- Version: 1.11.23
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
10
  Text Domain: updraftplus
4
  Plugin URI: https://updraftplus.com
5
  Description: Backup and restore: take backups locally, or backup to Amazon S3, Dropbox, Google Drive, Rackspace, (S)FTP, WebDAV & email, on automatic schedules.
6
  Author: UpdraftPlus.Com, DavidAnderson
7
+ Version: 1.11.24
8
  Donate link: http://david.dw-perspective.org.uk/donate
9
  License: GPLv3 or later
10
  Text Domain: updraftplus