PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.20
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.20
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 / central / modules / core.php

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

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