2005-09-12 20:13:04 +00:00
< ? php
// $Id$
/**
* @ file
* Database interface code for MySQL database servers using the mysqli client libraries . mysqli is included in PHP 5 by default and allows developers to use the advanced features of MySQL 4.1 . x , 5.0 . x and beyond .
*/
2007-12-31 08:54:37 +00:00
// Maintainers of this file should consult:
// http://www.php.net/manual/en/ref.mysqli.php
2005-09-12 20:13:04 +00:00
/**
* @ ingroup database
* @ {
*/
2007-05-25 12:46:46 +00:00
// Include functions shared between mysql and mysqli.
require_once './includes/database.mysql-common.inc' ;
2006-09-01 08:44:53 +00:00
/**
* Report database status .
*/
2006-09-13 01:38:42 +00:00
function db_status_report ( $phase ) {
2006-09-01 08:44:53 +00:00
$t = get_t ();
2006-10-22 16:46:41 +00:00
$version = db_version ();
2006-09-01 08:44:53 +00:00
$form [ 'mysql' ] = array (
'title' => $t ( 'MySQL database' ),
2007-10-20 21:57:50 +00:00
'value' => ( $phase == 'runtime' ) ? l ( $version , 'admin/reports/status/sql' ) : $version ,
2006-09-01 08:44:53 +00:00
);
if ( version_compare ( $version , DRUPAL_MINIMUM_MYSQL ) < 0 ) {
$form [ 'mysql' ][ 'severity' ] = REQUIREMENT_ERROR ;
$form [ 'mysql' ][ 'description' ] = $t ( 'Your MySQL Server is too old. Drupal requires at least MySQL %version.' , array ( '%version' => DRUPAL_MINIMUM_MYSQL ));
}
2006-10-22 16:46:41 +00:00
2006-09-01 08:44:53 +00:00
return $form ;
}
2006-10-22 16:46:41 +00:00
/**
* Returns the version of the database server currently in use .
*
* @ return Database server version
*/
function db_version () {
global $active_db ;
list ( $version ) = explode ( '-' , mysqli_get_server_info ( $active_db ));
return $version ;
}
2005-09-12 20:13:04 +00:00
/**
* Initialise a database connection .
*
* Note that mysqli does not support persistent connections .
*/
function db_connect ( $url ) {
2005-10-20 21:30:50 +00:00
// Check if MySQLi support is present in PHP
2005-11-18 14:03:55 +00:00
if ( ! function_exists ( 'mysqli_init' ) && ! extension_loaded ( 'mysqli' )) {
2007-12-19 13:03:16 +00:00
_db_error_page ( 'Unable to use the MySQLi database because the MySQLi extension for PHP is not installed. Check your <code>php.ini</code> to see how you can enable it.' );
2005-10-20 21:30:50 +00:00
}
2005-09-12 20:13:04 +00:00
$url = parse_url ( $url );
2006-01-24 08:29:33 +00:00
// Decode url-encoded information in the db connection string
$url [ 'user' ] = urldecode ( $url [ 'user' ]);
2006-09-16 19:26:22 +00:00
// Test if database url has a password.
2007-04-13 08:56:59 +00:00
if ( isset ( $url [ 'pass' ])) {
2006-09-16 19:26:22 +00:00
$url [ 'pass' ] = urldecode ( $url [ 'pass' ]);
}
else {
$url [ 'pass' ] = '' ;
}
2006-01-24 08:29:33 +00:00
$url [ 'host' ] = urldecode ( $url [ 'host' ]);
$url [ 'path' ] = urldecode ( $url [ 'path' ]);
2007-11-26 08:21:49 +00:00
if ( ! isset ( $url [ 'port' ])) {
$url [ 'port' ] = NULL ;
}
2006-01-24 08:29:33 +00:00
2005-09-12 20:13:04 +00:00
$connection = mysqli_init ();
2006-02-15 21:39:51 +00:00
@ mysqli_real_connect ( $connection , $url [ 'host' ], $url [ 'user' ], $url [ 'pass' ], substr ( $url [ 'path' ], 1 ), $url [ 'port' ], NULL , MYSQLI_CLIENT_FOUND_ROWS );
2005-09-12 20:13:04 +00:00
2007-12-19 13:03:16 +00:00
if ( mysqli_connect_errno () > 0 ) {
_db_error_page ( mysqli_connect_error ());
2005-09-12 20:13:04 +00:00
}
2007-12-31 08:54:37 +00:00
// Force UTF-8.
2006-01-21 01:42:52 +00:00
mysqli_query ( $connection , 'SET NAMES "utf8"' );
2005-11-18 14:03:55 +00:00
2005-09-12 20:13:04 +00:00
return $connection ;
}
/**
* Helper function for db_query () .
*/
function _db_query ( $query , $debug = 0 ) {
2007-10-11 16:22:45 +00:00
global $active_db , $queries , $user ;
2005-09-12 20:13:04 +00:00
if ( variable_get ( 'dev_query' , 0 )) {
list ( $usec , $sec ) = explode ( ' ' , microtime ());
$timer = ( float ) $usec + ( float ) $sec ;
2007-10-12 14:51:23 +00:00
// If devel.module query logging is enabled, prepend a comment with the username and calling function
// to the SQL string. This is useful when running mysql's SHOW PROCESSLIST to learn what exact
// code is issueing the slow query.
2007-10-11 16:22:45 +00:00
$bt = debug_backtrace ();
2007-10-12 14:51:23 +00:00
// t() may not be available yet so we don't wrap 'Anonymous'
$name = $user -> uid ? $user -> name : variable_get ( 'anonymous' , 'Anonymous' );
// str_replace() to prevent SQL injection via username or anonymous name.
$name = str_replace ( array ( '*' , '/' ), '' , $name );
2007-10-11 16:22:45 +00:00
$query = '/* ' . $name . ' : ' . $bt [ 2 ][ 'function' ] . ' */ ' . $query ;
2005-09-12 20:13:04 +00:00
}
$result = mysqli_query ( $active_db , $query );
if ( variable_get ( 'dev_query' , 0 )) {
2007-04-13 08:56:59 +00:00
$query = $bt [ 2 ][ 'function' ] . " \n " . $query ;
2005-09-12 20:13:04 +00:00
list ( $usec , $sec ) = explode ( ' ' , microtime ());
$stop = ( float ) $usec + ( float ) $sec ;
$diff = $stop - $timer ;
$queries [] = array ( $query , $diff );
}
if ( $debug ) {
print '<p>query: ' . $query . '<br />error:' . mysqli_error ( $active_db ) . '</p>' ;
}
if ( ! mysqli_errno ( $active_db )) {
return $result ;
}
else {
2007-08-29 18:38:55 +00:00
// Indicate to drupal_error_handler that this is a database error.
$ { DB_ERROR } = TRUE ;
2005-12-06 09:25:22 +00:00
trigger_error ( check_plain ( mysqli_error ( $active_db ) . " \n query: " . $query ), E_USER_WARNING );
2005-09-12 20:13:04 +00:00
return FALSE ;
}
}
/**
* Fetch one result row from the previous query as an object .
*
* @ param $result
* A database query result resource , as returned from db_query () .
* @ return
2007-07-22 07:23:27 +00:00
* An object representing the next row of the result , or FALSE . The attributes
* of this object are the table fields selected by the query .
2005-09-12 20:13:04 +00:00
*/
function db_fetch_object ( $result ) {
if ( $result ) {
2007-07-22 07:23:27 +00:00
$object = mysqli_fetch_object ( $result );
return isset ( $object ) ? $object : FALSE ;
2005-09-12 20:13:04 +00:00
}
}
/**
* Fetch one result row from the previous query as an array .
*
* @ param $result
* A database query result resource , as returned from db_query () .
* @ return
2007-07-23 08:05:14 +00:00
* An associative array representing the next row of the result , or FALSE .
* The keys of this object are the names of the table fields selected by the
2007-07-22 07:23:27 +00:00
* query , and the values are the field values for this result row .
2005-09-12 20:13:04 +00:00
*/
function db_fetch_array ( $result ) {
if ( $result ) {
2007-07-22 07:23:27 +00:00
$array = mysqli_fetch_array ( $result , MYSQLI_ASSOC );
return isset ( $array ) ? $array : FALSE ;
2005-09-12 20:13:04 +00:00
}
}
/**
2007-12-08 14:06:23 +00:00
* Return an individual result field from the previous query .
*
* Only use this function if exactly one field is being selected ; otherwise ,
* use db_fetch_object () or db_fetch_array () .
*
* @ param $result
* A database query result resource , as returned from db_query () .
* @ return
* The resulting field or FALSE .
*/
2007-08-11 14:14:46 +00:00
function db_result ( $result ) {
if ( $result && mysqli_num_rows ( $result ) > 0 ) {
// The mysqli_fetch_row function has an optional second parameter $row
// but that can't be used for compatibility with Oracle, DB2, etc.
$array = mysqli_fetch_row ( $result );
2005-09-12 20:13:04 +00:00
return $array [ 0 ];
}
2006-12-04 11:06:29 +00:00
return FALSE ;
2005-09-12 20:13:04 +00:00
}
/**
* Determine whether the previous query caused an error .
*/
function db_error () {
global $active_db ;
return mysqli_errno ( $active_db );
}
/**
* Determine the number of rows changed by the preceding query .
*/
function db_affected_rows () {
global $active_db ; /* mysqli connection resource */
return mysqli_affected_rows ( $active_db );
}
/**
* Runs a limited - range query in the active database .
*
* Use this as a substitute for db_query () when a subset of the query is to be
* returned .
* User - supplied arguments to the query should be passed in as separate parameters
* so that they can be properly escaped to avoid SQL injection attacks .
*
* @ param $query
* A string containing an SQL query .
* @ param ...
2005-11-27 11:52:08 +00:00
* A variable number of arguments which are substituted into the query
* using printf () syntax . The query arguments can be enclosed in one
* array instead .
* Valid %- modifiers are : % s , % d , % f , % b ( binary data , do not enclose
* in '' ) and %%.
*
* NOTE : using this syntax will cast NULL and FALSE values to decimal 0 ,
* and TRUE values to decimal 1.
*
2005-09-12 20:13:04 +00:00
* @ param $from
* The first result row to return .
* @ param $count
* The maximum number of result rows to return .
* @ return
* A database query result resource , or FALSE if the query was not executed
* correctly .
*/
function db_query_range ( $query ) {
$args = func_get_args ();
$count = array_pop ( $args );
$from = array_pop ( $args );
2005-11-27 11:52:08 +00:00
array_shift ( $args );
2005-09-12 20:13:04 +00:00
$query = db_prefix_tables ( $query );
2005-11-27 11:52:08 +00:00
if ( isset ( $args [ 0 ]) and is_array ( $args [ 0 ])) { // 'All arguments in one array' syntax
$args = $args [ 0 ];
2005-09-12 20:13:04 +00:00
}
2005-11-27 11:52:08 +00:00
_db_query_callback ( $args , TRUE );
$query = preg_replace_callback ( DB_QUERY_REGEXP , '_db_query_callback' , $query );
2006-05-24 20:46:56 +00:00
$query .= ' LIMIT ' . ( int ) $from . ', ' . ( int ) $count ;
2005-09-12 20:13:04 +00:00
return _db_query ( $query );
}
2005-10-18 14:41:27 +00:00
/**
* Runs a SELECT query and stores its results in a temporary table .
*
* Use this as a substitute for db_query () when the results need to stored
* in a temporary table . Temporary tables exist for the duration of the page
* request .
* User - supplied arguments to the query should be passed in as separate parameters
* so that they can be properly escaped to avoid SQL injection attacks .
*
* Note that if you need to know how many results were returned , you should do
2007-08-12 15:55:36 +00:00
* a SELECT COUNT ( * ) on the temporary table afterwards . db_affected_rows () does
* not give consistent result across different database types in this case .
2005-10-18 14:41:27 +00:00
*
* @ param $query
* A string containing a normal SELECT SQL query .
* @ param ...
2005-11-27 11:52:08 +00:00
* A variable number of arguments which are substituted into the query
* using printf () syntax . The query arguments can be enclosed in one
* array instead .
* Valid %- modifiers are : % s , % d , % f , % b ( binary data , do not enclose
* in '' ) and %%.
*
* NOTE : using this syntax will cast NULL and FALSE values to decimal 0 ,
* and TRUE values to decimal 1.
*
2005-10-18 14:41:27 +00:00
* @ param $table
* The name of the temporary table to select into . This name will not be
* prefixed as there is no risk of collision .
* @ return
* A database query result resource , or FALSE if the query was not executed
* correctly .
*/
function db_query_temporary ( $query ) {
$args = func_get_args ();
$tablename = array_pop ( $args );
2005-11-27 11:52:08 +00:00
array_shift ( $args );
2005-10-18 14:41:27 +00:00
2007-03-19 01:17:37 +00:00
$query = preg_replace ( '/^SELECT/i' , 'CREATE TEMPORARY TABLE ' . $tablename . ' Engine=HEAP SELECT' , db_prefix_tables ( $query ));
2005-11-27 11:52:08 +00:00
if ( isset ( $args [ 0 ]) and is_array ( $args [ 0 ])) { // 'All arguments in one array' syntax
$args = $args [ 0 ];
2005-10-18 14:41:27 +00:00
}
2005-11-27 11:52:08 +00:00
_db_query_callback ( $args , TRUE );
$query = preg_replace_callback ( DB_QUERY_REGEXP , '_db_query_callback' , $query );
2005-10-18 14:41:27 +00:00
return _db_query ( $query );
}
2005-09-12 20:13:04 +00:00
/**
2005-11-30 16:47:34 +00:00
* Returns a properly formatted Binary Large Object value .
2005-09-12 20:13:04 +00:00
*
* @ param $data
* Data to encode .
* @ return
* Encoded data .
*/
function db_encode_blob ( $data ) {
2005-11-30 16:47:34 +00:00
global $active_db ;
2007-04-13 08:56:59 +00:00
return " ' " . mysqli_real_escape_string ( $active_db , $data ) . " ' " ;
2005-09-12 20:13:04 +00:00
}
/**
* Returns text from a Binary Large OBject value .
*
* @ param $data
* Data to decode .
* @ return
* Decoded data .
*/
function db_decode_blob ( $data ) {
return $data ;
}
/**
* Prepare user input for use in a database query , preventing SQL injection attacks .
*/
function db_escape_string ( $text ) {
2005-11-18 14:03:55 +00:00
global $active_db ;
return mysqli_real_escape_string ( $active_db , $text );
2005-09-12 20:13:04 +00:00
}
/**
* Lock a table .
*/
function db_lock_table ( $table ) {
2006-04-27 20:38:49 +00:00
db_query ( 'LOCK TABLES {' . db_escape_table ( $table ) . '} WRITE' );
2005-09-12 20:13:04 +00:00
}
/**
* Unlock all locked tables .
*/
function db_unlock_tables () {
db_query ( 'UNLOCK TABLES' );
}
2006-07-26 07:16:08 +00:00
/**
* Check if a table exists .
*/
function db_table_exists ( $table ) {
2007-08-12 15:55:36 +00:00
return db_fetch_object ( db_query ( " SHOW TABLES LIKE ' { " . db_escape_table ( $table ) . " }' " )) ? TRUE : FALSE ;
2006-07-26 07:16:08 +00:00
}
2007-04-21 18:08:41 +00:00
/**
* Check if a column exists in the given table .
*/
function db_column_exists ( $table , $column ) {
2007-08-12 15:55:36 +00:00
return db_fetch_object ( db_query ( " SHOW COLUMNS FROM { %s} LIKE '%s' " , $table , $column )) ? TRUE : FALSE ;
2007-04-21 18:08:41 +00:00
}
2006-10-23 18:38:45 +00:00
/**
* Wraps the given table . field entry with a DISTINCT () . The wrapper is added to
* the SELECT list entry of the given query and the resulting query is returned .
* This function only applies the wrapper if a DISTINCT doesn ' t already exist in
* the query .
*
* @ param $table Table containing the field to set as DISTINCT
* @ param $field Field to set as DISTINCT
* @ param $query Query to apply the wrapper to
* @ return SQL query with the DISTINCT wrapper surrounding the given table . field .
*/
function db_distinct_field ( $table , $field , $query ) {
$field_to_select = 'DISTINCT(' . $table . '.' . $field . ')' ;
// (?<!text) is a negative look-behind (no need to rewrite queries that already use DISTINCT).
2006-11-21 19:46:10 +00:00
return preg_replace ( '/(SELECT.*)(?:' . $table . '\.|\s)(?<!DISTINCT\()(?<!DISTINCT\(' . $table . '\.)' . $field . '(.*FROM )/AUsi' , '\1 ' . $field_to_select . '\2' , $query );
2006-10-23 18:38:45 +00:00
}
2005-09-12 20:13:04 +00:00
/**
* @ } End of " ingroup database " .
*/