UpdraftPlus WordPress Backup Plugin - Version 1.16.21

Version Description

  • 10/Dec/2019 =

  • FIX: Correctly search and replace database views when importing on a site with a different table prefix

  • FIX: A bug that prevented the restore modal opening on the migrate/clone tab

  • FIX: Dropbox cURL issues on connection are resolved for PHP 7.4

  • TWEAK: Change the way the "Disabled Cron" warning appears on the administrative settings page

  • TWEAK: Improvements to error messages return for UpdraftCentral's plugin and theme installation process

  • TWEAK: Updates to credentials validation for UpdraftCentral's plugin and theme modules

  • TWEAK: Add media request handler for UpdraftCentral media module

  • TWEAK: On paid versions, again possibly adjust the daily update check time to further favour overnight hours

  • TWEAK: Mask classified information in WebDav URL settings

  • TWEAK: Add multiple range selection on certain backup using ctrl and shift buttons

  • TWEAK: Hide incremental backup link if the backup directory is not writable

  • TWEAK: Make Updraft_Restorer_Skin compatible with WP 5.3

  • TWEAK: Added Linode object storage link to list of supported S3 providers and updated existing links

  • TWEAK: Ensure some variables are defined to prevent unwanted warnings

Download this release

Release Info

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

Code changes from version 1.16.20 to 1.16.21

admin.php CHANGED
@@ -91,8 +91,8 @@ class UpdraftPlus_Admin {
91
  echo __('Error:', 'updraftplus').' '.__('template not found', 'updraftplus')." ($path)";
92
  } else {
93
  extract($extract_these);
94
- global $updraftplus, $wpdb;
95
- $updraftplus_admin = $this;
96
  include $template_file;
97
  }
98
 
