Index: src/wp-admin/info.php
===================================================================
--- src/wp-admin/info.php	(revision )
+++ src/wp-admin/info.php	(revision )
@@ -0,0 +1,485 @@
+<?php
+/**
+ * Get system status for debugging and support.
+ *
+ * @package WordPress
+ * @subpackage Administration
+ */
+
+/** WordPress Administration Bootstrap */
+require_once( dirname( __FILE__ ) . '/admin.php' );
+
+if ( ! current_user_can( 'update_core' ) ) {
+	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(
+	'wp-core'             => array(
+		'label'  => __( 'WordPress' ),
+		'fields' => array(
+			array(
+				'label' => __( 'Version' ),
+				'value' => get_bloginfo( 'version' )
+			),
+			array(
+				'label' => __( 'Language' ),
+				'value' => get_locale()
+			),
+			array(
+				'label'   => __( 'Home URL' ),
+				'value'   => get_bloginfo( 'url' ),
+				'private' => true
+			),
+			array(
+				'label'   => __( 'Site URL' ),
+				'value'   => get_bloginfo( 'wpurl' ),
+				'private' => true
+			),
+			array(
+				'label' => __( 'Is this site using HTTPS' ),
+				'value' => ( is_ssl() ? __( 'Enabled' ) : __( 'Disabled' ) )
+			),
+			array(
+				'label' => __( 'Is the theme directory writable' ),
+				'value' => ( wp_is_writable( TEMPLATEPATH . '/..' ) ? __( 'Yes' ) : __( 'No' ) )
+			),
+			array(
+				'label' => __( 'Is the plugin directory writable' ),
+				'value' => ( wp_is_writable( WP_PLUGIN_DIR ) ? __( 'Yes' ) : __( 'No' ) )
+			),
+			array(
+				'label' => __( 'WordPress memory limit' ),
+				'value' => WP_MAX_MEMORY_LIMIT
+			),
+			array(
+				'label' => __( 'Is this a multisite' ),
+				'value' => ( is_multisite() ? __( 'Yes' ) : __( 'No' ) )
+			)
+		),
+	),
+	'wp-active-theme'     => array(
+		'label'  => __( 'Active theme' ),
+		'fields' => array()
+	),
+	'wp-themes'           => array(
+		'label'      => __( 'Other themes' ),
+		'show_count' => true,
+		'fields'     => array()
+	),
+	'wp-mu-plugins'       => array(
+		'label'      => __( 'Must User Plugins' ),
+		'show_count' => true,
+		'fields'     => array()
+	),
+	'wp-plugins-active'   => array(
+		'label'      => __( 'Active Plugins' ),
+		'show_count' => true,
+		'fields'     => array()
+	),
+	'wp-plugins-inactive' => array(
+		'label'      => __( 'Inactive Plugins' ),
+		'show_count' => true,
+		'fields'     => array()
+	),
+	'wp-server'           => array(
+		'label'       => 'Server',
+		'description' => __( 'The options shown below relate to your server setup. If changes are required, you may need your web host\'s assistance.' ),
+		'fields'      => array()
+	),
+	'wp-database'         => array(
+		'label'  => __( 'Database' ),
+		'fields' => array()
+	),
+	'wp-constants'        => array(
+		'label'       => __( 'WordPress constants' ),
+		'description' => __( 'These values represent values set in your websites code which affect WordPress in various ways that may be of importance when seeking help with your site.' ),
+		'fields'      => array(
+			array(
+				'label' => 'WP_DEBUG',
+				'value' => ( ! defined( 'WP_DEBUG' ) ? __( 'Not defined' ) : ( WP_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'WP_DEBUG_DISPLAY',
+				'value' => ( ! defined( 'WP_DEBUG_DISPLAY' ) ? __( 'Not defined' ) : ( WP_DEBUG_DISPLAY ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'WP_DEBUG_LOG',
+				'value' => ( ! defined( 'WP_DEBUG_LOG' ) ? __( 'Not defined' ) : ( WP_DEBUG_LOG ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'SCRIPT_DEBUG',
+				'value' => ( ! defined( 'SCRIPT_DEBUG' ) ? __( 'Not defined' ) : ( SCRIPT_DEBUG ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'WP_CACHE',
+				'value' => ( ! defined( 'WP_CACHE' ) ? __( 'Not defined' ) : ( WP_CACHE ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'CONCATENATE_SCRIPTS',
+				'value' => ( ! defined( 'CONCATENATE_SCRIPTS' ) ? __( 'Not defined' ) : ( CONCATENATE_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'COMPRESS_SCRIPTS',
+				'value' => ( ! defined( 'COMPRESS_SCRIPTS' ) ? __( 'Not defined' ) : ( COMPRESS_SCRIPTS ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'COMPRESS_CSS',
+				'value' => ( ! defined( 'COMPRESS_CSS' ) ? __( 'Not defined' ) : ( COMPRESS_CSS ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			),
+			array(
+				'label' => 'WP_LOCAL_DEV',
+				'value' => ( ! defined( 'WP_LOCAL_DEV' ) ? __( 'Not defined' ) : ( WP_LOCAL_DEV ? __( 'Enabled' ) : __( 'Disabled' ) ) )
+			)
+		)
+	)
+);
+
+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['wp-core']['fields'][] = array(
+		'label' => __( 'User Count' ),
+		'value' => get_user_count()
+	);
+	$info['wp-core']['fields'][] = array(
+		'label' => __( 'Site Count' ),
+		'value' => $site_count
+	);
+	$info['wp-core']['fields'][] = array(
+		'label' => __( 'Network Count' ),
+		'value' => $network_query->found_networks
+	);
+} else {
+	$user_count = count_users();
+
+	$info['wp-core']['fields'][] = array(
+		'label' => __( 'User Count' ),
+		'value' => $user_count['total_users']
+	);
+}
+
+// Populate the server debug fields
+$info['wp-server']['fields'][] = array(
+	'label' => _( 'Server architecture' ),
+	'value' => ( ! function_exists( 'php_uname' ) ? __( 'Unable to determine architecture' ) : php_uname( 'm' ) )
+);
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'PHP Version' ),
+	'value' => phpversion()
+);
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'PHP SAPI' ),
+	'value' => php_sapi_name()
+);
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'PHP max input variables' ),
+	'value' => ini_get( 'max_input_vars' )
+);
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'PHP time limit' ),
+	'value' => ini_get( 'max_execution_time' )
+);
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'PHP memory limit' ),
+	'value' => ini_get( 'memory_limit' )
+);
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'Upload max filesize' ),
+	'value' => ini_get( 'upload_max_filesize' )
+);
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'PHP post max size' ),
+	'value' => ini_get( 'post_max_size' )
+);
+
+$cURL                          = curl_version();
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'cURL Version' ),
+	'value' => sprintf( '%s %s', $cURL['version'], $cURL['ssl_version'] )
+);
+
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'SUHOSIN installed' ),
+	'value' => ( ( extension_loaded( 'suhosin' ) || ( defined( 'SUHOSIN_PATCH' ) && constant( 'SUHOSIN_PATCH' ) ) ) ? __( 'Yes' ) : __( 'No' ) )
+);
+
+$info['wp-server']['fields'][] = array(
+	'label' => __( 'Is the Imagick library available' ),
+	'value' => ( extension_loaded( 'imagick' ) ? __( '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['wp-database']['fields'][] = array(
+	'label' => __( 'Extension' ),
+	'value' => $extension
+);
+$info['wp-database']['fields'][] = array(
+	'label' => __( 'Server version' ),
+	'value' => $server
+);
+$info['wp-database']['fields'][] = array(
+	'label' => __( 'Client version' ),
+	'value' => $client_version
+);
+$info['wp-database']['fields'][] = array(
+	'label'   => __( 'Database user' ),
+	'value'   => $wpdb->dbuser,
+	'private' => true
+);
+$info['wp-database']['fields'][] = array(
+	'label'   => __( 'Database host' ),
+	'value'   => $wpdb->dbhost,
+	'private' => true
+);
+$info['wp-database']['fields'][] = array(
+	'label'   => __( 'Database table' ),
+	'value'   => $wpdb->dbname,
+	'private' => true
+);
+$info['wp-database']['fields'][] = array(
+	'label' => __( 'Database prefix' ),
+	'value' => $wpdb->prefix
+);
+
+
+// List must use plugins if there are any
+$mu_plugins = get_mu_plugins();
+
+foreach ( $mu_plugins AS $plugin_path => $plugin ) {
+	$info['wp-mu-plugins']['fields'][] = array(
+		'label' => $plugin['Name'],
+		// translators: %1$s: Plugin version number. %2$s: Plugin author name.
+		'value' => sprintf( __( 'version %1$s by %2$s' ), $plugin['Version'], $plugin['Author'] )
+	);
+}
+
+
+// List all available plugins
+$plugins = get_plugins();
+
+foreach ( $plugins AS $plugin_path => $plugin ) {
+	$plugin_part = ( is_plugin_active( $plugin_path ) ) ? 'wp-plugins-active' : 'wp-plugins-inactive';
+
+	$info[ $plugin_part ]['fields'][] = array(
+		'label' => $plugin['Name'],
+		// translators: %1$s: Plugin version number. %2$s: Plugin author name.
+		'value' => sprintf( __( 'version %1$s by %2$s' ), $plugin['Version'], $plugin['Author'] )
+	);
+}
+
+
+// Populate the section for the currently active theme
+$theme                             = wp_get_theme();
+$info['wp-active-theme']['fields'] = array(
+	array(
+		'label' => __( 'Name' ),
+		'value' => $theme->Name
+	),
+	array(
+		'label' => __( 'Version' ),
+		'value' => $theme->Version
+	),
+	array(
+		'label' => __( 'Author' ),
+		'value' => wp_kses( $theme->Author, array() )
+	),
+	array(
+		'label' => __( 'Author website' ),
+		'value' => $theme->offsetGet( 'Author URI' )
+	),
+	array(
+		'label' => __( 'Parent theme' ),
+		'value' => ( $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['wp-themes']['fields'][] = array(
+		// translators: %1$s: Theme name. %2$s: Theme slug.
+		'label' => sprintf( '%1$s (%2$s)', $theme->Name, $theme_slug ),
+		// translators: %1$s Theme version number. %2$s: Theme author name.
+		'value' => sprintf( 'version %1$s by %2$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, take note that the core fields will take priority if a filtered value
+ * is trying to use the same array keys.
+ *
+ * Array keys added by core are all prefixed with `wp-`, plugins and themes are encouraged to use their own slug as
+ * a prefix, both for consistency as well as avoiding key collisions.
+ *
+ * @since 4.9.0
+ *
+ * @param array $args {
+ *     The debug information to be added to the core information page.
+ *
+ *     @type string $label        The title for this section of the debug output.
+ *     @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 boolean $show_count  Options. If set to `true` the amount of fields will be included in the title for
+ *                                this section.
+ *     @type array $fields {
+ *         An associative array containing the data to be displayed.
+ *
+ *         @type string $label     The label for this piece of information.
+ *         @type string $value     The output that is of interest for this field.
+ *         @type boolean $private  Optional. If set to `true` the field will not be included in the copy-paste text area
+ *                                 on top of the page, allowing you to show, for example, API keys here.
+ *     }
+ * }
+ */
+$external_info = apply_filters( 'debug_information', array() );
+
+// Merge the core and external debug fields
+$info = array_merge( $external_info, $info );
+?>
+
+	<div class="wrap">
+		<h1 class="wp-heading-inline">
+			<?php echo esc_html( $title ); ?>
+		</h1>
+
+		<div class="notice notice-info">
+			<p>
+				<?php esc_html_e( 'The system information shown below can also be copied and pasted into support requests such as on the WordPress.org forums, or to your theme and plugin developers.' ); ?>
+			</p>
+			<p>
+				<button type="button" class="button button-primary" onclick="document.getElementById('system-information-copy-wrapper').style.display = 'block'; this.style.display = 'none';"><?php esc_html_e( 'Show copy and paste field' ); ?></button>
+
+			<div id="system-information-copy-wrapper" style="display: none;">
+				<textarea id="system-information-copy-field" class="widefat" rows="10">`
+					<?php
+					foreach ( $info as $section => $details ) {
+						if ( empty( $details['fields'] ) ) {
+							continue;
+						}
+
+						printf(
+							"### %s%S ###\n\n",
+							$details['label'],
+							( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
+						);
+
+						foreach ( $details['fields'] as $field ) {
+							if ( isset( $field['private'] ) && true === $field['private'] ) {
+								continue;
+							}
+
+							printf(
+								"%s: %s\n",
+								$field['label'],
+								$field['value']
+							);
+						}
+						echo "\n";
+					}
+					?>
+					`</textarea>
+
+				<button type="button" class="button button-primary" onclick="document.getElementById('system-information-copy-field').select();"><?php esc_html_e( 'Mark field for copying' ); ?></button>
+			</div>
+			</p>
+		</div>
+
+		<?php
+		foreach ( $info AS $section => $details ) {
+			if ( ! isset( $details['fields'] ) || empty( $details['fields'] ) ) {
+				continue;
+			}
+
+			printf(
+				'<h2>%s%s</h2>',
+				esc_html( $details['label'] ),
+				( isset( $details['show_count'] ) && $details['show_count'] ? sprintf( ' (%d)', count( $details['fields'] ) ) : '' )
+			);
+
+			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 ) {
+					printf(
+						'<tr><td>%s</td><td>%s</td></tr>',
+						esc_html( $field['label'] ),
+						esc_html( $field['value'] )
+					);
+				}
+				?>
+				</tbody>
+			</table>
+			<?php
+		}
+		?>
+
+	</div>
+
+<?php
+include( ABSPATH . 'wp-admin/admin-footer.php' );
