/home/arranoyd/telegastro/wp-content/plugins/health-check/includes/class-health-check-updates.php
<?php
/**
* Class for testing plugin/theme updates in the WordPress code.
*
* @package Health Check
*/
// Make sure the file is not directly accessible.
if ( ! defined( 'ABSPATH' ) ) {
die( 'We\'re sorry, but you can not directly access this file.' );
}
/**
* Class Health_Check_Updates
*/
class Health_Check_Updates {
private $plugins_before;
private $plugins_after;
private static $plugins_blocked;
private $themes_before;
private $themes_after;
private static $themes_blocked;
/**
* Health_Check_Updates constructor.
*
* @uses Health_Check_Updates::init()
*
* @return void
*/
public function __construct() {
$this->init();
}
/**
* Initiate the plugin class.
*
* @return void
*/
public function init() {
$this->plugins_before = (array) array();
$this->plugins_after = (array) array();
self::$plugins_blocked = (bool) false;
$this->themes_before = (array) array();
$this->themes_after = (array) array();
self::$themes_blocked = (bool) false;
}
/**
* Run tests to determine if auto-updates can run.
*
* @uses get_class_methods()
* @uses substr()
* @uses call_user_func()
*
* @return array
*/
public function run_tests() {
$tests = array();
foreach ( get_class_methods( $this ) as $method ) {
if ( 'test_' !== substr( $method, 0, 5 ) ) {
continue;
}
$result = call_user_func( array( $this, $method ) );
if ( false === $result || null === $result ) {
continue;
}
$result = (object) $result;
if ( empty( $result->severity ) ) {
$result->severity = 'warning';
}
$tests[ $method ] = $result;
}
return $tests;
}
/**
* Check if plugin updates have been tampered with.
*
* @uses Health_Check_Updates::check_plugin_update_hooks()
* @uses esc_html__()
* @uses Health_Check_Updates::check_plugin_update_pre_request()
* @uses Health_Check_Updates::check_plugin_update_request_args()
*
* @return array
*/
function test_plugin_updates() {
// Check if any update hooks have been removed.
$hooks = $this->check_plugin_update_hooks();
if ( ! $hooks ) {
return array(
'desc' => esc_html__( 'Plugin update hooks have been removed.', 'health-check' ),
'severity' => 'fail',
);
}
// Check if update requests are being blocked.
$blocked = $this->check_plugin_update_pre_request();
if ( true === $blocked ) {
return array(
'desc' => esc_html__( 'Plugin update requests have been blocked.', 'health-check' ),
'severity' => 'fail',
);
}
// Check if plugins have been removed from the update requests.
$diff = (array) $this->check_plugin_update_request_args();
if ( 0 !== count( $diff ) ) {
return array(
'desc' => sprintf(
/* translators: %s: List of plugin names. */
esc_html__( 'The following Plugins have been removed from update checks: %s.', 'health-check' ),
implode( ',', $diff )
),
'severity' => 'warning',
);
}
return array(
'desc' => esc_html__( 'Plugin updates should be working as expected.', 'health-check' ),
'severity' => 'pass',
);
}
/**
* Check if any plugin update hooks have been removed.
*
* @uses has_filter()
* @uses wp_next_scheduled()
*
* @return array
*/
function check_plugin_update_hooks() {
$test1 = has_filter( 'load-plugins.php', 'wp_update_plugins' );
$test2 = has_filter( 'load-update.php', 'wp_update_plugins' );
$test3 = has_filter( 'load-update-core.php', 'wp_update_plugins' );
$test4 = has_filter( 'wp_update_plugins', 'wp_update_plugins' );
$test5 = has_filter( 'admin_init', '_maybe_update_plugins' );
$test6 = wp_next_scheduled( 'wp_update_plugins' );
return $test1 && $test2 && $test3 && $test4 && $test5 && $test6;
}
/**
* Check if plugin update request checks are being tampered with at the 'pre_http_request' filter.
*
* @uses add_action()
* @uses Health_Check_Updates::wp_plugin_update_fake_request()
* @uses esc_html__()
*
* @return array
*/
function check_plugin_update_pre_request() {
add_action( 'pre_http_request', array( $this, 'plugin_pre_request_check' ), PHP_INT_MAX, 3 );
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
$this->plugin_update_fake_request();
remove_action( 'pre_http_request', array( $this, 'plugin_pre_request_check' ), PHP_INT_MAX );
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
return self::$plugins_blocked;
}
/**
* Check plugin update requests to see if they are being blocked.
*
* @param bool $pre If not false, request cancelled.
* @param array $r Request parameters.
* @param string $url Request URL.
* @return bool
*/
function plugin_pre_request_check( $pre, $r, $url ) {
$check_url = 'api.wordpress.org/plugins/update-check/1.1/';
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
return $pre; // Not a plugin update request.
}
// If not false something is blocking update checks
if ( false !== $pre ) {
self::$plugins_blocked = (bool) true;
}
return $pre;
}
/**
* Check if plugins are being removed at the 'http_request_args' filter.
*
* @uses add_action()
* @uses Health_Check_Updates::wp_plugin_update_fake_request()
* @uses remove_action()
*
* @return array
*/
function check_plugin_update_request_args() {
add_action( 'http_request_args', array( $this, 'plugin_request_args_before' ), 1, 2 );
add_action( 'http_request_args', array( $this, 'plugin_request_args_after' ), PHP_INT_MAX, 2 );
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
$this->plugin_update_fake_request();
remove_action( 'http_request_args', array( $this, 'plugin_request_args_before' ), 1 );
remove_action( 'http_request_args', array( $this, 'plugin_request_args_after' ), PHP_INT_MAX );
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
$diff = array_diff_key( $this->plugins_before['plugins'], $this->plugins_after['plugins'] );
$titles = array();
foreach ( $diff as $item ) {
$titles[] = $item['Title'];
}
return $titles;
}
/**
* Record the list of plugins from plugin update requests at the start of filtering.
*
* @param array $r Request parameters.
* @param string $url Request URL.
* @return array
*/
function plugin_request_args_before( $r, $url ) {
$check_url = 'api.wordpress.org/plugins/update-check/1.1/';
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
return $r; // Not a plugin update request.
}
$this->plugins_before = (array) json_decode( $r['body']['plugins'], true );
return $r;
}
/**
* Record the list of plugins from plugin update requests at the end of filtering.
*
* @param array $r Request parameters.
* @param string $url Request URL.
* @return array
*/
function plugin_request_args_after( $r, $url ) {
$check_url = 'api.wordpress.org/plugins/update-check/1.1/';
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
return $r; // Not a plugin update request.
}
$this->plugins_after = (array) json_decode( $r['body']['plugins'], true );
return $r;
}
/**
* Create and trigger a fake plugin update check request.
*
* @uses get_plugins()
* @uses get_option()
* @uses wp_get_installed_translations()
* @uses apply_filters()
* @uses wp_json_encode()
* @uses get_bloginfo()
* @uses home_url()
* @uses wp_http_supports()
* @uses set_url_scheme()
* @uses wp_remote_post()
*
* @return void
*/
function plugin_update_fake_request() {
if ( ! function_exists( 'get_plugins' ) ) {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
// Prepare data for the request.
$plugins = get_plugins();
$active = get_option( 'active_plugins', array() );
$to_send = compact( 'plugins', 'active' );
$translations = wp_get_installed_translations( 'plugins' );
$locales = array_values( get_available_languages() );
$locales = (array) apply_filters( 'plugins_update_check_locales', $locales );
$locales = array_unique( $locales );
$timeout = 3 + (int) ( count( $plugins ) / 10 );
// Setup the request options.
if ( function_exists( 'wp_json_encode' ) ) {
$options = array(
'timeout' => $timeout,
'body' => array(
'plugins' => wp_json_encode( $to_send ),
'translations' => wp_json_encode( $translations ),
'locale' => wp_json_encode( $locales ),
'all' => wp_json_encode( true ),
),
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
);
} else {
$options = array(
'timeout' => $timeout,
'body' => array(
'plugins' => json_encode( $to_send ),
'translations' => json_encode( $translations ),
'locale' => json_encode( $locales ),
'all' => json_encode( true ),
),
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
);
}
// Set the URL
$http_url = 'http://api.wordpress.org/plugins/update-check/1.1/';
$url = wp_http_supports( array( 'ssl' ) ) ? set_url_scheme( $http_url, 'https' ) : $http_url;
// Ignore the response. Just need the hooks to fire.
wp_remote_post( $url, $options );
}
/**
* Check if theme updates have been tampered with.
*
* @uses Health_Check_Updates::check_theme_update_hooks()
* @uses esc_html__()
* @uses Health_Check_Updates::check_theme_update_pre_request()
* @uses Health_Check_Updates::check_theme_update_request_args()
*
* @return array
*/
function test_constant_theme_updates() {
// Check if any update hooks have been removed.
$hooks = $this->check_theme_update_hooks();
if ( ! $hooks ) {
return array(
'desc' => esc_html__( 'Theme update hooks have been removed.', 'health-check' ),
'severity' => 'fail',
);
}
// Check if update requests are being blocked.
$blocked = $this->check_theme_update_pre_request();
if ( true === $blocked ) {
return array(
'desc' => esc_html__( 'Theme update requests have been blocked.', 'health-check' ),
'severity' => 'fail',
);
}
// Check if themes have been removed from the update requests.
$diff = (array) $this->check_theme_update_request_args();
if ( 0 !== count( $diff ) ) {
return array(
'desc' => sprintf(
/* translators: %s: List of theme names. */
esc_html__( 'The following Themes have been removed from update checks: %s.', 'health-check' ),
implode( ',', $diff )
),
'severity' => 'warning',
);
}
return array(
'desc' => esc_html__( 'Theme updates should be working as expected.', 'health-check' ),
'severity' => 'pass',
);
}
/**
* Check if any theme update hooks have been removed.
*
* @uses has_filter()
* @uses wp_next_scheduled()
*
* @return array
*/
function check_theme_update_hooks() {
$test1 = has_filter( 'load-themes.php', 'wp_update_themes' );
$test2 = has_filter( 'load-update.php', 'wp_update_themes' );
$test3 = has_filter( 'load-update-core.php', 'wp_update_themes' );
$test4 = has_filter( 'wp_update_themes', 'wp_update_themes' );
$test5 = has_filter( 'admin_init', '_maybe_update_themes' );
$test6 = wp_next_scheduled( 'wp_update_themes' );
return $test1 && $test2 && $test3 && $test4 && $test5 && $test6;
}
/**
* Check if theme update request checks are being tampered with at the 'pre_http_request' filter.
*
* @uses add_action()
* @uses Health_Check_Updates::wp_theme_update_fake_request()
* @uses esc_html__()
*
* @return array
*/
function check_theme_update_pre_request() {
add_action( 'pre_http_request', array( $this, 'theme_pre_request_check' ), PHP_INT_MAX, 3 );
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
$this->theme_update_fake_request();
remove_action( 'pre_http_request', array( $this, 'theme_pre_request_check' ), PHP_INT_MAX );
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
return self::$themes_blocked;
}
/**
* Check theme update requests to see if they are being blocked.
*
* @param bool $pre If not false, request cancelled.
* @param array $r Request parameters.
* @param string $url Request URL.
* @return bool
*/
function theme_pre_request_check( $pre, $r, $url ) {
$check_url = 'api.wordpress.org/themes/update-check/1.1/';
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
return $pre; // Not a theme update request.
}
// If not false something is blocking update checks
if ( false !== $pre ) {
self::$themes_blocked = (bool) true;
}
return $pre;
}
/**
* Check if themes are being removed at the 'http_request_args' filter.
*
* @uses add_action()
* @uses Health_Check_Updates::wp_theme_update_fake_request()
* @uses remove_action()
*
* @return array
*/
function check_theme_update_request_args() {
add_action( 'http_request_args', array( $this, 'theme_request_args_before' ), 1, 2 );
add_action( 'http_request_args', array( $this, 'theme_request_args_after' ), PHP_INT_MAX, 2 );
add_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX, 3 );
$this->theme_update_fake_request();
remove_action( 'http_request_args', array( $this, 'theme_request_args_before' ), 1 );
remove_action( 'http_request_args', array( $this, 'theme_request_args_after' ), PHP_INT_MAX );
remove_action( 'pre_http_request', array( $this, 'block_fake_request' ), PHP_INT_MAX );
$diff = array_diff_key( $this->themes_before['themes'], $this->themes_after['themes'] );
$titles = array();
foreach ( $diff as $item ) {
$titles[] = $item['Title'];
}
return $titles;
}
/**
* Record the list of themes from theme update requests at the start of filtering.
*
* @param array $r Request parameters.
* @param string $url Request URL.
* @return array
*/
function theme_request_args_before( $r, $url ) {
$check_url = 'api.wordpress.org/themes/update-check/1.1/';
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
return $r; // Not a theme update request.
}
$this->themes_before = (array) json_decode( $r['body']['themes'], true );
return $r;
}
/**
* Record the list of themes from theme update requests at the end of filtering.
*
* @param array $r Request parameters.
* @param string $url Request URL.
* @return array
*/
function theme_request_args_after( $r, $url ) {
$check_url = 'api.wordpress.org/themes/update-check/1.1/';
if ( 0 !== substr_compare( $url, $check_url, -strlen( $check_url ) ) ) {
return $r; // Not a theme update request.
}
$this->themes_after = (array) json_decode( $r['body']['themes'], true );
return $r;
}
/**
* Create and trigger a fake theme update check request.
*
* @uses wp_get_themes()
* @uses wp_get_installed_translations()
* @uses get_option()
* @uses get_available_languages()
* @uses wp_json_encode()
* @uses get_bloginfo()
* @uses home_url()
* @uses wp_http_supports()
* @uses set_url_scheme()
* @uses wp_remote_post()
*
* @return void
*/
function theme_update_fake_request() {
$themes = array();
$checked = array();
$request = array();
$installed_themes = wp_get_themes();
$translations = wp_get_installed_translations( 'themes' );
$request['active'] = get_option( 'stylesheet' );
foreach ( $installed_themes as $theme ) {
$checked[ $theme->get_stylesheet() ] = $theme->get( 'Version' );
$themes[ $theme->get_stylesheet() ] = array(
'Name' => $theme->get( 'Name' ),
'Title' => $theme->get( 'Name' ),
'Version' => $theme->get( 'Version' ),
'Author' => $theme->get( 'Author' ),
'Author URI' => $theme->get( 'AuthorURI' ),
'Template' => $theme->get_template(),
'Stylesheet' => $theme->get_stylesheet(),
);
}
$request['themes'] = $themes;
$locales = array_values( get_available_languages() );
$timeout = 3 + (int) ( count( $themes ) / 10 );
if ( function_exists( 'wp_json_encode' ) ) {
$options = array(
'timeout' => $timeout,
'body' => array(
'themes' => wp_json_encode( $request ),
'translations' => wp_json_encode( $translations ),
'locale' => wp_json_encode( $locales ),
),
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
);
} else {
$options = array(
'timeout' => $timeout,
'body' => array(
'themes' => json_encode( $request ),
'translations' => json_encode( $translations ),
'locale' => json_encode( $locales ),
),
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
);
}
// Set the URL
$http_url = 'http://api.wordpress.org/themes/update-check/1.1/';
$url = wp_http_supports( array( 'ssl' ) ) ? set_url_scheme( $http_url, 'https' ) : $http_url;
// Ignore the response. Just need the hooks to fire.
wp_remote_post( $url, $options );
}
/**
* Blocks the fake update requests, ensuring they do not slow down page loads.
*
* @param bool $pre If not false, request cancelled.
* @param array $r Request parameters.
* @param string $url Request URL.
* @return bool
*/
function block_fake_request( $pre, $r, $url ) {
switch ( $url ) {
case 'https://api.wordpress.org/plugins/update-check/1.1/':
return 'block_request';
case 'https://api.wordpress.org/themes/update-check/1.1/':
return 'block_request';
default:
return $pre;
}
}
}