Index: src/wp-admin/info.php
===================================================================
--- src/wp-admin/info.php	(nonexistent)
+++ src/wp-admin/info.php	(working copy)
@@ -0,0 +1,232 @@
+<?php
+/**
+ * Get system status for debugging and support.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( dirname( __FILE__ ) . '/admin.php' );
+
+if ( ! is_super_admin() ) {
+	wp_die( __( 'Sorry, you do not have permission to access this page.' ) );
+}
+
+global $wpdb;
+
+$title = __( 'System information' );
+
+require_once( ABSPATH . 'wp-admin/admin-header.php' );
+
+$info = array(
+	'WordPress'        => array(
+		'fields'      => array(
+			'Version'                      => get_bloginfo( 'version' ),
+			'Debug mode'                   => ( defined( 'WP_DEBUG' ) && WP_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ) ),
+			'Language'                     => get_locale(),
+			'Home URL'                     => get_bloginfo( 'url' ),
+			'Site URL'                     => get_bloginfo( 'wpurl' ),
+			'HTTPS'                        => ( is_ssl() ? __( 'Enabled' ) : __( 'Disabled' ) ),
+			'Theme directory is writable'  => ( wp_is_writable( TEMPLATEPATH . '/..' ) ? __( 'Yes' ) : __( 'No' ) ),
+			'Plugin directory is writable' => ( wp_is_writable( WP_PLUGIN_DIR ) ? __( 'Yes' ) : __( 'No' ) ),
+			'WordPress memory limit'       => WP_MAX_MEMORY_LIMIT,
+			'Multisite'                    => ( is_multisite() ? __( 'Yes' ) : __( 'No' ) ),
+		),
+	),
+	'Active theme'     => array(),
+	'Other themes'     => array(),
+	'Must Use Plugins' => array(),
+	'Plugins'          => array(),
+	'Server'           => array(
+		'description' => __( 'The options shown below are relating to your server setup, and may require the help of your host if changes are required.' ),
+		'fields'      => array()
+	),
+	'Database'         => array(
+		'fields'      => array()
+	)
+);
+
+if ( is_multisite() ) {
+	$network_query = new WP_Network_Query();
+	$network_ids = $network_query->query( array(
+		'fields'        => 'ids',
+		'number'        => 100,
+		'no_found_rows' => false,
+	) );
+
+	$site_count = 0;
+	foreach ( $network_ids as $network_id ) {
+		$site_count += get_blog_count( $network_id );
+	}
+
+	$info['WordPress']['fields']['User Count'] = get_user_count();
+	$info['WordPress']['fields']['Site Count'] = $site_count;
+	$info['WordPress']['fields']['Network Count'] = $network_query->found_networks;
+} else {
+	$user_count = count_users();
+
+	$info['WordPress']['fields']['User Count'] = $user_count['total_users'];
+}
+
+// Populate the server debug fields
+$info['Server']['fields']['PHP Version'] = phpversion();
+$info['Server']['fields']['PHP SAPI'] = php_sapi_name();
+$info['Server']['fields']['PHP post max size'] = ini_get( 'post_max_size' );
+$info['Server']['fields']['PHP time limit'] = ini_get( 'max_execution_time' );
+$info['Server']['fields']['PHP memory limit'] = ini_get( 'memory_limit' );
+
+$cURL = curl_version();
+$info['Server']['fields']['cURL Version'] = sprintf( '%s %s', $cURL['version'], $cURL['ssl_version'] );
+
+$info['Server']['fields']['SUHOSIN installed'] = ( ( extension_loaded('suhosin') || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) ) ? __( 'Yes' ) : __( 'No' ) );
+
+
+// Populate the database debug fields.
+if ( is_resource( $wpdb->dbh ) ) {
+	# Old mysql extension
+	$extension = 'mysql';
+} else if ( is_object( $wpdb->dbh ) ) {
+	# mysqli or PDO
+	$extension = get_class( $wpdb->dbh );
+} else {
+	# Who knows?
+	$extension = null;
+}
+
+if ( method_exists( $wpdb, 'db_version' ) ) {
+	$server = $wpdb->db_version();
+} else {
+	$server = null;
+}
+
+if ( isset( $wpdb->use_mysqli ) && $wpdb->use_mysqli ) {
+	$client_version = mysqli_get_client_version();
+} else {
+	if ( preg_match( '|[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{1,2}|', mysql_get_client_info(), $matches ) ) {
+		$client_version = $matches[0];
+	} else {
+		$client_version = null;
+	}
+}
+
+$info['Database']['fields']['Extension'] = $extension;
+$info['Database']['fields']['Server version'] = $server;
+$info['Database']['fields']['Client version'] = $client_version;
+$info['Database']['fields']['Database user'] = $wpdb->dbuser;
+$info['Database']['fields']['Database host'] = $wpdb->dbhost;
+$info['Database']['fields']['Database table'] = $wpdb->dbname;
+$info['Database']['fields']['Database prefix'] = $wpdb->prefix;
+
+
+// List must use plugins if there are any
+$mu_plugins = get_mu_plugins();
+
+foreach ( $mu_plugins AS $plugin_path => $plugin ) {
+	$info['Must Use Plugins']['fields'][ $plugin['Name'] ] = sprintf( 'version %s by %s', $plugin['Version'], $plugin['Author'] );
+}
+
+
+// List all available plugins
+$plugins = get_plugins();
+
+foreach ( $plugins AS $plugin_path => $plugin ) {
+	$info['Plugins']['fields'][ $plugin['Name'] ] = sprintf( '%s - version %s by %s', ( is_plugin_active( $plugin_path ) ? __( 'Enabled' ) : __( 'Disabled' ) ), $plugin['Version'], $plugin['Author'] );
+}
+
+
+// Populate the section for the currently active theme
+$theme = wp_get_theme();
+$info['Active theme']['fields'] = array(
+	'Name'         => $theme->Name,
+	'Version'      => $theme->Version,
+	'Author'       => wp_kses( $theme->Author, array() ),
+	'Author URL'   => $theme->AuthorURI,
+	'Parent theme' => ( $theme->parent_Theme ?: 'Not a child theme' ),
+);
+
+
+// Populate a list of all themes available in the install
+$all_themes = wp_get_themes();
+
+foreach ( $all_themes AS $theme_slug => $theme ) {
+	$info['Other themes']['fields'][ sprintf( '%s (%s)', $theme->Name, $theme_slug ) ] = sprintf( 'version %s by %s', $theme->Version, wp_kses( $theme->Author, array() ) );
+}
+
+
+
+/**
+ * Add or modify new debug sections.
+ *
+ * Plugin or themes may wish to introduce their own debug information without creating additional admin pages for this
+ * kind of information as it is rarely needed, they can then utilize this filter to introduce their own sections.
+ *
+ * This filter intentionally does not include the fields introduced by core as those should always be un-modified
+ * and reliable for support related scenarios.
+ *
+ * @since 4.9.0
+ *
+ * @param array $args {
+ *     The debug information to be added to the core information page.
+ *
+ *     @type string $description Optional. A description for your information section which may contain basic HTML
+ *                               markup: `em`, `strong` and `a` for linking to documentation or putting emphasis.
+ *     @type array  $fields      {
+ *         An associative array containing the data to be displayed, using a label as the key.
+ *
+ *         @type string $information The details to be disclosed for this field.
+ *     }
+ * }
+ */
+$external_info = apply_filters( 'debug_information', array() );
+
+// Merge the core and external debug fields
+$info = array_merge( $info, $external_info );
+?>
+
+<div class="wrap">
+	<h1 class="wp-heading-inline">
+		<?php echo esc_html( $title ); ?>
+	</h1>
+
+	<?php
+	foreach ( $info AS $section => $details ) {
+		if ( ! isset( $details['fields'] ) || empty( $details['fields'] ) ) {
+			continue;
+		}
+
+		printf(
+			'<h2>%s</h2>',
+			esc_html( $section )
+		);
+
+		if ( isset( $details['description'] ) && ! empty( $details['description'] ) ) {
+			printf(
+				'<p>%s</p>',
+				wp_kses( $details['description'], array(
+					'a' => array(
+						'href' => true
+					),
+					'strong' => true,
+					'em' => true,
+				) )
+			);
+		}
+		?>
+		<table class="widefat">
+			<tbody>
+			<?php
+			foreach ( $details['fields'] AS $field_name => $field_value ) {
+				printf(
+					'<tr><td>%s</td><td>%s</td></tr>',
+					esc_html( $field_name ),
+					esc_html( $field_value )
+				);
+			}
+			?>
+			</tbody>
+		</table>
+		<?php
+	}
+
+	include( ABSPATH . 'wp-admin/admin-footer.php' );
