PluginProbe ʕ •ᴥ•ʔ
UpdraftPlus: WP Backup & Migration Plugin / 1.24.10
UpdraftPlus: WP Backup & Migration Plugin v1.24.10
1.26.5 1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 1.9.64 1.11.12 1.4.8 1.11.15 1.4.9 1.11.17 1.5.16 1.11.18 1.5.20 1.11.2 1.5.21 1.11.20 1.5.22 1.11.23 1.5.5 1.11.24 1.5.6 1.11.25 1.5.7 1.11.26 1.5.8 1.11.27 1.5.9 1.11.28 1.6.1 1.11.3 1.6.17 1.11.4 1.6.2 1.11.5 1.6.46 1.11.8 1.7.0 1.11.9 1.7.1 1.12.0 1.7.18 1.12.1 1.7.20 1.12.12 1.7.3 1.12.13 1.7.34 1.12.15 1.7.35 1.12.17 1.7.39 1.12.2 1.7.40 1.12.20 1.7.41 1.12.23 1.8.1 1.12.24 1.8.11 1.12.25 1.8.12 1.12.28 1.8.13 1.12.29 1.8.2 1.12.30 1.8.5 1.12.32 1.8.8 1.12.34 1.9.0 1.12.35 1.9.13 1.12.37 1.9.15 1.12.39 1.9.17 1.12.4 1.12.40 1.12.6 1.13.1 1.13.11 1.13.12 1.13.15 1.13.16 1.13.2 1.13.3 1.13.4 1.13.5 1.13.6 1.13.7 1.13.8 1.13.9 1.14.10 1.14.11 1.14.12 1.14.13 1.14.2 1.14.3 1.14.4 1.14.5 1.14.7 1.14.9 1.15.0 1.15.2 1.15.3 1.15.5 1.15.6 1.15.7 1.16.0 1.16.10 1.16.11 1.16.12 1.16.13 1.16.14 1.16.15 1.16.16 1.16.17 1.16.20 1.16.21 1.16.22 1.16.23 1.16.24 1.16.25 1.16.26 1.16.28 1.16.29 1.16.32 1.16.34 1.16.35 1.16.36 1.16.37 1.16.4 1.16.40 1.16.41 1.16.42 1.16.43 1.16.44 1.16.45 1.16.46 1.16.47 1.16.48 1.16.49 1.16.5 1.16.50 1.16.51 1.16.53 1.16.55 1.16.56 1.16.59 1.16.6 1.16.60 1.16.61 1.16.62 1.16.63 1.16.64 1.16.65 1.16.66 1.16.67 1.16.68 1.16.69 1.16.7 1.16.8 1.16.9 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.14 1.2.15 1.2.16 1.2.17 1.2.19 1.2.2 1.2.20 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.33 1.2.35 1.2.36 1.2.38 1.2.39 1.2.4 1.2.40 1.2.41 1.2.42 1.2.43 1.2.44 1.2.45 1.2.46 1.2.5 1.2.7 1.2.8 1.2.9 1.22.1 1.22.10 1.22.11 1.22.12 1.22.14 1.22.15 1.22.16 1.22.17 1.22.18 1.22.19 1.22.20 1.22.21 1.22.22 1.22.23 1.22.24 1.22.3 1.22.4 1.22.5 1.22.6 1.22.7 1.22.8 1.22.9 1.23.1 1.23.10 1.23.11 1.23.12 1.23.13 1.23.15 1.23.16 1.23.2 1.23.3 1.23.4 1.23.5 1.23.6 1.23.7 1.23.8 1.23.9 1.24.1 1.24.10 1.24.11 1.24.12 1.24.2 trunk 1.24.3 0.7.4 1.24.4 0.7.7 1.24.5 0.8.28 1.24.6 0.8.29 1.24.7 0.8.30 1.24.8 0.8.31 1.24.9 0.8.32 1.25.1 0.8.33 1.25.2 0.8.36 1.25.3 0.8.37 1.25.5 0.8.50 1.25.6 0.8.51 1.25.7 0.9.1 1.25.8 0.9.10 1.25.9 0.9.11 1.26.1 0.9.12 1.26.2 0.9.2 1.3.10 0.9.20 1.3.12 0.9.21 1.3.14 0.9.22 1.3.15 1.0.10 1.3.17 1.0.11 1.3.18 1.0.12 1.3.19 1.0.15 1.3.2 1.0.16 1.3.20 1.0.18 1.3.22 1.0.20 1.3.23 1.0.3 1.3.24 1.0.4 1.3.25 1.0.5 1.3.3 1.0.6 1.3.4 1.0.7 1.3.6 1.0.8 1.3.7 1.0.9 1.3.8 1.1.0 1.3.9 1.1.10 1.4.0 1.1.11 1.4.10 1.1.12 1.4.11 1.1.13 1.4.12 1.1.14 1.4.13 1.1.15 1.4.14 1.1.16 1.4.15 1.1.17 1.4.2 1.1.2 1.4.27 1.1.3 1.4.28 1.1.5 1.4.29 1.1.6 1.4.30 1.1.8 1.4.4 1.1.9 1.4.48 1.10.1 1.4.5 1.10.3 1.4.6 1.11.1 1.4.7
updraftplus / includes / class-wpadmin-commands.php
updraftplus / includes Last commit date
Dropbox2 2 years ago Google 2 years ago blockui 1 year ago checkout-embed 1 year ago cloudfiles 2 years ago handlebars 2 years ago images 9 years ago jquery-ui.dialog.extended 1 year ago jquery.serializeJSON 5 years ago jstree 1 year ago labelauty 1 year ago pcloud 2 years ago tether 6 years ago tether-shepherd 7 years ago updraftclone 2 years ago S3.php 2 years ago S3compat.php 1 year ago cacert.pem 2 years ago class-backup-history.php 1 year ago class-commands.php 1 year ago class-database-utility.php 2 years ago class-filesystem-functions.php 1 year ago class-http-error-descriptions.php 2 years ago class-job-scheduler.php 3 years ago class-manipulation-functions.php 2 years ago class-partialfileservlet.php 5 years ago class-remote-send.php 2 years ago class-search-replace.php 3 years ago class-semaphore.php 3 years ago class-storage-methods-interface.php 2 years ago class-updraft-dashboard-news.php 2 years ago class-updraft-semaphore.php 4 years ago class-updraftcentral-updraftplus-commands.php 3 years ago class-updraftplus-encryption.php 2 years ago class-wpadmin-commands.php 1 year ago class-zip.php 2 years ago ftp.class.php 2 years ago get-cpanel-quota-usage.pl 12 years ago google-extensions.php 3 years ago jquery-ui.custom-v1.11.4-1-24-10.min.css 1 year ago jquery-ui.custom-v1.11.4-1-24-10.min.css.map 1 year ago jquery-ui.custom-v1.11.4.css 3 years ago jquery-ui.custom-v1.12.1-1-24-10.min.css 1 year ago jquery-ui.custom-v1.12.1-1-24-10.min.css.map 1 year ago jquery-ui.custom-v1.12.1.css 3 years ago migrator-lite.php 1 year ago updraft-admin-common-1-24-10.min.js 1 year ago updraft-admin-common.js 1 year ago updraft-restorer-skin-compatibility.php 6 years ago updraft-restorer-skin.php 3 years ago updraftcentral.php 2 years ago updraftplus-clone.php 2 years ago updraftplus-login.php 7 years ago updraftplus-notices.php 2 years ago updraftplus-tour.php 2 years ago updraftvault.php 3 years ago
class-wpadmin-commands.php
875 lines
1 <?php
2
3 if (!defined('UPDRAFTPLUS_DIR')) die('No access.');
4
5 /*
6 See class-commands.php for explanation about how these classes work.
7 */
8
9 if (!class_exists('UpdraftPlus_Commands')) updraft_try_include_file('includes/class-commands.php', 'require_once');
10
11 /**
12 * An extension, because commands available via wp-admin are a super-set of those which are available through all mechanisms
13 */
14 class UpdraftPlus_WPAdmin_Commands extends UpdraftPlus_Commands {
15
16 private $_uc_helper;
17
18 private $_updraftplus_admin;
19
20 private $_updraftplus;
21
22 /**
23 * Constructor
24 *
25 * @param string $uc_helper The 'helper' needs to provide the method _updraftplus_background_operation_started
26 */
27 public function __construct($uc_helper) {
28 $this->_uc_helper = $uc_helper;
29 global $updraftplus_admin, $updraftplus;
30 $this->_updraftplus_admin = $updraftplus_admin;
31 $this->_updraftplus = $updraftplus;
32 parent::__construct($uc_helper);
33 }
34
35 /**
36 * Forces a resumption of a backup where the resumption is overdue (so apparently cron is not working)
37 *
38 * @param Array $info - keys 'job_id' and 'resumption'
39 *
40 * @return Array - if there is an error. Otherwise, dies.
41 */
42 public function forcescheduledresumption($info) {
43
44 // Casting $resumption to int is absolutely necessary, as the WP cron system uses a hashed serialisation of the parameters for identifying jobs. Different type => different hash => does not match
45 $resumption = (int) $info['resumption'];
46 $job_id = $info['job_id'];
47 $get_cron = $this->_updraftplus_admin->get_cron($job_id);
48 if (!is_array($get_cron)) {
49 return array('r' => false);
50 } else {
51 $this->_updraftplus->log("Forcing resumption: job id=$job_id, resumption=$resumption");
52 wp_clear_scheduled_hook('updraft_backup_resume', array($resumption, $job_id));
53 $this->_updraftplus->close_browser_connection(json_encode(array('r' => true)));
54 $this->_updraftplus->jobdata_set_from_array($get_cron[1]);
55 $this->_updraftplus->backup_resume($resumption, $job_id);
56 // We don't want to return. The close_browser_connection call already returned a result.
57 die;
58 }
59 }
60
61 /**
62 * Calls a WordPress action and dies
63 *
64 * @param Array $data - must have at least the key 'wpaction' with a string value
65 *
66 * @return WP_Error if no command was included
67 */
68 public function call_wordpress_action($data) {
69
70 if (empty($data['wpaction'])) return new WP_Error('error', '', 'no command sent');
71
72 $response = $this->_updraftplus_admin->call_wp_action($data, array($this->_uc_helper, '_updraftplus_background_operation_started'));// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused variable is for future use.
73
74 die;
75
76 // return array('response' => $response['response'], 'status' => $response['status'], 'log' => $response['log'] );
77 }
78
79 public function updraftcentral_delete_key($params) {
80 global $updraftcentral_main;
81 if (!is_a($updraftcentral_main, 'UpdraftCentral_Main')) {
82 return array('error' => 'UpdraftCentral_Main object not found');
83 }
84
85 return $updraftcentral_main->delete_key($params['key_id']);
86 }
87
88 public function updraftcentral_get_log($params) {
89 global $updraftcentral_main;
90 if (!is_a($updraftcentral_main, 'UpdraftCentral_Main')) {
91 return array('error' => 'UpdraftCentral_Main object not found');
92 }
93 return call_user_func(array($updraftcentral_main, 'get_log'), $params);
94 }
95
96 public function updraftcentral_create_key($params) {
97 global $updraftcentral_main;
98 if (!is_a($updraftcentral_main, 'UpdraftCentral_Main')) {
99 return array('error' => 'UpdraftCentral_Main object not found');
100 }
101 return call_user_func(array($updraftcentral_main, 'create_key'), $params);
102 }
103
104 public function restore_alldownloaded($params) {
105
106 $backups = UpdraftPlus_Backup_History::get_history();
107 $updraft_dir = $this->_updraftplus->backups_dir_location();
108
109 $timestamp = (int) $params['timestamp'];
110 if (!isset($backups[$timestamp])) {
111 return array('m' => '', 'w' => '', 'e' => __('No such backup set exists', 'updraftplus'));
112 }
113
114 $mess = array();
115 parse_str(stripslashes($params['restoreopts']), $res);
116
117 if (isset($res['updraft_restore'])) {
118
119 set_error_handler(array($this->_updraftplus_admin, 'get_php_errors'), E_ALL & ~E_STRICT);
120
121 $elements = array_flip($res['updraft_restore']);
122
123 $warn = array();
124 $err = array();
125
126 if (function_exists('set_time_limit')) @set_time_limit(UPDRAFTPLUS_SET_TIME_LIMIT);// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
127 $max_execution_time = (int) @ini_get('max_execution_time');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
128
129 if ($max_execution_time>0 && $max_execution_time<61) {
130 $warn[] = sprintf(__('The PHP setup on this webserver allows only %s seconds for PHP to run, and does not allow this limit to be raised.', 'updraftplus'), $max_execution_time).' '.__('If you have a lot of data to import, and if the restore operation times out, then you will need to ask your web hosting company for ways to raise this limit (or attempt the restoration piece-by-piece).', 'updraftplus');
131 }
132
133 if (isset($backups[$timestamp]['native']) && false == $backups[$timestamp]['native']) {
134 $warn[] = __('This backup set was not known by UpdraftPlus to be created by the current WordPress installation, but was either found in remote storage, or was sent from a remote site.', 'updraftplus').' '.__('You should make sure that this really is a backup set intended for use on this website, before you restore (rather than a backup set of an unrelated website).', 'updraftplus');
135 }
136
137 if (isset($elements['db'])) {
138
139 // Analyse the header of the database file + display results
140 list ($mess2, $warn2, $err2, $info) = $this->_updraftplus->analyse_db_file($timestamp, $res);
141 $mess = array_merge($mess, $mess2);
142 $warn = array_merge($warn, $warn2);
143 $err = array_merge($err, $err2);
144 foreach ($backups[$timestamp] as $bid => $bval) {
145 if ('db' != $bid && 'db' == substr($bid, 0, 2) && '-size' != substr($bid, -5, 5)) {
146 $warn[] = __('Only the WordPress database can be restored; you will need to deal with the external database manually.', 'updraftplus');
147 break;
148 }
149 }
150 }
151
152 $backupable_entities = $this->_updraftplus->get_backupable_file_entities(true, true);
153 $backupable_plus_db = $backupable_entities;
154 $backupable_plus_db['db'] = array('path' => 'path-unused', 'description' => __('Database', 'updraftplus'));
155
156 if (!empty($backups[$timestamp]['meta_foreign'])) {
157 $foreign_known = apply_filters('updraftplus_accept_archivename', array());
158 if (!is_array($foreign_known) || empty($foreign_known[$backups[$timestamp]['meta_foreign']])) {
159 $err[] = sprintf(__('Backup created by unknown source (%s) - cannot be restored.', 'updraftplus'), $backups[$timestamp]['meta_foreign']);
160 } else {
161 // For some reason, on PHP 5.5 passing by reference in a single array stopped working with apply_filters_ref_array (though not with do_action_ref_array).
162 $backupable_plus_db = apply_filters_ref_array("updraftplus_importforeign_backupable_plus_db", array($backupable_plus_db, array($foreign_known[$backups[$timestamp]['meta_foreign']], &$mess, &$warn, &$err)));
163 }
164 }
165
166 foreach ($backupable_plus_db as $type => $entity_info) {
167 if (!isset($elements[$type]) || (isset($entity_info['restorable']) && !$entity_info['restorable'])) continue;
168 $whatwegot = $backups[$timestamp][$type];
169 if (is_string($whatwegot)) $whatwegot = array($whatwegot);
170 $expected_index = 0;
171 $missing = '';
172 ksort($whatwegot);
173 $outof = false;
174 foreach ($whatwegot as $index => $file) {
175 if (preg_match('/\d+of(\d+)\.zip/', $file, $omatch)) {
176 $outof = max($omatch[1], 1);
177 }
178 while ($expected_index < $index) {
179 $missing .= ('' == $missing) ? (1+$expected_index) : ",".(1+$expected_index);
180 $expected_index++;
181 }
182 if (!file_exists($updraft_dir.'/'.$file)) {
183 $err[] = sprintf(__('File not found (you need to upload it): %s', 'updraftplus'), $updraft_dir.'/'.$file);
184 } elseif (filesize($updraft_dir.'/'.$file) == 0) {
185 $err[] = sprintf(__('File was found, but is zero-sized (you need to re-upload it): %s', 'updraftplus'), $file);
186 } else {
187 $itext = (0 == $index) ? '' : $index;
188 if (!empty($backups[$timestamp][$type.$itext.'-size']) && filesize($updraft_dir.'/'.$file) != $backups[$timestamp][$type.$itext.'-size']) {
189 if (empty($warn['doublecompressfixed'])) {
190 $warn[] = sprintf(__('File (%s) was found, but has a different size (%s) from what was expected (%s) - it may be corrupt.', 'updraftplus'), $file, filesize($updraft_dir.'/'.$file), $backups[$timestamp][$type.$itext.'-size']);
191 }
192 }
193 do_action_ref_array("updraftplus_checkzip_$type", array($updraft_dir.'/'.$file, &$mess, &$warn, &$err));
194 }
195 $expected_index++;
196 }
197 do_action_ref_array("updraftplus_checkzip_end_$type", array(&$mess, &$warn, &$err));
198 // Detect missing archives where they are missing from the end of the set
199 if ($outof>0 && $expected_index < $outof) {
200 for ($j = $expected_index; $j<$outof; $j++) {
201 $missing .= ('' == $missing) ? (1+$j) : ",".(1+$j);
202 }
203 }
204 if ('' != $missing) {
205 $warn[] = sprintf(__("This multi-archive backup set appears to have the following archives missing: %s", 'updraftplus'), $missing.' ('.$entity_info['description'].')');
206 }
207 }
208
209 // Check this backup set has a incremental_sets array e.g may have been created before this array was introduced
210 if (isset($backups[$timestamp]['incremental_sets'])) {
211 if (isset($elements['db']) && 1 === count($elements)) {
212 // Don't show the incremental dropdown if the user only selects 'database'
213 } else {
214 $incremental_sets = array_keys($backups[$timestamp]['incremental_sets']);
215 // Check if there are more than one timestamp in the incremental set
216 if (1 < count($incremental_sets)) {
217 $incremental_select_html = '<div class="udp-notice updraft-restore-option"><label>'.__('This backup set contains incremental backups of your files; please select the time you wish to restore your files to', 'updraftplus').': </label>';
218 $incremental_select_html .= '<select name="updraft_incremental_restore_point" id="updraft_incremental_restore_point">';
219 $incremental_sets = array_reverse($incremental_sets);
220 $first_timestamp = $incremental_sets[0];
221
222 foreach ($incremental_sets as $set_timestamp) {
223 $pretty_date = get_date_from_gmt(gmdate('Y-m-d H:i:s', (int) $set_timestamp), 'M d, Y G:i');
224 $esc_pretty_date = esc_attr($pretty_date);
225 $incremental_select_html .= '<option value="'.$set_timestamp.'" '.selected($set_timestamp, $first_timestamp, false).'>'.$esc_pretty_date.'</option>';
226 }
227
228 $incremental_select_html .= '</select>';
229 $incremental_select_html .= '</div>';
230 $info['addui'] = empty($info['addui']) ? $incremental_select_html : $info['addui'].'<br>'.$incremental_select_html;
231 }
232 }
233 }
234
235 if (0 == count($err) && 0 == count($warn)) {
236 $mess_first = __('The backup archive files have been successfully processed.', 'updraftplus').' '.__('Now press Restore to proceed.', 'updraftplus');
237 } elseif (0 == count($err)) {
238 $mess_first = __('The backup archive files have been processed, but with some warnings.', 'updraftplus').' '.__('If all is well, then press Restore to proceed.', 'updraftplus').' '.__('Otherwise, cancel and correct any problems first.', 'updraftplus');
239 } else {
240 $mess_first = __('The backup archive files have been processed, but with some errors.', 'updraftplus').' '.__('You will need to cancel and correct any problems before retrying.', 'updraftplus');
241 }
242
243 if (count($this->_updraftplus_admin->logged) >0) {
244 foreach ($this->_updraftplus_admin->logged as $lwarn) $warn[] = $lwarn;
245 }
246 restore_error_handler();
247
248 // Get the info if it hasn't already come from the DB scan
249 if (!isset($info) || !is_array($info)) $info = array();
250
251 // Not all characters can be json-encoded, and we don't need this potentially-arbitrary user-supplied info.
252 unset($info['label']);
253
254 if (!isset($info['created_by_version']) && !empty($backups[$timestamp]['created_by_version'])) $info['created_by_version'] = $backups[$timestamp]['created_by_version'];
255
256 if (!isset($info['multisite']) && !empty($backups[$timestamp]['is_multisite'])) $info['multisite'] = $backups[$timestamp]['is_multisite'];
257
258 do_action_ref_array('updraftplus_restore_all_downloaded_postscan', array($backups, $timestamp, $elements, &$info, &$mess, &$warn, &$err));
259
260 if (0 == count($err) && 0 == count($warn)) {
261 $mess_first = __('The backup archive files have been successfully processed.', 'updraftplus').' '.__('Now press Restore again to proceed.', 'updraftplus');
262 } elseif (0 == count($err)) {
263 $mess_first = __('The backup archive files have been processed, but with some warnings.', 'updraftplus').' '.__('If all is well, then now press Restore again to proceed.', 'updraftplus').' '.__('Otherwise, cancel and correct any problems first.', 'updraftplus');
264 } else {
265 $mess_first = __('The backup archive files have been processed, but with some errors.', 'updraftplus').' '.__('You will need to cancel and correct any problems before retrying.', 'updraftplus');
266 }
267
268 $warn_result = '';
269 foreach ($warn as $warning) {
270 if (!$warn_result) $warn_result = '<ul id="updraft_restore_warnings">';
271 $warn_result .= '<li>'.$warning.'</li>';
272 }
273 if ($warn_result) $warn_result .= '</ul>';
274
275 return array('m' => '<p>'.$mess_first.'</p>'.implode('<br>', $mess), 'w' => $warn_result, 'e' => implode('<br>', $err), 'i' => json_encode($info));
276 }
277
278 }
279
280 /**
281 * The purpose of this is to detect brokenness caused by extra line feeds in plugins/themes - before it breaks other AJAX operations and leads to support requests
282 *
283 * @return string
284 */
285 public function ping() {
286 return 'pong';
287 }
288
289 /**
290 * This function is called via ajax and will update the autobackup notice dismiss time
291 *
292 * @return array - an empty array
293 */
294 public function dismissautobackup() {
295 UpdraftPlus_Options::update_updraft_option('updraftplus_dismissedautobackup', time() + 84*86400);
296 return array();
297 }
298
299 /**
300 * This function is called via ajax and will update the general notice dismiss time
301 *
302 * @return array - an empty array
303 */
304 public function dismiss_notice() {
305 UpdraftPlus_Options::update_updraft_option('dismissed_general_notices_until', time() + 84*86400);
306 return array();
307 }
308
309 /**
310 * This function is called via ajax and will update the review notice dismiss time
311 *
312 * @param array $data - an array that contains the dismiss notice for time
313 *
314 * @return array - an empty array
315 */
316 public function dismiss_review_notice($data) {
317 if (empty($data['dismiss_forever'])) {
318 UpdraftPlus_Options::update_updraft_option('dismissed_review_notice', time() + 84*86400);
319 } else {
320 UpdraftPlus_Options::update_updraft_option('dismissed_review_notice', 100 * (365.25 * 86400));
321 }
322 return array();
323 }
324
325 /**
326 * This function is called via ajax and will update the season notice dismiss time
327 *
328 * @return array - an empty array
329 */
330 public function dismiss_season() {
331 UpdraftPlus_Options::update_updraft_option('dismissed_season_notices_until', time() + 366*86400);
332 return array();
333 }
334
335 /**
336 * This function is called via ajax and will update the clone php notice dismiss time
337 *
338 * @return array - an empty array
339 */
340 public function dismiss_clone_php_notice() {
341 UpdraftPlus_Options::update_updraft_option('dismissed_clone_php_notices_until', time() + 180 * 86400);
342 return array();
343 }
344
345 /**
346 * Update and set dismiss_phpseclib_notice option name to true
347 *
348 * @return array - an associative array containing a key named 'success' with 1 value which indicates the successful of updating the option
349 */
350 public function dismiss_phpseclib_notice() {
351 UpdraftPlus_Options::update_updraft_option('updraft_dismiss_phpseclib_notice', true);
352 return array('success' => 1);
353 }
354
355 /**
356 * This function is called via ajax and will update the WooCommerce clone notice dismiss time
357 *
358 * @return array - an empty array
359 */
360 public function dismiss_clone_wc_notice() {
361 UpdraftPlus_Options::update_updraft_option('dismissed_clone_wc_notices_until', time() + 90 * 86400);
362 return array();
363 }
364
365 public function set_autobackup_default($params) {
366 $default = empty($params['default']) ? 0 : 1;
367 UpdraftPlus_Options::update_updraft_option('updraft_autobackup_default', $default);
368 return array();
369 }
370
371 public function dismissexpiry() {
372 UpdraftPlus_Options::update_updraft_option('updraftplus_dismissedexpiry', time() + 14*86400);
373 return array();
374 }
375
376 public function dismissdashnotice() {
377 UpdraftPlus_Options::update_updraft_option('updraftplus_dismisseddashnotice', time() + 366*86400);
378 return array();
379 }
380
381 public function rawbackuphistory() {
382 // This is used for iframe source; hence, returns a string
383 $show_raw_data = $this->_updraftplus_admin->show_raw_backups();
384 return $show_raw_data['html'];
385 }
386
387 /**
388 * N.B. Not exactly the same as the phpinfo method in the UpdraftCentral core class
389 * Returns a string, as it is directly fetched as the source of an iframe
390 *
391 * @return String - returns the resulting HTML
392 */
393 public function phpinfo() {
394
395 ob_start();
396
397 if (function_exists('phpinfo')) phpinfo(INFO_ALL ^ (INFO_CREDITS | INFO_LICENSE));
398
399 echo '<h3 id="ud-debuginfo-constants">'.__('Constants', 'updraftplus').'</h3>';
400 $opts = @get_defined_constants();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
401 ksort($opts);
402 echo '<table><thead></thead><tbody>';
403 foreach ($opts as $key => $opt) {
404 // Administrators can already read these in other ways, but we err on the side of caution
405 if (is_string($opt) && false !== stripos($opt, 'api_key')) $opt = '***';
406 echo '<tr><td>'.htmlspecialchars($key).'</td><td>'.htmlspecialchars(print_r($opt, true)).'</td>';
407 }
408 echo '</tbody></table>';
409
410 $ret = ob_get_contents();
411 ob_end_clean();
412
413 return $ret;
414
415 }
416
417 /**
418 * Return messages if there are more than 4 overdue cron jobs
419 *
420 * @return Array - the messages are stored in an associative array and are indexed with key 'm'
421 */
422 public function check_overdue_crons() {
423 $messages = array();
424 $how_many_overdue = $this->_updraftplus_admin->howmany_overdue_crons();
425 if ($how_many_overdue >= 4) {
426 $messages['m'] = array();
427 $messages['m'][] = $this->_updraftplus_admin->show_admin_warning_overdue_crons($how_many_overdue);
428 if (defined('DISABLE_WP_CRON') && DISABLE_WP_CRON && (!defined('UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE') || !UPDRAFTPLUS_DISABLE_WP_CRON_NOTICE)) $messages['m'][] = $this->_updraftplus_admin->show_admin_warning_disabledcron();
429 }
430 return $messages;
431 }
432
433 public function whichdownloadsneeded($params) {
434 // The purpose of this is to look at the list of indicated downloads, and indicate which are not already fully downloaded. i.e. Which need further action.
435 $send_back = array();
436 $backup = UpdraftPlus_Backup_History::get_history($params['timestamp']);
437 $updraft_dir = $this->_updraftplus->backups_dir_location();
438 $backupable_entities = $this->_updraftplus->get_backupable_file_entities();
439
440 if (empty($backup)) return array('result' => 'asyouwere');
441
442 if (isset($params['updraftplus_clone']) && empty($params['downloads'])) {
443 $entities = array('db', 'plugins', 'themes', 'uploads', 'others');
444 foreach ($entities as $entity) {
445
446 foreach ($backup as $key => $data) {
447 if ($key != $entity) continue;
448
449 $set_contents = '';
450 $entity_array = array();
451 $entity_array[] = $key;
452
453 if ('db' == $key) {
454 $set_contents = "0";
455 } else {
456 foreach (array_keys($data) as $findex) {
457 $set_contents .= ('' == $set_contents) ? $findex : ",$findex";
458 }
459 }
460
461 $entity_array[] = $set_contents;
462 $params['downloads'][] = $entity_array;
463 }
464 }
465 }
466
467 foreach ($params['downloads'] as $i => $download) {
468 if (is_array($download) && 2 == count($download) && isset($download[0]) && isset($download[1])) {
469 $entity = $download[0];
470 if (('db' == $entity || isset($backupable_entities[$entity])) && isset($backup[$entity])) {
471 $indexes = explode(',', $download[1]);
472 $retain_string = '';
473 foreach ($indexes as $index) {
474 $retain = true; // default
475 $findex = (0 == $index) ? '' : (string) $index;
476 $files = $backup[$entity];
477 if (!is_array($files)) $files = array($files);
478 $size_key = $entity.$findex.'-size';
479 if (isset($files[$index]) && isset($backup[$size_key])) {
480 $file = $updraft_dir.'/'.$files[$index];
481 if (file_exists($file) && filesize($file) >= $backup[$size_key]) {
482 $retain = false;
483 }
484 }
485 if ($retain) {
486 $retain_string .= ('' === $retain_string) ? $index : ','.$index;
487 $send_back[$i][0] = $entity;
488 $send_back[$i][1] = $retain_string;
489 }
490 }
491 } else {
492 $send_back[$i][0] = $entity;
493 $send_back[$i][1] = $download[$i][1];
494 }
495 } else {
496 // Format not understood. Just send it back as-is.
497 $send_back[$i] = $download[$i];
498 }
499 }
500 // Finally, renumber the keys (to usual PHP style - 0, 1, ...). Otherwise, in order to preserve the indexes, json_encode() will create an object instead of an array in the case where $send_back only has one element (and is indexed with an index > 0)
501 $send_back = array_values($send_back);
502 return array('downloads' => $send_back);
503 }
504
505 /**
506 * This is an handler function that checks what entity has been specified in the $params and calls the required method
507 *
508 * @param [array] $params this is an array of parameters sent via ajax it can include various things depending on what has called this method, this method only cares about the entity parameter which is used to call the correct method and return tree nodes based on that
509 * @return [array] returns an array of jstree nodes
510 */
511 public function get_jstree_directory_nodes($params) {
512
513 if ('filebrowser' == $params['entity']) {
514 $node_array = $this->_updraft_jstree_directory($params);
515 } elseif ('zipbrowser' == $params['entity']) {
516 $node_array = $this->_updraft_jstree_zip($params);
517 } else {
518 $node_array = apply_filters('updraftplus_jstree_'.$params['entity'], array(), $params);
519 }
520 return empty($node_array['error']) ? array('nodes' => $node_array) : $node_array;
521 }
522
523 /**
524 * This creates an array of nodes, built from either ABSPATH or the given directory ready to be returned to the jstree object.
525 *
526 * @param [array] $params this is an array of parameters sent via ajax it can include the following:
527 * node - this is a jstree node object containing information about the selected node
528 * path - this is a path if provided this will be used to build the tree otherwise ABSPATH is used
529 * drop_directory - this is a boolean that if set to true will drop one directory level off the path this is used so that you can move above the current root directory
530 * @return [array] returns an array of jstree nodes
531 */
532 private function _updraft_jstree_directory($params) {
533 $node_array = array();
534
535 // # is the root node if it's the root node then this is the first call so create a parent node otherwise it's a child node and we should get the path from the node id
536 if ('#' == $params['node']['id']) {
537 $path = ABSPATH;
538
539 if (!empty($params['path']) && is_dir($params['path']) && is_readable($params['path'])) $path = $params['path'];
540 $one_dir_up = dirname($path);
541
542 if (!empty($params['drop_directory']) && true == $params['drop_directory'] && is_readable($one_dir_up)) $path = $one_dir_up;
543 if (empty($params['skip_root_node'])) {
544 $node_array[] = array(
545 'text' => basename($path),
546 'children' => true,
547 'id' => $path,
548 'icon' => 'jstree-folder',
549 'state' => array(
550 'opened' => true
551 )
552 );
553 }
554 } else {
555 $path = $params['node']['id'];
556 }
557
558 $page = empty($params['page']) ? '' : $params['page'];
559
560 if ($dh = opendir($path)) {
561 $path = rtrim($path, DIRECTORY_SEPARATOR);
562
563 $skip_paths = array(".", "..");
564
565 while (($value = readdir($dh)) !== false) {
566 if (!in_array($value, $skip_paths)) {
567 if (is_dir($path . DIRECTORY_SEPARATOR . $value)) {
568 $node_array[] = array(
569 'text' => $value,
570 'children' => true,
571 'id' => UpdraftPlus_Manipulation_Functions::wp_normalize_path($path . DIRECTORY_SEPARATOR . $value),
572 'icon' => 'jstree-folder'
573 );
574 } elseif (empty($params['directories_only']) && 'restore' != $page && is_file($path . DIRECTORY_SEPARATOR . $value)) {
575 $node_array[] = array(
576 'text' => $value,
577 'children' => false,
578 'id' => UpdraftPlus_Manipulation_Functions::wp_normalize_path($path . DIRECTORY_SEPARATOR . $value),
579 'type' => 'file',
580 'icon' => 'jstree-file'
581 );
582 }
583 }
584 }
585 } else {
586 $node_array['error'] = sprintf(__('Failed to open directory: %s.', 'updraftplus'), $path).' '.__('This is normally caused by file permissions.', 'updraftplus');
587 }
588
589 return $node_array;
590 }
591
592 /**
593 * This creates an array of nodes, built from a unzipped zip file structure.
594 *
595 * @param [array] $params this is an array of parameters sent via ajax it can include the following:
596 * node - this is a jstree node object containing information about the selected node
597 * timestamp - this is the backup timestamp and is used to get the backup archive
598 * type - this is the type of backup and is used to get the backup archive
599 * findex - this is the index used to get the correct backup archive if theres more than one of a single archive type
600 * @return [array] returns an array of jstree nodes
601 */
602 private function _updraft_jstree_zip($params) {
603
604 $updraftplus = $this->_updraftplus;
605
606 $node_array = array();
607
608 $zip_object = $updraftplus->get_zip_object_name();
609
610 // Retrieve the information from our backup history
611 $backup_history = UpdraftPlus_Backup_History::get_history();
612
613 if (!isset($backup_history[$params['timestamp']][$params['type']])) {
614 return array('error' => __('Backup set not found', 'updraftplus'));
615 }
616
617 // Base name
618 $file = $backup_history[$params['timestamp']][$params['type']];
619
620 // Get date in human readable form
621 $pretty_date = get_date_from_gmt(gmdate('Y-m-d H:i:s', (int) $params['timestamp']), 'M d, Y G:i');
622
623 $backupable_entities = $updraftplus->get_backupable_file_entities(true, true);
624
625 // Check the file type and set the name in a more friendly way
626 $archive_name = isset($backupable_entities[$params['type']]['description']) ? $backupable_entities[$params['type']]['description'] : $params['type'];
627
628 if (substr($params['type'], 0, 2) === 'db') $archive_name = __('Extra database', 'updraftplus') . ' ' . substr($params['type'], 3, 1);
629 if ('db' == $params['type']) $archive_name = __('Database', 'updraftplus');
630 if ('more' == $params['type']) $archive_name = $backupable_entities[$params['type']]['shortdescription'];
631 if ('wpcore' == $params['type']) $archive_name = __('WordPress Core', 'updraftplus');
632
633 $archive_set = ($params['findex'] + 1) . '/' . sizeof($file);
634
635 if ('1/1' == $archive_set) $archive_set = '';
636
637 $parent_name = $archive_name . ' ' . __('archive', 'updraftplus') . ' ' . $archive_set . ' ' . $pretty_date;
638
639 // Deal with multi-archive sets
640 if (is_array($file)) $file = $file[$params['findex']];
641
642 // Where it should end up being downloaded to
643 $fullpath = $updraftplus->backups_dir_location().'/'.$file;
644
645 if (file_exists($fullpath) && is_readable($fullpath) && filesize($fullpath)>0) {
646
647 $node_array[] = array(
648 'text' => $parent_name,
649 'parent' => '#',
650 'id' => $parent_name,
651 'icon' => 'jstree-folder',
652 'state' => array('opened' => true),
653 'li_attr' => array('path' => $parent_name)
654 );
655
656 $zip = new $zip_object;
657
658 $zip_opened = $zip->open($fullpath);
659
660 if (true !== $zip_opened) {
661 return array('error' => 'UpdraftPlus: opening zip (' . $fullpath . '): failed to open this zip file (object='.$zip_object.', code: '.$zip_opened.')');
662 } else {
663
664 $numfiles = $zip->numFiles;
665
666 if (false === $numfiles) return array('error' => 'UpdraftPlus: reading zip: '.$zip->last_error);
667
668 for ($i=0; $i < $numfiles; $i++) {
669 $si = $zip->statIndex($i);
670
671 // Fix for windows being unable to build jstree due to different directory separators being used
672 $si['name'] = str_replace("/", DIRECTORY_SEPARATOR, $si['name']);
673
674 // if it's a dot then we don't want to append this as it will break the ids and the tree structure
675 if ('.' == dirname($si['name'])) {
676 $node_id = $parent_name;
677 } else {
678 $node_id = $parent_name . DIRECTORY_SEPARATOR . dirname($si['name']) . DIRECTORY_SEPARATOR;
679 }
680
681 $extension = substr(strrchr($si['name'], "."), 1);
682
683 if (0 == $si['size'] && empty($extension)) {
684 $node_array[] = array(
685 'text' => basename($si['name']),
686 'parent' => $node_id,
687 'id' => $parent_name . DIRECTORY_SEPARATOR . $si['name'],
688 'icon' => 'jstree-folder',
689 'li_attr' => array(
690 'path' => $parent_name . DIRECTORY_SEPARATOR . $si['name']
691 )
692 );
693 } else {
694 $node_array[] = array(
695 'text' => basename($si['name']),
696 'parent' => $node_id,
697 'id' => $parent_name . DIRECTORY_SEPARATOR . $si['name'],
698 'type' => 'file',
699 'icon' => 'jstree-file',
700 'li_attr' => array(
701 'path' => $parent_name . DIRECTORY_SEPARATOR . $si['name'],
702 'size' => UpdraftPlus_Manipulation_Functions::convert_numeric_size_to_text($si['size'])
703 )
704 );
705 }
706 }
707
708 // check if this is an upload archive if it is add a 'uploads' folder so that the children can attach to it
709 if ('uploads' == $params['type']) $node_array[] = array(
710 'text' => 'uploads',
711 'parent' => $parent_name,
712 'id' => $parent_name . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR,
713 'icon' => 'jstree-folder',
714 'li_attr' => array(
715 'path' => $parent_name . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR
716 )
717 );
718
719 @$zip->close();// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the method.
720 }
721 }
722
723 return $node_array;
724 }
725
726 /**
727 * Return information on the zipfile download
728 *
729 * @param Array $params - details on the download; keys: type, findex, path, timestamp
730 *
731 * @return Array
732 */
733 public function get_zipfile_download($params) {
734 return apply_filters('updraftplus_command_get_zipfile_download', array('error' => 'UpdraftPlus: command (get_zipfile_download) not installed (are you missing an add-on?)'), $params);
735 }
736
737 /**
738 * Dismiss the notice which will if .htaccess have any old migrated site reference.
739 *
740 * @return Boolean Return true if migration notice is dismissed
741 */
742 public function dismiss_migration_notice_for_old_site_reference() {
743 delete_site_option('updraftplus_migrated_site_domain');
744 return true;
745 }
746
747 /**
748 * When character set and collate both are unsupported at restoration time and if user change anyone substitution dropdown from both, Other substitution select box value should be change respectively. To achieve this functionality, Ajax calls comes here.
749 *
750 * @param Array $params this is an array of parameters sent via ajax it can include the following:
751 * collate_change_on_charset_selection_data - It is data in serialize form which is need for choose other dropdown option value. It contains below elements data:
752 * db_supported_collations - All collations supported by current database. This is result of 'SHOW COLLATION' query
753 * db_unsupported_collate_unique - Unsupported collates unique array
754 * db_collates_found - All collates found in database backup file
755 * event_source_elem - Dropdown elemtn id which trigger the ajax request
756 * updraft_restorer_charset - Charset dropdown selected value option
757 * updraft_restorer_collate - Collate dropdown selected value option
758 *
759 * @return array - $action_data which contains following data:
760 * is_action_required - 1 or 0 Whether or not change other dropdown value
761 * elem_id - Dropdown element id which value need to change. The other dropdown element id
762 * elem_val - Dropdown element value which should be selected for other drodown
763 */
764 public function collate_change_on_charset_selection($params) {
765 $collate_change_on_charset_selection_data = json_decode(UpdraftPlus_Manipulation_Functions::wp_unslash($params['collate_change_on_charset_selection_data']), true);
766 $updraft_restorer_collate = $params['updraft_restorer_collate'];
767 $updraft_restorer_charset = $params['updraft_restorer_charset'];
768
769 $db_supported_collations = $collate_change_on_charset_selection_data['db_supported_collations'];
770 $db_unsupported_collate_unique = $collate_change_on_charset_selection_data['db_unsupported_collate_unique'];
771 $db_collates_found = $collate_change_on_charset_selection_data['db_collates_found'];
772
773 $action_data = array(
774 'is_action_required' => 0,
775 );
776 // No need to change other dropdown value
777 if (isset($db_supported_collations[$updraft_restorer_collate]->Charset) && $updraft_restorer_charset == $db_supported_collations[$updraft_restorer_collate]->Charset) {
778 return $action_data;
779 }
780 $similar_type_collate = $this->_updraftplus->get_similar_collate_related_to_charset($db_supported_collations, $db_unsupported_collate_unique, $updraft_restorer_charset);
781 if (empty($similar_type_collate)) {
782 $similar_type_collate = $this->_updraftplus->get_similar_collate_based_on_ocuurence_count($db_collates_found, $db_supported_collations, $updraft_restorer_collate);
783 }
784 // Default collation for changed character set
785 if (empty($similar_type_collate)) {
786 $charset_row = $GLOBALS['wpdb']->get_row($GLOBALS['wpdb']->prepare("SHOW CHARACTER SET LIKE '%s'", $updraft_restorer_charset));
787 if (null !== $charset_row && !empty($charset_row->{'Default collation'})) {
788 $similar_type_collate = $charset_row->{'Default collation'};
789 }
790 }
791 if (empty($similar_type_collate)) {
792 foreach ($db_supported_collations as $db_supported_collation => $db_supported_collation_info) {
793 if (isset($db_supported_collation_info->Charset) && $updraft_restorer_charset == $db_supported_collation_info->Charset) {
794 $similar_type_collate = $db_supported_collation;
795 break;
796 }
797 }
798 }
799 if (!empty($similar_type_collate)) {
800 $action_data['is_action_required'] = 1;
801 $action_data['similar_type_collate'] = $similar_type_collate;
802 }
803 return $action_data;
804 }
805
806 /**
807 * Set the Tour status
808 *
809 * @param array $params - the $_REQUEST. We're looking for 'current_step'
810 * @return bool
811 */
812 public function set_tour_status($params) {
813 return class_exists('UpdraftPlus_Tour') ? UpdraftPlus_Tour::get_instance()->set_tour_status($params) : false;
814 }
815
816 /**
817 * Resets the tour status
818 *
819 * @return bool
820 */
821 public function reset_tour_status() {
822 return class_exists('UpdraftPlus_Tour') ? UpdraftPlus_Tour::get_instance()->reset_tour_status() : false;
823 }
824
825 /**
826 * Return the database information
827 *
828 * @return array
829 */
830 public function db_size() {
831 global $wpdb;
832
833 $db_table_res = $wpdb->get_results('SHOW TABLE STATUS', ARRAY_A);
834 $db_table_size = 0;
835 $db_table_html = '';
836
837 if ($wpdb->num_rows > 0) {
838 $key_field_name = UpdraftPlus_Manipulation_Functions::backquote('Key');
839
840 foreach ($db_table_res as $row) {
841 // Try search from transient
842 $rows_count = get_transient('wpo_'.$row['Name'].'_count');
843 if (false === $rows_count) {
844 // If not found, try search primary key first
845 $table_name = UpdraftPlus_Manipulation_Functions::backquote($row['Name']);
846 $primary_key = $wpdb->get_row("SHOW COLUMNS FROM $table_name WHERE $key_field_name = 'PRI'", ARRAY_A);
847
848 if ($primary_key) {
849 // Count rows by primary key
850 $primary_key_field = UpdraftPlus_Manipulation_Functions::backquote($primary_key['Field']);
851 $rows_count = $wpdb->get_var("SELECT COUNT($primary_key_field) FROM ".$table_name);
852 }
853
854 if (is_null($rows_count) || false === $rows_count) $rows_count = $wpdb->get_var("SELECT COUNT(*) FROM ".$table_name);
855 }
856
857 $db_table_html .= '<tr>';
858 $db_table_html .= sprintf('<td>%s</td>', esc_html($row['Name']));
859 $db_table_html .= sprintf('<td>%s</td>', esc_html($rows_count));
860 $db_table_html .= sprintf('<td>%s</td>', esc_html(size_format($row['Data_length'], 2)));
861 $db_table_html .= sprintf('<td>%s</td>', esc_html(size_format($row['Index_length'], 2)));
862 $db_table_html .= sprintf('<td>%s</td>', esc_html($row['Engine']));
863 $db_table_html .= '</tr>';
864
865 $db_table_size += $row['Data_length'] + $row['Index_length'];
866 }
867 }
868
869 return array(
870 'size' => size_format((int) $db_table_size, 2),
871 'html' => $db_table_html
872 );
873 }
874 }
875