PluginProbe
WP Offload SES Lite / 1.2
WP Offload SES Lite v1.2
1.8.2 trunk 0.1.2 0.2.1 0.7.2.1 0.8.2 1.0 1.1 1.2 1.2.1 1.2.2 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 All 33 releases
wp-ses / classes / Compatibility-Check.php

Compatibility-Check.php in WP Offload SES Lite 1.2, at classes/Compatibility-Check.php

448 lines 11.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Checks compatibility for WP Offload SES.
4 *
5 * @author Delicious Brains
6 * @package WP Offload SES
7 */
8
9 namespace DeliciousBrains\WP_Offload_SES;
10
11 if ( class_exists( 'DeliciousBrains\WP_Offload_SES\Compatibility_Check' ) ) {
12 return;
13 }
14
15 /**
16 * Class Compatibility_Check
17 *
18 * @since 1.0.0
19 */
20 class Compatibility_Check {
21
22 /**
23 * The derived key of the plugin from the name, e.g. wp-offload-ses.
24 *
25 * @var string
26 */
27 protected $plugin_slug;
28
29 /**
30 * The name of the plugin, e.g. WP Offload SES.
31 *
32 * @var string
33 */
34 protected $plugin_name;
35
36 /**
37 * The file path to the plugin's main file.
38 *
39 * @var string
40 */
41 protected $plugin_file_path;
42
43 /**
44 * The error message to display in the admin notice.
45 *
46 * @var string
47 */
48 protected $error_message;
49
50 /**
51 * The CSS class for the notice.
52 *
53 * @var string
54 */
55 protected $notice_class = 'error';
56
57 /**
58 * Used to store if we are installing or updating plugins once per page request.
59 *
60 * @var bool
61 */
62 protected static $is_installing_or_updating_plugins;
63
64
65 /**
66 * Constructs the Compatibility_Check class.
67 *
68 * @param string $plugin_name The name of the plugin.
69 * @param string $plugin_slug The plugin slug.
70 * @param string $plugin_file_path The path to the main plugin file.
71 */
72 public function __construct( $plugin_name, $plugin_slug, $plugin_file_path ) {
73 $this->plugin_name = $plugin_name;
74 $this->plugin_slug = $plugin_slug;
75 $this->plugin_file_path = $plugin_file_path;
76
77 add_action( 'admin_notices', array( $this, 'hook_admin_notices' ) );
78 add_action( 'network_admin_notices', array( $this, 'hook_admin_notices' ) );
79 }
80
81 /**
82 * Is the plugin compatible?
83 *
84 * @return bool
85 */
86 public function is_compatible() {
87 $compatible = $this->get_error_msg() ? false : true;
88
89 $GLOBALS['wposes_meta'][ $this->plugin_slug ]['compatible'] = $compatible;
90
91 return $compatible;
92 }
93
94 /**
95 * Is a plugin active
96 *
97 * @param string $plugin_base
98 *
99 * @return bool
100 */
101 public function is_plugin_active( $plugin_base ) {
102 include_once ABSPATH . 'wp-admin/includes/plugin.php';
103
104 return is_plugin_active( $plugin_base );
105 }
106
107 /**
108 * Generate a URL to perform core actions on for a plugin
109 *
110 * @param string $action Such as activate, deactivate, install, upgrade
111 * @param string|null $basename
112 *
113 * @return string
114 */
115 public function get_plugin_action_url( $action, $basename = null ) {
116 if ( is_null( $basename ) ) {
117 $basename = $this->get_plugin_basename();
118 }
119
120 $nonce_action = $action . '-plugin_' . $basename;
121 $page = 'plugins';
122
123 if ( in_array( $action, array( 'upgrade', 'install' ) ) ) {
124 $page = 'update';
125 $action .= '-plugin';
126 }
127
128 $url = wp_nonce_url( network_admin_url( $page . '.php?action=' . $action . '&amp;plugin=' . $basename ), $nonce_action );
129
130 return $url;
131 }
132
133 /**
134 * Get the basename for the plugin
135 *
136 * @return string
137 */
138 public function get_plugin_basename() {
139 return plugin_basename( $this->plugin_file_path );
140 }
141
142 /**
143 * Set the error message to be returned for the admin notice
144 *
145 * @param string $message
146 *
147 * @return string
148 */
149 public function set_error_msg( $message ) {
150 // Replace the space between the last two words with &nbsp; to prevent typographic widows
151 $message = preg_replace( '/\s([\w]+[.,!\:;\\"-?]{0,1})$/', '&nbsp;\\1', $message, 1 );
152
153 $this->error_message = $message;
154
155 return $this->error_message;
156 }
157
158 /**
159 * Get the compatibility error message
160 *
161 * @return string|bool
162 */
163 public function get_error_msg() {
164 if ( ! is_null( $this->error_message ) ) {
165 return $this->error_message;
166 }
167
168 $plugin_basename = $this->get_plugin_basename();
169 $deactivate_url = $this->get_plugin_action_url( 'deactivate', $plugin_basename );
170 $deactivate_link = sprintf( '<a style="text-decoration:none;" href="%s">%s</a>', $deactivate_url, __( 'deactivate' ) );
171 $hide_notice_msg = '<br><em>' . sprintf( __( 'You can %s the %s plugin to get rid of this notice.' ), $deactivate_link, $this->plugin_name ) . '</em>';
172
173 // Check basic requirements for AWS SDK.
174 $sdk_errors = $this->get_sdk_requirements_errors();
175 if ( ! empty( $sdk_errors ) ) {
176 $sdk_errors = $this->get_sdk_error_msg() . $hide_notice_msg;
177
178 return $this->set_error_msg( $sdk_errors );
179 }
180
181 return false;
182 }
183
184 /**
185 * Check plugin capabilities for a user
186 *
187 * @return bool
188 */
189 public function check_capabilities() {
190 if ( is_multisite() ) {
191 if ( ! current_user_can( 'manage_network_plugins' ) ) {
192 return false; // Don't allow if the user can't manage network plugins
193 }
194 } else {
195 // Don't allow if user doesn't have plugin management privileges
196 $caps = array( 'activate_plugins', 'update_plugins', 'install_plugins' );
197 foreach ( $caps as $cap ) {
198 if ( ! current_user_can( $cap ) ) {
199 return false;
200 }
201 }
202 }
203
204 return true;
205 }
206
207 /**
208 * Display compatibility notices to users who can manage plugins
209 */
210 public function hook_admin_notices() {
211 if ( ! $this->check_capabilities() ) {
212 return;
213 }
214
215 if ( self::is_installing_or_updating_plugins() ) {
216 // Don't show notice when installing or updating plugins
217 return;
218 }
219
220 $this->get_admin_notice();
221 }
222
223 /**
224 * Get the admin notice to be displayed
225 */
226 public function get_admin_notice() {
227 $error_msg = $this->get_error_msg();
228
229 if ( false === $error_msg || '' === $error_msg ) {
230 return;
231 }
232
233 $this->render_notice( $error_msg );
234 }
235
236 /**
237 * Render the notice HTML
238 *
239 * @param string $message
240 */
241 public function render_notice( $message ) {
242 printf( '<div id="wposes-compat-notice' . $this->plugin_slug . '" class="' . $this->notice_class . ' wposes-compatibility-notice"><p>%s</p></div>', $message );
243 }
244
245 /**
246 * Is the current process an install or upgrade of plugin(s)
247 *
248 * @return bool
249 */
250 public static function is_installing_or_updating_plugins() {
251 if ( ! is_null( self::$is_installing_or_updating_plugins ) ) {
252 return self::$is_installing_or_updating_plugins;
253 }
254
255 self::$is_installing_or_updating_plugins = false;
256
257 global $pagenow;
258
259 if ( 'update.php' === $pagenow && isset( $_GET['action'] ) && 'install-plugin' === $_GET['action'] ) {
260 // We are installing a plugin
261 self::$is_installing_or_updating_plugins = true;
262 }
263
264 if ( 'plugins.php' === $pagenow && isset( $_POST['action'] ) ) {
265 $action = $_POST['action'];
266 if ( isset( $_POST['action2'] ) && '-1' !== $_POST['action2'] ) {
267 $action = $_POST['action2'];
268 }
269
270 if ( 'update-selected' === $action ) {
271 // We are updating plugins from the plugin page
272 self::$is_installing_or_updating_plugins = true;
273 }
274 }
275
276 if ( 'update-core.php' === $pagenow && isset( $_GET['action'] ) && 'do-plugin-upgrade' === $_GET['action'] ) {
277 // We are updating plugins from the updates page
278 self::$is_installing_or_updating_plugins = true;
279 }
280
281 return self::$is_installing_or_updating_plugins;
282 }
283
284 /**
285 * Checks if another version of WP Offload SES (lite/wpses) is active and deactivates it.
286 * To be hooked on `activated_plugin` so other plugin is deactivated when current plugin is activated.
287 *
288 * @param string $plugin The plugin.
289 *
290 * @return bool
291 */
292 public static function deactivate_other_instances( $plugin ) {
293 if ( ! in_array( basename( $plugin ), array( 'wp-offload-ses.php', 'wp-ses.php' ) ) ) {
294 return false;
295 }
296
297 $plugin_to_deactivate = 'wp-ses.php';
298 $deactivated_notice_id = '1';
299 $activated_plugin_min_version = '1.0-dev';
300 $plugin_to_deactivate_min_version = '0.1';
301
302 if ( basename( $plugin ) === $plugin_to_deactivate ) {
303 $plugin_to_deactivate = 'wp-offload-ses.php';
304 $deactivated_notice_id = '2';
305 $activated_plugin_min_version = '1.0-dev';
306 $plugin_to_deactivate_min_version = '1.1-dev';
307 }
308
309 $version = self::get_plugin_version_from_basename( $plugin );
310
311 if ( version_compare( $version, $activated_plugin_min_version, '<' ) ) {
312 return false;
313 }
314
315 if ( is_multisite() ) {
316 $active_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
317 $active_plugins = array_keys( $active_plugins );
318 } else {
319 $active_plugins = (array) get_option( 'active_plugins', array() );
320 }
321
322 foreach ( $active_plugins as $basename ) {
323 if ( false !== strpos( $basename, $plugin_to_deactivate ) ) {
324 $version = self::get_plugin_version_from_basename( $basename );
325
326 if ( version_compare( $version, $plugin_to_deactivate_min_version, '<' ) ) {
327 return false;
328 }
329
330 set_transient( 'wposes_deactivated_notice_id', $deactivated_notice_id, HOUR_IN_SECONDS );
331 deactivate_plugins( $basename );
332
333 return true;
334 }
335 }
336
337 return false;
338 }
339
340 /**
341 * Get plugin data from basename
342 *
343 * @param string $basename
344 *
345 * @return string
346 */
347 public static function get_plugin_version_from_basename( $basename ) {
348 require_once ABSPATH . 'wp-admin/includes/plugin.php';
349
350 $plugin_path = WP_PLUGIN_DIR . '/' . $basename;
351
352 // In case the plugin is installed as a MU plugin.
353 $basename = explode( '/', $basename );
354 $folder = $basename[0];
355 $file = $basename[1];
356
357 if ( file_exists( $plugin_path ) ) {
358 $path = $plugin_path;
359 } elseif ( file_exists( WPMU_PLUGIN_DIR . "/{$file}" ) ) {
360 $path = WPMU_PLUGIN_DIR . '/' . $file;
361 } elseif ( file_exists( WPMU_PLUGIN_DIR . "/$folder/$file" ) ) {
362 $path = WPMU_PLUGIN_DIR . "/$folder/$file";
363 } else {
364 return false;
365 }
366
367 $plugin_data = get_plugin_data( $path );
368 return $plugin_data['Version'];
369 }
370
371 /**
372 * Return an array of issues with the server's compatibility with the AWS SDK
373 *
374 * @return array
375 */
376 public function get_sdk_requirements_errors() {
377 static $errors;
378
379 if ( ! is_null( $errors ) ) {
380 return $errors;
381 }
382
383 $errors = array();
384
385 if ( version_compare( PHP_VERSION, '5.5', '<' ) ) {
386 $errors[] = __( 'a PHP version less than 5.5', 'wp-offload-ses' );
387 }
388
389 if ( ! function_exists( 'curl_version' ) ) {
390 $errors[] = __( 'no PHP cURL library activated', 'wp-offload-ses' );
391
392 return $errors;
393 }
394
395 if ( ! ( $curl = curl_version() ) || empty( $curl['version'] ) || empty( $curl['features'] ) || version_compare( $curl['version'], '7.16.2', '<' ) ) {
396 $errors[] = __( 'a cURL version less than 7.16.2', 'wp-offload-ses' );
397 }
398
399 if ( ! empty( $curl['features'] ) ) {
400 $curl_errors = array();
401
402 if ( ! CURL_VERSION_SSL ) {
403 $curl_errors[] = 'OpenSSL';
404 }
405
406 if ( ! CURL_VERSION_LIBZ ) {
407 $curl_errors[] = 'zlib';
408 }
409
410 if ( $curl_errors ) {
411 $errors[] = __( 'cURL compiled without', 'wp-offload-ses' ) . ' ' . implode( ' or ', $curl_errors ); // xss ok
412 }
413 }
414
415 if ( ! function_exists( 'curl_multi_exec' ) ) {
416 $errors[] = __( 'the function curl_multi_exec disabled', 'wp-offload-ses' );
417 }
418
419 return $errors;
420 }
421
422 /**
423 * Prepare an error message with compatibility issues
424 *
425 * @return string
426 */
427 public function get_sdk_error_msg() {
428 $errors = $this->get_sdk_requirements_errors();
429
430 if ( ! $errors ) {
431 return '';
432 }
433
434 $msg = __( 'The official Amazon&nbsp;Web&nbsp;Services SDK requires PHP 5.5+ and cURL 7.16.2+ compiled with OpenSSL and zlib. Your server currently has', 'wp-offload-ses' );
435
436 if ( count( $errors ) > 1 ) {
437 $last_one = ' and ' . array_pop( $errors );
438 } else {
439 $last_one = '';
440 }
441
442 $msg .= ' ' . implode( ', ', $errors ) . $last_one . '.';
443
444 return $msg;
445 }
446
447 }
448