@@ -244,10 +244,6 @@ class UpdraftPlus_Admin {
244
  private function setup_all_admin_notices_udonly($service, $override = false) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Filter use
245
  global $updraftplus;
246
 
247
- if (UpdraftPlus_Options::user_can_manage() && defined('DISABLE_WP_CRON') && DISABLE_WP_CRON && (!defined('UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE') || !UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE)) {
248
- add_action('all_admin_notices', array($this, 'show_admin_warning_disabledcron'));
249
- }
250
-
251
  if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
252
  @ini_set('display_errors', 1);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
253
  if (defined('E_DEPRECATED')) {
@@ -512,8 +508,8 @@ class UpdraftPlus_Admin {
512
 
513
  add_filter('woocommerce_in_plugin_update_message', array($this, 'woocommerce_in_plugin_update_message'));
514
 
515
- $updraftplus_dashboard_news = new Updraft_Dashboard_News('https://feeds.feedburner.com/updraftplus/', 'https://updraftplus.com/news/', $news_translations);
516
-
517
  // New-install admin tour
518
  if ((!defined('UPDRAFTPLUS_ENABLE_TOUR') || UPDRAFTPLUS_ENABLE_TOUR) && (!defined('UPDRAFTPLUS_THIS_IS_CLONE') || !UPDRAFTPLUS_THIS_IS_CLONE)) {
519
  include_once(UPDRAFTPLUS_DIR.'/includes/updraftplus-tour.php');
@@ -1147,13 +1143,13 @@ class UpdraftPlus_Admin {
1147
  if ($dismissed_until > time()) return;
1148
 
1149
  if ('upgrade-plugin' == $_GET['action']) {
1150
- $title = __('Update Plugin');
1151
- $parent_file = 'plugins.php';
1152
- $submenu_file = 'plugins.php';
1153
  } else {
1154
- $title = __('Update Theme');
1155
- $parent_file = 'themes.php';
1156
- $submenu_file = 'themes.php';
1157
  }
1158
 
1159
  include_once(ABSPATH.'wp-admin/admin-header.php');
@@ -1193,7 +1189,10 @@ class UpdraftPlus_Admin {
1193
  }
1194
 
1195
  public function show_admin_warning_disabledcron() {
1196
- $this->show_admin_warning('<strong>'.__('Warning', 'updraftplus').':</strong> '.__('The scheduler is disabled in your WordPress install, via the DISABLE_WP_CRON setting. No backups can run (even &quot;Backup Now&quot;) unless either you have set up a facility to call the scheduler manually, or until it is enabled.', 'updraftplus').' <a href="'.apply_filters('updraftplus_com_link', "https://updraftplus.com/faqs/my-scheduled-backups-and-pressing-backup-now-does-nothing-however-pressing-debug-backup-does-produce-a-backup/#disablewpcron/").'" target="_blank">'.__('Go here for more information.', 'updraftplus').'</a>', 'updated updraftplus-disable-wp-cron-warning');
 
 
 
1197
  }
1198
 
1199
  public function show_admin_warning_diskspace() {
@@ -1271,8 +1270,6 @@ class UpdraftPlus_Admin {
1271
  * @param String $method - the remote storage method
1272
  */
1273
  public function get_method_auth_link($method) {
1274
- global $updraftplus;
1275
-
1276
  $storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array($method));
1277
 
1278
  $object = $storage_objects_and_ids[$method]['object'];
@@ -1429,7 +1426,9 @@ class UpdraftPlus_Admin {
1429
 
1430
  $needs_downloading = false;
1431
 
1432
- if (!file_exists($fullpath)) {
 
 
1433
  // If the file doesn't exist and they're using one of the cloud options, fetch it down from the cloud.
1434
  $needs_downloading = true;
1435
  $updraftplus->log('File does not yet exist locally - needs downloading');
@@ -1473,20 +1472,22 @@ class UpdraftPlus_Admin {
1473
  }
1474
 
1475
  // Now, be ready to spool the thing to the browser
1476
- if (is_file($fullpath) && is_readable($fullpath)) {
1477
 
1478
  // That message is then picked up by the AJAX listener
1479
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'downloaded:'.filesize($fullpath).":$fullpath");
1480
 
1481
  $result = 'downloaded';
1482
 
1483
- } else {
1484
 
1485
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'failed');
1486
  $updraftplus->jobdata_set('dlerrors_'.$timestamp.'_'.$type.'_'.$findex, $updraftplus->errors);
1487
  $updraftplus->log('Remote fetch failed. File '.$fullpath.' did not exist or was unreadable. If you delete local backups then remote retrieval may have failed.');
1488
 
1489
  $result = 'download_failed';
 
 
1490
  }
1491
 
1492
  restore_error_handler();
@@ -1512,8 +1513,6 @@ class UpdraftPlus_Admin {
1512
 
1513
  public function updraft_ajax_handler() {
1514
 
1515
- global $updraftplus;
1516
-
1517
  $nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
1518
 
1519
  if (!wp_verify_nonce($nonce, 'updraftplus-credentialtest-nonce') || empty($_REQUEST['subaction'])) die('Security check');
@@ -1984,7 +1983,7 @@ class UpdraftPlus_Admin {
1984
 
1985
  $logs_exist = (false !== strpos($output, 'downloadlog'));
1986
  if (!$logs_exist) {
1987
- list($mod_time, $log_file, $nonce) = $updraftplus->last_modified_log();
1988
  if ($mod_time) $logs_exist = true;
1989
  }
1990
 
@@ -2081,8 +2080,6 @@ class UpdraftPlus_Admin {
2081
  */
2082
  public function get_activejobs_list($request) {
2083
 
2084
- global $updraftplus;
2085
-
2086
  $download_status = empty($request['downloaders']) ? array() : $this->get_download_statuses(explode(':', $request['downloaders']));
2087
 
2088
  if (!empty($request['oneshot'])) {
@@ -2121,9 +2118,8 @@ class UpdraftPlus_Admin {
2121
  public function request_backupnow($request, $close_connection_callable = false) {
2122
  global $updraftplus;
2123
 
2124
- $abort = false;
2125
  $backupnow_nocloud = !empty($request['backupnow_nocloud']);
2126
- $event = (!empty($request['backupnow_nofiles'])) ? 'updraft_backupnow_backup_database' : ((!empty($request['backupnow_nodb'])) ? 'updraft_backupnow_backup' : 'updraft_backupnow_backup_all');
2127
 
2128
  $request['incremental'] = !empty($request['incremental']);
2129
 
@@ -2145,7 +2141,7 @@ class UpdraftPlus_Admin {
2145
  $msg = array(
2146
  'error' => __('No suitable backup set (that already contains a full backup of all the requested file component types) was found, to add increments to. Aborting this backup.', 'updaftplus')
2147
  );
2148
- $abort = true;
2149
  }
2150
 
2151
  if ($close_connection_callable && is_callable($close_connection_callable)) {
@@ -2154,7 +2150,7 @@ class UpdraftPlus_Admin {
2154
  $updraftplus->close_browser_connection(json_encode($msg));
2155
  }
2156
 
2157
- if ($abort) die;
2158
 
2159
  $options = array('nocloud' => $backupnow_nocloud, 'use_nonce' => $nonce);
2160
  if (!empty($request['onlythisfileentity']) && is_string($request['onlythisfileentity'])) {
@@ -2170,8 +2166,10 @@ class UpdraftPlus_Admin {
2170
 
2171
  if (!empty($request['extradata'])) $options['extradata'] = $request['extradata'];
2172
 
2173
- $options['always_keep'] = empty($request['always_keep']) ? false : true;
2174
 
 
 
2175
  do_action($event, apply_filters('updraft_backupnow_options', $options, $request));
2176
  }
2177
 
@@ -2188,7 +2186,7 @@ class UpdraftPlus_Admin {
2188
  global $updraftplus;
2189
 
2190
  if (empty($backup_nonce)) {
2191
- list($mod_time, $log_file, $nonce) = $updraftplus->last_modified_log();
2192
  } else {
2193
  $nonce = $backup_nonce;
2194
  }
@@ -2708,21 +2706,21 @@ class UpdraftPlus_Admin {
2708
  }
2709
 
2710
  $this->include_template('wp-admin/settings/tab-bar.php', false, array('main_tabs' => $main_tabs, 'backup_history' => $backup_history, 'tabflag' => $tabflag));
2711
-
2712
- $updraft_dir = $updraftplus->backups_dir_location();
2713
- $backup_disabled = UpdraftPlus_Filesystem_Functions::really_is_writable($updraft_dir) ? '' : 'disabled="disabled"';
2714
  ?>
2715
 
2716
  <div id="updraft-poplog" >
2717
  <pre id="updraft-poplog-content"></pre>
2718
  </div>
2719
 
 
 
 
 
2720
  <div id="updraft-navtab-backups-content" <?php if ('backups' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('backups' != $tabflag) echo 'display:none;'; ?>">
2721
  <?php
2722
  $is_opera = (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/'));
2723
  $tmp_opts = array('include_opera_warning' => $is_opera);
2724
  $this->include_template('wp-admin/settings/tab-backups.php', false, array('backup_history' => $backup_history, 'options' => $tmp_opts));
2725
- $this->include_template('wp-admin/settings/delete-and-restore-modals.php');
2726
  $this->include_template('wp-admin/settings/upload-backups-modal.php');
2727
  ?>
2728
  </div>
@@ -3118,6 +3116,7 @@ class UpdraftPlus_Admin {
3118
  * @return String - the HTML output
3119
  */
3120
  public function render_active_jobs_and_log_table($wide_format = false, $print_active_jobs = true) {
 
3121
  ?>
3122
  <div id="updraft_activejobs_table">
3123
  <?php $active_jobs = ($print_active_jobs) ? $this->print_active_jobs() : '';?>
@@ -3178,7 +3177,7 @@ class UpdraftPlus_Admin {
3178
  private function most_recently_modified_log_link() {
3179
 
3180
  global $updraftplus;
3181
- list($mod_time, $log_file, $nonce) = $updraftplus->last_modified_log();
3182
 
3183
  ?>
3184
  <a href="?page=updraftplus&amp;action=downloadlatestmodlog&amp;wpnonce=<?php echo wp_create_nonce('updraftplus_download'); ?>" <?php if (!$mod_time) echo 'style="display:none;"'; ?> class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('');"><?php _e('Download most recently modified log file', 'updraftplus');?></a>
@@ -3319,7 +3318,7 @@ class UpdraftPlus_Admin {
3319
 
3320
  $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
3321
 
3322
- $began_at = (isset($jobdata['backup_time'])) ? get_date_from_gmt(gmdate('Y-m-d H:i:s', (int) $jobdata['backup_time']), 'D, F j, Y H:i') : '?';
3323
 
3324
  $remote_sent = (!empty($jobdata['service']) && ((is_array($jobdata['service']) && in_array('remotesend', $jobdata['service'])) || 'remotesend' === $jobdata['service'])) ? true : false;
3325
 
@@ -3430,8 +3429,8 @@ class UpdraftPlus_Admin {
3430
  }
3431
  }
3432
 
3433
- $runs_started = (empty($jobdata['runs_started'])) ? array() : $jobdata['runs_started'];
3434
- $time_passed = (empty($jobdata['run_times'])) ? array() : $jobdata['run_times'];
3435
  $last_checkin_ago = -1;
3436
  if (is_array($time_passed)) {
3437
  foreach ($time_passed as $run => $passed) {
@@ -4155,7 +4154,7 @@ class UpdraftPlus_Admin {
4155
  if (!empty($backup['meta_foreign']) && 'wpcore' != $type) continue;
4156
 
4157
  $ide = '';
4158
- if ('wpcore' == $type) $wpcore_restore_descrip = $info['description'];
4159
  if (empty($backup['meta_foreign'])) {
4160
  $sdescrip = preg_replace('/ \(.*\)$/', '', $info['description']);
4161
  if (strlen($sdescrip) > 20 && isset($info['shortdescription'])) $sdescrip = $info['shortdescription'];
@@ -4171,7 +4170,6 @@ class UpdraftPlus_Admin {
4171
  }
4172
 
4173
  $sdescrip = (empty($accept[$backup['meta_foreign']]['separatedb'])) ? sprintf(__('Files and database WordPress backup (created by %s)', 'updraftplus'), $desc_source) : sprintf(__('Files backup (created by %s)', 'updraftplus'), $desc_source);
4174
- if ('wpcore' == $type) $wpcore_restore_descrip = $sdescrip;
4175
  }
4176
  if (isset($backup[$type])) {
4177
  if (!is_array($backup[$type])) $backup[$type] = array($backup[$type]);
@@ -4296,7 +4294,6 @@ class UpdraftPlus_Admin {
4296
  if (empty($services)) return '';
4297
 
4298
  $show_upload = false;
4299
- $not_uploaded = array();
4300
 
4301
  // Check that the backup has not already been sent to remote storage before.
4302
  if (empty($backup['service']) || array('none') == $backup['service'] || array('') == $backup['service'] || 'none' == $backup['service']) {
@@ -4793,7 +4790,7 @@ ENDHERE;
4793
  */
4794
  private function restore_backup($timestamp, $continuation_data = null) {
4795
 
4796
- global $updraftplus, $wp_filesystem, $updraftplus_restorer;
4797
 
4798
  $second_loop_entities = empty($continuation_data['second_loop_entities']) ? array() : $continuation_data['second_loop_entities'];
4799
 
@@ -4938,7 +4935,6 @@ ENDHERE;
4938
  */
4939
  public function updraft_ajax_savesettings() {
4940
  try {
4941
- global $updraftplus;
4942
  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');
4943
 
4944
  if (empty($_POST['settings']) || !is_string($_POST['settings'])) die('Invalid data');
@@ -4969,8 +4965,6 @@ ENDHERE;
4969
 
4970
  public function updraft_ajax_importsettings() {
4971
  try {
4972
- global $updraftplus;
4973
-
4974
  if (empty($_POST) || empty($_POST['subaction']) || 'importsettings' != $_POST['subaction'] || !isset($_POST['nonce']) || !is_user_logged_in() || !UpdraftPlus_Options::user_can_manage() || !wp_verify_nonce($_POST['nonce'], 'updraftplus-settings-nonce')) die('Security check');
4975
 
4976
  if (empty($_POST['settings']) || !is_string($_POST['settings'])) die('Invalid data');
@@ -5000,8 +4994,6 @@ ENDHERE;
5000
  * @param Array $settings - The settings from the imported json file
5001
  */
5002
  public function import_settings($settings) {
5003
- global $updraftplus;
5004
-
5005
  // A bug in UD releases around 1.12.40 - 1.13.3 meant that it was saved in URL-string format, instead of JSON
5006
  $perhaps_not_yet_parsed = json_decode(stripslashes($settings['settings']), true);
5007
 
@@ -5121,8 +5113,8 @@ ENDHERE;
5121
 
5122
  // This flag indicates that either the stored database option was changed, or that the supplied option was changed before being stored. It isn't comprehensive - it's only used to update some UI elements with invalid input.
5123
  $updated = empty($mass_updated) ? (is_string($value) && UpdraftPlus_Options::get_updraft_option($key) != $value) : (is_string($value) && (!isset($original_settings[$key]) || $original_settings[$key] != $value));
5124
-
5125
- $db_updated = empty($mass_updated) ? UpdraftPlus_Options::update_updraft_option($key, $value) : true;
5126
 
5127
  // Add information on what has changed to array to loop through to update links etc.
5128
  // Restricting to strings for now, to prevent any unintended leakage (since this is just used for UI updating)
@@ -5309,8 +5301,6 @@ ENDHERE;
5309
  * @return object - the UpdraftVault option setup to use the passed in instance id or if one wasn't passed then use the default set of options
5310
  */
5311
  public function get_updraftvault($instance_id = '') {
5312
- global $updraftplus;
5313
-
5314
  $storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array('updraftvault'));
5315
 
5316
  if (isset($storage_objects_and_ids['updraftvault']['instance_settings'][$instance_id])) {
@@ -5487,7 +5477,7 @@ ENDHERE;
5487
  $res .= "Will despatch action: ".htmlspecialchars($action).", no parameters";
5488
  }
5489
 
5490
- $ret = ob_get_clean();
5491
 
5492
  // Need to add this as the close browser should only work for UDP
5493
  if ($close_connection_callable) {
@@ -5512,6 +5502,7 @@ ENDHERE;
5512
  $res .= " - do_action Trigger ";
5513
  }
5514
  }
 
5515
  $response['response'] = $res;
5516
  $response['log'] = $output;
5517
 
91
  echo __('Error:', 'updraftplus').' '.__('template not found', 'updraftplus')." ($path)";
92
  } else {
93
  extract($extract_these);
94
+ global $updraftplus, $wpdb;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
95
+ $updraftplus_admin = $this;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
96
  include $template_file;
97
  }
98
 
244
  private function setup_all_admin_notices_udonly($service, $override = false) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Filter use
245
  global $updraftplus;
246
 
 
 
 
 
247
  if (UpdraftPlus_Options::get_updraft_option('updraft_debug_mode')) {
248
  @ini_set('display_errors', 1);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
249
  if (defined('E_DEPRECATED')) {
508
 
509
  add_filter('woocommerce_in_plugin_update_message', array($this, 'woocommerce_in_plugin_update_message'));
510
 
511
+ new Updraft_Dashboard_News('https://feeds.feedburner.com/updraftplus/', 'https://updraftplus.com/news/', $news_translations);
512
+
513
  // New-install admin tour
514
  if ((!defined('UPDRAFTPLUS_ENABLE_TOUR') || UPDRAFTPLUS_ENABLE_TOUR) && (!defined('UPDRAFTPLUS_THIS_IS_CLONE') || !UPDRAFTPLUS_THIS_IS_CLONE)) {
515
  include_once(UPDRAFTPLUS_DIR.'/includes/updraftplus-tour.php');
1143
  if ($dismissed_until > time()) return;
1144
 
1145
  if ('upgrade-plugin' == $_GET['action']) {
1146
+ $title = __('Update Plugin');// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Passed though to wp-admin/admin-header.php
1147
+ $parent_file = 'plugins.php';// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Passed though to wp-admin/admin-header.php
1148
+ $submenu_file = 'plugins.php';// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Passed though to wp-admin/admin-header.php
1149
  } else {
1150
+ $title = __('Update Theme');// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Passed though to wp-admin/admin-header.php
1151
+ $parent_file = 'themes.php';// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Passed though to wp-admin/admin-header.php
1152
+ $submenu_file = 'themes.php';// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Passed though to wp-admin/admin-header.php
1153
  }
1154
 
1155
  include_once(ABSPATH.'wp-admin/admin-header.php');
1189
  }
1190
 
1191
  public function show_admin_warning_disabledcron() {
1192
+ $ret = '<div class="updraftmessage updated"><p>';
1193
+ $ret .= '<strong>'.__('Warning', 'updraftplus').':</strong> '.__('The scheduler is disabled in your WordPress install, via the DISABLE_WP_CRON setting. No backups can run (even &quot;Backup Now&quot;) unless either you have set up a facility to call the scheduler manually, or until it is enabled.', 'updraftplus').' <a href="'.apply_filters('updraftplus_com_link', "https://updraftplus.com/faqs/my-scheduled-backups-and-pressing-backup-now-does-nothing-however-pressing-debug-backup-does-produce-a-backup/#disablewpcron/").'" target="_blank">'.__('Go here for more information.', 'updraftplus').'</a>';
1194
+ $ret .= '</p></div>';
1195
+ return $ret;
1196
  }
1197
 
1198
  public function show_admin_warning_diskspace() {
1270
  * @param String $method - the remote storage method
1271
  */
1272
  public function get_method_auth_link($method) {
 
 
1273
  $storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array($method));
1274
 
1275
  $object = $storage_objects_and_ids[$method]['object'];
1426
 
1427
  $needs_downloading = false;
1428
 
1429
+ if (!file_exists($fullpath) && (array('none') === $services || empty($services))) {
1430
+ $updraftplus->log('This file does not exist locally, and there is no remote storage for this file.');
1431
+ } elseif (!file_exists($fullpath)) {
1432
  // If the file doesn't exist and they're using one of the cloud options, fetch it down from the cloud.
1433
  $needs_downloading = true;
1434
  $updraftplus->log('File does not yet exist locally - needs downloading');
1472
  }
1473
 
1474
  // Now, be ready to spool the thing to the browser
1475
+ if (is_file($fullpath) && is_readable($fullpath) && $needs_downloading) {
1476
 
1477
  // That message is then picked up by the AJAX listener
1478
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'downloaded:'.filesize($fullpath).":$fullpath");
1479
 
1480
  $result = 'downloaded';
1481
 
1482
+ } elseif ($needs_downloading) {
1483
 
1484
  $updraftplus->jobdata_set('dlfile_'.$timestamp.'_'.$type.'_'.$findex, 'failed');
1485
  $updraftplus->jobdata_set('dlerrors_'.$timestamp.'_'.$type.'_'.$findex, $updraftplus->errors);
1486
  $updraftplus->log('Remote fetch failed. File '.$fullpath.' did not exist or was unreadable. If you delete local backups then remote retrieval may have failed.');
1487
 
1488
  $result = 'download_failed';
1489
+ } else {
1490
+ $result = 'no_local_file';
1491
  }
1492
 
1493
  restore_error_handler();
1513
 
1514
  public function updraft_ajax_handler() {
1515
 
 
 
1516
  $nonce = empty($_REQUEST['nonce']) ? '' : $_REQUEST['nonce'];
1517
 
1518
  if (!wp_verify_nonce($nonce, 'updraftplus-credentialtest-nonce') || empty($_REQUEST['subaction'])) die('Security check');
1983
 
1984
  $logs_exist = (false !== strpos($output, 'downloadlog'));
1985
  if (!$logs_exist) {
1986
+ list($mod_time, $log_file, $nonce) = $updraftplus->last_modified_log();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
1987
  if ($mod_time) $logs_exist = true;
1988
  }
1989
 
2080
  */
2081
  public function get_activejobs_list($request) {
2082
 
 
 
2083
  $download_status = empty($request['downloaders']) ? array() : $this->get_download_statuses(explode(':', $request['downloaders']));
2084
 
2085
  if (!empty($request['oneshot'])) {
2118
  public function request_backupnow($request, $close_connection_callable = false) {
2119
  global $updraftplus;
2120
 
2121
+ $abort_before_booting = false;
2122
  $backupnow_nocloud = !empty($request['backupnow_nocloud']);
 
2123
 
2124
  $request['incremental'] = !empty($request['incremental']);
2125
 
2141
  $msg = array(
2142
  'error' => __('No suitable backup set (that already contains a full backup of all the requested file component types) was found, to add increments to. Aborting this backup.', 'updaftplus')
2143
  );
2144
+ $abort_before_booting = true;
2145
  }
2146
 
2147
  if ($close_connection_callable && is_callable($close_connection_callable)) {
2150
  $updraftplus->close_browser_connection(json_encode($msg));
2151
  }
2152
 
2153
+ if ($abort_before_booting) die;
2154
 
2155
  $options = array('nocloud' => $backupnow_nocloud, 'use_nonce' => $nonce);
2156
  if (!empty($request['onlythisfileentity']) && is_string($request['onlythisfileentity'])) {
2166
 
2167
  if (!empty($request['extradata'])) $options['extradata'] = $request['extradata'];
2168
 
2169
+ $options['always_keep'] = !empty($request['always_keep']);
2170
 
2171
+ $event = empty($request['backupnow_nofiles']) ? (empty($request['backupnow_nodb']) ? 'updraft_backupnow_backup_all' : 'updraft_backupnow_backup') : 'updraft_backupnow_backup_database';
2172
+
2173
  do_action($event, apply_filters('updraft_backupnow_options', $options, $request));
2174
  }
2175
 
2186
  global $updraftplus;
2187
 
2188
  if (empty($backup_nonce)) {
2189
+ list($mod_time, $log_file, $nonce) = $updraftplus->last_modified_log();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
2190
  } else {
2191
  $nonce = $backup_nonce;
2192
  }
2706
  }
2707
 
2708
  $this->include_template('wp-admin/settings/tab-bar.php', false, array('main_tabs' => $main_tabs, 'backup_history' => $backup_history, 'tabflag' => $tabflag));
 
 
 
2709
  ?>
2710
 
2711
  <div id="updraft-poplog" >
2712
  <pre id="updraft-poplog-content"></pre>
2713
  </div>
2714
 
2715
+ <?php
2716
+ $this->include_template('wp-admin/settings/delete-and-restore-modals.php');
2717
+ ?>
2718
+
2719
  <div id="updraft-navtab-backups-content" <?php if ('backups' != $tabflag) echo 'class="updraft-hidden"'; ?> style="<?php if ('backups' != $tabflag) echo 'display:none;'; ?>">
2720
  <?php
2721
  $is_opera = (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') || false !== strpos($_SERVER['HTTP_USER_AGENT'], 'OPR/'));
2722
  $tmp_opts = array('include_opera_warning' => $is_opera);
2723
  $this->include_template('wp-admin/settings/tab-backups.php', false, array('backup_history' => $backup_history, 'options' => $tmp_opts));
 
2724
  $this->include_template('wp-admin/settings/upload-backups-modal.php');
2725
  ?>
2726
  </div>
3116
  * @return String - the HTML output
3117
  */
3118
  public function render_active_jobs_and_log_table($wide_format = false, $print_active_jobs = true) {
3119
+ global $updraftplus;
3120
  ?>
3121
  <div id="updraft_activejobs_table">
3122
  <?php $active_jobs = ($print_active_jobs) ? $this->print_active_jobs() : '';?>
3177
  private function most_recently_modified_log_link() {
3178
 
3179
  global $updraftplus;
3180
+ list($mod_time, $log_file, $nonce) = $updraftplus->last_modified_log();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
3181
 
3182
  ?>
3183
  <a href="?page=updraftplus&amp;action=downloadlatestmodlog&amp;wpnonce=<?php echo wp_create_nonce('updraftplus_download'); ?>" <?php if (!$mod_time) echo 'style="display:none;"'; ?> class="updraft-log-link" onclick="event.preventDefault(); updraft_popuplog('');"><?php _e('Download most recently modified log file', 'updraftplus');?></a>
3318
 
3319
  $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
3320
 
3321
+ $began_at = isset($jobdata['backup_time']) ? get_date_from_gmt(gmdate('Y-m-d H:i:s', (int) $jobdata['backup_time']), 'D, F j, Y H:i') : '?';
3322
 
3323
  $remote_sent = (!empty($jobdata['service']) && ((is_array($jobdata['service']) && in_array('remotesend', $jobdata['service'])) || 'remotesend' === $jobdata['service'])) ? true : false;
3324
 
3429
  }
3430
  }
3431
 
3432
+ $runs_started = empty($jobdata['runs_started']) ? array() : $jobdata['runs_started'];
3433
+ $time_passed = empty($jobdata['run_times']) ? array() : $jobdata['run_times'];
3434
  $last_checkin_ago = -1;
3435
  if (is_array($time_passed)) {
3436
  foreach ($time_passed as $run => $passed) {
4154
  if (!empty($backup['meta_foreign']) && 'wpcore' != $type) continue;
4155
 
4156
  $ide = '';
4157
+
4158
  if (empty($backup['meta_foreign'])) {
4159
  $sdescrip = preg_replace('/ \(.*\)$/', '', $info['description']);
4160
  if (strlen($sdescrip) > 20 && isset($info['shortdescription'])) $sdescrip = $info['shortdescription'];
4170
  }
4171
 
4172
  $sdescrip = (empty($accept[$backup['meta_foreign']]['separatedb'])) ? sprintf(__('Files and database WordPress backup (created by %s)', 'updraftplus'), $desc_source) : sprintf(__('Files backup (created by %s)', 'updraftplus'), $desc_source);
 
4173
  }
4174
  if (isset($backup[$type])) {
4175
  if (!is_array($backup[$type])) $backup[$type] = array($backup[$type]);
4294
  if (empty($services)) return '';
4295
 
4296
  $show_upload = false;
 
4297
 
4298
  // Check that the backup has not already been sent to remote storage before.
4299
  if (empty($backup['service']) || array('none') == $backup['service'] || array('') == $backup['service'] || 'none' == $backup['service']) {
4790
  */
4791
  private function restore_backup($timestamp, $continuation_data = null) {
4792
 
4793
+ global $updraftplus, $updraftplus_restorer;
4794
 
4795
  $second_loop_entities = empty($continuation_data['second_loop_entities']) ? array() : $continuation_data['second_loop_entities'];
4796
 
4935
  */
4936
  public function updraft_ajax_savesettings() {
4937
  try {
 
4938
  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');
4939
 
4940
  if (empty($_POST['settings']) || !is_string($_POST['settings'])) die('Invalid data');
4965
 
4966
  public function updraft_ajax_importsettings() {
4967
  try {
 
 
4968
  if (empty($_POST) || empty($_POST['subaction']) || 'importsettings' != $_POST['subaction'] || !isset($_POST['nonce']) || !is_user_logged_in() || !UpdraftPlus_Options::user_can_manage() || !wp_verify_nonce($_POST['nonce'], 'updraftplus-settings-nonce')) die('Security check');
4969
 
4970
  if (empty($_POST['settings']) || !is_string($_POST['settings'])) die('Invalid data');
4994
  * @param Array $settings - The settings from the imported json file
4995
  */
4996
  public function import_settings($settings) {
 
 
4997
  // A bug in UD releases around 1.12.40 - 1.13.3 meant that it was saved in URL-string format, instead of JSON
4998
  $perhaps_not_yet_parsed = json_decode(stripslashes($settings['settings']), true);
4999
 
5113
 
5114
  // This flag indicates that either the stored database option was changed, or that the supplied option was changed before being stored. It isn't comprehensive - it's only used to update some UI elements with invalid input.
5115
  $updated = empty($mass_updated) ? (is_string($value) && UpdraftPlus_Options::get_updraft_option($key) != $value) : (is_string($value) && (!isset($original_settings[$key]) || $original_settings[$key] != $value));
5116
+
5117
+ if (empty($mass_updated)) UpdraftPlus_Options::update_updraft_option($key, $value);
5118
 
5119
  // Add information on what has changed to array to loop through to update links etc.
5120
  // Restricting to strings for now, to prevent any unintended leakage (since this is just used for UI updating)
5301
  * @return object - the UpdraftVault option setup to use the passed in instance id or if one wasn't passed then use the default set of options
5302
  */
5303
  public function get_updraftvault($instance_id = '') {
 
 
5304
  $storage_objects_and_ids = UpdraftPlus_Storage_Methods_Interface::get_storage_objects_and_ids(array('updraftvault'));
5305
 
5306
  if (isset($storage_objects_and_ids['updraftvault']['instance_settings'][$instance_id])) {
5477
  $res .= "Will despatch action: ".htmlspecialchars($action).", no parameters";
5478
  }
5479
 
5480
+ ob_get_clean();
5481
 
5482
  // Need to add this as the close browser should only work for UDP
5483
  if ($close_connection_callable) {
5502
  $res .= " - do_action Trigger ";
5503
  }
5504
  }
5505
+ $response = array();
5506
  $response['response'] = $res;
5507
  $response['log'] = $output;
5508
 
backup.php CHANGED
@@ -353,7 +353,6 @@ class UpdraftPlus_Backup {
353
  }
354
  if (class_exists($objname)) {
355
  $remote_obj = new $objname;
356
- $pass_to_prune = null;
357
  $prune_services[$service]['all'] = array($remote_obj, null);
358
  } else {
359
  $updraftplus->log("Could not prune from service $service: remote method not found");
@@ -623,8 +622,6 @@ class UpdraftPlus_Backup {
623
 
624
  // Returns an array, most recent first, of backup sets
625
  $backup_history = UpdraftPlus_Backup_History::get_history();
626
- $db_backups_found = 0;
627
- $file_backups_found = 0;
628
 
629
  $ignored_because_imported = array();
630
 
@@ -654,8 +651,6 @@ class UpdraftPlus_Backup {
654
  }
655
  $updraftplus->log("Number of backup sets in history: ".count($backup_history)."; groups (db): ".count($backup_db_groups));
656
 
657
- $started_main_prune_loop_at = time();
658
-
659
  foreach ($backup_db_groups as $group_id => $group) {
660
 
661
  // N.B. The array returned by UpdraftPlus_Backup_History::get_history() is already sorted, with most-recent first
@@ -1270,16 +1265,13 @@ class UpdraftPlus_Backup {
1270
  // Add the final part of the array
1271
  if ($index > 0) {
1272
  $zip_file = (isset($this->backup_files_array[$youwhat]) && isset($this->backup_files_array[$youwhat][$index])) ? $this->backup_files_array[$youwhat][$index] : $backup_file_basename.'-'.$youwhat.($index+1).'.zip';
1273
-
1274
- // $fbase = $backup_file_basename.'-'.$youwhat.($index+1).'.zip';
1275
  $z = $this->updraft_dir.'/'.$zip_file;
1276
  $fs_key = $youwhat.$index.'-size';
 
1277
  if (file_exists($z)) {
1278
- $backup_array[$youwhat][$index] = $fbase;
1279
  $backup_array[$fs_key] = filesize($z);
1280
  } elseif (isset($this->backup_files_array[$fs_key])) {
1281
- $backup_array[$youwhat][$index] = $fbase;
1282
- $backup_array[$fs_key] = $this->backup_files_array[$fskey];
1283
  }
1284
  } else {
1285
  $zip_file = (isset($this->backup_files_array[$youwhat]) && isset($this->backup_files_array[$youwhat][0])) ? $this->backup_files_array[$youwhat][0] : $backup_file_basename.'-'.$youwhat.'.zip';
@@ -3009,7 +3001,7 @@ class UpdraftPlus_Backup {
3009
  $zipfiles_added_thisbatch++;
3010
 
3011
  if (method_exists($zip, 'setCompressionName') && $this->file_should_be_stored_without_compression($add_as)) {
3012
- if (false == ($set_compress = $zip->setCompressionName($add_as, ZipArchive::CM_STORE))) {
3013
  $updraftplus->log("Zip: setCompressionName failed on: $add_as");
3014
  }
3015
  }
@@ -3141,7 +3133,7 @@ class UpdraftPlus_Backup {
3141
  if ($updraftplus->current_resumption >= 1) {
3142
  $time_passed = $updraftplus->jobdata_get('run_times');
3143
  if (!is_array($time_passed)) $time_passed = array();
3144
- list($max_time, $timings_string, $run_times_known) = UpdraftPlus_Manipulation_Functions::max_time_passed($time_passed, $updraftplus->current_resumption-1, $this->first_run);
3145
  } else {
3146
  // $run_times_known = 0;
3147
  // $max_time = -1;
353
  }
354
  if (class_exists($objname)) {
355
  $remote_obj = new $objname;
 
356
  $prune_services[$service]['all'] = array($remote_obj, null);
357
  } else {
358
  $updraftplus->log("Could not prune from service $service: remote method not found");
622
 
623
  // Returns an array, most recent first, of backup sets
624
  $backup_history = UpdraftPlus_Backup_History::get_history();
 
 
625
 
626
  $ignored_because_imported = array();
627
 
651
  }
652
  $updraftplus->log("Number of backup sets in history: ".count($backup_history)."; groups (db): ".count($backup_db_groups));
653
 
 
 
654
  foreach ($backup_db_groups as $group_id => $group) {
655
 
656
  // N.B. The array returned by UpdraftPlus_Backup_History::get_history() is already sorted, with most-recent first
1265
  // Add the final part of the array
1266
  if ($index > 0) {
1267
  $zip_file = (isset($this->backup_files_array[$youwhat]) && isset($this->backup_files_array[$youwhat][$index])) ? $this->backup_files_array[$youwhat][$index] : $backup_file_basename.'-'.$youwhat.($index+1).'.zip';
 
 
1268
  $z = $this->updraft_dir.'/'.$zip_file;
1269
  $fs_key = $youwhat.$index.'-size';
1270
+ $backup_array[$youwhat][$index] = $zip_file;
1271
  if (file_exists($z)) {
 
1272
  $backup_array[$fs_key] = filesize($z);
1273
  } elseif (isset($this->backup_files_array[$fs_key])) {
1274
+ $backup_array[$fs_key] = $this->backup_files_array[$fs_key];
 
1275
  }
1276
  } else {
1277
  $zip_file = (isset($this->backup_files_array[$youwhat]) && isset($this->backup_files_array[$youwhat][0])) ? $this->backup_files_array[$youwhat][0] : $backup_file_basename.'-'.$youwhat.'.zip';
3001
  $zipfiles_added_thisbatch++;
3002
 
3003
  if (method_exists($zip, 'setCompressionName') && $this->file_should_be_stored_without_compression($add_as)) {
3004
+ if (false == ($set_compress = $zip->setCompressionName($add_as, ZipArchive::CM_STORE))) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
3005
  $updraftplus->log("Zip: setCompressionName failed on: $add_as");
3006
  }
3007
  }
3133
  if ($updraftplus->current_resumption >= 1) {
3134
  $time_passed = $updraftplus->jobdata_get('run_times');
3135
  if (!is_array($time_passed)) $time_passed = array();
3136
+ list($max_time, $timings_string, $run_times_known) = UpdraftPlus_Manipulation_Functions::max_time_passed($time_passed, $updraftplus->current_resumption-1, $this->first_run);// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
3137
  } else {
3138
  // $run_times_known = 0;
3139
  // $max_time = -1;
central/bootstrap.php CHANGED
@@ -13,6 +13,9 @@ if (!class_exists('UpdraftPlus_UpdraftCentral_Listener')) require_once('listener
13
 
14
  class UpdraftPlus_UpdraftCentral_Main {
15
 
 
 
 
16
  public function __construct() {
17
 
18
  // Add the section to the 'advanced tools' page
@@ -31,7 +34,8 @@ class UpdraftPlus_UpdraftCentral_Main {
31
  'analytics' => 'UpdraftCentral_Analytics_Commands',
32
  'plugin' => 'UpdraftCentral_Plugin_Commands',
33
  'theme' => 'UpdraftCentral_Theme_Commands',
34
- 'posts' => 'UpdraftCentral_Posts_Commands'
 
35
  ));
36
 
37
  // If nothing was sent, then there is no incoming message, so no need to set up a listener (or CORS request, etc.). This avoids a DB SELECT query on the option below in the case where it didn't get autoloaded, which is the case when there are no keys.
@@ -46,6 +50,9 @@ class UpdraftPlus_UpdraftCentral_Main {
46
 
47
  }
48
 
 
 
 
49
  public function wp_ajax_updraftcentral_receivepublickey() {
50
 
51
  // The actual nonce check is done in the method below
@@ -57,12 +64,12 @@ class UpdraftPlus_UpdraftCentral_Main {
57
  echo '<html><head><title>UpdraftCentral</title></head><body><h1>'.__('UpdraftCentral Connection', 'updraftplus').'</h1><h2>'.htmlspecialchars(network_site_url()).'</h2><p>';
58
 
59
  if ('ok' == $result['responsetype']) {
60
- echo __('An UpdraftCentral connection has been made successfully.', 'updraftplus');
61
  } else {
62
  echo '<strong>'.__('A new UpdraftCentral connection has not been made.', 'updraftplus').'</strong><br>';
63
  switch ($result['code']) {
64
  case 'unknown_key':
65
- echo __('The key referred to was unknown.', 'updraftplus');
66
  break;
67
  case 'not_logged_in':
68
  echo __('You are not logged into this WordPress site in your web browser.', 'updraftplus').' '.__('You must visit this URL in the same browser and login session as you created the key in.', 'updraftplus');
@@ -72,7 +79,7 @@ class UpdraftPlus_UpdraftCentral_Main {
72
  _e('You must visit this link in the same browser and login session as you created the key in.', 'updraftplus');
73
  break;
74
  case 'already_have':
75
- echo __('This connection appears to already have been made.', 'updraftplus');
76
  break;
77
  default:
78
  echo htmlspecialchars(print_r($result, true));
@@ -262,6 +269,13 @@ class UpdraftPlus_UpdraftCentral_Main {
262
  return $created;
263
  }
264
 
 
 
 
 
 
 
 
265
  private function indicator_name_from_index($index) {
266
  return $index.'.central.updraftplus.com';
267
  }
@@ -401,8 +415,6 @@ class UpdraftPlus_UpdraftCentral_Main {
401
  return array(
402
  'bundle' => $local_bundle,
403
  'r' => __('Key created successfully.', 'updraftplus').' '.__('You must copy and paste this key now - it cannot be shown again.', 'updraftplus'),
404
- // 'selector' => $this->get_remotesites_selector(array()),
405
- // 'ourkeys' => $this->list_our_keys($our_keys),
406
  );
407
  }
408
 
@@ -410,6 +422,11 @@ class UpdraftPlus_UpdraftCentral_Main {
410
 
411
  }
412
 
 
 
 
 
 
413
  public function get_keys_table() {
414
 
415
  $ret = '';
@@ -577,7 +594,12 @@ class UpdraftPlus_UpdraftCentral_Main {
577
  return ob_get_clean();
578
  }
579
 
580
- private function create_log_markup() {
 
 
 
 
 
581
  ob_start();
582
  ?>
583
  <div id="updraftcentral_view_log_container" style="margin: 10px 0;">
@@ -589,6 +611,9 @@ class UpdraftPlus_UpdraftCentral_Main {
589
  return ob_get_clean();
590
  }
591
 
 
 
 
592
  public function debugtools_dashboard() {
593
  ?>
594
  <div class="advanced_tools updraft_central">
@@ -600,7 +625,7 @@ class UpdraftPlus_UpdraftCentral_Main {
600
  <?php echo $this->create_key_markup(); ?>
601
  <?php echo $this->get_keys_table(); ?>
602
  <button style="display: none;" type="button" class="button button-primary" id="updraftcentral_wizard_go"><?php _e('Create another key', 'updraftplus'); ?></button>
603
- <?php echo $this->create_log_markup(); ?>
604
  </div>
605
  </div>
606
  <?php
13
 
14
  class UpdraftPlus_UpdraftCentral_Main {
15
 
16
+ /**
17
+ * Class constructor
18
+ */
19
  public function __construct() {
20
 
21
  // Add the section to the 'advanced tools' page
34
  'analytics' => 'UpdraftCentral_Analytics_Commands',
35
  'plugin' => 'UpdraftCentral_Plugin_Commands',
36
  'theme' => 'UpdraftCentral_Theme_Commands',
37
+ 'posts' => 'UpdraftCentral_Posts_Commands',
38
+ 'media' => 'UpdraftCentral_Media_Commands'
39
  ));
40
 
41
  // If nothing was sent, then there is no incoming message, so no need to set up a listener (or CORS request, etc.). This avoids a DB SELECT query on the option below in the case where it didn't get autoloaded, which is the case when there are no keys.
50
 
51
  }
52
 
53
+ /**
54
+ * Receive a new public key in $_GET, and echo a response. Will die() if called.
55
+ */
56
  public function wp_ajax_updraftcentral_receivepublickey() {
57
 
58
  // The actual nonce check is done in the method below
64
  echo '<html><head><title>UpdraftCentral</title></head><body><h1>'.__('UpdraftCentral Connection', 'updraftplus').'</h1><h2>'.htmlspecialchars(network_site_url()).'</h2><p>';
65
 
66
  if ('ok' == $result['responsetype']) {
67
+ _e('An UpdraftCentral connection has been made successfully.', 'updraftplus');
68
  } else {
69
  echo '<strong>'.__('A new UpdraftCentral connection has not been made.', 'updraftplus').'</strong><br>';
70
  switch ($result['code']) {
71
  case 'unknown_key':
72
+ _e('The key referred to was unknown.', 'updraftplus');
73
  break;
74
  case 'not_logged_in':
75
  echo __('You are not logged into this WordPress site in your web browser.', 'updraftplus').' '.__('You must visit this URL in the same browser and login session as you created the key in.', 'updraftplus');
79
  _e('You must visit this link in the same browser and login session as you created the key in.', 'updraftplus');
80
  break;
81
  case 'already_have':
82
+ _e('This connection appears to already have been made.', 'updraftplus');
83
  break;
84
  default:
85
  echo htmlspecialchars(print_r($result, true));
269
  return $created;
270
  }
271
 
272
+ /**
273
+ * Given an index, return the indicator name
274
+ *
275
+ * @param String $index
276
+ *
277
+ * @return String
278
+ */
279
  private function indicator_name_from_index($index) {
280
  return $index.'.central.updraftplus.com';
281
  }
415
  return array(
416
  'bundle' => $local_bundle,
417
  'r' => __('Key created successfully.', 'updraftplus').' '.__('You must copy and paste this key now - it cannot be shown again.', 'updraftplus'),
 
 
418
  );
419
  }
420
 
422
 
423
  }
424
 
425
+ /**
426
+ * Get the HTML for the keys table
427
+ *
428
+ * @return String
429
+ */
430
  public function get_keys_table() {
431
 
432
  $ret = '';
594
  return ob_get_clean();
595
  }
596
 
597
+ /**
598
+ * Get log event viewer mark-up
599
+ *
600
+ * @return String - the HTML
601
+ */
602
+ private function get_log_markup() {
603
  ob_start();
604
  ?>
605
  <div id="updraftcentral_view_log_container" style="margin: 10px 0;">
611
  return ob_get_clean();
612
  }
613
 
614
+ /**
615
+ * Echo the debug-tools dashboard HTML. Called by the WP action updraftplus_debugtools_dashboard.
616
+ */
617
  public function debugtools_dashboard() {
618
  ?>
619
  <div class="advanced_tools updraft_central">
625
  <?php echo $this->create_key_markup(); ?>
626
  <?php echo $this->get_keys_table(); ?>
627
  <button style="display: none;" type="button" class="button button-primary" id="updraftcentral_wizard_go"><?php _e('Create another key', 'updraftplus'); ?></button>
628
+ <?php echo $this->get_log_markup(); ?>
629
  </div>
630
  </div>
631
  <?php
central/classes/automatic-upgrader-skin-compatibility.php ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('ABSPATH')) die('No direct access.');
4
+
5
+ class Automatic_Upgrader_Skin extends Automatic_Upgrader_Skin_Main {
6
+
7
+ public function feedback($string, ...$args) { // phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ellipsisFound -- spread operator is not supported in PHP < 5.5 but WP 5.3 supports PHP 5.6 minimum
8
+ parent::updraft_feedback($string);
9
+ }
10
+ }
central/classes/class-automatic-upgrader-skin.php CHANGED
@@ -18,7 +18,7 @@ if (!defined('ABSPATH')) die('No direct access.');
18
  * @subpackage Upgrader
19
  * @since 3.7.0
20
  */
21
- class Automatic_Upgrader_Skin extends WP_Upgrader_Skin {
22
 
23
  protected $messages = array();
24
 
@@ -56,7 +56,7 @@ class Automatic_Upgrader_Skin extends WP_Upgrader_Skin {
56
  *
57
  * @param string|array|WP_Error $data THis is the data to be used for the feedback
58
  */
59
- public function feedback($data) {
60
  if (is_wp_error($data)) {
61
  $string = $data->get_error_message();
62
  } elseif (is_array($data)) {
@@ -110,3 +110,17 @@ class Automatic_Upgrader_Skin extends WP_Upgrader_Skin {
110
  public function bulk_footer() {
111
  }
112
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  * @subpackage Upgrader
19
  * @since 3.7.0
20
  */
21
+ class Automatic_Upgrader_Skin_Main extends WP_Upgrader_Skin {
22
 
23
  protected $messages = array();
24
 
56
  *
57
  * @param string|array|WP_Error $data THis is the data to be used for the feedback
58
  */
59
+ protected function updraft_feedback($data) {
60
  if (is_wp_error($data)) {
61
  $string = $data->get_error_message();
62
  } elseif (is_array($data)) {
110
  public function bulk_footer() {
111
  }
112
  }
113
+
114
+ global $updraftplus;
115
+ $wp_version = $updraftplus->get_wordpress_version();
116
+
117
+ if (version_compare($wp_version, '5.3', '>=')) {
118
+ if (!class_exists('Automatic_Upgrader_Skin')) require_once(UPDRAFTPLUS_DIR.'/central/classes/automatic-upgrader-skin-compatibility.php');
119
+ } else {
120
+ class Automatic_Upgrader_Skin extends Automatic_Upgrader_Skin_Main {
121
+
122
+ public function feedback($string) {
123
+ parent::updraft_feedback($string);
124
+ }
125
+ }
126
+ }
central/commands.php CHANGED
@@ -16,6 +16,11 @@ abstract class UpdraftCentral_Commands {
16
 
17
  protected $installed_data;
18
 
 
 
 
 
 
19
  public function __construct($rc) {
20
  $this->rc = $rc;
21
  global $updraftplus;
@@ -23,6 +28,9 @@ abstract class UpdraftCentral_Commands {
23
  $this->installed_data = array();
24
  }
25
 
 
 
 
26
  final protected function _admin_include() {
27
  $files = func_get_args();
28
  foreach ($files as $file) {
@@ -30,6 +38,9 @@ abstract class UpdraftCentral_Commands {
30
  }
31
  }
32
 
 
 
 
33
  final protected function _frontend_include() {
34
  $files = func_get_args();
35
  foreach ($files as $file) {
16
 
17
  protected $installed_data;
18
 
19
+ /**
20
+ * Class constructor
21
+ *
22
+ * @param string $rc
23
+ */
24
  public function __construct($rc) {
25
  $this->rc = $rc;
26
  global $updraftplus;
28
  $this->installed_data = array();
29
  }
30
 
31
+ /**
32
+ * Include a file or files from wp-admin/includes
33
+ */
34
  final protected function _admin_include() {
35
  $files = func_get_args();
36
  foreach ($files as $file) {
38
  }
39
  }
40
 
41
+ /**
42
+ * Include a file or files from wp-includes
43
+ */
44
  final protected function _frontend_include() {
45
  $files = func_get_args();
46
  foreach ($files as $file) {
central/listener.php CHANGED
@@ -23,6 +23,12 @@ class UpdraftPlus_UpdraftCentral_Listener {
23
 
24
  private $command_classes;
25
 
 
 
 
 
 
 
26
  public function __construct($keys = array(), $command_classes = array()) {
27
  global $updraftplus;
28
  $this->ud = $updraftplus;
23
 
24
  private $command_classes;
25
 
26
+ /**
27
+ * Class constructor
28
+ *
29
+ * @param Array $keys - keys to set up listeners for
30
+ * @param Array $command_classes - commands
31
+ */
32
  public function __construct($keys = array(), $command_classes = array()) {
33
  global $updraftplus;
34
  $this->ud = $updraftplus;
central/modules/core.php CHANGED
@@ -136,28 +136,15 @@ class UpdraftCentral_Core_Commands extends UpdraftCentral_Commands {
136
 
137
  // Check if credentials are valid and have sufficient
138
  // privileges to create and delete (e.g. write)
 
139
  $credentials = request_filesystem_credentials($url, '', false, $directory);
140
- if (WP_Filesystem($credentials, $directory)) {
141
-
142
- global $wp_filesystem;
143
- $path = $entity_directories[$entity].'/.updraftcentral';
144
-
145
- if (!$wp_filesystem->put_contents($path, '', 0644)) {
146
- // Add useful error details to help with any future debugging. Usually, if the user
147
- // gets to this area then that would mean that the user does not have "write" permission
148
- // to the target folder (plugins, themes, etc.). Probably, some added restrictions were
149
- // implemented by his or her hosting.
150
- $errors = array();
151
- if (isset($wp_filesystem->errors) && is_wp_error($wp_filesystem->errors)) {
152
- $errors = $wp_filesystem->errors->errors;
153
- }
154
 
155
- $result = array('error' => true, 'message' => 'failed_credentials', 'values' => array('errors' => $errors));
156
- } else {
157
- $wp_filesystem->delete($path);
158
- $result = array('error' => false, 'message' => 'credentials_ok', 'values' => array());
159
- }
160
-
161
  } else {
162
  // We're adding some useful error information to help troubleshooting any problems
163
  // that may arise in the future. If the user submitted a wrong password or username
136
 
137
  // Check if credentials are valid and have sufficient
138
  // privileges to create and delete (e.g. write)
139
+ ob_start();
140
  $credentials = request_filesystem_credentials($url, '', false, $directory);
141
+ ob_end_clean();
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
+ // The "WP_Filesystem" will suffice in validating the inputted credentials
144
+ // from UpdraftCentral, as it is already attempting to connect to the filesystem
145
+ // using the chosen transport (e.g. ssh, ftp, etc.)
146
+ if (WP_Filesystem($credentials, $directory)) {
147
+ $result = array('error' => false, 'message' => 'credentials_ok', 'values' => array());
 
148
  } else {
149
  // We're adding some useful error information to help troubleshooting any problems
150
  // that may arise in the future. If the user submitted a wrong password or username
central/modules/media.php ADDED
@@ -0,0 +1,568 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
4
+
5
+ /**
6
+ * Handles Media Commands
7
+ */
8
+ class UpdraftCentral_Media_Commands extends UpdraftCentral_Commands {
9
+
10
+ private $switched = false;
11
+
12
+ /**
13
+ * Function that gets called before every action
14
+ *
15
+ * @param string $command a string that corresponds to UDC command to call a certain method for this class.
16
+ * @param array $data an array of data post or get fields
17
+ * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
18
+ *
19
+ * link to udrpc_action main function in class UpdraftPlus_UpdraftCentral_Listener
20
+ */
21
+ public function _pre_action($command, $data, $extra_info) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
22
+ // Here we assign the current blog_id to a variable $blog_id
23
+ $blog_id = get_current_blog_id();
24
+ if (!empty($data['site_id'])) $blog_id = $data['site_id'];
25
+
26
+ if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
27
+ $this->switched = switch_to_blog($blog_id);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Function that gets called after every action
33
+ *
34
+ * @param string $command a string that corresponds to UDC command to call a certain method for this class.
35
+ * @param array $data an array of data post or get fields
36
+ * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
37
+ *
38
+ * link to udrpc_action main function in class UpdraftPlus_UpdraftCentral_Listener
39
+ */
40
+ public function _post_action($command, $data, $extra_info) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
41
+ // Here, we're restoring to the current (default) blog before we switched
42
+ if ($this->switched) restore_current_blog();
43
+ }
44
+
45
+ /**
46
+ * Fetch and retrieves posts based from the submitted parameters
47
+ *
48
+ * @param array $params Containing all the needed information to filter the results of the current request
49
+ * @return array
50
+ */
51
+ public function get_media_items($params) {
52
+ $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
53
+ if (!empty($error)) return $error;
54
+
55
+ // check paged parameter; if empty set to defaults
56
+ $paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
57
+ $numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
58
+ $offset = ($paged - 1) * $numberposts;
59
+
60
+ $args = array(
61
+ 'posts_per_page' => $numberposts,
62
+ 'paged' => $paged,
63
+ 'offset' => $offset,
64
+ 'post_type' => 'attachment',
65
+ 'post_status' => 'inherit',
66
+ );
67
+
68
+ if (!empty($params['keyword'])) {
69
+ $args['s'] = $params['keyword'];
70
+ }
71
+
72
+ if (!empty($params['category'])) {
73
+ if (in_array($params['category'], array('detached', 'unattached'))) {
74
+ $attachment_ids = $this->get_unattached_ids();
75
+ } else {
76
+ $attachment_ids = $this->get_type_ids($params['category']);
77
+ }
78
+
79
+ $args['post__in'] = $attachment_ids;
80
+ }
81
+
82
+ if (!empty($params['date'])) {
83
+ $date = $params['date'];
84
+ list($monthnum, $year) = explode(':', $params['date']);
85
+
86
+ $args['monthnum'] = $monthnum;
87
+ $args['year'] = $year;
88
+ }
89
+
90
+ $query = new WP_Query($args);
91
+ $result = $query->posts;
92
+
93
+ $count_posts = (int) $query->found_posts;
94
+ $page_count = 0;
95
+
96
+ if ($count_posts > 0) {
97
+ $page_count = absint($count_posts / $numberposts);
98
+ $remainder = absint($count_posts % $numberposts);
99
+ $page_count = ($remainder > 0) ? ++$page_count : $page_count;
100
+ }
101
+
102
+ $info = array(
103
+ 'page' => $paged,
104
+ 'pages' => $page_count,
105
+ 'results' => $count_posts,
106
+ 'items_from' => (($paged * $numberposts) - $numberposts) + 1,
107
+ 'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
108
+ );
109
+
110
+ $media_items = array();
111
+ if (!empty($result)) {
112
+ foreach ($result as $item) {
113
+ $media = $this->get_media_item($item, null, true);
114
+ if (!empty($media)) {
115
+ array_push($media_items, $media);
116
+ }
117
+ }
118
+ }
119
+
120
+ $response = array(
121
+ 'items' => $media_items,
122
+ 'info' => $info,
123
+ 'options' => array(
124
+ 'date' => $this->get_date_options(),
125
+ 'type' => $this->get_type_options()
126
+ )
127
+ );
128
+
129
+ return $this->_response($response);
130
+ }
131
+
132
+ /**
133
+ * Fetch a single media item information
134
+ *
135
+ * @param array $params Containing all the needed information to filter the results of the current request
136
+ * @param array|null $extra_info Additional information from the current request
137
+ * @param boolean $raw If set, returns the result of the fetch process unwrapped by the response array
138
+ * @return array
139
+ */
140
+ public function get_media_item($params, $extra_info = null, $raw = false) {
141
+ $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
142
+ if (!empty($error)) return $error;
143
+
144
+ // Raw means that we need to return the result without wrapping it
145
+ // with the "$this->_response" function which indicates that the call
146
+ // was done locally (within the class) and not directly from UpdraftCentral.
147
+ if ($raw && is_object($params) && isset($params->ID)) {
148
+ $media = $params;
149
+ } elseif (is_array($params) && !empty($params['id'])) {
150
+ $media = get_post($params['id']);
151
+ }
152
+
153
+ if (!function_exists('get_post_mime_types')) {
154
+ global $updraftplus;
155
+ // For a much later version of WP the "get_post_mime_types" is located
156
+ // in a different folder. So, we make sure that we have it loaded before
157
+ // actually using it.
158
+ if (version_compare($updraftplus->get_wordpress_version(), '3.5', '>=')) {
159
+ require_once(ABSPATH.WPINC.'/post.php');
160
+ } else {
161
+ // For WP 3.4, the "get_post_mime_types" is located in the location provided below.
162
+ require_once(ABSPATH.'wp-admin/includes/post.php');
163
+ }
164
+ }
165
+
166
+ if (!function_exists('wp_image_editor')) {
167
+ require_once(ABSPATH.'wp-admin/includes/image-edit.php');
168
+ }
169
+
170
+ if (!function_exists('get_media_item')) {
171
+ require_once(ABSPATH.'wp-admin/includes/template.php');
172
+ require_once(ABSPATH.'wp-admin/includes/media.php');
173
+ }
174
+
175
+
176
+ if ($media) {
177
+ $thumb = wp_get_attachment_image_src($media->ID, 'thumbnail', true);
178
+ if (!empty($thumb)) $media->thumb_url = $thumb[0];
179
+
180
+ $media->url = wp_get_attachment_url($media->ID);
181
+ $media->parent_post_title = get_the_title($media->post_parent);
182
+ $media->author = get_the_author_meta('display_name', $media->post_author);
183
+ $media->filename = basename($media->url);
184
+ $media->date = date('Y/m/d', strtotime($media->post_date));
185
+ $media->upload_date = mysql2date(get_option('date_format'), $media->post_date);
186
+
187
+ $media->filesize = 0;
188
+ $file = get_attached_file($media->ID);
189
+ if (!empty($file) && file_exists($file)) {
190
+ $media->filesize = size_format(filesize($file));
191
+ }
192
+
193
+ $media->nonce = wp_create_nonce('image_editor-'.$media->ID);
194
+ if (false !== strpos($media->post_mime_type, 'image/')) {
195
+ $meta = wp_get_attachment_metadata($media->ID);
196
+
197
+ $thumb = image_get_intermediate_size($media->ID, 'thumbnail');
198
+ $sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
199
+
200
+ // Pulling details
201
+ $sizer = 1;
202
+ if (isset($meta['width'], $meta['height'])) {
203
+ $big = max($meta['width'], $meta['height']);
204
+ $sizer = $big > 400 ? 400 / $big : 1;
205
+ }
206
+
207
+ $constrained_dims = array();
208
+ if ($thumb && $sub_sizes) {
209
+ $constrained_dims = wp_constrain_dimensions($thumb['width'], $thumb['height'], 160, 120);
210
+ }
211
+
212
+ $rotate_supported = false;
213
+ if (function_exists('imagerotate') || wp_image_editor_supports(array('mime_type' => get_post_mime_type($media->ID), 'methods' => array('rotate')))) {
214
+ $rotate_supported = true;
215
+ }
216
+
217
+ // Check for alternative text if present
218
+ $alt = get_post_meta($media->ID, '_wp_attachment_image_alt', true);
219
+ $media->alt = !empty($alt) ? $alt : '';
220
+
221
+ // Check whether edited images are restorable
222
+ $backup_sizes = get_post_meta($media->ID, '_wp_attachment_backup_sizes', true);
223
+ $can_restore = !empty($backup_sizes) && isset($backup_sizes['full-orig']) && basename($meta['file']) != $backup_sizes['full-orig']['file'];
224
+
225
+ $image_edit_overwrite = (!defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE) ? 0 : 1;
226
+ $media->misc = array(
227
+ 'sizer' => $sizer,
228
+ 'rand' => rand(1, 99999),
229
+ 'constrained_dims' => $constrained_dims,
230
+ 'rotate_supported' => (int) $rotate_supported,
231
+ 'thumb' => $thumb,
232
+ 'meta' => $meta,
233
+ 'alt_text' => $alt,
234
+ 'can_restore' => $can_restore,
235
+ 'image_edit_overwrite' => $image_edit_overwrite
236
+ );
237
+ }
238
+ }
239
+
240
+ return $raw ? $media : $this->_response(array('item' => $media));
241
+ }
242
+
243
+ /**
244
+ * Fetch and retrieves posts based from the submitted parameters
245
+ *
246
+ * @param array $params Containing all the needed information to filter the results of the current request
247
+ * @return array
248
+ */
249
+ public function get_posts($params) {
250
+ $error = $this->_validate_capabilities(array('edit_posts'));
251
+ if (!empty($error)) return $error;
252
+
253
+ // check paged parameter; if empty set to defaults
254
+ $paged = !empty($params['paged']) ? (int) $params['paged'] : 1;
255
+ $numberposts = !empty($params['numberposts']) ? (int) $params['numberposts'] : 10;
256
+ $offset = ($paged - 1) * $numberposts;
257
+
258
+ $args = array(
259
+ 'posts_per_page' => $numberposts,
260
+ 'paged' => $paged,
261
+ 'offset' => $offset,
262
+ 'post_type' => 'post',
263
+ 'post_status' => 'publish,private,draft,pending,future',
264
+ );
265
+
266
+ if (!empty($params['keyword'])) {
267
+ $args['s'] = $params['keyword'];
268
+ }
269
+
270
+ $query = new WP_Query($args);
271
+ $result = $query->posts;
272
+
273
+ $count_posts = (int) $query->found_posts;
274
+ $page_count = 0;
275
+
276
+ if ($count_posts > 0) {
277
+ $page_count = absint($count_posts / $numberposts);
278
+ $remainder = absint($count_posts % $numberposts);
279
+ $page_count = ($remainder > 0) ? ++$page_count : $page_count;
280
+ }
281
+
282
+ $info = array(
283
+ 'page' => $paged,
284
+ 'pages' => $page_count,
285
+ 'results' => $count_posts,
286
+ 'items_from' => (($paged * $numberposts) - $numberposts) + 1,
287
+ 'items_to' => ($paged == $page_count) ? $count_posts : $paged * $numberposts,
288
+ );
289
+
290
+ $posts = array();
291
+ if (!empty($result)) {
292
+ foreach ($result as $post) {
293
+ array_push($posts, array('ID' => $post->ID, 'title' => $post->post_title));
294
+ }
295
+ }
296
+
297
+ $response = array(
298
+ 'posts' => $posts,
299
+ 'info' => $info
300
+ );
301
+ return $this->_response($response);
302
+ }
303
+
304
+ /**
305
+ * Saves media changes from UpdraftCentral
306
+ *
307
+ * @param array $params Containing all the needed information to filter the results of the current request
308
+ * @return array
309
+ */
310
+ public function save_media_item($params) {
311
+ $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
312
+ if (!empty($error)) return $error;
313
+
314
+ $args = array(
315
+ 'post_title' => $params['image_title'],
316
+ 'post_excerpt' => $params['image_caption'],
317
+ 'post_content' => $params['image_description']
318
+ );
319
+
320
+ if (!empty($params['new'])) {
321
+ $args['post_type'] = 'attachment';
322
+ $media_id = wp_insert_post($args, true);
323
+ } else {
324
+ $args['ID'] = $params['id'];
325
+ $args['post_modified'] = date('Y-m-d H:i:s');
326
+ $args['post_modified_gmt'] = gmdate('Y-m-d H:i:s');
327
+
328
+ $media_id = wp_update_post($args, true);
329
+ }
330
+
331
+ if (!empty($media_id)) {
332
+ // Update alternative text if not empty
333
+ if (!empty($params['image_alternative_text'])) {
334
+ update_post_meta($media_id, '_wp_attachment_image_alt', $params['image_alternative_text']);
335
+ }
336
+
337
+ $result = array(
338
+ 'status' => 'success',
339
+ 'item' => $this->get_media_item(array('id' => $media_id), null, true)
340
+ );
341
+ } else {
342
+ $result = array('status' => 'failed');
343
+ }
344
+
345
+ return $this->_response($result);
346
+ }
347
+
348
+ /**
349
+ * Executes media action (e.g. attach, detach and delete)
350
+ *
351
+ * @param array $params Containing all the needed information to filter the results of the current request
352
+ * @return array
353
+ */
354
+ public function execute_media_action($params) {
355
+ $error = $this->_validate_capabilities(array('upload_files', 'edit_posts'));
356
+ if (!empty($error)) return $error;
357
+
358
+ $result = array();
359
+ switch ($params['do']) {
360
+ case 'attach':
361
+ global $wpdb;
362
+ $query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = %d WHERE `post_type` = 'attachment' AND ID = %d", $params['parent_id'], $params['id']));
363
+
364
+ if (false === $query_result) {
365
+ $result['error'] = __('Failed to attach media.', 'updraftplus');
366
+ } else {
367
+ $result['msg'] = __('Media has been attached to post.', 'updraftplus');
368
+ }
369
+ break;
370
+ case 'detach':
371
+ global $wpdb;
372
+ $query_result = $wpdb->query($wpdb->prepare("UPDATE {$wpdb->posts} SET `post_parent` = 0 WHERE `post_type` = 'attachment' AND ID = %d", $params['id']));
373
+
374
+ if (false === $query_result) {
375
+ $result['error'] = __('Failed to detach media.', 'updraftplus');
376
+ } else {
377
+ $result['msg'] = __('Media has been detached from post.', 'updraftplus');
378
+ }
379
+ break;
380
+ case 'delete':
381
+ $failed_items = array();
382
+ foreach ($params['ids'] as $id) {
383
+ // Delete permanently
384
+ if (false === wp_delete_attachment($id, true)) {
385
+ $failed_items[] = $id;
386
+ }
387
+ }
388
+
389
+ if (!empty($failed_items)) {
390
+ $result['error'] = __('Failed to delete selected media.', 'updraftplus');
391
+ $result['items'] = $failed_items;
392
+ } else {
393
+ $result['msg'] = __('Selected media has been deleted successfully.', 'updraftplus');
394
+ }
395
+ break;
396
+ default:
397
+ break;
398
+ }
399
+
400
+ return $this->_response($result);
401
+ }
402
+
403
+ /**
404
+ * Retrieves a collection of formatted dates found for the given post statuses.
405
+ * It will be used as options for the date filter when managing the media items in UpdraftCentral.
406
+ *
407
+ * @return array
408
+ */
409
+ private function get_date_options() {
410
+ global $wpdb;
411
+ $options = array();
412
+
413
+ $date_options = $wpdb->get_col("SELECT DATE_FORMAT(`post_date`, '%M %Y') as `formatted_post_date` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `formatted_post_date` ORDER BY `post_date` DESC");
414
+
415
+ if (!empty($date_options)) {
416
+ foreach ($date_options as $monthyear) {
417
+ $timestr = strtotime($monthyear);
418
+ $options[] = array('label' => date('F Y', $timestr), 'value' => date('n:Y', $timestr));
419
+ }
420
+ }
421
+
422
+ return $options;
423
+ }
424
+
425
+ /**
426
+ * Retrieves mime types that will be use as filter option in UpdraftCentral
427
+ *
428
+ * @return array
429
+ */
430
+ private function get_type_options() {
431
+ global $wpdb;
432
+ $options = array();
433
+
434
+ if (!function_exists('get_post_mime_types')) {
435
+ global $updraftplus;
436
+ // For a much later version of WP the "get_post_mime_types" is located
437
+ // in a different folder. So, we make sure that we have it loaded before
438
+ // actually using it.
439
+ if (version_compare($updraftplus->get_wordpress_version(), '3.5', '>=')) {
440
+ require_once(ABSPATH.WPINC.'/post.php');
441
+ } else {
442
+ // For WP 3.4, the "get_post_mime_types" is located in the location provided below.
443
+ require_once(ABSPATH.'wp-admin/includes/post.php');
444
+ }
445
+ }
446
+
447
+ $post_mime_types = get_post_mime_types();
448
+ $type_options = $wpdb->get_col("SELECT `post_mime_type` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' GROUP BY `post_mime_type` ORDER BY `post_mime_type` DESC");
449
+
450
+ foreach ($post_mime_types as $mime_type => $label) {
451
+ if (!wp_match_mime_types($mime_type, $type_options)) continue;
452
+ $options[] = array('label' => $label[0], 'value' => esc_attr($mime_type));
453
+ }
454
+
455
+ $options[] = array('label' => __('Unattached', 'updraftplus'), 'value' => 'detached');
456
+ return $options;
457
+ }
458
+
459
+ /**
460
+ * Retrieves media items that haven't been attached to any posts
461
+ *
462
+ * @return array
463
+ */
464
+ private function get_unattached_ids() {
465
+ global $wpdb;
466
+ return $wpdb->get_col("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_parent` = '0'");
467
+ }
468
+
469
+ /**
470
+ * Retrieves IDs of media items that has the given mime type
471
+ *
472
+ * @param string $type The mime type to search for
473
+ * @return array
474
+ */
475
+ private function get_type_ids($type) {
476
+ global $wpdb;
477
+ return $wpdb->get_col($wpdb->prepare("SELECT `ID` FROM {$wpdb->posts} WHERE `post_type` = 'attachment' AND `post_status` = 'inherit' AND `post_mime_type` LIKE '%s/%%'", $type));
478
+ }
479
+
480
+ /**
481
+ * Checks whether we have the required fields submitted and the user has
482
+ * the capabilities to execute the requested action
483
+ *
484
+ * @param array $capabilities The capabilities to check and validate
485
+ *
486
+ * @return array|void
487
+ */
488
+ private function _validate_capabilities($capabilities) {
489
+ foreach ($capabilities as $capability) {
490
+ if (!current_user_can($capability)) {
491
+ return $this->_generic_error_response('insufficient_permission');
492
+ }
493
+ }
494
+ }
495
+
496
+ /**
497
+ * Populates the $_REQUEST global variable with the submitted data
498
+ *
499
+ * @param array $params Submitted data received from UpdraftCentral
500
+ * @return array
501
+ */
502
+ private function populate_request($params) {
503
+ if (!empty($params)) {
504
+ foreach ($params as $key => $value) {
505
+ $_REQUEST[$key] = $value;
506
+ }
507
+ }
508
+ }
509
+
510
+ /**
511
+ * Handles image editing requests coming from UpdraftCentral
512
+ *
513
+ * @param array $params Containing all the needed information to filter the results of the current request
514
+ * @return array
515
+ */
516
+ public function image_editor($params) {
517
+ $error = $this->_validate_capabilities(array('edit_posts'));
518
+ if (!empty($error)) return $error;
519
+
520
+ $attachment_id = intval($params['postid']);
521
+ $this->populate_request($params);
522
+
523
+ if (!function_exists('load_image_to_edit')) {
524
+ require_once(ABSPATH.'wp-admin/includes/image.php');
525
+ }
526
+
527
+ include_once(ABSPATH.'wp-admin/includes/image-edit.php');
528
+ $msg = false;
529
+ switch ($params['do']) {
530
+ case 'save':
531
+ case 'scale':
532
+ $msg = wp_save_image($attachment_id);
533
+ break;
534
+ case 'restore':
535
+ $msg = wp_restore_image($attachment_id);
536
+ break;
537
+ }
538
+
539
+ $msg = (false !== $msg) ? json_encode($msg) : $msg;
540
+ return $this->_response(array('content' => $msg));
541
+ }
542
+
543
+ /**
544
+ * Handles image preview requests coming from UpdraftCentral
545
+ *
546
+ * @param array $params Containing all the needed information to filter the results of the current request
547
+ * @return array
548
+ */
549
+ public function image_preview($params) {
550
+ $error = $this->_validate_capabilities(array('edit_posts'));
551
+ if (!empty($error)) return $error;
552
+
553
+ if (!function_exists('load_image_to_edit')) {
554
+ require_once(ABSPATH.'wp-admin/includes/image.php');
555
+ }
556
+
557
+ include_once(ABSPATH.'wp-admin/includes/image-edit.php');
558
+ $this->populate_request($params);
559
+ $post_id = intval($params['postid']);
560
+
561
+ ob_start();
562
+ stream_preview_image($post_id);
563
+ $content = ob_get_contents();
564
+ ob_end_clean();
565
+
566
+ return $this->_response(array('content' => base64_encode($content)));
567
+ }
568
+ }
central/modules/plugin.php CHANGED
@@ -162,20 +162,42 @@ class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
162
  $download_link = $api->download_link;
163
  $installed = $upgrader->install($download_link);
164
 
165
- if (is_wp_error($skin->result)) {
 
 
 
166
  $error_code = $skin->result->get_error_code();
167
  $error_message = $skin->result->get_error_message();
168
 
169
  $error_data = $skin->result->get_error_data($error_code);
170
  if (!empty($error_data)) {
171
  if (is_array($error_data)) $error_data = json_encode($error_data);
172
-
173
  $error_message .= ' '.$error_data;
174
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
176
  }
177
 
178
- if (!$installed) {
179
  $result = $this->_generic_error_response('plugin_install_failed', array(
180
  'plugin' => $query['plugin'],
181
  'error_code' => $error_code,
162
  $download_link = $api->download_link;
163
  $installed = $upgrader->install($download_link);
164
 
165
+ if (is_wp_error($installed)) {
166
+ $error_code = $installed->get_error_code();
167
+ $error_message = $installed->get_error_message();
168
+ } elseif (is_wp_error($skin->result)) {
169
  $error_code = $skin->result->get_error_code();
170
  $error_message = $skin->result->get_error_message();
171
 
172
  $error_data = $skin->result->get_error_data($error_code);
173
  if (!empty($error_data)) {
174
  if (is_array($error_data)) $error_data = json_encode($error_data);
 
175
  $error_message .= ' '.$error_data;
176
  }
177
+ } elseif (is_null($installed) || !$installed) {
178
+ global $wp_filesystem;
179
+ $upgrade_messages = $skin->get_upgrade_messages();
180
+
181
+ if (!class_exists('WP_Filesystem_Base')) include_once(ABSPATH.'/wp-admin/includes/class-wp-filesystem-base.php');
182
+
183
+ // Pass through the error from WP_Filesystem if one was raised.
184
+ if ($wp_filesystem instanceof WP_Filesystem_Base && is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
185
+ $error_code = $wp_filesystem->errors->get_error_code();
186
+ $error_message = $wp_filesystem->errors->get_error_message();
187
+ } elseif (!empty($upgrade_messages)) {
188
+ // We're only after for the last feedback that we received from the install process. Mostly,
189
+ // that is where the last error has been inserted.
190
+ $messages = $skin->get_upgrade_messages();
191
+ $error_code = 'install_failed';
192
+ $error_message = end($messages);
193
+ } else {
194
+ $error_code = 'unable_to_connect_to_filesystem';
195
+ $error_message = __('Unable to connect to the filesystem. Please confirm your credentials.');
196
+ }
197
  }
198
  }
199
 
200
+ if (!$installed || is_wp_error($installed)) {
201
  $result = $this->_generic_error_response('plugin_install_failed', array(
202
  'plugin' => $query['plugin'],
203
  'error_code' => $error_code,
central/modules/theme.php CHANGED
@@ -184,20 +184,42 @@ class UpdraftCentral_Theme_Commands extends UpdraftCentral_Commands {
184
  $download_link = $api->download_link;
185
  $installed = $upgrader->install($download_link);
186
 
187
- if (is_wp_error($skin->result)) {
 
 
 
188
  $error_code = $skin->result->get_error_code();
189
  $error_message = $skin->result->get_error_message();
190
 
191
  $error_data = $skin->result->get_error_data($error_code);
192
  if (!empty($error_data)) {
193
  if (is_array($error_data)) $error_data = json_encode($error_data);
194
-
195
  $error_message .= ' '.$error_data;
196
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  }
198
  }
199
 
200
- if (!$installed) {
201
  $result = $this->_generic_error_response('theme_install_failed', array(
202
  'theme' => $query['theme'],
203
  'error_code' => $error_code,
184
  $download_link = $api->download_link;
185
  $installed = $upgrader->install($download_link);
186
 
187
+ if (is_wp_error($installed)) {
188
+ $error_code = $installed->get_error_code();
189
+ $error_message = $installed->get_error_message();
190
+ } elseif (is_wp_error($skin->result)) {
191
  $error_code = $skin->result->get_error_code();
192
  $error_message = $skin->result->get_error_message();
193
 
194
  $error_data = $skin->result->get_error_data($error_code);
195
  if (!empty($error_data)) {
196
  if (is_array($error_data)) $error_data = json_encode($error_data);
 
197
  $error_message .= ' '.$error_data;
198
  }
199
+ } elseif (is_null($installed) || !$installed) {
200
+ global $wp_filesystem;
201
+ $upgrade_messages = $skin->get_upgrade_messages();
202
+
203
+ if (!class_exists('WP_Filesystem_Base')) include_once(ABSPATH.'/wp-admin/includes/class-wp-filesystem-base.php');
204
+
205
+ // Pass through the error from WP_Filesystem if one was raised.
206
+ if ($wp_filesystem instanceof WP_Filesystem_Base && is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
207
+ $error_code = $wp_filesystem->errors->get_error_code();
208
+ $error_message = $wp_filesystem->errors->get_error_message();
209
+ } elseif (!empty($upgrade_messages)) {
210
+ // We're only after for the last feedback that we received from the install process. Mostly,
211
+ // that is where the last error has been inserted.
212
+ $messages = $skin->get_upgrade_messages();
213
+ $error_code = 'install_failed';
214
+ $error_message = end($messages);
215
+ } else {
216
+ $error_code = 'unable_to_connect_to_filesystem';
217
+ $error_message = __('Unable to connect to the filesystem. Please confirm your credentials.');
218
+ }
219
  }
220
  }
221
 
222
+ if (!$installed || is_wp_error($installed)) {
223
  $result = $this->_generic_error_response('theme_install_failed', array(
224
  'theme' => $query['theme'],
225
  'error_code' => $error_code,
class-updraftplus.php CHANGED
@@ -210,22 +210,18 @@ class UpdraftPlus {
210
  /**
211
  * WordPress filter itsec_scheduled_external_backup - from iThemes Security
212
  *
213
- * @param Boolean $x - whether a backup is scheduled
214
- *
215
  * @return Boolean - filtered value
216
  */
217
- public function itsec_scheduled_external_backup($x) {// phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Filter use
218
  return wp_next_scheduled('updraft_backup') ? true : false;
219
  }
220
 
221
  /**
222
  * WordPress filter itsec_external_backup_link - from iThemes security
223
  *
224
- * @param String $x - link
225
- *
226
  * @return String - filtered value
227
  */
228
- public function itsec_external_backup_link($x) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Filter use
229
  return UpdraftPlus_Options::admin_page_url().'?page=updraftplus';
230
  }
231
 
@@ -428,7 +424,7 @@ class UpdraftPlus {
428
 
429
  if (isset($_GET['wpnonce']) && isset($_GET['page']) && isset($_GET['action']) && 'updraftplus' == $_GET['page'] && 'downloadlatestmodlog' == $_GET['action'] && wp_verify_nonce($_GET['wpnonce'], 'updraftplus_download')) {
430
 
431
- list ($mod_time, $log_file, $nonce) = $this->last_modified_log();
432
 
433
  if ($mod_time >0) {
434
  if (is_readable($log_file)) {
@@ -1685,7 +1681,6 @@ class UpdraftPlus {
1685
  if (function_exists('gzopen')) {
1686
  if (!class_exists('PclZip')) include_once(ABSPATH.'/wp-admin/includes/class-pclzip.php');
1687
  $zip = new PclZip($updraft_dir.'/binziptest/test.zip');
1688
- $foundit = 0;
1689
  if (($list = $zip->listContent()) != 0) {
1690
  foreach ($list as $obj) {
1691
  if ($obj['filename'] && !empty($obj['stored_filename']) && 'binziptest/subdir1/subdir2/test.html' == $obj['stored_filename'] && 131 == $obj['size']) $found_first=true;
@@ -2742,29 +2737,53 @@ class UpdraftPlus {
2742
  return $file_backups;
2743
  }
2744
 
 
 
 
2745
  public function backup_files() {
2746
  // Note that the "false" for database gets over-ridden automatically if they turn out to have the same schedules
2747
  $this->boot_backup(true, false);
2748
  }
2749
 
 
 
 
2750
  public function backup_database() {
2751
  // Note that nothing will happen if the file backup had the same schedule
2752
  $this->boot_backup(false, true);
2753
  }
2754
 
 
 
 
 
 
 
2755
  public function backup_all($options) {
2756
  $skip_cloud = empty($options['nocloud']) ? false : true;
2757
- $this->boot_backup(1, 1, false, false, ($skip_cloud) ? 'none' : false, $options);
2758
  }
2759
 
 
 
 
 
 
 
2760
  public function backupnow_files($options) {
2761
  $skip_cloud = empty($options['nocloud']) ? false : true;
2762
- $this->boot_backup(1, 0, false, false, ($skip_cloud) ? 'none' : false, $options);
2763
  }
2764
 
 
 
 
 
 
 
2765
  public function backupnow_database($options) {
2766
  $skip_cloud = empty($options['nocloud']) ? false : true;
2767
- $this->boot_backup(0, 1, false, false, ($skip_cloud) ? 'none' : false, $options);
2768
  }
2769
 
2770
  /**
@@ -2876,7 +2895,8 @@ class UpdraftPlus {
2876
  * @param Boolean $one_shot
2877
  * @param Boolean|Array|String $service
2878
  * @param Array $options
2879
- * @return Boolean|Void - not currently well specified (though false indicates definite failure)
 
2880
  */
2881
  public function boot_backup($backup_files, $backup_database, $restrict_files_to_override = false, $one_shot = false, $service = false, $options = array()) {
2882
 
@@ -3004,10 +3024,14 @@ class UpdraftPlus {
3004
  if (!UpdraftPlus_Options::get_updraft_option('updraft_debug_mode') && !empty($this->logfile_name) && file_exists($this->logfile_name)) {
3005
  unlink($this->logfile_name);
3006
  }
 
3007
  return $ret;
3008
  }
3009
 
3010
- if (!$this->get_semaphore_lock($backup_files, $backup_database)) return;
 
 
 
3011
 
3012
  // Allow the resume interval to be more than 300 if last time we know we went beyond that - but never more than 600
3013
  if (defined('UPDRAFTPLUS_INITIAL_RESUME_INTERVAL') && is_numeric(UPDRAFTPLUS_INITIAL_RESUME_INTERVAL)) {
@@ -3102,6 +3126,8 @@ class UpdraftPlus {
3102
 
3103
  if ($one_shot) delete_site_option('updraft_oneshotnonce');
3104
 
 
 
3105
  }
3106
 
3107
  /**
@@ -4174,7 +4200,6 @@ class UpdraftPlus {
4174
  // Don't enable this line - it causes 500 HTTP errors in some cases/hosts on some large files, for unknown reason
4175
  // @ini_set('display_errors', '0');
4176
 
4177
- $spooled = false;
4178
  if (UpdraftPlus_Encryption::is_file_encrypted($fullpath)) {
4179
  if (ob_get_level()) {
4180
  $flush_max = min(5, (int) ob_get_level());
@@ -4717,7 +4742,7 @@ class UpdraftPlus {
4717
  $option_other_attr[] = 'style="display:none;"';
4718
  }
4719
  }
4720
- $collate_select_html .= '<option value="'.esc_attr($collate).'" '.selected($collate, $similar_type_collate, $echo = false).' '.implode(' ', $option_other_attr).'>'.esc_html($collate).'</option>';
4721
  }
4722
 
4723
  if (count($db_charsets_found_unique) > 1 && !$db_charset_forbidden) {
@@ -5014,21 +5039,14 @@ class UpdraftPlus {
5014
 
5015
  foreach ($dbsinfo as $key => $value) {
5016
  if ('wp' == $key) {
5017
- // The table prefix after being filtered - i.e. what filters what we'll actually backup
5018
- $table_prefix = $this->get_table_prefix(true);
5019
  // The unfiltered table prefix - i.e. the real prefix that things are relative to
5020
  $table_prefix_raw = $this->get_table_prefix(false);
5021
- $dbinfo['host'] = DB_HOST;
5022
- $dbinfo['name'] = DB_NAME;
5023
- $dbinfo['user'] = DB_USER;
5024
- $dbinfo['pass'] = DB_PASSWORD;
5025
  $dbhandle = $wpdb;
5026
  } else {
5027
  $dbhandle = new UpdraftPlus_WPDB_OtherDB_Utility($dbsinfo[$key]['user'], $dbsinfo[$key]['pass'], $dbsinfo[$key]['name'], $dbsinfo[$key]['host']);
5028
  if (!empty($dbhandle->error)) {
5029
  return $this->log_wp_error($dbhandle->error);
5030
  }
5031
- $table_prefix = $dbsinfo[$key]['prefix'];
5032
  $table_prefix_raw = $dbsinfo[$key]['prefix'];
5033
  }
5034
 
@@ -5211,6 +5229,7 @@ class UpdraftPlus {
5211
  * @return void|array There is a possibility if there is no restore in progress this can return a void. However, in every other case, it will return an array.
5212
  */
5213
  public function check_restore_progress($job_time_greater_than = 120) {
 
5214
  $restore_progress['status'] = false;
5215
  $restore_in_progress = get_site_option('updraft_restore_in_progress');
5216
  if (empty($restore_in_progress)) return;
210
  /**
211
  * WordPress filter itsec_scheduled_external_backup - from iThemes Security
212
  *
 
 
213
  * @return Boolean - filtered value
214
  */
215
+ public function itsec_scheduled_external_backup() {
216
  return wp_next_scheduled('updraft_backup') ? true : false;
217
  }
218
 
219
  /**
220
  * WordPress filter itsec_external_backup_link - from iThemes security
221
  *
 
 
222
  * @return String - filtered value
223
  */
224
+ public function itsec_external_backup_link() {
225
  return UpdraftPlus_Options::admin_page_url().'?page=updraftplus';
226
  }
227
 
424
 
425
  if (isset($_GET['wpnonce']) && isset($_GET['page']) && isset($_GET['action']) && 'updraftplus' == $_GET['page'] && 'downloadlatestmodlog' == $_GET['action'] && wp_verify_nonce($_GET['wpnonce'], 'updraftplus_download')) {
426
 
427
+ list($mod_time, $log_file, $nonce) = $this->last_modified_log();// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
428
 
429
  if ($mod_time >0) {
430
  if (is_readable($log_file)) {
1681
  if (function_exists('gzopen')) {
1682
  if (!class_exists('PclZip')) include_once(ABSPATH.'/wp-admin/includes/class-pclzip.php');
1683
  $zip = new PclZip($updraft_dir.'/binziptest/test.zip');
 
1684
  if (($list = $zip->listContent()) != 0) {
1685
  foreach ($list as $obj) {
1686