database.php
来自「php 开发的内容管理系统」· PHP 代码 · 共 2,046 行 · 第 1/4 页
PHP
2,046 行
* $obj- >page_id is the ID of the Astronomy article
*
* @todo migrate documentation to phpdocumentor format
*/
function selectRow( $table, $vars, $conds, $fname = 'mwDatabase::selectRow', $options = array() ) {
$options['LIMIT'] = 1;
$res = $this->select( $table, $vars, $conds, $fname, $options );
if ( $res === false )
return false;
if ( !$this->numRows($res) ) {
$this->freeResult($res);
return false;
}
$obj = $this->fetchObject( $res );
$this->freeResult( $res );
return $obj;
}
/**
* Removes most variables from an SQL query and replaces them with X or N for numbers.
* It's only slightly flawed. Don't use for anything important.
*
* @param string $sql A SQL Query
* @static
*/
static function generalizeSQL( $sql ) {
# This does the same as the regexp below would do, but in such a way
# as to avoid crashing php on some large strings.
# $sql = preg_replace ( "/'([^\\\\']|\\\\.)*'|\"([^\\\\\"]|\\\\.)*\"/", "'X'", $sql);
$sql = str_replace ( "\\\\", '', $sql);
$sql = str_replace ( "\\'", '', $sql);
$sql = str_replace ( "\\\"", '', $sql);
$sql = preg_replace ("/'.*'/s", "'X'", $sql);
$sql = preg_replace ('/".*"/s', "'X'", $sql);
# All newlines, tabs, etc replaced by single space
$sql = preg_replace ( "/\s+/", ' ', $sql);
# All numbers => N
$sql = preg_replace ('/-?[0-9]+/s', 'N', $sql);
return $sql;
}
/**
* Determines whether a field exists in a table
* Usually aborts on failure
* If errors are explicitly ignored, returns NULL on failure
*/
function fieldExists( $table, $field, $fname = 'mwDatabase::fieldExists' ) {
$table = $this->tableName( $table );
$res = $this->query( 'DESCRIBE '.$table, $fname );
if ( !$res ) {
return NULL;
}
$found = false;
while ( $row = $this->fetchObject( $res ) ) {
if ( $row->Field == $field ) {
$found = true;
break;
}
}
return $found;
}
/**
* Determines whether an index exists
* Usually aborts on failure
* If errors are explicitly ignored, returns NULL on failure
*/
function indexExists( $table, $index, $fname = 'mwDatabase::indexExists' ) {
$info = $this->indexInfo( $table, $index, $fname );
if ( is_null( $info ) ) {
return NULL;
} else {
return $info !== false;
}
}
/**
* Get information about an index into an object
* Returns false if the index does not exist
*/
function indexInfo( $table, $index, $fname = 'mwDatabase::indexInfo' ) {
# SHOW INDEX works in MySQL 3.23.58, but SHOW INDEXES does not.
# SHOW INDEX should work for 3.x and up:
# http://dev.mysql.com/doc/mysql/en/SHOW_INDEX.html
$table = $this->tableName( $table );
$sql = 'SHOW INDEX FROM '.$table;
$res = $this->query( $sql, $fname );
if ( !$res ) {
return NULL;
}
while ( $row = $this->fetchObject( $res ) ) {
if ( $row->Key_name == $index ) {
return $row;
}
}
return false;
}
/**
* Query whether a given table exists
*/
function tableExists( $table ) {
$table = $this->tableName( $table );
$old = $this->ignoreErrors( true );
$res = $this->query( "SELECT 1 FROM $table LIMIT 1" );
$this->ignoreErrors( $old );
if( $res ) {
$this->freeResult( $res );
return true;
} else {
return false;
}
}
/**
* mysql_fetch_field() wrapper
* Returns false if the field doesn't exist
*
* @param $table
* @param $field
*/
function fieldInfo( $table, $field ) {
$table = $this->tableName( $table );
$res = $this->query( "SELECT * FROM $table LIMIT 1" );
$n = mysql_num_fields( $res );
for( $i = 0; $i < $n; $i++ ) {
$meta = mysql_fetch_field( $res, $i );
if( $field == $meta->name ) {
return $meta;
}
}
return false;
}
/**
* mysql_field_type() wrapper
*/
function fieldType( $res, $index ) {
return mysql_field_type( $res, $index );
}
/**
* Determines if a given index is unique
*/
function indexUnique( $table, $index ) {
$indexInfo = $this->indexInfo( $table, $index );
if ( !$indexInfo ) {
return NULL;
}
return !$indexInfo->Non_unique;
}
/**
* INSERT wrapper, inserts an array into a table
*
* $a may be a single associative array, or an array of these with numeric keys, for
* multi-row insert.
*
* Usually aborts on failure
* If errors are explicitly ignored, returns success
*/
function insert( $table, $a, $fname = 'mwDatabase::insert', $options = array() ) {
# No rows to insert, easy just return now
if ( !count( $a ) ) {
return true;
}
$table = $this->tableName( $table );
if ( !is_array( $options ) ) {
$options = array( $options );
}
if ( isset( $a[0] ) && is_array( $a[0] ) ) {
$multi = true;
$keys = array_keys( $a[0] );
} else {
$multi = false;
$keys = array_keys( $a );
}
$sql = 'INSERT ' . implode( ' ', $options ) .
" INTO $table (" . implode( ',', $keys ) . ') VALUES ';
if ( $multi ) {
$first = true;
foreach ( $a as $row ) {
if ( $first ) {
$first = false;
} else {
$sql .= ',';
}
$sql .= '(' . $this->makeList( $row ) . ')';
}
} else {
$sql .= '(' . $this->makeList( $a ) . ')';
}
return (bool)$this->query( $sql, $fname );
}
/**
* Make UPDATE options for the Database::update function
*
* @private
* @param array $options The options passed to Database::update
* @return string
*/
function makeUpdateOptions( $options ) {
if( !is_array( $options ) ) {
$options = array( $options );
}
$opts = array();
if ( in_array( 'LOW_PRIORITY', $options ) )
$opts[] = $this->lowPriorityOption();
if ( in_array( 'IGNORE', $options ) )
$opts[] = 'IGNORE';
return implode(' ', $opts);
}
/**
* UPDATE wrapper, takes a condition array and a SET array
*
* @param string $table The table to UPDATE
* @param array $values An array of values to SET
* @param array $conds An array of conditions (WHERE). Use '*' to update all rows.
* @param string $fname The Class::Function calling this function
* (for the log)
* @param array $options An array of UPDATE options, can be one or
* more of IGNORE, LOW_PRIORITY
*/
function update( $table, $values, $conds, $fname = 'mwDatabase::update', $options = array() ) {
$table = $this->tableName( $table );
$opts = $this->makeUpdateOptions( $options );
$sql = "UPDATE $opts $table SET " . $this->makeList( $values, LIST_SET );
if ( $conds != '*' ) {
$sql .= " WHERE " . $this->makeList( $conds, LIST_AND );
}
$this->query( $sql, $fname );
}
/**
* Makes a wfStrencoded list from an array
* $mode:
* LIST_COMMA - comma separated, no field names
* LIST_AND - ANDed WHERE clause (without the WHERE)
* LIST_OR - ORed WHERE clause (without the WHERE)
* LIST_SET - comma separated with field names, like a SET clause
* LIST_NAMES - comma separated field names
*/
function makeList( $a, $mode = LIST_COMMA ) {
if ( !is_array( $a ) ) {
throw new DBUnexpectedError( $this, 'mwDatabase::makeList called with incorrect parameters' );
}
$first = true;
$list = '';
foreach ( $a as $field => $value ) {
if ( !$first ) {
if ( $mode == LIST_AND ) {
$list .= ' AND ';
} elseif($mode == LIST_OR) {
$list .= ' OR ';
} else {
$list .= ',';
}
} else {
$first = false;
}
if ( ($mode == LIST_AND || $mode == LIST_OR) && is_numeric( $field ) ) {
$list .= "($value)";
} elseif ( ($mode == LIST_AND || $mode == LIST_OR) && is_array ($value) ) {
$list .= $field." IN (".$this->makeList($value).") ";
} else {
if ( $mode == LIST_AND || $mode == LIST_OR || $mode == LIST_SET ) {
$list .= "$field = ";
}
$list .= $mode == LIST_NAMES ? $value : $this->addQuotes( $value );
}
}
return $list;
}
/**
* Change the current database
*/
function selectDB( $db ) {
$this->mDBname = $db;
return mysql_select_db( $db, $this->mConn );
}
/**
* Format a table name ready for use in constructing an SQL query
*
* This does two important things: it quotes table names which as necessary,
* and it adds a table prefix if there is one.
*
* All functions of this object which require a table name call this function
* themselves. Pass the canonical name to such functions. This is only needed
* when calling query() directly.
*
* @param string $name database table name
*/
function tableName( $name ) {
global $wgSharedDB;
# Skip quoted literals
if ( $name{0} != '`' ) {
if ( $this->mTablePrefix !== '' && strpos( '.', $name ) === false ) {
$name = "{$this->mTablePrefix}$name";
}
if ( isset( $wgSharedDB ) && "{$this->mTablePrefix}user" == $name ) {
$name = "`$wgSharedDB`.`$name`";
} else {
# Standard quoting
$name = "`$name`";
}
}
return $name;
}
/**
* Fetch a number of table names into an array
* This is handy when you need to construct SQL for joins
*
* Example:
* extract($dbr->tableNames('user','watchlist'));
* $sql = "SELECT wl_namespace,wl_title FROM $watchlist,$user
* WHERE wl_user=user_id AND wl_user=$nameWithQuotes";
*/
function tableNames() {
$inArray = func_get_args();
$retVal = array();
foreach ( $inArray as $name ) {
$retVal[$name] = $this->tableName( $name );
}
return $retVal;
}
/**
* @private
*/
function tableNamesWithUseIndex( $tables, $use_index ) {
$ret = array();
foreach ( $tables as $table )
if ( @$use_index[$table] !== null )
$ret[] = $this->tableName( $table ) . ' ' . $this->useIndexClause( implode( ',', (array)$use_index[$table] ) );
else
$ret[] = $this->tableName( $table );
return implode( ',', $ret );
}
/**
* Wrapper for addslashes()
* @param string $s String to be slashed.
* @return string slashed string.
*/
function strencode( $s ) {
return mysql_real_escape_string( $s, $this->mConn );
}
/**
* If it's a string, adds quotes and backslashes
* Otherwise returns as-is
*/
function addQuotes( $s ) {
if ( is_null( $s ) ) {
return 'NULL';
} else {
# This will also quote numeric values. This should be harmless,
# and protects against weird problems that occur when they really
# _are_ strings such as article titles and string->number->string
# conversion is not 1:1.
return "'" . $this->strencode( $s ) . "'";
}
}
/**
* Escape string for safe LIKE usage
*/
function escapeLike( $s ) {
$s=$this->strencode( $s );
$s=str_replace(array('%','_'),array('\%','\_'),$s);
return $s;
}
/**
* Returns an appropriately quoted sequence value for inserting a new row.
* MySQL has autoincrement fields, so this is just NULL. But the PostgreSQL
* subclass will return an integer, and save the value for insertId()
*/
function nextSequenceValue( $seqName ) {
return NULL;
}
/**
* USE INDEX clause
* PostgreSQL doesn't have them and returns ""
*/
function useIndexClause( $index ) {
return "FORCE INDEX ($index)";
}
/**
* REPLACE query wrapper
* PostgreSQL simulates this with a DELETE followed by INSERT
* $row is the row to insert, an associative array
* $uniqueIndexes is an array of indexes. Each element may be either a
* field name or an array of field names
*
* It may be more efficient to leave off unique indexes which are unlikely to collide.
* However if you do this, you run the risk of encountering errors which wouldn't have
* occurred in MySQL
*
* @todo migrate comment to phodocumentor format
*/
function replace( $table, $uniqueIndexes, $rows, $fname = 'mwDatabase::replace' ) {
$table = $this->tableName( $table );
# Single row case
if ( !is_array( reset( $rows ) ) ) {
$rows = array( $rows );
}
$sql = "REPLACE INTO $table (" . implode( ',', array_keys( $rows[0] ) ) .') VALUES ';
$first = true;
foreach ( $rows as $row ) {
if ( $first ) {
$first = false;
} else {
$sql .= ',';
}
$sql .= '(' . $this->makeList( $row ) . ')';
}
return $this->query( $sql, $fname );
}
/**
* DELETE where the condition is a join
* MySQL does this with a multi-table DELETE syntax, PostgreSQL does it with sub-selects
*
* For safety, an empty $conds will not delete everything. If you want to delete all rows where the
* join condition matches, set $conds='*'
*
* DO NOT put the join condition in $conds
*
* @param string $delTable The table to delete from.
* @param string $joinTable The other table.
* @param string $delVar The variable to join on, in the first table.
* @param string $joinVar The variable to join on, in the second table.
* @param array $conds Condition array of field names mapped to variables, ANDed together in the WHERE clause
*/
function deleteJoin( $delTable, $joinTable, $delVar, $joinVar, $conds, $fname = 'mwDatabase::deleteJoin' ) {
if ( !$conds ) {
throw new DBUnexpectedError( $this, 'mwDatabase::deleteJoin() called with empty $conds' );
}
$delTable = $this->tableName( $delTable );
$joinTable = $this->tableName( $joinTable );
$sql = "DELETE $delTable FROM $delTable, $joinTable WHERE $delVar=$joinVar ";
if ( $conds != '*' ) {
$sql .= ' AND ' . $this->makeList( $conds, LIST_AND );
}
return $this->query( $sql, $fname );
}
/**
* Returns the size of a text field, or -1 for "unlimited"
*/
function textFieldSize( $table, $field ) {
$table = $this->tableName( $table );
$sql = "SHOW COLUMNS FROM $table LIKE \"$field\";";
$res = $this->query( $sql, 'mwDatabase::textFieldSize' );
$row = $this->fetchObject( $res );
$this->freeResult( $res );
if ( preg_match( "/\((.*)\)/", $row->Type, $m ) ) {
$size = $m[1];
} else {
$size = -1;
}
return $size;
}
/**
* @return string Returns the text of the low priority option if it is supported, or a blank string otherwise
*/
function lowPriorityOption() {
return 'LOW_PRIORITY';
}
/**
* DELETE query wrapper
*
* Use $conds == "*" to delete all rows
*/
function delete( $table, $conds, $fname = 'mwDatabase::delete' ) {
if ( !$conds ) {
throw new DBUnexpectedError( $this, 'mwDatabase::delete() called with no conditions' );
}
$table = $this->tableName( $table );
$sql = "DELETE FROM $table";
if ( $conds != '*' ) {
$sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?