Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 180 additions & 16 deletions functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,175 @@ function upload_results( $results, $rev, $message, $env, $api_key ) {
return array( $status_code, $return );
}

/**
* Parse a WordPress-style database host into mysqli connection pieces.
*
* @param string $host Database host string.
*
* @return array|false Parsed connection pieces, or false on invalid input.
*/
function wpt_runner_parse_db_host( $host ) {
$host = (string) $host;
$socket = null;
$port = null;
$is_ipv6 = false;

if ( '' === $host ) {
return false;
}

$socket_pos = strpos( $host, ':/' );
if ( false !== $socket_pos ) {
$socket = substr( $host, $socket_pos + 1 );
$host = substr( $host, 0, $socket_pos );
}

if ( substr_count( $host, ':' ) > 1 ) {
if ( 1 !== preg_match( '/^(?:\[(?P<host>[0-9a-fA-F:.]+)\](?::(?P<port>[0-9]+))?|(?P<host_unbracketed>[0-9a-fA-F:.]+))$/', $host, $matches ) ) {
return false;
}
$parsed_host = ! empty( $matches['host'] ) ? $matches['host'] : ( isset( $matches['host_unbracketed'] ) ? $matches['host_unbracketed'] : '' );
$is_ipv6 = true;
} else {
if ( 1 !== preg_match( '/^(?P<host>[^:]*)(?::(?P<port>[0-9]+))?$/', $host, $matches ) ) {
return false;
}
$parsed_host = $matches['host'];
}

if ( '' === $parsed_host ) {
return false;
}

if ( isset( $matches['port'] ) && '' !== $matches['port'] ) {
$port = (int) $matches['port'];
}

return array(
'host' => $parsed_host,
'port' => $port,
'socket' => $socket,
'is_ipv6' => $is_ipv6,
);
}

/**
* Gets the database server version, if it can be detected safely.
*
* @param string $db_host Database host.
* @param string $db_user Database user.
* @param string $db_password Database password.
* @param string $db_name Database name.
*
* @return string Raw server version string, or an empty string.
*/
function wpt_runner_get_db_server_version( $db_host, $db_user, $db_password, $db_name ) {
$db_host = trim( (string) $db_host );
$db_user = trim( (string) $db_user );
$db_password = (string) $db_password;
$db_name = trim( (string) $db_name );

if ( '' === $db_host ) {
$db_host = 'localhost';
}

if ( '' === $db_user || '' === $db_name ) {
return '';
}

if ( ! class_exists( 'mysqli' ) ) {
return '';
}

$required_functions = array(
'mysqli_close',
'mysqli_fetch_row',
'mysqli_free_result',
'mysqli_init',
'mysqli_options',
'mysqli_query',
'mysqli_real_connect',
);

foreach ( $required_functions as $function_name ) {
if ( ! function_exists( $function_name ) ) {
return '';
}
}

$parsed_host = wpt_runner_parse_db_host( $db_host );
if ( false === $parsed_host ) {
return '';
}
$connect_host = $parsed_host['host'];
// mysqlnd expects IPv6 hosts in brackets, matching WordPress core's connection handling.
if ( $parsed_host['is_ipv6'] && extension_loaded( 'mysqlnd' ) ) {
$connect_host = '[' . $connect_host . ']';
}

$mysqli = null;
$mysqli_report_mode = null;

try {
if ( class_exists( 'mysqli_driver' ) ) {
$mysqli_driver = new mysqli_driver();
$mysqli_report_mode = $mysqli_driver->report_mode;
}

if ( function_exists( 'mysqli_report' ) ) {
mysqli_report( MYSQLI_REPORT_OFF );
}

$mysqli = mysqli_init();
if ( false === $mysqli ) {
return '';
}

if ( defined( 'MYSQLI_OPT_CONNECT_TIMEOUT' ) ) {
mysqli_options( $mysqli, MYSQLI_OPT_CONNECT_TIMEOUT, 5 );
}

if ( ! @mysqli_real_connect(
$mysqli,
$connect_host,
$db_user,
$db_password,
$db_name,
$parsed_host['port'],
$parsed_host['socket']
) ) {
return '';
}

$result = @mysqli_query( $mysqli, 'SELECT VERSION()' );
if ( ! is_object( $result ) ) {
return '';
}

$row = mysqli_fetch_row( $result );
mysqli_free_result( $result );

if ( ! is_array( $row ) || ! isset( $row[0] ) || '' === (string) $row[0] ) {
return '';
}

return (string) $row[0];
} catch ( Throwable $e ) {
return '';
} finally {
if ( $mysqli instanceof mysqli ) {
@mysqli_close( $mysqli );
}
if ( null !== $mysqli_report_mode && function_exists( 'mysqli_report' ) ) {
mysqli_report( $mysqli_report_mode );
}
}
}

