PluginProbe
Plugin Check (PCP) / 1.5.0
Plugin Check (PCP) v1.5.0
2.1.0 trunk 0.1 0.2.0 0.2.1 0.2.2 0.2.3 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.3.0 1.3.1 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 ci-artifacts
plugin-check / includes / Utilities / Plugin_Request_Utility.php

Plugin_Request_Utility.php in Plugin Check (PCP) 1.5.0, at includes/Utilities/Plugin_Request_Utility.php

327 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class WordPress\Plugin_Check\Utilities
4 *
5 * @package plugin-check
6 */
7
8 namespace WordPress\Plugin_Check\Utilities;
9
10 use Exception;
11 use WordPress\Plugin_Check\Checker\Abstract_Check_Runner;
12 use WordPress\Plugin_Check\Checker\AJAX_Runner;
13 use WordPress\Plugin_Check\Checker\CLI_Runner;
14
15 /**
16 * Class providing utility methods to return plugin information based on the request.
17 *
18 * @since 1.0.0
19 */
20 class Plugin_Request_Utility {
21
22 /**
23 * Instance of the current runner based on the request.
24 *
25 * @since 1.0.0
26 * @var Abstract_Check_Runner|null
27 */
28 protected static $runner;
29
30 /**
31 * The universal runtime preparation cleanups if applied.
32 *
33 * @since 1.0.0
34 * @var callable|null
35 */
36 protected static $cleanup;
37
38 /**
39 * Returns the plugin basename based on the input provided.
40 *
41 * @since 1.0.0
42 *
43 * @param string $plugin_slug The plugin slug or basename.
44 * @return string The plugin basename.
45 *
46 * @throws Exception Thrown if an invalid basename or plugin slug is provided.
47 */
48 public static function get_plugin_basename_from_input( $plugin_slug ) {
49 require_once ABSPATH . 'wp-admin/includes/plugin.php';
50
51 if ( empty( $plugin_slug ) ) {
52 throw new Exception( 'Invalid plugin slug: Plugin slug must not be empty.' );
53 }
54
55 $plugins = get_plugins();
56
57 // Is the provided value is a full plugin basename?
58 if ( isset( $plugins[ $plugin_slug ] ) ) {
59 return $plugin_slug;
60 }
61
62 if ( strpos( $plugin_slug, '/' ) ) {
63 throw new Exception(
64 sprintf(
65 'Invalid plugin basename: Plugin with basename %s is not installed.',
66 $plugin_slug
67 )
68 );
69 }
70
71 foreach ( array_keys( $plugins ) as $plugin_basename ) {
72 if ( strpos( $plugin_basename, $plugin_slug . '/' ) === 0 ) {
73 return $plugin_basename;
74 }
75 }
76
77 throw new Exception(
78 sprintf(
79 'Invalid plugin slug: Plugin with slug %s is not installed.',
80 $plugin_slug
81 )
82 );
83 }
84
85 /**
86 * Initializes the runner classes.
87 *
88 * @since 1.0.0
89 */
90 public static function initialize_runner() {
91 $runners = array(
92 new CLI_Runner(),
93 new AJAX_Runner(),
94 );
95
96 foreach ( $runners as $runner ) {
97 if ( $runner->is_plugin_check() ) {
98 add_action(
99 'muplugins_loaded',
100 function () use ( $runner ) {
101 static::$cleanup = $runner->prepare();
102 static::$runner = $runner;
103 }
104 );
105
106 break;
107 }
108 }
109 }
110
111 /**
112 * Get the Runner class for the current request.
113 *
114 * @since 1.0.0
115 *
116 * @return Abstract_Check_Runner|null The Runner class for the request or null.
117 */
118 public static function get_runner() {
119 if ( null !== static::$runner ) {
120 return static::$runner;
121 }
122
123 return null;
124 }
125
126 /**
127 * Runs the cleanup functions and destroys the runner.
128 *
129 * @since 1.0.0
130 */
131 public static function destroy_runner() {
132 // Run the cleanup functions.
133 if ( null !== self::$cleanup ) {
134 call_user_func( self::$cleanup );
135 }
136
137 static::$runner = null;
138 }
139
140 /**
141 * Gets the directories to ignore using the filter.
142 *
143 * @since 1.0.0
144 */
145 public static function get_directories_to_ignore() {
146 // By default, ignore the '.git', 'vendor' and 'node_modules' directories.
147 $default_ignore_directories = array(
148 '.git',
149 'vendor',
150 'node_modules',
151 );
152
153 /**
154 * Filters the directories to ignore.
155 *
156 * @since 1.0.0
157 *
158 * @param array $default_ignore_directories An array of directories to ignore.
159 */
160 $directories_to_ignore = (array) apply_filters( 'wp_plugin_check_ignore_directories', $default_ignore_directories );
161
162 return $directories_to_ignore;
163 }
164
165 /**
166 * Gets the files to ignore using the filter.
167 *
168 * @since 1.0.2
169 */
170 public static function get_files_to_ignore() {
171 $default_ignore_files = array();
172
173 /**
174 * Filters the files to ignore.
175 *
176 * @since 1.0.2
177 *
178 * @param array $default_ignore_files An array of files to ignore.
179 */
180 $files_to_ignore = (array) apply_filters( 'wp_plugin_check_ignore_files', $default_ignore_files );
181
182 return $files_to_ignore;
183 }
184
185 /**
186 * Returns the plugin basename after downloading and installing the plugin.
187 *
188 * @since 1.1.0
189 *
190 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
191 *
192 * @param string $plugin_url The URL of the plugin to download.
193 * @return string The plugin basename after downloading and installing the plugin.
194 *
195 * @throws Exception Thrown if an invalid URL given or zip could be extracted properly.
196 *
197 * @SuppressWarnings(PHPMD.NPathComplexity)
198 */
199 public static function download_plugin( $plugin_url ) {
200 $args = array(
201 'timeout' => 60,
202 );
203 $response = wp_safe_remote_get( $plugin_url, $args );
204
205 if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
206 throw new Exception(
207 __( 'Downloading the zip file failed.', 'plugin-check' )
208 );
209 }
210
211 // Prevents URL from wporg.
212 if ( false !== strpos( $plugin_url, '#wporgapi:' ) ) {
213 $plugin_info_url = substr( $plugin_url, strpos( $plugin_url, '#wporgapi:' ) );
214 $plugin_info_url = str_replace( '#wporgapi:', '', $plugin_info_url );
215 $plugin_url = substr( $plugin_url, 0, strpos( $plugin_url, '#' ) );
216 }
217
218 $basename = basename( $plugin_url );
219
220 require_once ABSPATH . 'wp-admin/includes/file.php';
221
222 WP_Filesystem();
223
224 global $wp_filesystem;
225
226 // Create the name of the file and the declare the directory and path.
227 $plugin_check_dir = self::get_upload_dir();
228
229 $response_zip_body = wp_remote_retrieve_body( $response );
230
231 $file_path = $plugin_check_dir . $basename;
232
233 if ( ! $wp_filesystem->put_contents( $plugin_check_dir . $basename, $response_zip_body ) ) {
234 throw new Exception(
235 __( 'Saving zip file failed.', 'plugin-check' )
236 );
237 }
238
239 $temp_dir = $plugin_check_dir . strtotime( 'now' ) . '/';
240
241 // Unzip file.
242 $unzip_file = unzip_file( $file_path, $temp_dir );
243
244 if ( true !== $unzip_file ) {
245 throw new Exception( $unzip_file->get_error_message() );
246 }
247
248 // Remove zip file.
249 unlink( $file_path );
250
251 if ( ! empty( $plugin_info_url ) && filter_var( $plugin_info_url, FILTER_VALIDATE_URL ) ) {
252 $response_json = wp_safe_remote_get( $plugin_info_url );
253
254 if ( is_wp_error( $response_json ) || 200 !== wp_remote_retrieve_response_code( $response_json ) ) {
255 throw new Exception(
256 __( 'Fetching data failed.', 'plugin-check' )
257 );
258 }
259
260 $response_body = wp_remote_retrieve_body( $response_json );
261
262 json_decode( $response_body );
263
264 if ( JSON_ERROR_NONE !== json_last_error() ) {
265 throw new Exception(
266 __( 'Invalid JSON content.', 'plugin-check' )
267 );
268 }
269
270 if ( ! $wp_filesystem->put_contents( $plugin_check_dir . 'plugin-info.json', $response_body ) ) {
271 throw new Exception(
272 __( 'Saving JSON file failed.', 'plugin-check' )
273 );
274 }
275 }
276
277 $files = scandir( $temp_dir );
278 $files = array_diff( $files, array( '.', '..' ) );
279 $target_folder_name = ! empty( $files ) && 1 === count( $files ) ? reset( $files ) : '';
280
281 return $temp_dir . $target_folder_name;
282 }
283
284 /**
285 * Get the upload directory for the plugin check.
286 *
287 * @since 1.1.0
288 *
289 * @return string The upload directory for the plugin check.
290 */
291 public static function get_upload_dir() {
292 $upload_dir = trailingslashit( get_temp_dir() ) . 'plugin-check/';
293
294 if ( ! is_dir( $upload_dir ) ) {
295 mkdir( $upload_dir, 0755, true );
296 }
297
298 return $upload_dir;
299 }
300
301 /**
302 * Checks if the directory is a valid plugin.
303 *
304 * @since 1.1.0
305 *
306 * @param string $directory Directory.
307 * @return bool true if the directory is valid plugin, otherwise false.
308 */
309 public static function is_directory_valid_plugin( $directory ) {
310 $is_valid = false;
311
312 if ( is_dir( $directory ) ) {
313 $files = glob( $directory . '/*.php' );
314
315 foreach ( $files as $file ) {
316 $plugin_data = get_plugin_data( $file );
317 if ( ! empty( $plugin_data['Name'] ) ) {
318 $is_valid = true;
319 break;
320 }
321 }
322 }
323
324 return $is_valid;
325 }
326 }
327