summaryrefslogtreecommitdiff
blob: 8e679976492865dab97b5d0d068b229f98c832b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
<?php
/**
 * This file was automatically generated by automattic/jetpack-autoloader.
 *
 * @package automattic/jetpack-autoloader
 */

namespace Automattic\Jetpack\Autoloader\jpf11009ded9fc4592b6a05b61ce272b3c_jetpackⓥ11_0;

 // phpcs:ignore

/**
 * This class scans the WordPress installation to find active plugins.
 */
class Plugin_Locator {

	/**
	 * The path processor for finding plugin paths.
	 *
	 * @var Path_Processor
	 */
	private $path_processor;

	/**
	 * The constructor.
	 *
	 * @param Path_Processor $path_processor The Path_Processor instance.
	 */
	public function __construct( $path_processor ) {
		$this->path_processor = $path_processor;
	}

	/**
	 * Finds the path to the current plugin.
	 *
	 * @return string $path The path to the current plugin.
	 *
	 * @throws \RuntimeException If the current plugin does not have an autoloader.
	 */
	public function find_current_plugin() {
		// Escape from `vendor/__DIR__` to root plugin directory.
		$plugin_directory = dirname( dirname( __DIR__ ) );

		// Use the path processor to ensure that this is an autoloader we're referencing.
		$path = $this->path_processor->find_directory_with_autoloader( $plugin_directory, array() );
		if ( false === $path ) {
			throw new \RuntimeException( 'Failed to locate plugin ' . $plugin_directory );
		}

		return $path;
	}

	/**
	 * Checks a given option for plugin paths.
	 *
	 * @param string $option_name  The option that we want to check for plugin information.
	 * @param bool   $site_option  Indicates whether or not we want to check the site option.
	 *
	 * @return array $plugin_paths The list of absolute paths we've found.
	 */
	public function find_using_option( $option_name, $site_option = false ) {
		$raw = $site_option ? get_site_option( $option_name ) : get_option( $option_name );
		if ( false === $raw ) {
			return array();
		}

		return $this->convert_plugins_to_paths( $raw );
	}

	/**
	 * Checks for plugins in the `action` request parameter.
	 *
	 * @param string[] $allowed_actions The actions that we're allowed to return plugins for.
	 *
	 * @return array $plugin_paths The list of absolute paths we've found.
	 */
	public function find_using_request_action( $allowed_actions ) {
		// phpcs:disable WordPress.Security.NonceVerification.Recommended

		/**
		 * Note: we're not actually checking the nonce here because it's too early
		 * in the execution. The pluggable functions are not yet loaded to give
		 * plugins a chance to plug their versions. Therefore we're doing the bare
		 * minimum: checking whether the nonce exists and it's in the right place.
		 * The request will fail later if the nonce doesn't pass the check.
		 */
		if ( empty( $_REQUEST['_wpnonce'] ) ) {
			return array();
		}

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated just below.
		$action = isset( $_REQUEST['action'] ) ? wp_unslash( $_REQUEST['action'] ) : false;
		if ( ! in_array( $action, $allowed_actions, true ) ) {
			return array();
		}

		$plugin_slugs = array();
		switch ( $action ) {
			case 'activate':
			case 'deactivate':
				if ( empty( $_REQUEST['plugin'] ) ) {
					break;
				}

				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated by convert_plugins_to_paths.
				$plugin_slugs[] = wp_unslash( $_REQUEST['plugin'] );
				break;

			case 'activate-selected':
			case 'deactivate-selected':
				if ( empty( $_REQUEST['checked'] ) ) {
					break;
				}

				// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated by convert_plugins_to_paths.
				$plugin_slugs = wp_unslash( $_REQUEST['checked'] );
				break;
		}

		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		return $this->convert_plugins_to_paths( $plugin_slugs );
	}

	/**
	 * Given an array of plugin slugs or paths, this will convert them to absolute paths and filter
	 * out the plugins that are not directory plugins. Note that array keys will also be included
	 * if they are plugin paths!
	 *
	 * @param string[] $plugins Plugin paths or slugs to filter.
	 *
	 * @return string[]
	 */
	private function convert_plugins_to_paths( $plugins ) {
		if ( ! is_array( $plugins ) || empty( $plugins ) ) {
			return array();
		}

		// We're going to look for plugins in the standard directories.
		$path_constants = array( WP_PLUGIN_DIR, WPMU_PLUGIN_DIR );

		$plugin_paths = array();
		foreach ( $plugins as $key => $value ) {
			$path = $this->path_processor->find_directory_with_autoloader( $key, $path_constants );
			if ( $path ) {
				$plugin_paths[] = $path;
			}

			$path = $this->path_processor->find_directory_with_autoloader( $value, $path_constants );
			if ( $path ) {
				$plugin_paths[] = $path;
			}
		}

		return $plugin_paths;
	}
}