WP_Site_Health::get_test_php_extensions()publicWP 5.2.0

Tests if required PHP modules are installed on the host.

This test builds on the recommendations made by the WordPress Hosting Team as seen at https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions

Method of the class: WP_Site_Health{}

Hooks from the method

Return

Array.

Usage

$WP_Site_Health = new WP_Site_Health();
$WP_Site_Health->get_test_php_extensions();

Changelog

Since 5.2.0 Introduced.

WP_Site_Health::get_test_php_extensions() code WP 6.6.2

public function get_test_php_extensions() {
	$result = array(
		'label'       => __( 'Required and recommended modules are installed' ),
		'status'      => 'good',
		'badge'       => array(
			'label' => __( 'Performance' ),
			'color' => 'blue',
		),
		'description' => sprintf(
			'<p>%s</p><p>%s</p>',
			__( 'PHP modules perform most of the tasks on the server that make your site run. Any changes to these must be made by your server administrator.' ),
			sprintf(
				/* translators: 1: Link to the hosting group page about recommended PHP modules. 2: Additional link attributes. 3: Accessibility text. */
				__( 'The WordPress Hosting Team maintains a list of those modules, both recommended and required, in <a href="%1$s" %2$s>the team handbook%3$s</a>.' ),
				/* translators: Localized team handbook, if one exists. */
				esc_url( __( 'https://make.wordpress.org/hosting/handbook/handbook/server-environment/#php-extensions' ) ),
				'target="_blank" rel="noopener"',
				sprintf(
					'<span class="screen-reader-text"> %s</span><span aria-hidden="true" class="dashicons dashicons-external"></span>',
					/* translators: Hidden accessibility text. */
					__( '(opens in a new tab)' )
				)
			)
		),
		'actions'     => '',
		'test'        => 'php_extensions',
	);

	$modules = array(
		'curl'      => array(
			'function' => 'curl_version',
			'required' => false,
		),
		'dom'       => array(
			'class'    => 'DOMNode',
			'required' => false,
		),
		'exif'      => array(
			'function' => 'exif_read_data',
			'required' => false,
		),
		'fileinfo'  => array(
			'function' => 'finfo_file',
			'required' => false,
		),
		'hash'      => array(
			'function' => 'hash',
			'required' => false,
		),
		'imagick'   => array(
			'extension' => 'imagick',
			'required'  => false,
		),
		'json'      => array(
			'function' => 'json_last_error',
			'required' => true,
		),
		'mbstring'  => array(
			'function' => 'mb_check_encoding',
			'required' => false,
		),
		'mysqli'    => array(
			'function' => 'mysqli_connect',
			'required' => false,
		),
		'libsodium' => array(
			'constant'            => 'SODIUM_LIBRARY_VERSION',
			'required'            => false,
			'php_bundled_version' => '7.2.0',
		),
		'openssl'   => array(
			'function' => 'openssl_encrypt',
			'required' => false,
		),
		'pcre'      => array(
			'function' => 'preg_match',
			'required' => false,
		),
		'mod_xml'   => array(
			'extension' => 'libxml',
			'required'  => false,
		),
		'zip'       => array(
			'class'    => 'ZipArchive',
			'required' => false,
		),
		'filter'    => array(
			'function' => 'filter_list',
			'required' => false,
		),
		'gd'        => array(
			'extension'    => 'gd',
			'required'     => false,
			'fallback_for' => 'imagick',
		),
		'iconv'     => array(
			'function' => 'iconv',
			'required' => false,
		),
		'intl'      => array(
			'extension' => 'intl',
			'required'  => false,
		),
		'mcrypt'    => array(
			'extension'    => 'mcrypt',
			'required'     => false,
			'fallback_for' => 'libsodium',
		),
		'simplexml' => array(
			'extension'    => 'simplexml',
			'required'     => false,
			'fallback_for' => 'mod_xml',
		),
		'xmlreader' => array(
			'extension'    => 'xmlreader',
			'required'     => false,
			'fallback_for' => 'mod_xml',
		),
		'zlib'      => array(
			'extension'    => 'zlib',
			'required'     => false,
			'fallback_for' => 'zip',
		),
	);

	/**
	 * Filters the array representing all the modules we wish to test for.
	 *
	 * @since 5.2.0
	 * @since 5.3.0 The `$constant` and `$class` parameters were added.
	 *
	 * @param array $modules {
	 *     An associative array of modules to test for.
	 *
	 *     @type array ...$0 {
	 *         An associative array of module properties used during testing.
	 *         One of either `$function` or `$extension` must be provided, or they will fail by default.
	 *
	 *         @type string $function     Optional. A function name to test for the existence of.
	 *         @type string $extension    Optional. An extension to check if is loaded in PHP.
	 *         @type string $constant     Optional. A constant name to check for to verify an extension exists.
	 *         @type string $class        Optional. A class name to check for to verify an extension exists.
	 *         @type bool   $required     Is this a required feature or not.
	 *         @type string $fallback_for Optional. The module this module replaces as a fallback.
	 *     }
	 * }
	 */
	$modules = apply_filters( 'site_status_test_php_modules', $modules );

	$failures = array();

	foreach ( $modules as $library => $module ) {
		$extension_name = ( isset( $module['extension'] ) ? $module['extension'] : null );
		$function_name  = ( isset( $module['function'] ) ? $module['function'] : null );
		$constant_name  = ( isset( $module['constant'] ) ? $module['constant'] : null );
		$class_name     = ( isset( $module['class'] ) ? $module['class'] : null );

		// If this module is a fallback for another function, check if that other function passed.
		if ( isset( $module['fallback_for'] ) ) {
			/*
			 * If that other function has a failure, mark this module as required for usual operations.
			 * If that other function hasn't failed, skip this test as it's only a fallback.
			 */
			if ( isset( $failures[ $module['fallback_for'] ] ) ) {
				$module['required'] = true;
			} else {
				continue;
			}
		}

		if ( ! $this->test_php_extension_availability( $extension_name, $function_name, $constant_name, $class_name )
			&& ( ! isset( $module['php_bundled_version'] )
				|| version_compare( PHP_VERSION, $module['php_bundled_version'], '<' ) )
		) {
			if ( $module['required'] ) {
				$result['status'] = 'critical';

				$class = 'error';
				/* translators: Hidden accessibility text. */
				$screen_reader = __( 'Error' );
				$message       = sprintf(
					/* translators: %s: The module name. */
					__( 'The required module, %s, is not installed, or has been disabled.' ),
					$library
				);
			} else {
				$class = 'warning';
				/* translators: Hidden accessibility text. */
				$screen_reader = __( 'Warning' );
				$message       = sprintf(
					/* translators: %s: The module name. */
					__( 'The optional module, %s, is not installed, or has been disabled.' ),
					$library
				);
			}

			if ( ! $module['required'] && 'good' === $result['status'] ) {
				$result['status'] = 'recommended';
			}

			$failures[ $library ] = "<span class='dashicons $class'><span class='screen-reader-text'>$screen_reader</span></span> $message";
		}
	}

	if ( ! empty( $failures ) ) {
		$output = '<ul>';

		foreach ( $failures as $failure ) {
			$output .= sprintf(
				'<li>%s</li>',
				$failure
			);
		}

		$output .= '</ul>';
	}

	if ( 'good' !== $result['status'] ) {
		if ( 'recommended' === $result['status'] ) {
			$result['label'] = __( 'One or more recommended modules are missing' );
		}
		if ( 'critical' === $result['status'] ) {
			$result['label'] = __( 'One or more required modules are missing' );
		}

		$result['description'] .= $output;
	}

	return $result;
}