From 1586c43c8daf68741d5401fdf3525806188509df Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Fri, 22 Mar 2019 00:36:30 +0000 Subject: [PATCH] Plugins: Block plugin activation if it requires a higher version of PHP or WordPress. Introduce `validate_plugin_requirements()` for validating a plugin's WordPress and PHP version requirements. Introduce `wp_is_wp_compatible()` and `wp_is_php_compatible()` for checking compatibility with the current WordPress or PHP version. Props afragen, joyously, DrewAPicture, TimothyBlynJacobs, desrosj, flixos90, SergeyBiryukov. See #43992. git-svn-id: https://develop.svn.wordpress.org/trunk@44978 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/plugin.php | 55 ++++++++++++++++++++++++++++++++ src/wp-includes/functions.php | 26 +++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/wp-admin/includes/plugin.php b/src/wp-admin/includes/plugin.php index f44b5aff02..f54717f804 100644 --- a/src/wp-admin/includes/plugin.php +++ b/src/wp-admin/includes/plugin.php @@ -597,6 +597,7 @@ function is_network_only_plugin( $plugin ) { * ensure that the success redirection will update the error redirection. * * @since 2.5.0 + * @since 5.2.0 Test for WordPress version and PHP version compatibility. * * @param string $plugin Path to the plugin file relative to the plugins directory. * @param string $redirect Optional. URL to redirect to. @@ -621,6 +622,11 @@ function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silen return $valid; } + $requirements = validate_plugin_requirements( $plugin ); + if ( is_wp_error( $requirements ) ) { + return $requirements; + } + if ( ( $network_wide && ! isset( $current[ $plugin ] ) ) || ( ! $network_wide && ! in_array( $plugin, $current ) ) ) { if ( ! empty( $redirect ) ) { wp_redirect( add_query_arg( '_error_nonce', wp_create_nonce( 'plugin-activation-error_' . $plugin ), $redirect ) ); // we'll override this later if the plugin can be included without fatal error @@ -1060,6 +1066,55 @@ function validate_plugin( $plugin ) { return 0; } +/** + * Validate the plugin requirements for WP version and PHP version. + * + * @since 5.2.0 + * + * @param string $plugin Path to the plugin file relative to the plugins directory. + * @return true|WP_Error True if requirements are met, WP_Error on failure. + */ +function validate_plugin_requirements( $plugin ) { + $readme_file = WP_PLUGIN_DIR . '/' . dirname( $plugin ) . '/readme.txt'; + + if ( file_exists( $readme_file ) ) { + $plugin_data = get_file_data( + $readme_file, + array( + 'requires' => 'Requires at least', + 'requires_php' => 'Requires PHP', + ), + 'plugin' + ); + } else { + return true; + } + + $plugin_data['wp_compatible'] = wp_is_wp_compatible( $plugin_data['requires'] ); + $plugin_data['php_compatible'] = wp_is_php_compatible( $plugin_data['requires_php'] ); + + $plugin_data = array_merge( $plugin_data, get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ) ); + + if ( ! $plugin_data['wp_compatible'] && ! $plugin_data['php_compatible'] ) { + return new WP_Error( 'plugin_wp_php_incompatible', sprintf( + /* translators: %s: plugin name */ + __( 'Error: Current WordPress and PHP versions do not meet minimum requirements for %s.' ), $plugin_data['Name'] ) + ); + } elseif ( ! $plugin_data['php_compatible'] ) { + return new WP_Error( 'plugin_php_incompatible', sprintf( + /* translators: %s: plugin name */ + __( 'Error: Current PHP version does not meet minimum requirements for %s.' ), $plugin_data['Name'] ) + ); + } elseif ( ! $plugin_data['wp_compatible'] ) { + return new WP_Error( 'plugin_wp_incompatible', sprintf( + /* translators: %s: plugin name */ + __( 'Error: Current WordPress version does not meet minimum requirements for %s.' ), $plugin_data['Name'] ) + ); + } + + return true; +} + /** * Whether the plugin can be uninstalled. * diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index 86cdabe7e0..b8a0a7db07 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -6897,3 +6897,29 @@ function wp_direct_php_update_button() { ); echo '

'; } + +/** + * Checks compatibility with the current WordPress version. + * + * @since 5.2.0 + * + * @param string $required Minimum required WordPress version. + * @return bool True if required version is compatible or empty, false if not. + */ +function wp_is_wp_compatible( $required ) { + $wp_version = get_bloginfo( 'version' ); + + return empty( $required ) || version_compare( $wp_version, $required, '>=' ); +} + +/** + * Checks compatibility with the current PHP version. + * + * @since 5.2.0 + * + * @param string $required Minimum required PHP version. + * @return bool True if required version is compatible or empty, false if not. + */ +function wp_is_php_compatible( $required ) { + return empty( $required ) || version_compare( phpversion(), $required, '>=' ); +}