WP_Site_Health::get_test_php_extensions(): array

In this article

Tests if required PHP modules are installed on the host.

Description

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

Return

array

Source

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;
}

Hooks

apply_filters( ‘site_status_test_php_modules’, array $modules )

Filters the array representing all the modules we wish to test for.

Changelog

VersionDescription
5.2.0Introduced.

User Contributed Notes

You must log in before being able to contribute a note or feedback.