X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/8f374b7233bc2815ccc387e448d208c5434eb961..245e789b234afa4525862e7a6e5e3c2e7a52ef20:/wp-includes/wp-db.php?ds=sidebyside diff --git a/wp-includes/wp-db.php b/wp-includes/wp-db.php index f4187459..c72a644c 100644 --- a/wp-includes/wp-db.php +++ b/wp-includes/wp-db.php @@ -17,7 +17,8 @@ define( 'EZSQL_VERSION', 'WP1.25' ); /** * @since 0.71 */ -define( 'OBJECT', 'OBJECT', true ); +define( 'OBJECT', 'OBJECT' ); +define( 'object', 'OBJECT' ); // Back compat. /** * @since 2.5.0 @@ -88,7 +89,7 @@ class wpdb { /** * Count of rows returned by previous query * - * @since 1.2.0 + * @since 0.71 * @access private * @var int */ @@ -113,9 +114,9 @@ class wpdb { var $insert_id = 0; /** - * Saved result of the last query made + * Last query made * - * @since 1.2.0 + * @since 0.71 * @access private * @var array */ @@ -124,20 +125,29 @@ class wpdb { /** * Results of the last query made * - * @since 1.0.0 + * @since 0.71 * @access private * @var array|null */ var $last_result; + /** + * MySQL result, which is either a resource or boolean. + * + * @since 0.71 + * @access protected + * @var mixed + */ + protected $result; + /** * Saved info on the table column * - * @since 1.2.0 - * @access private + * @since 0.71 + * @access protected * @var array */ - var $col_info; + protected $col_info; /** * Saved queries that were executed @@ -148,6 +158,16 @@ class wpdb { */ var $queries; + /** + * The number of times to retry reconnecting before dying. + * + * @since 3.9.0 + * @access protected + * @see wpdb::check_connection() + * @var int + */ + protected $reconnect_retries = 5; + /** * WordPress table prefix * @@ -155,16 +175,25 @@ class wpdb { * in a single database. The second reason is for possible * security precautions. * - * @since 0.71 + * @since 2.5.0 * @access private * @var string */ var $prefix = ''; + /** + * WordPress base table prefix. + * + * @since 3.0.0 + * @access public + * @var string + */ + public $base_prefix; + /** * Whether the database queries are ready to start executing. * - * @since 2.5.0 + * @since 2.3.2 * @access private * @var bool */ @@ -433,22 +462,49 @@ class wpdb { var $collate; /** - * Whether to use mysql_real_escape_string + * Database Username * - * @since 2.8.0 - * @access public - * @var bool + * @since 2.9.0 + * @access protected + * @var string */ - var $real_escape = false; + protected $dbuser; /** - * Database Username + * Database Password * - * @since 2.9.0 - * @access private + * @since 3.1.0 + * @access protected + * @var string + */ + protected $dbpassword; + + /** + * Database Name + * + * @since 3.1.0 + * @access protected + * @var string + */ + protected $dbname; + + /** + * Database Host + * + * @since 3.1.0 + * @access protected + * @var string + */ + protected $dbhost; + + /** + * Database Handle + * + * @since 0.71 + * @access protected * @var string */ - var $dbuser; + protected $dbh; /** * A textual description of the last query/get_row/get_var call @@ -473,6 +529,34 @@ class wpdb { */ public $is_mysql = null; + /** + * A list of incompatible SQL modes. + * + * @since 3.9.0 + * @access protected + * @var array + */ + 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; + + /** + * Whether we've managed to successfully connect at some point + * + * @since 3.9.0 + * @access private + * @var bool + */ + private $has_connected = false; + /** * Connects to the database server and selects a database * @@ -489,11 +573,27 @@ class wpdb { * @param string $dbhost MySQL database host */ function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) { - register_shutdown_function( array( &$this, '__destruct' ) ); + register_shutdown_function( array( $this, '__destruct' ) ); - if ( WP_DEBUG ) + if ( WP_DEBUG && WP_DEBUG_DISPLAY ) $this->show_errors(); + /* Use ext/mysqli if it exists and: + * - WP_USE_EXT_MYSQL is defined as false, or + * - We are a development version of WordPress, or + * - We are running PHP 5.5 or greater, or + * - ext/mysql is not loaded. + */ + if ( function_exists( 'mysqli_connect' ) ) { + if ( defined( 'WP_USE_EXT_MYSQL' ) ) { + $this->use_mysqli = ! WP_USE_EXT_MYSQL; + } elseif ( version_compare( phpversion(), '5.5', '>=' ) || ! function_exists( 'mysql_connect' ) ) { + $this->use_mysqli = true; + } elseif ( false !== strpos( $GLOBALS['wp_version'], '-' ) ) { + $this->use_mysqli = true; + } + } + $this->init_charset(); $this->dbuser = $dbuser; @@ -515,6 +615,57 @@ class wpdb { return true; } + /** + * PHP5 style magic getter, used to lazy-load expensive data. + * + * @since 3.5.0 + * + * @param string $name The private member to get, and optionally process + * @return mixed The private member + */ + function __get( $name ) { + if ( 'col_info' == $name ) + $this->load_col_info(); + + return $this->$name; + } + + /** + * Magic function, for backwards compatibility + * + * @since 3.5.0 + * + * @param string $name The private member to set + * @param mixed $value The value to set + */ + function __set( $name, $value ) { + $this->$name = $value; + } + + /** + * Magic function, for backwards compatibility + * + * @since 3.5.0 + * + * @param string $name The private member to check + * + * @return bool If the member is set or not + */ + function __isset( $name ) { + return isset( $this->$name ); + } + + /** + * Magic function, for backwards compatibility + * + * @since 3.5.0 + * + * @param string $name The private member to unset + */ + function __unset( $name ) { + unset( $this->$name ); + } + /** * Set $this->charset and $this->collate * @@ -544,21 +695,98 @@ class wpdb { * @param string $charset The character set (optional) * @param string $collate The collation (optional) */ - function set_charset($dbh, $charset = null, $collate = null) { - if ( !isset($charset) ) + function set_charset( $dbh, $charset = null, $collate = null ) { + if ( ! isset( $charset ) ) $charset = $this->charset; - if ( !isset($collate) ) + if ( ! isset( $collate ) ) $collate = $this->collate; - if ( $this->has_cap( 'collation', $dbh ) && !empty( $charset ) ) { - if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset', $dbh ) ) { - mysql_set_charset( $charset, $dbh ); - $this->real_escape = true; + 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 { + $query = $this->prepare( 'SET NAMES %s', $charset ); + if ( ! empty( $collate ) ) + $query .= $this->prepare( ' COLLATE %s', $collate ); + mysql_query( $query, $dbh ); + } + } + } + } + + /** + * Change the current SQL mode, and ensure its WordPress compatibility. + * + * If no modes are passed, it will ensure the current MySQL server + * modes are compatible. + * + * @since 3.9.0 + * + * @param array $modes Optional. A list of SQL modes to set. + */ + function set_sql_mode( $modes = array() ) { + if ( empty( $modes ) ) { + 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 { - $query = $this->prepare( 'SET NAMES %s', $charset ); - if ( ! empty( $collate ) ) - $query .= $this->prepare( ' COLLATE %s', $collate ); - mysql_query( $query, $dbh ); + $modes_str = mysql_result( $res, 0 ); + } + + if ( empty( $modes_str ) ) { + return; } + + $modes = explode( ',', $modes_str ); + } + + $modes = array_change_key_case( $modes, CASE_UPPER ); + + /** + * Filter the list of incompatible SQL modes to exclude. + * + * @since 3.9.0 + * + * @see wpdb::$incompatible_modes + * + * @param array $incompatible_modes An array of incompatible modes. + */ + $incompatible_modes = (array) apply_filters( 'incompatible_sql_modes', $this->incompatible_modes ); + + foreach( $modes as $i => $mode ) { + if ( in_array( $mode, $incompatible_modes ) ) { + unset( $modes[ $i ] ); + } + } + + $modes_str = implode( ',', $modes ); + + 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 ); } } @@ -744,40 +972,53 @@ 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( __( '
We were able to connect to the database server (which means your username and password is okay) but not able to select the %1$s
database.
%2$s
have permission to use the %1$s
database?username_%1$s
. Could that be the problem?If you don\'t know how to set up a database you should contact your host. If all else fails you may find help at the WordPress Support Forums.
' ), htmlspecialchars( $db, ENT_QUOTES ), htmlspecialchars( $this->dbuser, ENT_QUOTES ) ), 'db_select_fail' ); +If you don\'t know how to set up a database you should contact your host. If all else fails you may find help at the WordPress Support Forums.
' ), htmlspecialchars( $db, ENT_QUOTES ), htmlspecialchars( $this->dbuser, ENT_QUOTES ) ), 'db_select_fail' ); + } return; } } /** - * Weak escape, using addslashes() + * Do not use, deprecated. + * + * Use esc_sql() or wpdb::prepare() instead. * - * @see addslashes() * @since 2.8.0 + * @deprecated 3.6.0 + * @see wpdb::prepare + * @see esc_sql() * @access private * * @param string $string * @return string */ function _weak_escape( $string ) { + if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) + _deprecated_function( __METHOD__, '3.6', 'wpdb::prepare() or esc_sql()' ); return addslashes( $string ); } /** - * Real escape, using mysql_real_escape_string() or addslashes() + * Real escape, using mysqli_real_escape_string() or mysql_real_escape_string() * + * @see mysqli_real_escape_string() * @see mysql_real_escape_string() - * @see addslashes() * @since 2.8.0 * @access private * @@ -785,16 +1026,22 @@ class wpdb { * @return string escaped */ function _real_escape( $string ) { - if ( $this->dbh && $this->real_escape ) - return mysql_real_escape_string( $string, $this->dbh ); - else - return addslashes( $string ); + 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 ); + return addslashes( $string ); } /** * Escape data. Works on arrays. * - * @uses wpdb::_escape() * @uses wpdb::_real_escape() * @since 2.8.0 * @access private @@ -804,7 +1051,7 @@ class wpdb { */ function _escape( $data ) { if ( is_array( $data ) ) { - foreach ( (array) $data as $k => $v ) { + foreach ( $data as $k => $v ) { if ( is_array($v) ) $data[$k] = $this->_escape( $v ); else @@ -818,24 +1065,30 @@ class wpdb { } /** - * Escapes content for insertion into the database using addslashes(), for security. + * Do not use, deprecated. * - * Works on arrays. + * Use esc_sql() or wpdb::prepare() instead. * * @since 0.71 - * @param string|array $data to escape - * @return string|array escaped as query safe string + * @deprecated 3.6.0 + * @see wpdb::prepare() + * @see esc_sql() + * + * @param mixed $data + * @return mixed */ function escape( $data ) { + if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) + _deprecated_function( __METHOD__, '3.6', 'wpdb::prepare() or esc_sql()' ); if ( is_array( $data ) ) { - foreach ( (array) $data as $k => $v ) { + foreach ( $data as $k => $v ) { if ( is_array( $v ) ) - $data[$k] = $this->escape( $v ); + $data[$k] = $this->escape( $v, 'recursive' ); else - $data[$k] = $this->_weak_escape( $v ); + $data[$k] = $this->_weak_escape( $v, 'internal' ); } } else { - $data = $this->_weak_escape( $data ); + $data = $this->_weak_escape( $data, 'internal' ); } return $data; @@ -850,7 +1103,8 @@ class wpdb { * @return void */ function escape_by_ref( &$string ) { - $string = $this->_real_escape( $string ); + if ( ! is_float( $string ) ) + $string = $this->_real_escape( $string ); } /** @@ -890,10 +1144,15 @@ class wpdb { * @return null|false|string Sanitized query string, null if there is no query, false if there is an error and string * if there was something to prepare */ - function prepare( $query = null ) { // ( $query, *$args ) + function prepare( $query, $args ) { if ( is_null( $query ) ) return; + // This is not meant to be foolproof -- but it will catch obviously incorrect usage. + if ( strpos( $query, '%' ) === false ) { + _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9' ); + } + $args = func_get_args(); array_shift( $args ); // If args were passed as an array (as in vsprintf), move them up @@ -901,8 +1160,9 @@ class wpdb { $args = $args[0]; $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting + $query = preg_replace( '|(?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 ) @@ -932,11 +1197,7 @@ class wpdb { else $error_str = sprintf( __( 'WordPress database error %1$s for query %2$s' ), $str, $this->last_query ); - if ( function_exists( 'error_log' ) - && ( $log_file = @ini_get( 'error_log' ) ) - && ( 'syslog' == $log_file || @is_writable( $log_file ) ) - ) - @error_log( $error_str ); + error_log( $error_str ); // Are we showing errors? if ( ! $this->show_errors ) @@ -1023,25 +1284,106 @@ class wpdb { $this->last_result = array(); $this->col_info = null; $this->last_query = null; + $this->rows_affected = $this->num_rows = 0; + $this->last_error = ''; + + 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 + * Connect to and select database. + * + * If $allow_bail is false, the lack of database connection will need + * to be handled manually. * * @since 3.0.0 + * @since 3.9.0 $allow_bail parameter added. + * + * @param bool $allow_bail Optional. Allows the function to bail. Default true. + * @return bool True with a successful connection, false on failure. */ - function db_connect() { + function db_connect( $allow_bail = true ) { $this->is_mysql = true; - if ( WP_DEBUG ) { - $this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true ); + $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 = substr( $host, 0, strpos( $host, ':' ) ); + $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 ) { + 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 ); + } + + if ( $this->dbh->connect_errno ) { + $this->dbh = null; + + /* It's possible ext/mysqli is misconfigured. Fall back to ext/mysql if: + * - We haven't previously connected, and + * - WP_USE_EXT_MYSQL isn't set to false, and + * - ext/mysql is loaded. + */ + $attempt_fallback = true; + + if ( $this->has_connected ) { + $attempt_fallback = false; + } else if ( defined( 'WP_USE_EXT_MYSQL' ) && ! WP_USE_EXT_MYSQL ) { + $attempt_fallback = false; + } else if ( ! function_exists( 'mysql_connect' ) ) { + $attempt_fallback = false; + } + + if ( $attempt_fallback ) { + $this->use_mysqli = false; + $this->db_connect(); + } + } } else { - $this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, true ); + 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 ) { + if ( ! $this->dbh && $allow_bail ) { wp_load_translations_early(); + + // Load custom DB error template, if present. + if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) { + require_once( WP_CONTENT_DIR . '/db-error.php' ); + die(); + } + $this->bail( sprintf( __( "This either means that the username and password information in your wp-config.php
file is incorrect or we can't contact the database server at %s
. This could mean your host's database server is down.
If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums.
+If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums.
" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' ); - return; + return false; + } else if ( $this->dbh ) { + $this->has_connected = true; + $this->set_charset( $this->dbh ); + $this->set_sql_mode(); + $this->ready = true; + $this->select( $this->dbname, $this->dbh ); + + return true; + } + + return false; + } + + /** + * Check that the connection to the database is still up. If not, try to reconnect. + * + * If this function is unable to reconnect, it will forcibly die, or if after the + * the template_redirect hook has been fired, return false instead. + * + * If $allow_bail is false, the lack of database connection will need + * to be handled manually. + * + * @since 3.9.0 + * + * @param bool $allow_bail Optional. Allows the function to bail. Default true. + * @return bool True if the connection is up. + */ + function check_connection( $allow_bail = true ) { + if ( $this->use_mysqli ) { + if ( @mysqli_ping( $this->dbh ) ) { + return true; + } + } else { + if ( @mysql_ping( $this->dbh ) ) { + return true; + } } - $this->set_charset( $this->dbh ); + $error_reporting = false; - $this->ready = true; + // Disable warnings, as we don't want to see a multitude of "unable to connect" messages + if ( WP_DEBUG ) { + $error_reporting = error_reporting(); + error_reporting( $error_reporting & ~E_WARNING ); + } - $this->select( $this->dbname, $this->dbh ); + for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) { + // On the last try, re-enable warnings. We want to see a single instance of the + // "unable to connect" message on the bail() screen, if it appears. + if ( $this->reconnect_retries === $tries && WP_DEBUG ) { + error_reporting( $error_reporting ); + } + + if ( $this->db_connect( false ) ) { + if ( $error_reporting ) { + error_reporting( $error_reporting ); + } + + return true; + } + + sleep( 1 ); + } + + // If template_redirect has already happened, it's too late for wp_die()/dead_db(). + // Let's just return and hope for the best. + if ( did_action( 'template_redirect' ) ) { + return false; + } + + if ( ! $allow_bail ) { + return false; + } + + // We weren't able to reconnect, so we better bail. + $this->bail( sprintf( ( " +This means that we lost contact with the database server at %s
. This could mean your host's database server is down.
If you're unsure what these terms mean you should probably contact your host. If you still need help you can always visit the WordPress Support Forums.
+" ), htmlspecialchars( $this->dbhost, ENT_QUOTES ) ), 'db_connect_fail' ); + + // Call dead_db() if bail didn't die, because this database is no more. It has ceased to be (at least temporarily). + dead_db(); } /** @@ -1077,7 +1499,16 @@ class wpdb { if ( ! $this->ready ) return false; - // some queries are made before the plugins have been loaded, and thus cannot be filtered with this method + /** + * Filter the database query. + * + * Some queries are made before the plugins have been loaded, + * and thus cannot be filtered with this method. + * + * @since 2.1.0 + * + * @param string $query Database query. + */ $query = apply_filters( 'query', $query ); $return_val = 0; @@ -1089,45 +1520,75 @@ class wpdb { // Keep track of the last query for debug.. $this->last_query = $query; - if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) - $this->timer_start(); + $this->_do_query( $query ); - $this->result = @mysql_query( $query, $this->dbh ); - $this->num_queries++; + // MySQL server has gone away, try to reconnect + $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 ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) - $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() ); + if ( empty( $this->dbh ) || 2006 == $mysql_errno ) { + if ( $this->check_connection() ) { + $this->_do_query( $query ); + } else { + $this->insert_id = 0; + return false; + } + } // 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; + $this->print_error(); return false; } - if ( preg_match( '/^\s*(create|alter|truncate|drop) /i', $query ) ) { + if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) { $return_val = $this->result; - } elseif ( preg_match( '/^\s*(insert|delete|update|replace) /i', $query ) ) { - $this->rows_affected = mysql_affected_rows( $this->dbh ); + } 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) /i', $query ) ) { - $this->insert_id = mysql_insert_id($this->dbh); + 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 { - $i = 0; - while ( $i < @mysql_num_fields( $this->result ) ) { - $this->col_info[$i] = @mysql_fetch_field( $this->result ); - $i++; - } $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++; + } } - @mysql_free_result( $this->result ); - // Log number of rows the query returned // and return number of rows selected $this->num_rows = $num_rows; @@ -1137,6 +1598,33 @@ class wpdb { return $return_val; } + /** + * Internal function to perform the mysql_query() call. + * + * @since 3.9.0 + * + * @access private + * @see wpdb::query() + * + * @param string $query The query to run. + */ + private function _do_query( $query ) { + if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) { + $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 ) { + $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() ); + } + } + /** * Insert a row into a table. * @@ -1204,6 +1692,7 @@ class wpdb { function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) { if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) return false; + $this->insert_id = 0; $formats = $format = (array) $format; $fields = array_keys( $data ); $formatted_fields = array(); @@ -1372,6 +1861,9 @@ class wpdb { return $this->last_result[$y] ? get_object_vars( $this->last_result[$y] ) : null; } elseif ( $output == ARRAY_N ) { return $this->last_result[$y] ? array_values( get_object_vars( $this->last_result[$y] ) ) : null; + } elseif ( strtoupper( $output ) === OBJECT ) { + // Back compat for OBJECT being previously case insensitive. + return $this->last_result[$y] ? $this->last_result[$y] : null; } else { $this->print_error( " \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N" ); } @@ -1451,10 +1943,35 @@ class wpdb { } } return $new_array; + } elseif ( strtoupper( $output ) === OBJECT ) { + // Back compat for OBJECT being previously case insensitive. + return $this->last_result; } return null; } + /** + * Load the column metadata from the last query. + * + * @since 3.5.0 + * + * @access protected + */ + protected function load_col_info() { + 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 ); + } + } 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. * @@ -1465,6 +1982,8 @@ class wpdb { * @return mixed Column Results */ function get_col_info( $info_type = 'name', $col_offset = -1 ) { + $this->load_col_info(); + if ( $this->col_info ) { if ( $col_offset == -1 ) { $i = 0; @@ -1506,7 +2025,7 @@ class wpdb { /** * Wraps errors in a nice header and footer and dies. * - * Will not die if wpdb::$show_errors is true + * Will not die if wpdb::$show_errors is false. * * @since 1.5.0 * @@ -1547,20 +2066,41 @@ class wpdb { * Called when WordPress is generating the table scheme. * * @since 2.5.0 + * @deprecated 3.5.0 + * @deprecated Use wpdb::has_cap( 'collation' ) * * @return bool True if collation is supported, false if version does not */ function supports_collation() { + _deprecated_function( __FUNCTION__, '3.5', 'wpdb::has_cap( \'collation\' )' ); return $this->has_cap( 'collation' ); } /** - * Determine if a database supports a particular feature + * The database character collate. + * + * @since 3.5.0 + * + * @return string The database character collate. + */ + public function get_charset_collate() { + $charset_collate = ''; + + if ( ! empty( $this->charset ) ) + $charset_collate = "DEFAULT CHARACTER SET $this->charset"; + if ( ! empty( $this->collate ) ) + $charset_collate .= " COLLATE $this->collate"; + + return $charset_collate; + } + + /** + * Determine if a database supports a particular feature. * * @since 2.7.0 - * @see wpdb::db_version() + * @see wpdb::db_version() * - * @param string $db_cap the feature + * @param string $db_cap The feature to check for. * @return bool */ function has_cap( $db_cap ) { @@ -1568,11 +2108,11 @@ class wpdb { switch ( strtolower( $db_cap ) ) { case 'collation' : // @since 2.5.0 - case 'group_concat' : // @since 2.7 - case 'subqueries' : // @since 2.7 + case 'group_concat' : // @since 2.7.0 + case 'subqueries' : // @since 2.7.0 return version_compare( $version, '4.1', '>=' ); case 'set_charset' : - return version_compare($version, '5.0.7', '>='); + return version_compare( $version, '5.0.7', '>=' ); }; return false; @@ -1600,6 +2140,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 ); } }