Commit 06082188 authored by Andrew Nacin's avatar Andrew Nacin
Browse files

Use ext/mysqli in PHP 5.5 or greater. Expect minor explosions.

props aaroncampbell, pento.
see #21663.

Built from https://develop.svn.wordpress.org/trunk@27250


git-svn-id: https://core.svn.wordpress.org/trunk@27107 1a063a9b-81f0-0310-95a4-ce76da25c4cd
parent 046ffe3a
Loading
Loading
Loading
Loading
+172 −39
Original line number Diff line number Diff line
@@ -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,6 +677,16 @@ class wpdb {
		if ( ! isset( $collate ) )
			$collate = $this->collate;
		if ( $this->has_cap( 'collation' ) && ! empty( $charset ) ) {
			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 {
				if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
					mysql_set_charset( $charset, $dbh );
				} else {
@@ -676,6 +697,7 @@ class wpdb {
				}
			}
		}
	}

	/**
	 * Change the current SQL mode, and ensure its WordPress compatibility.
@@ -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;
			}

			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( __( '<h1>Can&#8217;t select database</h1>
@@ -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 )
		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 )
		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,9 +1261,14 @@ class wpdb {
		$this->rows_affected = $this->num_rows = 0;
		$this->last_error  = '';

		if ( is_resource( $this->result ) )
		if ( is_resource( $this->result ) ) {
			if ( $this->use_mysqli ) {
				mysqli_free_result( $this->result );
			} else {
				mysql_free_result( $this->result );
			}
		}
	}

	/**
	 * Connect to and select database.
@@ -1228,19 +1288,41 @@ class wpdb {
		$new_link = defined( 'MYSQL_NEW_LINK' ) ? MYSQL_NEW_LINK : true;
		$client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;

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

			if ( WP_DEBUG ) {
			$error_reporting = false;
			if ( defined( 'E_DEPRECATED' ) ) {
				$error_reporting = error_reporting();
				error_reporting( $error_reporting ^ E_DEPRECATED );
				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 {
			if ( WP_DEBUG ) {
				$this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
			if ( false !== $error_reporting ) {
				error_reporting( $error_reporting );
			}
			} else {
				$this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
			}
		}

		if ( ! $this->dbh && $allow_bail ) {
			wp_load_translations_early();
@@ -1285,9 +1367,15 @@ class wpdb {
	 * @return bool True if the connection is up.
	 */
	function check_connection() {
		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,19 +1490,34 @@ 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 ) ) {
			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 ) ) {
				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;
			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
			// and return number of rows selected
@@ -1425,7 +1543,11 @@ class wpdb {
			$this->timer_start();
		}

		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,10 +1885,16 @@ class wpdb {
		if ( $this->col_info )
			return;

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

	/**
	 * Retrieve column metadata from the last query.
@@ -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 );
	}
}