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 / plugin.php

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

691 lines 23.3 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 * Handles UpdraftCentral Plugin Commands which basically handles
7 * the installation and activation of a plugin
8 */
9 class UpdraftCentral_Plugin_Commands extends UpdraftCentral_Commands {
10
11 private $switched = false;
12
13 /**
14 * Function that gets called before every action
15 *
16 * @param string $command a string that corresponds to UDC command to call a certain method for this class.
17 * @param array $data an array of data post or get fields
18 * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
19 *
20 * link to udrpc_action main function in class UpdraftCentral_Listener
21 */
22 public function _pre_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- This function is called from listener.php and $extra_info is being sent.
23 // Here we assign the current blog_id to a variable $blog_id
24 $blog_id = get_current_blog_id();
25 if (!empty($data['site_id'])) $blog_id = $data['site_id'];
26
27 if (function_exists('switch_to_blog') && is_multisite() && $blog_id) {
28 $this->switched = switch_to_blog($blog_id);
29 }
30 }
31
32 /**
33 * Function that gets called after every action
34 *
35 * @param string $command a string that corresponds to UDC command to call a certain method for this class.
36 * @param array $data an array of data post or get fields
37 * @param array $extra_info extrainfo use in the udrpc_action, e.g. user_id
38 *
39 * link to udrpc_action main function in class UpdraftCentral_Listener
40 */
41 public function _post_action($command, $data, $extra_info) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- Unused parameter is present because the caller from UpdraftCentral_Listener class uses 3 arguments.
42 // Here, we're restoring to the current (default) blog before we switched
43 if ($this->switched) restore_current_blog();
44 }
45
46 /**
47 * Constructor
48 */
49 public function __construct() {
50 $this->_admin_include('plugin.php', 'file.php', 'template.php', 'class-wp-upgrader.php', 'plugin-install.php', 'update.php');
51 }
52
53 /**
54 * Installs and activates a plugin through upload
55 *
56 * @param array $params Parameter array containing information pertaining the currently uploaded plugin
57 * @return array Contains the result of the current process
58 */
59 public function upload_plugin($params) {
60 return $this->process_chunk_upload($params, 'plugin');
61 }
62
63 /**
64 * Checks whether the plugin is currently installed and activated.
65 *
66 * @param array $query Parameter array containing the name of the plugin to check
67 * @return array Contains the result of the current process
68 */
69 public function is_plugin_installed($query) {
70
71 if (!isset($query['plugin']))
72 return $this->_generic_error_response('plugin_name_required');
73
74
75 $result = $this->_get_plugin_info($query);
76 return $this->_response($result);
77 }
78
79 /**
80 * Applies currently requested action for plugin processing
81 *
82 * @param string $action The action to apply (e.g. activate or install)
83 * @param array $query Parameter array containing information for the currently requested action
84 *
85 * @return array
86 */
87 private function _apply_plugin_action($action, $query) {
88
89 $result = array();
90 switch ($action) {
91 case 'activate':
92 case 'network_activate':
93 $info = $this->_get_plugin_info($query);
94 if ($info['installed']) {
95 $activate = activate_plugin($info['plugin_path']);
96 if (is_wp_error($activate)) {
97 $result = $this->_generic_error_response('generic_response_error', array(
98 'plugin' => $query['plugin'],
99 'error_code' => 'generic_response_error',
100 'error_message' => $activate->get_error_message(),
101 'info' => $this->_get_plugin_info($query)
102 ));
103 } else {
104 $result = array('activated' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
105 }
106 } else {
107 $result = $this->_generic_error_response('plugin_not_installed', array(
108 'plugin' => $query['plugin'],
109 'error_code' => 'plugin_not_installed',
110 'error_message' => __('The plugin you wish to activate is either not installed or has been removed recently.', 'updraftplus'),
111 'info' => $info
112 ));
113 }
114 break;
115 case 'deactivate':
116 case 'network_deactivate':
117 $info = $this->_get_plugin_info($query);
118 if ($info['active']) {
119 deactivate_plugins($info['plugin_path']);
120 if (!is_plugin_active($info['plugin_path'])) {
121 $result = array('deactivated' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
122 } else {
123 $result = $this->_generic_error_response('deactivate_plugin_failed', array(
124 'plugin' => $query['plugin'],
125 'error_code' => 'deactivate_plugin_failed',
126 'error_message' => __('There appears to be a problem deactivating the intended plugin.', 'updraftplus').' '.__('Please check your permissions and try again.', 'updraftplus'),
127 'info' => $this->_get_plugin_info($query)
128 ));
129 }
130 } else {
131 $result = $this->_generic_error_response('not_active', array(
132 'plugin' => $query['plugin'],
133 'error_code' => 'not_active',
134 'error_message' => __('The plugin you wish to deactivate is currently not active or is already deactivated.', 'updraftplus'),
135 'info' => $info
136 ));
137 }
138 break;
139 case 'install':
140 $api = plugins_api('plugin_information', array(
141 'slug' => $query['slug'],
142 'fields' => array(
143 'short_description' => false,
144 'sections' => false,
145 'requires' => false,
146 'rating' => false,
147 'ratings' => false,
148 'downloaded' => false,
149 'last_updated' => false,
150 'added' => false,
151 'tags' => false,
152 'compatibility' => false,
153 'homepage' => false,
154 'donate_link' => false,
155 )
156 ));
157
158 $info = $this->_get_plugin_info($query);
159 if (is_wp_error($api)) {
160 $result = $this->_generic_error_response('generic_response_error', array(
161 'plugin' => $query['plugin'],
162 'error_code' => 'generic_response_error',
163 'error_message' => $api->get_error_message(),
164 'info' => $info
165 ));
166 } else {
167 $installed = $info['installed'];
168
169 $error_code = $error_message = '';
170 if (!$installed) {
171 // WP < 3.7
172 if (!class_exists('Automatic_Upgrader_Skin')) include_once(dirname(dirname(__FILE__)).'/classes/class-automatic-upgrader-skin.php');
173
174 $skin = new Automatic_Upgrader_Skin();
175 $upgrader = new Plugin_Upgrader($skin);
176
177 $download_link = $api->download_link;
178 $installed = $upgrader->install($download_link);
179
180 if (is_wp_error($installed)) {
181 $error_code = $installed->get_error_code();
182 $error_message = $installed->get_error_message();
183 } elseif (is_wp_error($skin->result)) {
184 $error_code = $skin->result->get_error_code();
185 $error_message = $skin->result->get_error_message();
186
187 $error_data = $skin->result->get_error_data($error_code);
188 if (!empty($error_data)) {
189 if (is_array($error_data)) $error_data = json_encode($error_data);
190 $error_message .= ' '.$error_data;
191 }
192 } elseif (is_null($installed) || !$installed) {
193 global $wp_filesystem;
194 $upgrade_messages = $skin->get_upgrade_messages();
195
196 if (!class_exists('WP_Filesystem_Base')) include_once(ABSPATH.'/wp-admin/includes/class-wp-filesystem-base.php');
197
198 // Pass through the error from WP_Filesystem if one was raised.
199 if ($wp_filesystem instanceof WP_Filesystem_Base && is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code()) {
200 $error_code = $wp_filesystem->errors->get_error_code();
201 $error_message = $wp_filesystem->errors->get_error_message();
202 } elseif (!empty($upgrade_messages)) {
203 // We're only after for the last feedback that we received from the install process. Mostly,
204 // that is where the last error has been inserted.
205 $messages = $skin->get_upgrade_messages();
206 $error_code = 'install_failed';
207 $error_message = end($messages);
208 } else {
209 $error_code = 'unable_to_connect_to_filesystem';
210 $error_message = __('Unable to connect to the filesystem.', 'updraftplus').' '.__('Please confirm your credentials.');
211 }
212 }
213 }
214
215 if (!$installed || is_wp_error($installed)) {
216 $result = $this->_generic_error_response('plugin_install_failed', array(
217 'plugin' => $query['plugin'],
218 'error_code' => $error_code,
219 'error_message' => $error_message,
220 'info' => $this->_get_plugin_info($query)
221 ));
222 } else {
223 $result = array('installed' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
224 }
225 }
226 break;
227 }
228
229 return $result;
230 }
231
232 /**
233 * Preloads the submitted credentials to the global $_POST variable
234 *
235 * @param array $query Parameter array containing information for the currently requested action
236 */
237 private function _preload_credentials($query) {
238 if (!empty($query) && isset($query['filesystem_credentials'])) {
239 parse_str($query['filesystem_credentials'], $filesystem_credentials);
240 if (is_array($filesystem_credentials)) {
241 foreach ($filesystem_credentials as $key => $value) {
242 // Put them into $_POST, which is where request_filesystem_credentials() checks for them.
243 $_POST[$key] = $value;
244 }
245 }
246 }
247 }
248
249 /**
250 * Checks whether we have the required fields submitted and the user has
251 * the capabilities to execute the requested action
252 *
253 * @param array $query The submitted information
254 * @param array $fields The required fields to check
255 * @param array $capabilities The capabilities to check and validate
256 *
257 * @return array|string
258 */
259 private function _validate_fields_and_capabilities($query, $fields, $capabilities) {
260
261 $error = '';
262 if (!empty($fields)) {
263 for ($i=0; $i<count($fields); $i++) {
264 $field = $fields[$i];
265
266 if (!isset($query[$field])) {
267 if ('keyword' === $field) {
268 $error = $this->_generic_error_response('keyword_required');
269 } else {
270 $error = $this->_generic_error_response('plugin_'.$query[$field].'_required');
271 }
272 break;
273 }
274 }
275 }
276
277 if (empty($error) && !empty($capabilities)) {
278 for ($i=0; $i<count($capabilities); $i++) {
279 if (!current_user_can($capabilities[$i])) {
280 $error = $this->_generic_error_response('plugin_insufficient_permission');
281 break;
282 }
283 }
284 }
285
286 return $error;
287 }
288
289 /**
290 * Processing an action for multiple items
291 *
292 * @param array $query Parameter array containing a list of plugins to process
293 * @return array Contains the results of the bulk process
294 */
295 public function process_action_in_bulk($query) {
296 $action = isset($query['action']) ? $query['action'] : '';
297 $items = isset($query['args']) ? $query['args']['items'] : array();
298
299 $results = array();
300 if (!empty($action) && !empty($items) && is_array($items)) {
301 foreach ($items as $value) {
302 if (method_exists($this, $action)) {
303 $results[] = $this->$action($value);
304 }
305 }
306 }
307
308 return $this->_response($results);
309 }
310
311 /**
312 * Activates the plugin
313 *
314 * @param array $query Parameter array containing the name of the plugin to activate
315 * @return array Contains the result of the current process
316 */
317 public function activate_plugin($query) {
318
319 $fields = array('plugin');
320 $permissions = array('activate_plugins');
321
322 $error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
323 if (!empty($error)) {
324 return $error;
325 }
326
327 $this->_preload_credentials($query);
328
329 $result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_activate' : 'activate', $query);
330 if (empty($result['activated'])) {
331 return $result;
332 }
333
334 return $this->_response($result);
335 }
336
337 /**
338 * Deactivates the plugin
339 *
340 * @param array $query Parameter array containing the name of the plugin to deactivate
341 * @return array Contains the result of the current process
342 */
343 public function deactivate_plugin($query) {
344
345 $fields = array('plugin');
346 $permissions = array('activate_plugins');
347
348 $error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
349 if (!empty($error)) {
350 return $error;
351 }
352
353 $this->_preload_credentials($query);
354
355 $result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_deactivate' : 'deactivate', $query);
356 if (empty($result['deactivated'])) {
357 return $result;
358 }
359
360 return $this->_response($result);
361 }
362
363 /**
364 * Download, install and activates the plugin
365 *
366 * @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
367 * @return array Contains the result of the current process
368 */
369 public function install_activate_plugin($query) {
370
371 $fields = array('plugin', 'slug');
372 $permissions = array('install_plugins', 'activate_plugins');
373
374 $error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
375 if (!empty($error)) {
376 return $error;
377 }
378
379 $this->_preload_credentials($query);
380
381 $result = $this->_apply_plugin_action('install', $query);
382 if (!empty($result['installed']) && $result['installed']) {
383 $result = $this->_apply_plugin_action((!empty($query['multisite']) && (bool) $query['multisite']) ? 'network_activate' : 'activate', $query);
384 if (empty($result['activated'])) {
385 return $result;
386 }
387 } else {
388 return $result;
389 }
390
391 return $this->_response($result);
392 }
393
394 /**
395 * Download, install the plugin
396 *
397 * @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
398 * @return array Contains the result of the current process
399 */
400 public function install_plugin($query) {
401
402 $fields = array('plugin', 'slug');
403 $permissions = array('install_plugins');
404
405 $error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
406 if (!empty($error)) {
407 return $error;
408 }
409
410 $this->_preload_credentials($query);
411
412 $result = $this->_apply_plugin_action('install', $query);
413 if (empty($result['installed'])) {
414 return $result;
415 }
416
417 return $this->_response($result);
418 }
419
420 /**
421 * Uninstall/delete the plugin
422 *
423 * @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
424 * @return array Contains the result of the current process
425 */
426 public function delete_plugin($query) {
427
428 $fields = array('plugin');
429 $permissions = array('delete_plugins');
430
431 $error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
432 if (!empty($error)) {
433 return $error;
434 }
435
436 $this->_preload_credentials($query);
437
438 $info = $this->_get_plugin_info($query);
439 if ($info['installed']) {
440 // Deactivate first before delete to invalidate the activate
441 // state/status prior to deleting the item. Otherwise, WordPress will keep
442 // that state, and as soon as you install the same plugin it will be automatically
443 // activated since it's previous state was kept.
444 deactivate_plugins($info['plugin_path']);
445
446 $deleted = delete_plugins(array($info['plugin_path']));
447 if ($deleted) {
448 $result = array('deleted' => true, 'info' => $this->_get_plugin_info($query), 'last_state' => $info);
449 } else {
450 return $this->_generic_error_response('delete_plugin_failed', array(
451 'plugin' => $query['plugin'],
452 'error_code' => 'delete_plugin_failed',
453 'info' => $info
454 ));
455 }
456 } else {
457 return $this->_generic_error_response('plugin_not_installed', array(
458 'plugin' => $query['plugin'],
459 'error_code' => 'plugin_not_installed',
460 'info' => $info
461 ));
462 }
463
464 return $this->_response($result);
465 }
466
467 /**
468 * Updates/upgrade the plugin
469 *
470 * @param array $query Parameter array containing the filesystem credentials entered by the user along with the plugin name and slug
471 * @return array Contains the result of the current process
472 */
473 public function update_plugin($query) {
474
475 $fields = array('plugin', 'slug');
476 $permissions = array('update_plugins');
477
478 $error = $this->_validate_fields_and_capabilities($query, $fields, $permissions);
479 if (!empty($error)) {
480 return $error;
481 }
482
483 $this->_preload_credentials($query);
484
485 // Make sure that we still have the plugin installed before running
486 // the update process
487 $info = $this->_get_plugin_info($query);
488 if ($info['installed']) {
489 // Load the updates command class if not existed
490 if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
491 $update_command = new UpdraftCentral_Updates_Commands($this->rc);
492
493 $result = $update_command->update_plugin($info['plugin_path'], $query['slug']);
494 if (!empty($result['error'])) {
495 $result['values'] = array('plugin' => $query['plugin'], 'info' => $info);
496 }
497 } else {
498 return $this->_generic_error_response('plugin_not_installed', array(
499 'plugin' => $query['plugin'],
500 'error_code' => 'plugin_not_installed',
501 'info' => $info
502 ));
503 }
504
505 return $this->_response($result);
506 }
507
508 /**
509 * Gets the plugin information along with its active and install status
510 *
511 * @internal
512 * @param array $query Contains either the plugin name or slug or both to be used when retrieving information
513 * @return array
514 */
515 private function _get_plugin_info($query) {
516
517 $info = array(
518 'active' => false,
519 'installed' => false
520 );
521
522 // Clear plugin cache so that newly installed/downloaded plugins
523 // gets reflected when calling "get_plugins"
524 if (function_exists('wp_clean_plugins_cache')) {
525 wp_clean_plugins_cache();
526 }
527
528 // Gets all plugins available.
529 $get_plugins = get_plugins();
530
531 // Loops around each plugin available.
532 foreach ($get_plugins as $key => $value) {
533 $slug = $this->extract_slug_from_info($key, $value);
534
535 // If the plugin name matches that of the specified name, it will gather details.
536 // In case name check isn't enough, we'll use slug to verify if the plugin being queried is actually installed.
537 //
538 // Reason for name check failure:
539 // Due to plugin name inconsistencies - where wordpress.org registered plugin name is different
540 // from the actual plugin files's metadata (found inside the plugin's PHP file itself).
541 if ((!empty($query['plugin']) && html_entity_decode($value['Name']) === html_entity_decode($query['plugin'])) || (!empty($query['slug']) && $slug === $query['slug'])) {
542 $info['installed'] = true;
543 $info['active'] = is_plugin_active($key);
544 $info['plugin_path'] = $key;
545 $info['data'] = $value;
546 $info['name'] = $value['Name'];
547 $info['slug'] = $slug;
548 break;
549 }
550 }
551
552 return $info;
553 }
554
555 /**
556 * Extract the slug from the plugin data
557 *
558 * @param string $key They key of the current info
559 * @param array $info Data pulled from the plugin file
560 *
561 * @return string
562 */
563 private function extract_slug_from_info($key, $info) {
564 if (!is_array($info) || empty($info) || empty($key)) return '';
565
566 $temp = explode('/', $key);
567 $slug = !empty($info['TextDomain']) ? $info['TextDomain'] : basename($temp[0], '.php');
568
569 // If in case the user kept the hello-dolly plugin then we'll make sure that it gets
570 // the proper slug for it, otherwise, we'll end up with the wrong slug 'hello' instead of
571 // 'hello-dolly'. Wrong slug will produce error in UpdraftCentral when running it against
572 // wordpress.org for further information retrieval.
573 $slug = ('Hello Dolly' === $info['Name']) ? 'hello-dolly' : $slug;
574
575 return $slug;
576 }
577
578 /**
579 * Loads all available plugins with additional attributes and settings needed by UpdraftCentral
580 *
581 * @param array $query Parameter array Any available parameters needed for this action
582 * @return array Contains the result of the current process
583 */
584 public function load_plugins($query) {
585
586 $permissions = array('install_plugins', 'activate_plugins');
587 if (is_multisite() && !is_super_admin(get_current_user_id())) $permissions = array('activate_plugins');
588
589 $error = $this->_validate_fields_and_capabilities($query, array(), $permissions);
590 if (!empty($error)) {
591 return $error;
592 }
593
594 $website = get_bloginfo('name');
595 $results = array();
596
597 // Load the updates command class if not existed
598 if (!class_exists('UpdraftCentral_Updates_Commands')) include_once('updates.php');
599 $updates = new UpdraftCentral_Updates_Commands($this->rc);
600
601 // Get plugins for update
602 $plugin_updates = $updates->get_item_updates('plugins');
603
604 // Get all plugins
605 $plugins = get_plugins();
606
607 if (is_multisite() && !is_super_admin(get_current_user_id())) {
608
609 // If the "Plugins" menu is disabled for the subsites on a multisite
610 // network then we return an empty "plugins" array.
611 $menu_items = get_site_option('menu_items');
612 if (empty($menu_items) || !isset($menu_items['plugins'])) {
613 $plugins = array();
614 } else {
615 $show_network_active = apply_filters('show_network_active_plugins', current_user_can('manage_network_plugins'));
616
617 $filtered_plugins = array();
618 foreach ($plugins as $file => $data) {
619 if (is_network_only_plugin($file) && !is_plugin_active($file)) {
620 if ($show_network_active) $filtered_plugins[$file] = $data;
621 } elseif (is_plugin_active_for_network($file)) {
622 if ($show_network_active) $filtered_plugins[$file] = $data;
623 } else {
624 $filtered_plugins[$file] = $data;
625 }
626 }
627
628 $plugins = $filtered_plugins;
629 }
630 }
631
632 foreach ($plugins as $key => $value) {
633 $slug = $this->extract_slug_from_info($key, $value);
634
635 $plugin = new stdClass();
636 $plugin->name = $value['Name'];
637 $plugin->description = $value['Description'];
638 $plugin->slug = $slug;
639 $plugin->version = $value['Version'];
640 $plugin->author = $value['Author'];
641 $plugin->status = is_plugin_active($key) ? 'active' : 'inactive';
642 $plugin->website = $website;
643 $plugin->multisite = is_multisite();
644 $plugin->site_url = trailingslashit(get_bloginfo('url'));
645
646 if (!empty($plugin_updates[$key])) {
647 $update_info = $plugin_updates[$key];
648
649 if (version_compare($update_info->Version, $update_info->update->new_version, '<')) {
650 if (!empty($update_info->update->new_version)) $plugin->latest_version = $update_info->update->new_version;
651 if (!empty($update_info->update->package)) $plugin->download_link = $update_info->update->package;
652 if (!empty($update_info->update->sections)) $plugin->sections = $update_info->update->sections;
653 }
654 }
655
656 if (empty($plugin->short_description) && !empty($plugin->description)) {
657 // Only pull the first sentence as short description, it should be enough rather than displaying
658 // an empty description or a full blown one which the user can access anytime if they press on
659 // the view details link in UpdraftCentral.
660 $temp = explode('.', $plugin->description);
661 $short_description = $temp[0];
662
663 // Adding the second sentence wouldn't hurt, in case the first sentence is too short.
664 if (isset($temp[1])) $short_description .= '.'.$temp[1];
665
666 $plugin->short_description = $short_description.'.';
667 }
668
669 $results[] = $plugin;
670 }
671
672 $result = array(
673 'plugins' => $results,
674 'is_super_admin' => is_super_admin(),
675 );
676
677 $result = array_merge($result, $this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
678 return $this->_response($result);
679 }
680
681 /**
682 * Gets the backup and security credentials settings for this website
683 *
684 * @param array $query Parameter array Any available parameters needed for this action
685 * @return array Contains the result of the current process
686 */
687 public function get_plugin_requirements() {
688 return $this->_response($this->_get_backup_credentials_settings(WP_PLUGIN_DIR));
689 }
690 }
691