diff --git a/src/wp-includes/wp-db.php b/src/wp-includes/wp-db.php index 6426bd367a..dabce8cdfe 100644 --- a/src/wp-includes/wp-db.php +++ b/src/wp-includes/wp-db.php @@ -538,6 +538,15 @@ class wpdb { protected $incompatible_modes = array( 'NO_ZERO_DATE', 'ONLY_FULL_GROUP_BY', 'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'TRADITIONAL' ); + /** + * Whether to use mysqli over mysql. + * + * @since 3.9.0 + * @access private + * @var bool + */ + private $use_mysqli = false; + /** * Connects to the database server and selects a database * @@ -559,6 +568,8 @@ class wpdb { if ( WP_DEBUG && WP_DEBUG_DISPLAY ) $this->show_errors(); + $this->use_mysqli = ( version_compare( phpversion(), '5.5', '>=' ) && function_exists( 'mysqli_connect' ) ); + $this->init_charset(); $this->dbuser = $dbuser; @@ -666,13 +677,24 @@ class wpdb { if ( ! isset( $collate ) ) $collate = $this->collate; if ( $this->has_cap( 'collation' ) && ! empty( $charset ) ) { - if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset' ) ) { - mysql_set_charset( $charset, $dbh ); + if ( $this->use_mysqli ) { + if ( function_exists( 'mysqli_set_charset' ) && $this->has_cap( 'set_charset' ) ) { + mysqli_set_charset( $dbh, $charset ); + } else { + $query = $this->prepare( 'SET NAMES %s', $charset ); + if ( ! empty( $collate ) ) + $query .= $this->prepare( ' COLLATE %s', $collate ); + mysqli_query( $query, $dbh ); + } } else { - $query = $this->prepare( 'SET NAMES %s', $charset ); - if ( ! empty( $collate ) ) - $query .= $this->prepare( ' COLLATE %s', $collate ); - mysql_query( $query, $dbh ); + if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset' ) ) { + mysql_set_charset( $charset, $dbh ); + } else { + $query = $this->prepare( 'SET NAMES %s', $charset ); + if ( ! empty( $collate ) ) + $query .= $this->prepare( ' COLLATE %s', $collate ); + mysql_query( $query, $dbh ); + } } } } @@ -689,12 +711,25 @@ class wpdb { */ function set_sql_mode( $modes = array() ) { if ( empty( $modes ) ) { - $res = mysql_query( 'SELECT @@SESSION.sql_mode;', $this->dbh ); + if ( $this->use_mysqli ) { + $res = mysqli_query( $this->dbh, 'SELECT @@SESSION.sql_mode' ); + } else { + $res = mysql_query( 'SELECT @@SESSION.sql_mode', $this->dbh ); + } + if ( empty( $res ) ) { return; } - $modes_str = mysql_result( $res, 0 ); + if ( $this->use_mysqli ) { + $modes_array = mysqli_fetch_array( $res ); + if ( empty( $modes_array[0] ) ) { + return; + } + $modes_str = $modes_array[0]; + } else { + $modes_str = mysql_result( $res, 0 ); + } if ( empty( $modes_str ) ) { return; @@ -724,7 +759,11 @@ class wpdb { $modes_str = implode( ',', $modes ); - mysql_query( "SET SESSION sql_mode='$modes_str';", $this->dbh ); + if ( $this->use_mysqli ) { + mysqli_query( $this->dbh, "SET SESSION sql_mode='$modes_str'" ); + } else { + mysql_query( "SET SESSION sql_mode='$modes_str'", $this->dbh ); + } } /** @@ -909,7 +948,12 @@ class wpdb { if ( is_null($dbh) ) $dbh = $this->dbh; - if ( !@mysql_select_db( $db, $dbh ) ) { + if ( $this->use_mysqli ) { + $success = @mysqli_select_db( $dbh, $db ); + } else { + $success = @mysql_select_db( $db, $dbh ); + } + if ( ! $success ) { $this->ready = false; wp_load_translations_early(); $this->bail( sprintf( __( '

Can’t select database

@@ -945,8 +989,9 @@ class wpdb { } /** - * Real escape, using mysql_real_escape_string() + * Real escape, using mysqli_real_escape_string() or mysql_real_escape_string() * + * @see mysqli_real_escape_string() * @see mysql_real_escape_string() * @since 2.8.0 * @access private @@ -955,8 +1000,13 @@ class wpdb { * @return string escaped */ function _real_escape( $string ) { - if ( $this->dbh ) - return mysql_real_escape_string( $string, $this->dbh ); + if ( $this->dbh ) { + if ( $this->use_mysqli ) { + return mysqli_real_escape_string( $this->dbh, $string ); + } else { + return mysql_real_escape_string( $string, $this->dbh ); + } + } $class = get_class( $this ); _doing_it_wrong( $class, "$class must set a database connection for use with escaping.", E_USER_NOTICE ); @@ -1102,8 +1152,13 @@ class wpdb { function print_error( $str = '' ) { global $EZSQL_ERROR; - if ( !$str ) - $str = mysql_error( $this->dbh ); + if ( !$str ) { + if ( $this->use_mysqli ) { + $str = mysqli_error( $this->dbh ); + } else { + $str = mysql_error( $this->dbh ); + } + } $EZSQL_ERROR[] = array( 'query' => $this->last_query, 'error_str' => $str ); if ( $this->suppress_errors ) @@ -1206,8 +1261,13 @@ class wpdb { $this->rows_affected = $this->num_rows = 0; $this->last_error = ''; - if ( is_resource( $this->result ) ) - mysql_free_result( $this->result ); + if ( is_resource( $this->result ) ) { + if ( $this->use_mysqli ) { + mysqli_free_result( $this->result ); + } else { + mysql_free_result( $this->result ); + } + } } /** @@ -1228,18 +1288,40 @@ class wpdb { $new_link = defined( 'MYSQL_NEW_LINK' ) ? MYSQL_NEW_LINK : true; $client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0; - if ( WP_DEBUG ) { - $error_reporting = false; - if ( defined( 'E_DEPRECATED' ) ) { - $error_reporting = error_reporting(); - error_reporting( $error_reporting ^ E_DEPRECATED ); + if ( $this->use_mysqli ) { + $this->dbh = mysqli_init(); + + // mysqli_real_connect doesn't support the host param including a port or socket + // like mysql_connect does. This duplicates how mysql_connect detects a port and/or socket file. + $port = null; + $socket = null; + $host = $this->dbhost; + $port_or_socket = strstr( $host, ':' ); + if ( ! empty( $port_or_socket ) ) { + $host = strstr( $host, ':', true ); + $port_or_socket = substr( $port_or_socket, 1 ); + if ( 0 !== strpos( $port_or_socket, '/' ) ) { + $port = intval( $port_or_socket ); + $maybe_socket = strstr( $port_or_socket, ':' ); + if ( ! empty( $maybe_socket ) ) { + $socket = substr( $maybe_socket, 1 ); + } + } else { + $socket = $port_or_socket; + } } - $this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags ); - if ( false !== $error_reporting ) { - error_reporting( $error_reporting ); + + if ( WP_DEBUG ) { + mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags ); + } else { + @mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags ); } } else { - $this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags ); + if ( WP_DEBUG ) { + $this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags ); + } else { + $this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags ); + } } if ( ! $this->dbh && $allow_bail ) { @@ -1285,8 +1367,14 @@ class wpdb { * @return bool True if the connection is up. */ function check_connection() { - if ( @mysql_ping( $this->dbh ) ) { - return true; + if ( $this->use_mysqli ) { + if ( @mysqli_ping( $this->dbh ) ) { + return true; + } + } else { + if ( @mysql_ping( $this->dbh ) ) { + return true; + } } $error_reporting = false; @@ -1368,14 +1456,29 @@ class wpdb { $this->_do_query( $query ); // MySQL server has gone away, try to reconnect - if ( empty( $this->dbh ) || 2006 == mysql_errno( $this->dbh ) ) { + $mysql_errno = 0; + if ( ! empty( $this->dbh ) ) { + if ( $this->use_mysqli ) { + $mysql_errno = mysqli_errno( $this->dbh ); + } else { + $mysql_errno = mysql_errno( $this->dbh ); + } + } + + if ( empty( $this->dbh ) || 2006 == $mysql_errno ) { if ( $this->check_connection() ) { $this->_do_query( $query ); } } // If there is an error then take note of it.. - if ( $this->last_error = mysql_error( $this->dbh ) ) { + if ( $this->use_mysqli ) { + $this->last_error = mysqli_error( $this->dbh ); + } else { + $this->last_error = mysql_error( $this->dbh ); + } + + if ( $this->last_error ) { // Clear insert_id on a subsequent failed insert. if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) ) $this->insert_id = 0; @@ -1387,18 +1490,33 @@ class wpdb { if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) { $return_val = $this->result; } elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) { - $this->rows_affected = mysql_affected_rows( $this->dbh ); + if ( $this->use_mysqli ) { + $this->rows_affected = mysqli_affected_rows( $this->dbh ); + } else { + $this->rows_affected = mysql_affected_rows( $this->dbh ); + } // Take note of the insert_id if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) { - $this->insert_id = mysql_insert_id($this->dbh); + if ( $this->use_mysqli ) { + $this->insert_id = mysqli_insert_id( $this->dbh ); + } else { + $this->insert_id = mysql_insert_id( $this->dbh ); + } } // Return number of rows affected $return_val = $this->rows_affected; } else { $num_rows = 0; - while ( $row = @mysql_fetch_object( $this->result ) ) { - $this->last_result[$num_rows] = $row; - $num_rows++; + if ( $this->use_mysqli ) { + while ( $row = @mysqli_fetch_object( $this->result ) ) { + $this->last_result[$num_rows] = $row; + $num_rows++; + } + } else { + while ( $row = @mysql_fetch_object( $this->result ) ) { + $this->last_result[$num_rows] = $row; + $num_rows++; + } } // Log number of rows the query returned @@ -1425,7 +1543,11 @@ class wpdb { $this->timer_start(); } - $this->result = @mysql_query( $query, $this->dbh ); + if ( $this->use_mysqli ) { + $this->result = @mysqli_query( $this->dbh, $query ); + } else { + $this->result = @mysql_query( $query, $this->dbh ); + } $this->num_queries++; if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { @@ -1763,8 +1885,14 @@ class wpdb { if ( $this->col_info ) return; - for ( $i = 0; $i < @mysql_num_fields( $this->result ); $i++ ) { - $this->col_info[ $i ] = @mysql_fetch_field( $this->result, $i ); + if ( $this->use_mysqli ) { + for ( $i = 0; $i < @mysqli_num_fields( $this->result ); $i++ ) { + $this->col_info[ $i ] = @mysqli_fetch_field( $this->result, $i ); + } + } else { + for ( $i = 0; $i < @mysql_num_fields( $this->result ); $i++ ) { + $this->col_info[ $i ] = @mysql_fetch_field( $this->result, $i ); + } } } @@ -1936,6 +2064,11 @@ class wpdb { * @return false|string false on failure, version number on success */ function db_version() { - return preg_replace( '/[^0-9.].*/', '', mysql_get_server_info( $this->dbh ) ); + if ( $this->use_mysqli ) { + $server_info = mysqli_get_server_info( $this->dbh ); + } else { + $server_info = mysql_get_server_info( $this->dbh ); + } + return preg_replace( '/[^0-9.].*/', '', $server_info ); } } diff --git a/tests/phpunit/tests/db.php b/tests/phpunit/tests/db.php index 3ccb5948d7..367abea17e 100644 --- a/tests/phpunit/tests/db.php +++ b/tests/phpunit/tests/db.php @@ -50,7 +50,11 @@ class Tests_DB extends WP_UnitTestCase { $var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" ); $this->assertGreaterThan( 0, $var ); - mysql_close( $wpdb->dbh ); + if ( $wpdb->use_mysqli ) { + mysqli_close( $wpdb->dbh ); + } else { + mysql_close( $wpdb->dbh ); + } unset( $wpdb->dbh ); $var = $wpdb->get_var( "SELECT ID FROM $wpdb->users LIMIT 1" );