PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / team-updraft / lib-central / central / modules / core.php

core.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at vendor/team-updraft/lib-central/central/modules/core.php

509 lines 17.1 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 * Retrieve site icon (favicon)
15 *
16 * @return array An array containing the site icon (favicon) byte string if available
17 */
18 public function get_site_icon() {
19
20 if (!function_exists('get_site_icon_url')) {
21 include_once(ABSPATH.'wp-includes/general-template.php');
22 }
23
24 $site_icon_url = get_site_icon_url();
25
26 // If none is set in WordPress, let's try to search for the default favicon
27 // within the site's directory
28 if (empty($site_icon_url)) {
29
30 if (!function_exists('get_site_url')) {
31 include_once(ABSPATH.'wp-includes/link-template.php');
32 }
33
34 // Common favicon locations to check
35 $potential_locations = array(
36 '/favicon.ico',
37 '/favicon.png',
38 '/favicon.svg',
39 '/assets/favicon.ico',
40 '/assets/images/favicon.ico',
41 '/apple-touch-icon.png',
42 '/apple-touch-icon-precomposed.png',
43 );
44
45 foreach ($potential_locations as $location) {
46 $path = rtrim(ABSPATH, '/\\').$location;
47 if (file_exists($path)) {
48 $site_icon_url = get_site_url().$location;
49 break;
50 }
51 }
52 }
53
54 // We are returning the site icon as byte string instead of URL in order to avoid
55 // any hotlink protection that might prevent us to show the icon in UpdraftCentral
56 // dashboard successfully.
57 $site_icon = '';
58 if (!empty($site_icon_url)) {
59 $content = file_get_contents($site_icon_url);
60
61 $mime_type = '';
62 foreach ($http_response_header as $value) {
63 if (false !== stripos($value, 'content-type:')) {
64 list(, $mime_type) = explode(':', preg_replace('/\s+/', '', $value));
65 break;
66 }
67 }
68
69 if ($content && !empty($mime_type)) {
70 $site_icon = 'data: '.$mime_type.';base64,'.base64_encode($content);
71 }
72 }
73
74 return $this->_response(array('site_icon' => $site_icon));
75 }
76
77 /**
78 * Executes a list of submitted commands (multiplexer)
79 *
80 * @param Array $query An array containing the commands to execute and a flag to indicate how to handle command execution failure.
81 * @return Array An array containing the results of the process.
82 */
83 public function execute_commands($query) {
84
85 try {
86
87 $commands = $query['commands'];
88 $command_results = array();
89 $error_count = 0;
90
91 /**
92 * Should be one of the following options:
93 * 1 = Abort on first failure
94 * 2 = Abort if any command fails
95 * 3 = Abort if all command fails (default)
96 */
97 $error_flag = isset($query['error_flag']) ? (int) $query['error_flag'] : 3;
98
99
100 foreach ($commands as $command => $params) {
101 $command_info = apply_filters('updraftcentral_get_command_info', false, $command);
102 if (!$command_info) {
103 list($_prefix, $_command) = explode('.', $command);
104 $command_results[$_prefix][$_command] = array('response' => 'rpcerror', 'data' => array('code' => 'unknown_rpc_command', 'data' => $command));
105
106 $error_count++;
107 if (1 === $error_flag) break;
108 } else {
109
110 $action = $command_info['command'];
111 $command_php_class = $command_info['command_php_class'];
112
113 // Instantiate the command class and execute the needed action
114 if (class_exists($command_php_class)) {
115 $instance = new $command_php_class($this->rc);
116
117 if (method_exists($instance, $action)) {
118 $params = empty($params) ? array() : $params;
119 $call_result = call_user_func(array($instance, $action), $params);
120
121 $command_results[$command] = $call_result;
122 if ('rpcerror' === $call_result['response'] || (isset($call_result['data']['error']) && $call_result['data']['error'])) {
123 $error_count++;
124 if (1 === $error_flag) break;
125 }
126 }
127 }
128 }
129 }
130
131 if (0 !== $error_count) {
132 // N.B. These error messages should be defined in UpdraftCentral's translation file (dashboard-translations.php)
133 // before actually using this multiplexer function.
134 $message = 'general_command_execution_error';
135
136 switch ($error_flag) {
137 case 1:
138 $message = 'command_execution_aborted';
139 break;
140 case 2:
141 $message = 'failed_to_execute_some_commands';
142 break;
143 case 3:
144 if (count($commands) === $error_count) {
145 $message = 'failed_to_execute_all_commands';
146 }
147 break;
148 default:
149 break;
150 }
151
152 $result = array('error' => true, 'message' => $message, 'values' => $command_results);
153 } else {
154 $result = $command_results;
155 }
156
157 } catch (Exception $e) {
158 $result = array('error' => true, 'message' => $e->getMessage());
159 }
160
161 return $this->_response($result);
162 }
163
164 /**
165 * Validates the credentials entered by the user
166 *
167 * @param array $creds an array of filesystem credentials
168 * @return array An array containing the result of the validation process.
169 */
170 public function validate_credentials($creds) {
171
172 try {
173
174 $entity = $creds['entity'];
175 if (isset($creds['filesystem_credentials'])) {
176 parse_str($creds['filesystem_credentials'], $filesystem_credentials);
177 if (is_array($filesystem_credentials)) {
178 foreach ($filesystem_credentials as $key => $value) {
179 // Put them into $_POST, which is where request_filesystem_credentials() checks for them.
180 $_POST[$key] = $value;
181 }
182 }
183 }
184
185 // Include the needed WP Core file(s)
186 // template.php needed for submit_button() which is called by request_filesystem_credentials()
187 $this->_admin_include('file.php', 'template.php');
188
189 // Directory entities that we currently need permissions
190 // to update.
191 $entity_directories = array(
192 'plugins' => WP_PLUGIN_DIR,
193 'themes' => WP_CONTENT_DIR.'/themes',
194 'core' => untrailingslashit(ABSPATH)
195 );
196
197 if ('translations' === $entity) {
198 // 'en_US' don't usually have the "languages" folder, thus, we
199 // check if there's a need to ask for filesystem credentials for that
200 // folder if it exists, most especially for locale other than 'en_US'.
201 $language_dir = WP_CONTENT_DIR.'/languages';
202 if ('en_US' !== get_locale() && is_dir($language_dir)) {
203 $entity_directories['translations'] = $language_dir;
204 }
205 }
206
207 $url = wp_nonce_url(site_url());
208
209 $passed = false;
210 if (isset($entity_directories[$entity])) {
211 $directory = $entity_directories[$entity];
212
213 // Check if credentials are valid and have sufficient
214 // privileges to create and delete (e.g. write)
215 ob_start();
216 $credentials = request_filesystem_credentials($url, '', false, $directory);
217 ob_end_clean();
218
219 // The "WP_Filesystem" will suffice in validating the inputted credentials
220 // from UpdraftCentral, as it is already attempting to connect to the filesystem
221 // using the chosen transport (e.g. ssh, ftp, etc.)
222 $passed = WP_Filesystem($credentials, $directory);
223 }
224
225 if ($passed) {
226 $result = array('error' => false, 'message' => 'credentials_ok', 'values' => array());
227 } else {
228 // We're adding some useful error information to help troubleshooting any problems
229 // that may arise in the future. If the user submitted a wrong password or username
230 // it usually falls through here.
231 global $wp_filesystem;
232
233 $errors = array();
234 if (isset($wp_filesystem->errors) && is_wp_error($wp_filesystem->errors)) {
235 $errors = $wp_filesystem->errors->errors;
236 }
237
238 $result = array('error' => true, 'message' => 'failed_credentials', 'values' => array('errors' => $errors));
239 }
240
241 } catch (Exception $e) {
242 $result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
243 }
244
245 return $this->_response($result);
246 }
247
248 /**
249 * Gets the FileSystem Credentials
250 *
251 * Extract the needed filesystem credentials (permissions) to be used
252 * to update/upgrade the plugins, themes and the WP core.
253 *
254 * @return array $result - An array containing the creds form and some flags
255 * to determine whether we need to extract the creds
256 * manually from the user.
257 */
258 public function get_credentials() {
259
260 try {
261
262 // Check whether user has enough permission to update entities
263 if (!current_user_can('update_plugins') && !current_user_can('update_themes') && !current_user_can('update_core')) return $this->_generic_error_response('updates_permission_denied');
264
265 // Include the needed WP Core file(s)
266 $this->_admin_include('file.php', 'template.php');
267
268 // A container that will hold the state (in this case, either true or false) of
269 // each directory entities (plugins, themes, core) that will be used to determine
270 // whether or not there's a need to show a form that will ask the user for their credentials
271 // manually.
272 $request_filesystem_credentials = array();
273
274 // A container for the filesystem credentials form if applicable.
275 $filesystem_form = '';
276
277 // Directory entities that we currently need permissions
278 // to update.
279 $check_fs = array(
280 'plugins' => WP_PLUGIN_DIR,
281 'themes' => WP_CONTENT_DIR.'/themes',
282 'core' => untrailingslashit(ABSPATH)
283 );
284
285 // Here, we're looping through each entities and find output whether
286 // we have sufficient permissions to update objects belonging to them.
287 foreach ($check_fs as $entity => $dir) {
288
289 // We're determining which method to use when updating
290 // the files in the filesystem.
291 $filesystem_method = get_filesystem_method(array(), $dir);
292
293 // Buffering the output to pull the actual credentials form
294 // currently being used by this WP instance if no sufficient permissions
295 // is found.
296 $url = wp_nonce_url(site_url());
297
298 ob_start();
299 $filesystem_credentials_are_stored = request_filesystem_credentials($url, $filesystem_method);
300 $form = strip_tags(ob_get_contents(), '<div><h2><p><input><label><fieldset><legend><span><em>');
301
302 if (!empty($form)) {
303 $filesystem_form = $form;
304 }
305 ob_end_clean();
306
307 // Save the state whether or not there's a need to show the
308 // credentials form to the user.
309 $request_filesystem_credentials[$entity] = ('direct' !== $filesystem_method && !$filesystem_credentials_are_stored);
310 }
311
312 // Wrapping the credentials info before passing it back
313 // to the client issuing the request.
314 $result = array(
315 'request_filesystem_credentials' => $request_filesystem_credentials,
316 'filesystem_form' => $filesystem_form
317 );
318
319 } catch (Exception $e) {
320 $result = array('error' => true, 'message' => $e->getMessage(), 'values' => array());
321 }
322
323 return $this->_response($result);
324 }
325
326 /**
327 * Fetches a browser-usable URL which will automatically log the user in to the site
328 *
329 * @param String $redirect_to - the URL to got to after logging in
330 * @param Array $extra_info - valid keys are user_id, which should be a numeric user ID to log in as.
331 */
332 public function get_login_url($redirect_to, $extra_info) {
333
334 if (is_array($extra_info) && !empty($extra_info['user_id']) && is_numeric($extra_info['user_id'])) {
335
336 $user_id = $extra_info['user_id'];
337
338 if (false == ($login_key = $this->_get_autologin_key($user_id))) return $this->_generic_error_response('user_key_failure');
339
340 // Default value
341 $redirect_url = network_admin_url();
342 if (is_array($redirect_to) && !empty($redirect_to['module'])) {
343 switch ($redirect_to['module']) {
344 case 'updraftplus':
345 if ('initiate_restore' == $redirect_to['action'] && class_exists('UpdraftPlus_Options')) {
346 $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'];
347
348 } elseif ('download_file' == $redirect_to['action']) {
349 $findex = empty($redirect_to['data']['findex']) ? 0 : (int) $redirect_to['data']['findex'];
350 // e.g. ?udcentral_action=dl&action=updraftplus_spool_file&backup_timestamp=1455101696&findex=0&what=plugins
351 $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'];
352 }
353 break;
354 case 'direct_url':
355 $redirect_url = $redirect_to['url'];
356 break;
357 }
358 }
359
360 $login_key = apply_filters('updraftplus_remotecontrol_login_key', array(
361 'key' => $login_key,
362 'created' => time(),
363 'redirect_url' => $redirect_url
364 ), $redirect_to, $extra_info);
365
366 // Over-write any previous value - only one can be valid at a time)
367 update_user_meta($user_id, 'updraftcentral_login_key', $login_key);
368
369 return $this->_response(array(
370 'login_url' => network_site_url('?udcentral_action=login&login_id='.$user_id.'&login_key='.$login_key['key'])
371 ));
372
373 } else {
374 return $this->_generic_error_response('user_unknown');
375 }
376 }
377
378 /**
379 * Get information derived from phpinfo()
380 *
381 * @return Array
382 */
383 public function phpinfo() {
384 $phpinfo = $this->_get_phpinfo_array();
385
386 if (!empty($phpinfo)) {
387 return $this->_response($phpinfo);
388 }
389
390 return $this->_generic_error_response('phpinfo_fail');
391 }
392
393 /**
394 * 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.
395 *
396 * @param Integer $user_id Specific user ID to get the autologin key
397 * @return Array
398 */
399 public function _get_autologin_key($user_id) {
400 $secure_auth_key = defined('SECURE_AUTH_KEY') ? SECURE_AUTH_KEY : hash('sha256', DB_PASSWORD).'_'.rand(0, 999999999);
401 if (!defined('SECURE_AUTH_KEY')) return false;
402 $hash_it = $user_id.'_'.microtime(true).'_'.rand(0, 999999999).'_'.$secure_auth_key;
403 $hash = hash('sha256', $hash_it);
404 return $hash;
405 }
406
407 public function site_info() {
408 global $wpdb;
409
410 // THis is included so we can get $wp_version
411 @include(ABSPATH.WPINC.'/version.php');// phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged -- Silenced to suppress errors that may arise because of the function.
412
413 $ud_version = is_a($this->ud, 'UpdraftPlus') ? $this->ud->version : 'none';
414
415 return $this->_response(array(
416 'versions' => array(
417 'ud' => $ud_version,
418 'php' => PHP_VERSION,
419 'wp' => $wp_version,// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- The variable is defined inside the ABSPATH.WPINC.'/version.php'.
420 'mysql' => $wpdb->db_version(),
421 'udrpc_php' => $this->rc->udrpc_version,
422 ),
423 'bloginfo' => array(
424 'url' => network_site_url(),
425 'name' => get_bloginfo('name'),
426 )
427 ));
428 }
429
430 /**
431 * This calls the WP_Action within WP
432 *
433 * @param array $data Array of Data to be used within call_wp_action
434 * @return array
435 */
436 public function call_wordpress_action($data) {
437 if (false === ($updraftplus_admin = $this->_load_ud_admin())) return $this->_generic_error_response('no_updraftplus');
438 $response = $updraftplus_admin->call_wp_action($data);
439
440 if (empty($data["wpaction"])) {
441 return $this->_generic_error_response("error", "no command sent");
442 }
443
444 return $this->_response(array(
445 "response" => $response['response'],
446 "status" => $response['status'],
447 "log" => $response['log']
448 ));
449 }
450
451 /**
452 * Get disk space used
453 *
454 * @uses UpdraftPlus_Filesystem_Functions::get_disk_space_used()
455 *
456 * @param String $entity - the entity to count (e.g. 'plugins', 'themes')
457 *
458 * @return Array - response
459 */
460 public function count($entity) {
461 if (!class_exists('UpdraftPlus_Filesystem_Functions')) return $this->_generic_error_response('no_updraftplus');
462 $response = UpdraftPlus_Filesystem_Functions::get_disk_space_used($entity);
463
464 return $this->_response($response);
465 }
466
467 /**
468 * https://secure.php.net/phpinfo
469 *
470 * @return null|array
471 */
472 private function _get_phpinfo_array() {
473 if (!function_exists('phpinfo')) return null;
474 ob_start();
475 phpinfo(INFO_GENERAL|INFO_CREDITS|INFO_MODULES);
476 $phpinfo = array('phpinfo' => array());
477
478 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)) {
479 foreach ($matches as $match) {
480 if (strlen($match[1])) {
481 $phpinfo[$match[1]] = array();
482 } elseif (isset($match[3])) {
483 $keys1 = array_keys($phpinfo);
484 $phpinfo[end($keys1)][$match[2]] = isset($match[4]) ? array($match[3], $match[4]) : $match[3];
485 } else {
486 $keys1 = array_keys($phpinfo);
487 $phpinfo[end($keys1)][] = $match[2];
488
489 }
490
491 }
492 return $phpinfo;
493 }
494 return false;
495 }
496
497 /**
498 * Return an UpdraftPlus_Admin object
499 *
500 * @return UpdraftPlus_Admin|Boolean - false in case of failure
501 */
502 private function _load_ud_admin() {
503 if (!defined('UPDRAFTPLUS_DIR') || !is_file(UPDRAFTPLUS_DIR.'/admin.php')) return false;
504 updraft_try_include_file('admin.php', 'include_once');
505 global $updraftplus_admin;
506 return $updraftplus_admin;
507 }
508 }
509