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

core.php in UpdraftPlus: WP Backup & Migration Plugin 1.16.5, at central/modules/core.php

423 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('UPDRAFTCENTRAL_CLIENT_DIR')) die('No access.');
4
5 /**
6 * - A container for RPC commands (core UpdraftCentral commands). Commands map exactly onto method names (and hence this class should not implement anything else, beyond the constructor, and private methods)
7 * - Return format is array('response' => (string - a code), 'data' => (mixed));
8 *
9 * RPC commands are not allowed to begin with an underscore. So, any private methods can be prefixed with an underscore.
10 */
11 class UpdraftCentral_Core_Commands extends UpdraftCentral_Commands {
12
13 /**
14 * Executes a list of submitted commands (multiplexer)
15 *
16 * @param Array $query An array containing the commands to execute and a flag to indicate how to handle command execution failure.
17 * @return Array An array containing the results of the process.
18 */
19 public function execute_commands($query) {
20
21 try {
22
23 $commands = $query['commands'];
24 $command_results = array();
25 $error_count = 0;
26
27 /**
28 * Should be one of the following options:
29 * 1 = Abort on first failure
30 * 2 = Abort if any command fails
31 * 3 = Abort if all command fails (default)
32 */
33 $error_flag = isset($query['error_flag']) ? (int) $query['error_flag'] : 3;
34
35
36 foreach ($commands as $command => $params) {
37 $command_info = apply_filters('updraftcentral_get_command_info', false, $command);
38 if (!$command_info) {
39 list($_prefix, $_command) = explode('.', $command);
40 $command_results[$_prefix][$_command] = array('response' => 'rpcerror', 'data' => array('code' => 'unknown_rpc_command', 'data' => $command));
41
42 $error_count++;
43 if (1 === $error_flag) break;
44 } else {
45
46 $class_prefix = $command_info['class_prefix'];
47 $action = $command_info['command'];
48 $command_php_class = $command_info['command_php_class'];
49
50 // Instantiate the command class and execute the needed action
51 if (class_exists($command_php_class)) {
52 $instance = new $command_php_class($this->rc);
53
54 if (method_exists($instance, $action)) {
55 $params = empty($params) ? array() : $params;
56 $call_result = call_user_func_array(array($instance, $action), $params);
57
58 $command_results[$command] = $call_result;
59 if ('rpcerror' === $call_result['response'] || (isset($call_result['data']['error']) && $call_result['data']['error'])) {
60 $error_count++;
61 if (1 === $error_flag) break;
62 }
63 }
64 }
65 }
66 }
67
68 if (0 !== $error_count) {
69 // N.B. These error messages should be defined in UpdraftCentral's translation file (dashboard-translations.php)
70 // before actually using this multiplexer function.
71 $message = 'general_command_execution_error';
72
73 switch ($error_flag) {
74 case 1:
75 $message = 'command_execution_aborted';
76 break;
77 case 2:
78 $message = 'failed_to_execute_some_commands';
79 break;
80 case 3:
81 if (count($commands) === $error_count) {
82 $message = 'failed_to_execute_all_commands';
83 }
84 break;
85 default:
86 break;
87 }
88
89 $result = array('error' => true, 'message' => $message, 'values' => $command_results);
90 } else {
91 $result = $command_results;
92 }
93
94 } catch (Exception $e) {
95 $result = array('error' => true, 'message' => $e->getMessage());
96 }
97
98 return $this->_response($result);
99 }
100
101 /**
102 * Validates the credentials entered by the user
103 *
104 * @param array $creds an array of filesystem credentials
105 * @return array An array containing the result of the validation process.
106 */
107 public function validate_credentials($creds) {
108
109 try {
110
111 $entity = $creds['entity'];
112 if (isset($creds['filesystem_credentials'])) {
113 parse_str($creds['filesystem_credentials'], $filesystem_credentials);
114 if (is_array($filesystem_credentials)) {
115 foreach ($filesystem_credentials as $key => $value) {
116 // Put them into $_POST, which is where request_filesystem_credentials() checks for them.
117 $_POST[$key] = $value;
118 }
119 }
120 }
121
122 // Include the needed WP Core file(s)
123 // template.php needed for submit_button() which is called by request_filesystem_credentials()
124 $this->_admin_include('file.php', 'template.php');
125
126 // Directory entities that we currently need permissions
127 // to update.
128 $entity_directories = array(
129 'plugins' => WP_PLUGIN_DIR,
130 'themes' => WP_CONTENT_DIR.'/themes',
131 'core' => untrailingslashit(ABSPATH)
132 );
133
134 $url = wp_nonce_url(site_url());
135 $directory = $entity_directories[$entity];
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 $result = array('error' => true, 'message' => 'failed_credentials', 'values' => array());
147 } else {
148 $wp_filesystem->delete($path);
149 $result = array('error' => false, 'message' => 'credentials_ok', 'values' => array());
150 }
151
152 } else {
153 $result = array('error' => true, 'message' => 'failed_credentials', 'values' => array());
154 }
155
156 } catch (Exception $e) {
157 $result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
158 }
159
160 return $this->_response($result);
161 }
162
163 /**
164 * Gets the FileSystem Credentials
165 *
166 * Extract the needed filesystem credentials (permissions) to be used
167 * to update/upgrade the plugins, themes and the WP core.
168 *
169 * @return array $result - An array containing the creds form and some flags
170 * to determine whether we need to extract the creds
171 * manually from the user.
172 */
173 public function get_credentials() {
174
175 try {
176
177 // Check whether user has enough permission to update entities
178 if (!current_user_can('update_plugins') && !current_user_can('update_themes') && !current_user_can('update_core')) return $this->_generic_error_response('updates_permission_denied');
179
180 // Include the needed WP Core file(s)
181 $this->_admin_include('file.php', 'template.php');
182
183 // A container that will hold the state (in this case, either true or false) of
184 // each directory entities (plugins, themes, core) that will be used to determine
185 // whether or not there's a need to show a form that will ask the user for their credentials
186 // manually.
187 $request_filesystem_credentials = array();
188
189 // A container for the filesystem credentials form if applicable.
190 $filesystem_form = '';
191
192 // Directory entities that we currently need permissions
193 // to update.
194 $check_fs = array(
195 'plugins' => WP_PLUGIN_DIR,
196 'themes' => WP_CONTENT_DIR.'/themes',
197 'core' => untrailingslashit(ABSPATH)
198 );
199
200 // Here, we're looping through each entities and find output whether
201 // we have sufficient permissions to update objects belonging to them.
202 foreach ($check_fs as $entity => $dir) {
203
204 // We're determining which method to use when updating
205 // the files in the filesystem.
206 $filesystem_method = get_filesystem_method(array(), $dir);
207
208 // Buffering the output to pull the actual credentials form
209 // currently being used by this WP instance if no sufficient permissions
210 // is found.
211 $url = wp_nonce_url(site_url());
212
213 ob_start();
214 $filesystem_credentials_are_stored = request_filesystem_credentials($url, $filesystem_method);
215 $form = strip_tags(ob_get_contents(), '<div><h2><p><input><label><fieldset><legend><span><em>');
216
217 if (!empty($form)) {
218 $filesystem_form = $form;
219 }
220 ob_end_clean();
221
222 // Save the state whether or not there's a need to show the
223 // credentials form to the user.
224 $request_filesystem_credentials[$entity] = ('direct' !== $filesystem_method && !$filesystem_credentials_are_stored);
225 }
226
227 // Wrapping the credentials info before passing it back
228 // to the client issuing the request.
229 $result = array(
230 'request_filesystem_credentials' => $request_filesystem_credentials,
231 'filesystem_form' => $filesystem_form
232 );
233
234 } catch (Exception $e) {
235 $result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
236 }
237
238 return $this->_response($result);
239 }
240
241 /**
242 * Fetches a browser-usable URL which will automatically log the user in to the site
243 *
244 * @param String $redirect_to - the URL to got to after logging in
245 * @param Array $extra_info - valid keys are user_id, which should be a numeric user ID to log in as.
246 */
247 public function get_login_url($redirect_to, $extra_info) {
248 if (is_array($extra_info) && !empty($extra_info['user_id']) && is_numeric($extra_info['user_id'])) {
249
250 $user_id = $extra_info['user_id'];
251
252 if (false == ($login_key = $this->_get_autologin_key($user_id))) return $this->_generic_error_response('user_key_failure');
253
254 // Default value
255 $redirect_url = network_admin_url();
256 if (is_array($redirect_to) && !empty($redirect_to['module'])) {
257 switch ($redirect_to['module']) {
258 case 'updraftplus':
259 if ('initiate_restore' == $redirect_to['action'] && class_exists('UpdraftPlus_Options')) {
260 $redirect_url = UpdraftPlus_Options::admin_page_url().'?page=updraftplus&udaction=initiate_restore&entities='.urlencode($redirect_to['data']['entities']).'&showdata='.urlencode($redirect_to['data']['showdata']).'&backup_timestamp='.(int) $redirect_to['data']['backup_timestamp'];
261 } elseif ('download_file' == $redirect_to['action']) {
262 $findex = empty($redirect_to['data']['findex']) ? 0 : (int) $redirect_to['data']['findex'];
263 // e.g. ?udcentral_action=dl&action=updraftplus_spool_file&backup_timestamp=1455101696&findex=0&what=plugins
264 $redirect_url = site_url().'?udcentral_action=spool_file&action=updraftplus_spool_file&findex='.$findex.'&what='.urlencode($redirect_to['data']['what']).'&backup_timestamp='.(int) $redirect_to['data']['backup_timestamp'];
265 }
266 break;
267 case 'direct_url':
268 $redirect_url = $redirect_to['url'];
269 break;
270 }
271 }
272
273 $login_key = apply_filters('updraftplus_remotecontrol_login_key', array(
274 'key' => $login_key,
275 'created' => time(),
276 'redirect_url' => $redirect_url
277 ), $redirect_to, $extra_info);
278
279 // Over-write any previous value - only one can be valid at a time)
280 update_user_meta($user_id, 'updraftcentral_login_key', $login_key);
281
282 return $this->_response(array(
283 'login_url' => network_site_url('?udcentral_action=login&login_id='.$user_id.'&login_key='.$login_key['key'])
284 ));
285
286 } else {
287 return $this->_generic_error_response('user_unknown');
288 }
289 }
290
291 /**
292 * Get information derived from phpinfo()
293 *
294 * @return Array
295 */
296 public function phpinfo() {
297 $phpinfo = $this->_get_phpinfo_array();
298
299 if (!empty($phpinfo)) {
300 return $this->_response($phpinfo);
301 }
302
303 return $this->_generic_error_response('phpinfo_fail');
304 }
305
306 /**
307 * The key obtained is only intended to be short-lived. Hence, there's no intention other than that it is random and only used once - only the most recent one is valid.
308 *
309 * @param Integer $user_id Specific user ID to get the autologin key
310 * @return Array
311 */
312 public function _get_autologin_key($user_id) {
313 $secure_auth_key = defined('SECURE_AUTH_KEY') ? SECURE_AUTH_KEY : hash('sha256', DB_PASSWORD).'_'.rand(0, 999999999);
314 if (!defined('SECURE_AUTH_KEY')) return false;
315 $hash_it = $user_id.'_'.microtime(true).'_'.rand(0, 999999999).'_'.$secure_auth_key;
316 $hash = hash('sha256', $hash_it);
317 return $hash;
318 }
319
320 public function site_info() {
321
322 global $wpdb;
323 @include(ABSPATH.WPINC.'/version.php');
324
325 $ud_version = is_a($this->ud, 'UpdraftPlus') ? $this->ud->version : 'none';
326
327 return $this->_response(array(
328 'versions' => array(
329 'ud' => $ud_version,
330 'php' => PHP_VERSION,
331 'wp' => $wp_version,
332 'mysql' => $wpdb->db_version(),
333 'udrpc_php' => $this->rc->udrpc_version,
334 ),
335 'bloginfo' => array(
336 'url' => network_site_url(),
337 'name' => get_bloginfo('name'),
338 )
339 ));
340 }
341
342 /**
343 * This calls the WP_Action within WP
344 *
345 * @param array $data Array of Data to be used within call_wp_action
346 * @return array
347 */
348 public function call_wordpress_action($data) {
349 if (false === ($updraftplus_admin = $this->_load_ud_admin())) return $this->_generic_error_response('no_updraftplus');
350
351 $response = $updraftplus_admin->call_wp_action($data);
352
353 if (empty($data["wpaction"])) {
354 return $this->_generic_error_response("error", "no command sent");
355 }
356
357 return $this->_response(array(
358 "response" => $response['response'],
359 "status" => $response['status'],
360 "log" => $response['log']
361 ));
362 }
363
364 /**
365 * Get disk space used
366 *
367 * @uses UpdraftPlus_Filesystem_Functions::get_disk_space_used()
368 *
369 * @param String $entity - the entity to count (e.g. 'plugins', 'themes')
370 *
371 * @return Array - response
372 */
373 public function count($entity) {
374
375 if (!class_exists('UpdraftPlus_Filesystem_Functions')) return $this->_generic_error_response('no_updraftplus');
376
377 $response = UpdraftPlus_Filesystem_Functions::get_disk_space_used($entity);
378
379 return $this->_response($response);
380 }
381
382 /**
383 * https://secure.php.net/phpinfo
384 *
385 * @return null|array
386 */
387 private function _get_phpinfo_array() {
388 ob_start();
389 phpinfo(INFO_GENERAL|INFO_CREDITS|INFO_MODULES);
390 $phpinfo = array('phpinfo' => array());
391
392 if (preg_match_all('#(?:<h2>(?:<a name=".*?">)?(.*?)(?:</a>)?</h2>)|(?:<tr(?: class=".*?")?><t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>(?:<t[hd](?: class=".*?")?>(.*?)\s*</t[hd]>)?)?</tr>)#s', ob_get_clean(), $matches, PREG_SET_ORDER)) {
393 foreach ($matches as $match) {
394 if (strlen($match[1])) {
395 $phpinfo[$match[1]] = array();
396 } elseif (isset($match[3])) {
397 $keys1 = array_keys($phpinfo);
398 $phpinfo[end($keys1)][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3];
399 } else {
400 $keys1 = array_keys($phpinfo);
401 $phpinfo[end($keys1)][] = $match[2];
402
403 }
404
405 }
406 return $phpinfo;
407 }
408 return false;
409 }
410
411 /**
412 * Return an UpdraftPlus_Admin object
413 *
414 * @return UpdraftPlus_Admin|Boolean - false in case of failure
415 */
416 private function _load_ud_admin() {
417 if (!defined('UPDRAFTPLUS_DIR') || !is_file(UPDRAFTPLUS_DIR.'/admin.php')) return false;
418 include_once(UPDRAFTPLUS_DIR.'/admin.php');
419 global $updraftplus_admin;
420 return $updraftplus_admin;
421 }
422 }
423