/**
* Collects and returns an array of key environment details relevant to the application's context. This includes
* the PHP version, installed PHP modules with their versions, system utilities like curl and OpenSSL versions,
* MySQL version, and operating system details. This function is useful for diagnostic purposes, ensuring
* database server version, and operating system details. This function is useful for diagnostic purposes, ensuring
* compatibility, or for reporting system configurations in debugging or error logs.
*
* The function checks for the availability of specific PHP modules and system utilities and captures their versions.
Expand All @@ -324,12 +489,12 @@ function upload_results( $results, $rev, $message, $env, $api_key ) {
* - 'php_version': The current PHP version.
* - 'php_modules': An associative array of selected PHP modules and their versions.
* - 'system_utils': Versions of certain system utilities such as 'curl', 'imagemagick', 'graphicsmagick', and 'openssl'.
* - 'mysql_version': The version of MySQL installed.
* - 'mysql_version': The version of the database server.
* - 'os_name': The name of the operating system.
* - 'os_version': The version of the operating system.
*
* @uses phpversion() to get the PHP version and module versions.
* @uses shell_exec() to execute system commands for retrieving MySQL version, OS details, and versions of utilities like curl and OpenSSL.
* @uses shell_exec() to execute system commands for retrieving OS details and versions of utilities like curl and OpenSSL.
* @uses class_exists() to check for the availability of the Imagick and Gmagick classes for version detection.
*/
function get_env_details() {
Expand All @@ -343,12 +508,23 @@ function get_env_details() {
$imagick_info = Imagick::queryFormats();
}

$WPT_DB_HOST = trim( getenv( 'WPT_DB_HOST' ) );
if( ! $WPT_DB_HOST ) {
$WPT_DB_HOST = 'localhost';
}
$WPT_DB_USER = trim( getenv( 'WPT_DB_USER' ) );
$WPT_DB_PASSWORD = getenv( 'WPT_DB_PASSWORD' );
if( false === $WPT_DB_PASSWORD ) {
$WPT_DB_PASSWORD = '';
}
$WPT_DB_NAME = trim( getenv( 'WPT_DB_NAME' ) );

$env = array(
'php_version' => phpversion(),
'php_modules' => array(),
'gd_info' => $gd_info,
'imagick_info' => $imagick_info,
'mysql_version' => trim( shell_exec( 'mysql --version' ) ),
'mysql_version' => wpt_runner_get_db_server_version( $WPT_DB_HOST, $WPT_DB_USER, $WPT_DB_PASSWORD, $WPT_DB_NAME ),
'system_utils' => array(),
'os_name' => trim( shell_exec( 'uname -s' ) ),
'os_version' => trim( shell_exec( 'uname -r' ) ),
Expand Down Expand Up @@ -400,18 +576,6 @@ function curl_selected_bits($k) { return in_array($k, array('version', 'ssl_vers
$curl_bits = curl_version();
$env['system_utils']['curl'] = implode(' ',array_values(array_filter($curl_bits, 'curl_selected_bits',ARRAY_FILTER_USE_KEY) ));

$WPT_DB_HOST = trim( getenv( 'WPT_DB_HOST' ) );
if( ! $WPT_DB_HOST ) {
$WPT_DB_HOST = 'localhost';
}
$WPT_DB_USER = trim( getenv( 'WPT_DB_USER' ) );
$WPT_DB_PASSWORD = trim( getenv( 'WPT_DB_PASSWORD' ) );
$WPT_DB_NAME = trim( getenv( 'WPT_DB_NAME' ) );

//$mysqli = new mysqli( $WPT_DB_HOST, $WPT_DB_USER, $WPT_DB_PASSWORD, $WPT_DB_NAME );
//$env['mysql_version'] = $mysqli->query("SELECT VERSION()")->fetch_row()[0];
//$mysqli->close();

if ( class_exists( 'Imagick' ) ) {
$imagick = new Imagick();
$version = $imagick->getVersion();
Expand Down
Loading