2036 lines
50 KiB
PHP
2036 lines
50 KiB
PHP
<?php
|
|
|
|
/**
|
|
* <pre>
|
|
* Invision Power Services
|
|
* IP.Board v3.4.8
|
|
* Database Abstraction Layer
|
|
* Last Updated: $Date: 2013-05-20 16:38:23 -0400 (Mon, 20 May 2013) $
|
|
* </pre>
|
|
*
|
|
* @author $Author: bfarber $
|
|
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
|
* @license http://www.invisionpower.com/company/standards.php#license
|
|
* @package IP.Board
|
|
* @subpackage Kernel
|
|
* @link http://www.invisionpower.com
|
|
* @since Monday 28th February 2005 16:46
|
|
* @version $Revision: 12261 $
|
|
*
|
|
* Basic Usage Examples
|
|
* <code>
|
|
* $db = new db_driver();
|
|
* Update:
|
|
* $db->update( 'table', array( 'field' => 'value', 'field2' => 'value2' ), 'id=1' );
|
|
* Insert
|
|
* $db->insert( 'table', array( 'field' => 'value', 'field2' => 'value2' ) );
|
|
* Delete
|
|
* $db->delete( 'table', 'id=1' );
|
|
* Select
|
|
* $db->build( array( 'select' => '*',
|
|
* 'from' => 'table',
|
|
* 'where' => 'id=2 and mid=1',
|
|
* 'order' => 'date DESC',
|
|
* 'limit' => array( 0, 30 ) ) );
|
|
* $db->execute();
|
|
* while( $row = $db->fetch() ) { .... }
|
|
* Select with join
|
|
* $db->build( array( 'select' => 'd.*',
|
|
* 'from' => array( 'dnames_change' => 'd' ),
|
|
* 'where' => 'dname_member_id='.$id,
|
|
* 'add_join' => array( 0 => array( 'select' => 'm.members_display_name',
|
|
* 'from' => array( 'members' => 'm' ),
|
|
* 'where' => 'm.member_id=d.dname_member_id',
|
|
* 'type' => 'inner' ) ),
|
|
* 'order' => 'dname_date DESC' ) );
|
|
* $db->execute();
|
|
* </code>
|
|
*/
|
|
|
|
/**
|
|
* This can be overridden by using
|
|
* $DB->allow_sub_select = 1;
|
|
* before any query construct
|
|
*/
|
|
|
|
define( 'IPS_DB_ALLOW_SUB_SELECTS', 0 );
|
|
|
|
/**
|
|
* Database interface
|
|
*/
|
|
interface interfaceDb
|
|
{
|
|
/**
|
|
* Connect to database server
|
|
*
|
|
* @return @e boolean
|
|
*/
|
|
public function connect();
|
|
|
|
/**
|
|
* Return the connection ID
|
|
*
|
|
* @return @e resource
|
|
*/
|
|
public function getConnectionId();
|
|
|
|
/**
|
|
* Close database connection
|
|
*
|
|
* @return @e boolean
|
|
*/
|
|
public function disconnect();
|
|
|
|
/**
|
|
* Returns the currently formed SQL query
|
|
*
|
|
* @return @e string
|
|
*/
|
|
public function fetchSqlString();
|
|
|
|
/**
|
|
* Delete data from a table
|
|
*
|
|
* @param string Table name
|
|
* @param string [Optional] Where clause
|
|
* @param string [Optional] Order by
|
|
* @param array [Optional] Limit clause
|
|
* @param boolean [Optional] Run on shutdown
|
|
* @return @e resource
|
|
*/
|
|
public function delete( $table, $where='', $orderBy='', $limit=array(), $shutdown=false );
|
|
|
|
/**
|
|
* Update data in a table
|
|
*
|
|
* @param string Table name
|
|
* @param mixed Array of field => values, or pre-formatted "SET" clause
|
|
* @param string [Optional] Where clause
|
|
* @param boolean [Optional] Run on shutdown
|
|
* @param boolean [Optional] $set is already pre-formatted
|
|
* @param array [Optional] Joined table data
|
|
* @return @e resource
|
|
*/
|
|
public function update( $table, $set, $where='', $shutdown=false, $preformatted=false, $add_join=array() );
|
|
|
|
/**
|
|
* Insert data into a table
|
|
*
|
|
* @param string Table name
|
|
* @param array Array of field => values
|
|
* @param boolean [Optional] Run on shutdown
|
|
* @return @e resource
|
|
*/
|
|
public function insert( $table, $set, $shutdown=false );
|
|
|
|
/**
|
|
* Insert record into table if not present, otherwise update existing record
|
|
*
|
|
* @param string Table name
|
|
* @param array Array of field => values
|
|
* @param array Array of fields to check
|
|
* @param boolean [Optional] Run on shutdown
|
|
* @return @e resource
|
|
*/
|
|
public function replace( $table, $set, $where, $shutdown=false );
|
|
|
|
/**
|
|
* Run a "kill" statement
|
|
*
|
|
* @param integer Thread ID
|
|
* @return @e resource
|
|
*/
|
|
public function kill( $threadId );
|
|
|
|
/**
|
|
* Takes array of set commands and generates a SQL formatted query
|
|
*
|
|
* @param array Set commands (select, from, where, order, limit, etc)
|
|
* @return @e void
|
|
*/
|
|
public function build( $data );
|
|
|
|
/**
|
|
* Build a query based on template from cache file
|
|
*
|
|
* @param string Name of query file method to use
|
|
* @param array Optional arguments to be parsed inside query function
|
|
* @param string Optional class name
|
|
* @return @e void
|
|
*/
|
|
public function buildFromCache( $method, $args=array(), $class='sql_queries' );
|
|
|
|
/**
|
|
* Executes stored SQL query
|
|
*
|
|
* @return @e resource
|
|
*/
|
|
public function execute();
|
|
|
|
/**
|
|
* Stores a query for shutdown execution
|
|
*
|
|
* @return @e mixed
|
|
*/
|
|
public function executeOnShutdown();
|
|
|
|
/**
|
|
* Generates and executes SQL query, and returns the first result
|
|
*
|
|
* @param array Set commands (select, from, where, order, limit, etc)
|
|
* @return @e array
|
|
*/
|
|
public function buildAndFetch( $data );
|
|
|
|
/**
|
|
* Generates and executes SQL query, and returns the all results in an array
|
|
*
|
|
* @param array Set commands (select, from, where, order, limit, etc)
|
|
* @param string Key to index array on (member_id, for example)
|
|
* @return @e array
|
|
*/
|
|
public function buildAndFetchAll( $data, $arrayIndex=null );
|
|
|
|
/**
|
|
* Execute a direct database query
|
|
*
|
|
* @param string Database query
|
|
* @param boolean [Optional] Do not convert table prefix
|
|
* @return @e resource
|
|
*/
|
|
public function query( $the_query, $bypass=false );
|
|
|
|
/**
|
|
* Retrieve number of rows affected by last query
|
|
*
|
|
* @return @e integer
|
|
*/
|
|
public function getAffectedRows();
|
|
|
|
/**
|
|
* Retrieve number of rows in result set
|
|
*
|
|
* @param resource [Optional] Query id
|
|
* @return @e integer
|
|
*/
|
|
public function getTotalRows( $query_id=null );
|
|
|
|
/**
|
|
* Retrieve latest autoincrement insert id
|
|
*
|
|
* @return @e integer
|
|
*/
|
|
public function getInsertId();
|
|
|
|
/**
|
|
* Retrieve the current thread id
|
|
*
|
|
* @return @e integer
|
|
*/
|
|
public function getThreadId();
|
|
|
|
/**
|
|
* Free result set from memory
|
|
*
|
|
* @param resource [Optional] Query id
|
|
* @return @e void
|
|
*/
|
|
public function freeResult( $query_id=null );
|
|
|
|
/**
|
|
* Retrieve row from database
|
|
*
|
|
* @param resource [Optional] Query result id
|
|
* @return @e mixed
|
|
*/
|
|
public function fetch( $query_id=null );
|
|
|
|
/**
|
|
* Return the number calculated rows (as if there was no limit clause)
|
|
*
|
|
* @param string [ alias name for the count(*) ]
|
|
* @return @e integer
|
|
*/
|
|
public function fetchCalculatedRows( $alias='count' );
|
|
|
|
/**
|
|
* Get array of fields in result set
|
|
*
|
|
* @param resource [Optional] Query id
|
|
* @return @e array
|
|
*/
|
|
public function getResultFields( $query_id=null );
|
|
|
|
/**
|
|
* Subqueries supported by driver?
|
|
*
|
|
* @return @e boolean
|
|
*/
|
|
public function checkSubquerySupport();
|
|
|
|
/**
|
|
* Fulltext searching supported by driver?
|
|
*
|
|
* @return @e boolean
|
|
*/
|
|
public function checkFulltextSupport();
|
|
|
|
/**
|
|
* Boolean fulltext searching supported by driver?
|
|
*
|
|
* @return @e boolean
|
|
*/
|
|
public function checkBooleanFulltextSupport();
|
|
|
|
/**
|
|
* Test to see whether an index exists in a table
|
|
*
|
|
* @param string Index name
|
|
* @param string Table name
|
|
* @return @e boolean
|
|
*/
|
|
public function checkForIndex( $index, $table );
|
|
|
|
/**
|
|
* Test to see whether a field exists in a table
|
|
*
|
|
* @param string Field name
|
|
* @param string Table name
|
|
* @return @e boolean
|
|
*/
|
|
public function checkForField( $field, $table );
|
|
|
|
/**
|
|
* Test to see whether a table exists
|
|
*
|
|
* @param string Table name
|
|
* @return @e boolean
|
|
*/
|
|
public function checkForTable( $table );
|
|
|
|
/**
|
|
* Drop database table
|
|
*
|
|
* @param string Table to drop
|
|
* @return @e resource
|
|
*/
|
|
public function dropTable( $table );
|
|
|
|
/**
|
|
* Drop field in database table
|
|
*
|
|
* @param string Table name
|
|
* @param string Field to drop
|
|
* @return @e resource
|
|
*/
|
|
public function dropField( $table, $field );
|
|
|
|
/**
|
|
* Add field to table in database
|
|
*
|
|
* @param string Table name
|
|
* @param string Field to add
|
|
* @param string Field type
|
|
* @param string [Optional] Default value
|
|
* @return @e resource
|
|
*/
|
|
public function addField( $table, $field, $type, $default=NULL );
|
|
|
|
/**
|
|
* Add index to database column
|
|
*
|
|
* @param string Table name table
|
|
* @param string Index name multicol
|
|
* @param string Fieldlist col1, col2
|
|
* @param bool Is primary key?
|
|
* @return @e resource
|
|
* @todo [Future] Add support for fulltext indexes (right now can only do generic index or primary key)
|
|
* @see addFulltextIndex()
|
|
*/
|
|
public function addIndex( $table, $name, $fieldlist, $isPrimary=false );
|
|
|
|
/**
|
|
* Change field in database table
|
|
*
|
|
* @param string Table name
|
|
* @param string Existing field name
|
|
* @param string New field name
|
|
* @param string [Optional] Field type
|
|
* @param string [Optional] Default value
|
|
* @return @e resource
|
|
*/
|
|
public function changeField( $table, $old_field, $new_field, $type='', $default=NULL );
|
|
|
|
/**
|
|
* Optimize database table
|
|
*
|
|
* @param string Table name
|
|
* @return @e resource
|
|
*/
|
|
public function optimize( $table );
|
|
|
|
/**
|
|
* Add fulltext index to database column
|
|
*
|
|
* @param string Table name
|
|
* @param string Field name
|
|
* @return @e resource
|
|
*/
|
|
public function addFulltextIndex( $table, $field );
|
|
|
|
/**
|
|
* Get table schematic
|
|
*
|
|
* @param string Table name
|
|
* @return @e array
|
|
*/
|
|
public function getTableSchematic( $table );
|
|
|
|
/**
|
|
* Get array of table names in database
|
|
*
|
|
* @return @e array
|
|
*/
|
|
public function getTableNames();
|
|
|
|
/**
|
|
* Get array of field names in table
|
|
*
|
|
* @param string Table name
|
|
* @return @e array
|
|
*/
|
|
public function getFieldNames( $table );
|
|
|
|
/**
|
|
* Determine if table already has a fulltext index
|
|
*
|
|
* @param string Table name
|
|
* @return @e boolean
|
|
*/
|
|
public function getFulltextStatus( $table );
|
|
|
|
/**
|
|
* Retrieve SQL server version
|
|
*
|
|
* @return @e string
|
|
*/
|
|
public function getSqlVersion();
|
|
|
|
/**
|
|
* Set debug mode flag
|
|
*
|
|
* @param boolean [Optional] Set debug mode on/off
|
|
* @return @e void
|
|
*/
|
|
public function setDebugMode( $enable=false );
|
|
|
|
/**
|
|
* Returns current number queries run
|
|
*
|
|
* @return @e integer
|
|
*/
|
|
public function getQueryCount();
|
|
|
|
/**
|
|
* Flushes the currently queued query
|
|
*
|
|
* @return @e void
|
|
*/
|
|
public function flushQuery();
|
|
|
|
/**
|
|
* Load extra SQL query file
|
|
*
|
|
* @param string File name
|
|
* @param string Classname of file
|
|
* @return @e void
|
|
*/
|
|
public function loadCacheFile( $filepath, $classname );
|
|
|
|
/**
|
|
* Checks to see if a query file has been loaded
|
|
*
|
|
* @param string Classname of file
|
|
* @return @e void
|
|
*/
|
|
public function hasLoadedCacheFile( $classname );
|
|
|
|
/**
|
|
* Set fields that shouldn't be escaped
|
|
*
|
|
* @param array SQL table fields
|
|
* @return @e void
|
|
*/
|
|
public function preventAddSlashes( $fields=array() );
|
|
|
|
/**
|
|
* Compiles SQL fields for insertion
|
|
*
|
|
* @param array Array of field => value pairs
|
|
* @return @e array
|
|
*/
|
|
public function compileInsertString( $data );
|
|
|
|
/**
|
|
* Compiles SQL fields for update query
|
|
*
|
|
* @param array Array of field => value pairs
|
|
* @return @e string
|
|
*/
|
|
public function compileUpdateString( $data );
|
|
|
|
/**
|
|
* Escape strings for DB insertion
|
|
*
|
|
* @param string Text to escape
|
|
* @return @e string
|
|
*/
|
|
public function addSlashes( $t );
|
|
|
|
/**
|
|
* Build concat string
|
|
*
|
|
* @param array Array of data to concat
|
|
* @return @e string
|
|
*/
|
|
public function buildConcat( $data );
|
|
|
|
/**
|
|
* Build CAST string
|
|
*
|
|
* @param string Value to CAST
|
|
* @param string Type to cast to
|
|
* @return @e string
|
|
*/
|
|
public function buildCast( $data, $columnType );
|
|
|
|
/**
|
|
* Build between statement
|
|
*
|
|
* @param string Column
|
|
* @param integer Value 1
|
|
* @param integer Value 2
|
|
* @return @e string
|
|
*/
|
|
public function buildBetween( $column, $value1, $value2 );
|
|
|
|
/**
|
|
* Build regexp 'or'
|
|
*
|
|
* @param string Column
|
|
* @param array Array of values to allow
|
|
* @return @e string
|
|
*/
|
|
public function buildRegexp( $column, $data );
|
|
|
|
/**
|
|
* Build LIKE CHAIN string (ONLY supports a regexp equivalent of "or field like value")
|
|
*
|
|
* @param string Database column
|
|
* @param array Array of values to allow
|
|
* @return @e string
|
|
*/
|
|
public function buildLikeChain( $column, $data );
|
|
|
|
/**
|
|
* Build instr string
|
|
*
|
|
* @param string String to look in
|
|
* @param string String to look for
|
|
* @return @e string
|
|
*/
|
|
public function buildInstring( $look_in, $look_for );
|
|
|
|
/**
|
|
* Build substr string
|
|
*
|
|
* @param string String of characters/Column
|
|
* @param integer Offset
|
|
* @param integer [Optional] Number of chars
|
|
* @return @e string
|
|
*/
|
|
public function buildSubstring( $look_for, $offset, $length=0 );
|
|
|
|
/**
|
|
* Build distinct string
|
|
*
|
|
* @param string Column name
|
|
* @return @e string
|
|
*/
|
|
public function buildDistinct( $column );
|
|
|
|
/**
|
|
* Build length string
|
|
*
|
|
* @param string Column name
|
|
* @return @e string
|
|
*/
|
|
public function buildLength( $column );
|
|
|
|
/**
|
|
* Build lower string
|
|
*
|
|
* @param string Column name
|
|
* @return @e string
|
|
*/
|
|
public function buildLower( $column );
|
|
|
|
/**
|
|
* Build right string
|
|
*
|
|
* @param string Column name
|
|
* @param integer Number of chars
|
|
* @return @e string
|
|
*/
|
|
public function buildRight( $column, $chars );
|
|
|
|
/**
|
|
* Build left string
|
|
*
|
|
* @param string Column name
|
|
* @param integer Number of chars
|
|
* @return @e string
|
|
*/
|
|
public function buildLeft( $column, $chars );
|
|
|
|
/**
|
|
* Builds a call to MD5 equivalent
|
|
*
|
|
* @param string Column name or value to MD5-hash
|
|
* @return @e string
|
|
*/
|
|
public function buildMd5Statement( $statement );
|
|
|
|
/**
|
|
* Build "is null" and "is not null" string
|
|
*
|
|
* @param boolean is null flag
|
|
* @return @e string
|
|
*/
|
|
public function buildIsNull( $is_null=true );
|
|
|
|
/**
|
|
* Build coalesce statement
|
|
*
|
|
* @param array Values to check
|
|
* @return @e string
|
|
*/
|
|
public function buildCoalesce( $values=array() );
|
|
|
|
/**
|
|
* Build from_unixtime string
|
|
*
|
|
* @param string Column name
|
|
* @param string [Optional] Format
|
|
* @return @e string
|
|
*/
|
|
public function buildFromUnixtime( $column, $format='' );
|
|
|
|
/**
|
|
* Build unix_timestamp string
|
|
*
|
|
* @param string Column name
|
|
* @return @e string
|
|
*/
|
|
public function buildUnixTimestamp( $column );
|
|
|
|
/**
|
|
* Build date_format string
|
|
*
|
|
* @param string Date string
|
|
* @param string Format
|
|
* @return @e string
|
|
*/
|
|
public function buildDateFormat( $column, $format );
|
|
|
|
/**
|
|
* Build rand() string
|
|
*
|
|
* @return @e string
|
|
*/
|
|
public function buildRandomOrder();
|
|
|
|
/**
|
|
* Build fulltext search string
|
|
*
|
|
* @param string Column to search against
|
|
* @param string String to search
|
|
* @param boolean Search in boolean mode
|
|
* @param boolean Return a "as ranking" statement from the build
|
|
* @param boolean Use fulltext search
|
|
* @return @e string
|
|
*/
|
|
public function buildSearchStatement( $column, $keyword, $booleanMode=true, $returnRanking=false, $useFulltext=true );
|
|
|
|
/**
|
|
* Prints SQL error message
|
|
*
|
|
* @param string Additional error message
|
|
* @return @e mixed
|
|
*/
|
|
public function throwFatalError( $the_error='' );
|
|
|
|
/**
|
|
* Returns a portion of a WHERE query suitable for use.
|
|
* Specific to tables with a field that has a comma separated list of IDs.
|
|
*
|
|
* @param array Array of perm IDs
|
|
* @param string DB field to search in
|
|
* @param boolean check for '*' in the field to denote 'global'
|
|
* @return @e mixed
|
|
*/
|
|
public function buildWherePermission( array $ids, $field='', $incStarCheck=true );
|
|
|
|
/**
|
|
* Set Timezone
|
|
*
|
|
* @param float UTC Offset (e.g. 6 or -4.5)
|
|
* @return @e void
|
|
*/
|
|
public function setTimeZone( $offset );
|
|
|
|
/**
|
|
* Logs SQL error message to log file
|
|
*
|
|
* @param string SQL Query
|
|
* @param string Data to log (i.e. error message)
|
|
* @param integer Timestamp for log
|
|
* @return @e void
|
|
*/
|
|
public function writeDebugLog( $query, $data, $endtime );
|
|
}
|
|
|
|
/**
|
|
* Abstract database class
|
|
*/
|
|
abstract class dbMain
|
|
{
|
|
/**
|
|
* DB object array
|
|
*
|
|
* @var array
|
|
*/
|
|
public $obj = array( "sql_database" => "" ,
|
|
"sql_user" => "root" ,
|
|
"sql_pass" => "" ,
|
|
"sql_host" => "localhost" ,
|
|
"sql_port" => "" ,
|
|
"persistent" => "0" ,
|
|
"sql_tbl_prefix" => "" ,
|
|
"cached_queries" => array() ,
|
|
'shutdown_queries' => array() ,
|
|
'debug' => 0 ,
|
|
'use_shutdown' => 1 ,
|
|
'query_cache_file' => '' ,
|
|
'force_new_connection' => 0 ,
|
|
'error_log' => '' ,
|
|
'use_error_log' => 0 ,
|
|
'use_debug_log' => 0 ,
|
|
'bad_log' => '' ,
|
|
'use_bad_log' => 0 );
|
|
|
|
/**
|
|
* Error message
|
|
*
|
|
* @var string
|
|
*/
|
|
public $error = "";
|
|
|
|
/**
|
|
* Error code
|
|
*
|
|
* @var mixed
|
|
*/
|
|
public $error_no = 0;
|
|
|
|
/**
|
|
* Return error message or die inline
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $return_die = false;
|
|
|
|
/**
|
|
* DB query failed
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $failed = false;
|
|
|
|
/**
|
|
* Object reference to query cache file
|
|
*
|
|
* @var object
|
|
*/
|
|
protected $sql = null;
|
|
|
|
/**
|
|
* Current sql query
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $cur_query = "";
|
|
|
|
/**
|
|
* Current DB query ID
|
|
*
|
|
* @var resource
|
|
*/
|
|
protected $query_id = null;
|
|
|
|
/**
|
|
* Current DB connection ID
|
|
*
|
|
* @var resource
|
|
*/
|
|
protected $connection_id = null;
|
|
|
|
/**
|
|
* Number of queries run so far
|
|
*
|
|
* @var integer
|
|
*/
|
|
public $query_count = 0;
|
|
|
|
/**
|
|
* Escape / don't escape slashes during insert ops
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $manual_addslashes = false;
|
|
|
|
/**
|
|
* Is a shutdown query
|
|
*
|
|
* @var boolean
|
|
*/
|
|
protected $is_shutdown = false;
|
|
|
|
/**
|
|
* Prefix already converted
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $no_prefix_convert = false;
|
|
|
|
/**
|
|
* DB record row
|
|
*
|
|
* @var array
|
|
*/
|
|
public $record_row = array();
|
|
|
|
/**
|
|
* Extra classes loaded
|
|
*
|
|
* @var array
|
|
*/
|
|
public $loaded_classes = array();
|
|
|
|
/**
|
|
* Optimization to stop querying the same loaded cache over and over
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_triedToLoadCacheFiles = array();
|
|
|
|
/**
|
|
* Connection variables set when installed
|
|
*
|
|
* @var array
|
|
*/
|
|
public $connect_vars = array();
|
|
|
|
/**
|
|
* Over-ride guessed data types in insert/update ops
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $_dataTypes = array();
|
|
|
|
/**
|
|
* Select which fields aren't escaped during insert/update ops. Set using preventAddSlashes()
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $no_escape_fields = array();
|
|
|
|
/**
|
|
* Classname of query cache file
|
|
*
|
|
* @var string
|
|
*/
|
|
public $sql_queries_name = 'sql_queries';
|
|
|
|
/**
|
|
* SQL server version (human)
|
|
*
|
|
* @var string
|
|
*/
|
|
public $sql_version = "";
|
|
|
|
/**
|
|
* SQL server version (long)
|
|
*
|
|
* @var string
|
|
*/
|
|
public $true_version = 0;
|
|
|
|
/**
|
|
* Allow sub selects for this query
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $allow_sub_select = false;
|
|
|
|
/**
|
|
* Use (root path)/cache/ipsDriverError.php template
|
|
*
|
|
* @var boolean
|
|
*/
|
|
public $use_template = true;
|
|
|
|
/**
|
|
* Driver Class Name
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $usingClass = '';
|
|
|
|
/**
|
|
* Field encapsulation character
|
|
*
|
|
* @see http://community.invisionpower.com/tracker/issue-19899-postgresql-driver-fields-not-properly-escaped/
|
|
* @var string
|
|
*/
|
|
public $fieldEncapsulate = "'";
|
|
|
|
/**
|
|
* Field name encapsulation character
|
|
*
|
|
* @see http://community.invisionpower.com/tracker/issue-20621-postgresql-driver-field-names-not-properly-escaped/
|
|
* @var string
|
|
*/
|
|
public $fieldNameEncapsulate = '';
|
|
|
|
/**
|
|
* Is running shut down queries
|
|
* @var boolean
|
|
*/
|
|
private $_isShutDown = '';
|
|
|
|
/**
|
|
* Defend against unserialize vuln
|
|
*/
|
|
public function __wakeup()
|
|
{
|
|
foreach( get_object_vars( $this ) as $k => $v )
|
|
{
|
|
$this->$k = null;
|
|
}
|
|
|
|
throw new Exception("Cannot unserialize this object");
|
|
}
|
|
|
|
/**
|
|
* db_driver constructor
|
|
*
|
|
* @return @e void
|
|
*/
|
|
public function __construct()
|
|
{
|
|
//--------------------------------------------
|
|
// Set up any required connect vars here:
|
|
//--------------------------------------------
|
|
|
|
$this->connect_vars = array();
|
|
}
|
|
|
|
/**
|
|
* Global connect class
|
|
*
|
|
* @return @e void
|
|
*/
|
|
public function connect()
|
|
{
|
|
$this->usingClass = strtolower( get_class( $this ) );
|
|
$this->writeDebugLog( '{start}', '', '' );
|
|
}
|
|
|
|
/**
|
|
* Returns the currently formed SQL query
|
|
*
|
|
* @return @e string
|
|
*/
|
|
public function fetchSqlString()
|
|
{
|
|
return $this->cur_query;
|
|
}
|
|
|
|
/**
|
|
* Turns table identity insert on/off
|
|
*
|
|
* @param string Table name
|
|
* @param string On or Off
|
|
* @return @e string
|
|
*/
|
|
public function setTableIdentityInsert( $tableName, $status='OFF' )
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Force a column data type
|
|
*
|
|
* @param mixed $column Column name, or an array of column names
|
|
* @param string $type Data type to use
|
|
* @return @e void
|
|
*/
|
|
public function setDataType( $column, $type='string' )
|
|
{
|
|
if( is_array($column) )
|
|
{
|
|
foreach( $column as $_column )
|
|
{
|
|
$this->_dataTypes[ $_column ] = $type;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->_dataTypes[ $column ] = $type;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset forced data types
|
|
*
|
|
* @return @e void
|
|
*/
|
|
public function resetDataTypes()
|
|
{
|
|
$this->_dataTypes = array();
|
|
}
|
|
|
|
/**
|
|
* Takes array of set commands and generates a SQL formatted query
|
|
*
|
|
* @param array Set commands (select, from, where, order, limit, etc)
|
|
* @return @e void
|
|
*/
|
|
public function build( $data )
|
|
{
|
|
/* Inline build from cache files? Not all drviers may have a cache file.. */
|
|
if ( $this->usingClass != 'db_driver_mysql' AND ( $data['queryKey'] AND $data['queryLocation'] AND $data['queryClass'] ) )
|
|
{
|
|
if ( self::loadCacheFile( $data['queryLocation'], $data['queryClass'] ) === TRUE )
|
|
{
|
|
self::buildFromCache( $data['queryKey'], $data['queryVars'], $data['queryClass'] );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( !empty($data['select']) )
|
|
{
|
|
$this->_buildSelect( $data['select'], $data['from'], isset($data['where']) ? $data['where'] : '', isset( $data['add_join'] ) ? $data['add_join'] : array(), isset( $data['calcRows'] ) ? $data['calcRows'] : '', $data['forceIndex'] );
|
|
}
|
|
|
|
if ( !empty($data['update']) )
|
|
{
|
|
$this->update( $data['update'], $data['set'], isset($data['where']) ? $data['where'] : '', false, true, isset( $data['add_join'] ) ? $data['add_join'] : array() );
|
|
return;
|
|
}
|
|
|
|
if ( !empty($data['delete']) )
|
|
{
|
|
$this->delete( $data['delete'], $data['where'], $data['order'], $data['limit'], false );
|
|
return;
|
|
}
|
|
|
|
if ( !empty($data['group']) )
|
|
{
|
|
$this->_buildGroupBy( $data['group'] );
|
|
}
|
|
|
|
if ( !empty($data['having']) )
|
|
{
|
|
$this->_buildHaving( $data['having'] );
|
|
}
|
|
|
|
if ( !empty($data['order']) )
|
|
{
|
|
$this->_buildOrderBy( $data['order'] );
|
|
}
|
|
|
|
if ( isset( $data['calcRows'] ) AND $data['calcRows'] === TRUE )
|
|
{
|
|
$this->_buildCalcRows();
|
|
}
|
|
|
|
if ( isset($data['limit']) && is_array( $data['limit'] ) )
|
|
{
|
|
$this->_buildLimit( $data['limit'][0], $data['limit'][1] );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build a query based on template from cache file
|
|
*
|
|
* @param string Name of query file method to use
|
|
* @param array Optional arguments to be parsed inside query function
|
|
* @param string Optional class name
|
|
* @return @e void
|
|
*/
|
|
public function buildFromCache( $method, $args=array(), $class='sql_queries' )
|
|
{
|
|
$instance = null;
|
|
|
|
if ( $class == 'sql_queries' and method_exists( $this->sql, $method ) )
|
|
{
|
|
$instance = $this->sql;
|
|
}
|
|
else if( $class != 'sql_queries' AND method_exists( $this->loaded_classes[ $class ], $method ) )
|
|
{
|
|
$instance = $this->loaded_classes[ $class ];
|
|
}
|
|
|
|
if ( $class == 'sql_queries' and !method_exists( $this->sql, $method ) )
|
|
{
|
|
if ( is_array( $this->loaded_classes ) )
|
|
{
|
|
foreach ( $this->loaded_classes as $class_name => $class_instance )
|
|
{
|
|
if ( method_exists( $this->loaded_classes[ $class_name ], $method ) )
|
|
{
|
|
$instance = $this->loaded_classes[ $class_name ];
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( $instance )
|
|
{
|
|
$this->cur_query .= $instance->$method( $args );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Executes stored SQL query
|
|
*
|
|
* @return @e resource
|
|
*/
|
|
public function execute()
|
|
{
|
|
if ( $this->cur_query != "" )
|
|
{
|
|
$res = $this->query( $this->cur_query );
|
|
}
|
|
|
|
$this->cur_query = "";
|
|
$this->is_shutdown = false;
|
|
|
|
return $res;
|
|
}
|
|
|
|
/**
|
|
* Stores a query for shutdown execution
|
|
*
|
|
* @return @e mixed
|
|
*/
|
|
public function executeOnShutdown()
|
|
{
|
|
if ( ! $this->obj['use_shutdown'] )
|
|
{
|
|
$this->is_shutdown = true;
|
|
return $this->execute();
|
|
}
|
|
else
|
|
{
|
|
$this->obj['shutdown_queries'][] = $this->cur_query;
|
|
$this->cur_query = "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates and executes SQL query, and returns the first result
|
|
*
|
|
* @param array Set commands (select, from, where, order, limit, etc)
|
|
* @return @e array
|
|
*/
|
|
public function buildAndFetch( $data )
|
|
{
|
|
$this->build( $data );
|
|
|
|
$res = $this->execute();
|
|
|
|
if ( !empty($data['select']) )
|
|
{
|
|
return $this->fetch( $res );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates and executes SQL query, and returns the all results in an array
|
|
*
|
|
* @param array Set commands (select, from, where, order, limit, etc)
|
|
* @param string Key to index array on (member_id, for example)
|
|
* @return @e array
|
|
*/
|
|
public function buildAndFetchAll( $data, $arrayIndex=null )
|
|
{
|
|
$return = array();
|
|
|
|
$this->build( $data );
|
|
|
|
$res = $this->execute();
|
|
|
|
if ( ! empty( $data['select'] ) )
|
|
{
|
|
while( $row = $this->fetch( $res ) )
|
|
{
|
|
if ( $arrayIndex !== null )
|
|
{
|
|
if ( ! count( $return ) && ! array_key_exists( $arrayIndex, $row ) )
|
|
{
|
|
trigger_error( 'Index ' . $arrayIndex . ' not found in results' );
|
|
}
|
|
|
|
$return[ $row[ $arrayIndex ] ] = $row;
|
|
}
|
|
else
|
|
{
|
|
$return[] = $row;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Determine if query is shutdown and run it
|
|
*
|
|
* @param string Query
|
|
* @param boolean [Optional] Run on shutdown
|
|
* @return @e mixed
|
|
*/
|
|
protected function _determineShutdownAndRun( $query, $shutdown=false )
|
|
{
|
|
//-----------------------------------------
|
|
// Shut down query?
|
|
//-----------------------------------------
|
|
|
|
$current = $this->no_prefix_convert;
|
|
$this->no_prefix_convert = true;
|
|
|
|
if ( $shutdown )
|
|
{
|
|
if ( ! $this->obj['use_shutdown'] )
|
|
{
|
|
$current_shutdown = $this->is_shutdown;
|
|
$this->is_shutdown = true;
|
|
$return = $this->query( $query );
|
|
$this->no_prefix_convert = $current;
|
|
$this->is_shutdown = $current_shutdown;
|
|
return $return;
|
|
}
|
|
else
|
|
{
|
|
$this->obj['shutdown_queries'][] = $query;
|
|
$this->no_prefix_convert = $current;
|
|
$this->cur_query = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$return = $this->query( $query );
|
|
$this->no_prefix_convert = $current;
|
|
return $return;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test to see whether an index exists in a table
|
|
*
|
|
* @param string Index name
|
|
* @param string Table name
|
|
* @return @e boolean
|
|
*/
|
|
public function checkForIndex( $index, $table )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Test to see whether a field exists in a table
|
|
*
|
|
* @param string Field name
|
|
* @param string Table name
|
|
* @return @e boolean
|
|
*/
|
|
public function checkForField( $field, $table )
|
|
{
|
|
$current = $this->return_die;
|
|
$this->return_die = true;
|
|
$this->error = "";
|
|
|
|
$this->build( array( 'select' => "COUNT($field) as count", 'from' => $table ) );
|
|
$this->execute();
|
|
|
|
$return = true;
|
|
|
|
if ( $this->failed )
|
|
{
|
|
$return = false;
|
|
}
|
|
|
|
$this->error = "";
|
|
$this->return_die = $current;
|
|
$this->error_no = 0;
|
|
$this->failed = false;
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Set debug mode flag
|
|
*
|
|
* @param boolean [Optional] Set debug mode on/off
|
|
* @return @e void
|
|
*/
|
|
public function setDebugMode( $enable=false )
|
|
{
|
|
$this->obj['debug'] = intval($enable);
|
|
|
|
//-----------------------------------------
|
|
// If debug, no shutdown....
|
|
//-----------------------------------------
|
|
|
|
if ( $this->obj['debug'] )
|
|
{
|
|
$this->obj['use_shutdown'] = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns current number queries run
|
|
*
|
|
* @return @e integer
|
|
*/
|
|
public function getQueryCount()
|
|
{
|
|
return $this->query_count;
|
|
}
|
|
|
|
/**
|
|
* Flushes the currently queued query
|
|
*
|
|
* @return @e void
|
|
*/
|
|
public function flushQuery()
|
|
{
|
|
$this->cur_query = "";
|
|
}
|
|
|
|
/**
|
|
* Set SQL Prefix
|
|
*
|
|
* @return @e void
|
|
*/
|
|
protected function _setPrefix()
|
|
{
|
|
/*if ( ! defined( 'IPSDB::driver()' ) )
|
|
{
|
|
$this->obj['sql_tbl_prefix'] = isset($this->obj['sql_tbl_prefix']) ? $this->obj['sql_tbl_prefix'] : 'ibf_';
|
|
|
|
define( 'IPSDB::driver()', $this->obj['sql_tbl_prefix'] );
|
|
}*/
|
|
}
|
|
|
|
/**
|
|
* Has loaded cache file
|
|
*
|
|
* @param string Classname
|
|
* @return @e boolean
|
|
*/
|
|
public function hasLoadedCacheFile( $classname )
|
|
{
|
|
if ( isset( $this->loaded_classes[ $classname ] ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load extra SQL query file
|
|
*
|
|
* @param string File name
|
|
* @param string Classname of file
|
|
* @param boolean Ignore missing files, FALSE $this->error is set, TRUE, nothing happens.
|
|
* @return @e boolean
|
|
*/
|
|
public function loadCacheFile( $filepath, $classname, $ignoreMissing=FALSE )
|
|
{
|
|
/* Tried to load this already? */
|
|
if ( ! isset( $this->_triedToLoadCacheFiles[ $classname ] ) )
|
|
{
|
|
/* Try and load it */
|
|
if ( ! is_file( $filepath ) AND $ignoreMissing === FALSE )
|
|
{
|
|
$this->error = "Cannot locate {$filepath} - exiting!";
|
|
|
|
$this->_triedToLoadCacheFiles[ $classname ] = FALSE;
|
|
}
|
|
else if ( $this->hasLoadedCacheFile( $classname ) !== TRUE )
|
|
{
|
|
require_once( $filepath );/*noLibHook*/
|
|
|
|
if( class_exists( $classname ) )
|
|
{
|
|
$this->loaded_classes[ $classname ] = new $classname( $this );
|
|
|
|
$this->_triedToLoadCacheFiles[ $classname ] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $this->_triedToLoadCacheFiles[ $classname ];
|
|
}
|
|
|
|
/**
|
|
* Returns a portion of a WHERE query suitable for use.
|
|
* Specific to tables with a field that has a comma separated list of IDs.
|
|
*
|
|
* @param array Array of perm IDs
|
|
* @param string DB field to search in
|
|
* @param boolean check for '*' in the field to denote 'global'
|
|
* @return @e string
|
|
*/
|
|
public function buildWherePermission( array $ids, $field='', $incStarCheck=true )
|
|
{
|
|
/* Just use a LIKE chain for items without a specific implementation */
|
|
$where = '(' . $this->buildLikeChain( $field, $ids ) . ')';
|
|
|
|
if ( $incStarCheck === true )
|
|
{
|
|
$where .= ' OR ( ' . $field . '=\'*\' )';
|
|
}
|
|
|
|
return "( " . $where . " )";
|
|
}
|
|
|
|
/**
|
|
* Load Query cache file
|
|
*
|
|
* @return @e void
|
|
*/
|
|
protected function _loadCacheFile()
|
|
{
|
|
if ( $this->obj['query_cache_file'] )
|
|
{
|
|
require_once( $this->obj['query_cache_file'] );/*noLibHook*/
|
|
|
|
$sql_queries_name = $this->sql_queries_name ? $this->sql_queries_name : 'sql_queries';
|
|
|
|
$this->sql = new $sql_queries_name( $this );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set fields that shouldn't be escaped
|
|
*
|
|
* @param array SQL table fields
|
|
* @return @e void
|
|
*/
|
|
public function preventAddSlashes( $fields=array() )
|
|
{
|
|
$this->no_escape_fields = $fields;
|
|
}
|
|
|
|
/**
|
|
* Compiles SQL fields for insertion
|
|
*
|
|
* @param array Array of field => value pairs
|
|
* @return @e array
|
|
*/
|
|
public function compileInsertString( $data )
|
|
{
|
|
$field_names = "";
|
|
$field_values = "";
|
|
|
|
foreach( $data as $k => $v )
|
|
{
|
|
$add_slashes = 1;
|
|
|
|
if ( $this->manual_addslashes )
|
|
{
|
|
$add_slashes = 0;
|
|
}
|
|
|
|
if ( !empty($this->no_escape_fields[ $k ]) )
|
|
{
|
|
$add_slashes = 0;
|
|
}
|
|
|
|
if ( $add_slashes )
|
|
{
|
|
$v = $this->addSlashes( $v );
|
|
}
|
|
|
|
$field_names .= $this->fieldNameEncapsulate . "$k" . $this->fieldNameEncapsulate . ',';
|
|
|
|
//-----------------------------------------
|
|
// Forcing data type?
|
|
//-----------------------------------------
|
|
|
|
if ( substr( $v, -1 ) == '\\' )
|
|
{
|
|
$v = preg_replace( '#\\\{1}$#', '\', $v );
|
|
}
|
|
|
|
if ( !empty($this->_dataTypes[ $k ]) )
|
|
{
|
|
if ( $this->_dataTypes[ $k ] == 'string' )
|
|
{
|
|
$field_values .= $this->fieldEncapsulate . $v . $this->fieldEncapsulate . ',';
|
|
}
|
|
else if ( $this->_dataTypes[ $k ] == 'int' )
|
|
{
|
|
$field_values .= intval($v).",";
|
|
}
|
|
else if ( $this->_dataTypes[ $k ] == 'float' )
|
|
{
|
|
$field_values .= floatval($v).",";
|
|
}
|
|
if ( $this->_dataTypes[ $k ] == 'null' )
|
|
{
|
|
$field_values .= "NULL,";
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// No? best guess it is then..
|
|
//-----------------------------------------
|
|
|
|
else
|
|
{
|
|
if ( is_numeric( $v ) and strcmp( intval($v), $v ) === 0 )
|
|
{
|
|
$field_values .= $v.",";
|
|
}
|
|
else
|
|
{
|
|
$field_values .= $this->fieldEncapsulate . $v . $this->fieldEncapsulate . ',';
|
|
}
|
|
}
|
|
}
|
|
|
|
$field_names = rtrim( $field_names, "," );
|
|
$field_values = rtrim( $field_values, "," );
|
|
|
|
return array( 'FIELD_NAMES' => $field_names,
|
|
'FIELD_VALUES' => $field_values,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Compiles SQL fields for update query
|
|
*
|
|
* @param array Array of field => value pairs
|
|
* @return @e string
|
|
*/
|
|
public function compileUpdateString( $data )
|
|
{
|
|
$return_string = "";
|
|
|
|
foreach( $data as $k => $v )
|
|
{
|
|
//-----------------------------------------
|
|
// Adding slashes?
|
|
//-----------------------------------------
|
|
|
|
$add_slashes = 1;
|
|
|
|
if ( $this->manual_addslashes )
|
|
{
|
|
$add_slashes = 0;
|
|
}
|
|
|
|
if ( !empty($this->no_escape_fields[ $k ]) )
|
|
{
|
|
$add_slashes = 0;
|
|
}
|
|
|
|
if ( $add_slashes )
|
|
{
|
|
$v = $this->addSlashes( $v );
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Forcing data type?
|
|
//-----------------------------------------
|
|
|
|
if ( !empty($this->_dataTypes[ $k ]) )
|
|
{
|
|
if ( $this->_dataTypes[ $k ] == 'string' )
|
|
{
|
|
if ( substr( $v, -1 ) == '\\' )
|
|
{
|
|
$v = preg_replace( '#\\\{1}$#', '\', $v );
|
|
}
|
|
|
|
$return_string .= $k . '=' . $this->fieldEncapsulate . $v . $this->fieldEncapsulate . ',';
|
|
}
|
|
else if ( $this->_dataTypes[ $k ] == 'int' )
|
|
{
|
|
if ( strstr( $v, 'plus:' ) )
|
|
{
|
|
$return_string .= $k . "=" . $k . '+' . intval( str_replace( 'plus:', '', $v ) ).",";
|
|
}
|
|
else if ( strstr( $v, 'minus:' ) )
|
|
{
|
|
$return_string .= $k . "=" . $k . '-' . intval( str_replace( 'minus:', '', $v ) ).",";
|
|
}
|
|
else
|
|
{
|
|
$return_string .= $k . "=" . intval($v) . ",";
|
|
}
|
|
}
|
|
else if ( $this->_dataTypes[ $k ] == 'float' )
|
|
{
|
|
$return_string .= $k . "=" . floatval($v) . ",";
|
|
}
|
|
else if ( $this->_dataTypes[ $k ] == 'null' )
|
|
{
|
|
$return_string .= $k . "=NULL,";
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// No? best guess it is then..
|
|
//-----------------------------------------
|
|
|
|
else
|
|
{
|
|
if ( is_numeric( $v ) and strcmp( intval($v), $v ) === 0 )
|
|
{
|
|
$return_string .= $k . "=" . $v . ",";
|
|
}
|
|
else
|
|
{
|
|
if ( substr( $v, -1 ) == '\\' )
|
|
{
|
|
$v = preg_replace( '#\\\{1}$#', '\', $v );
|
|
}
|
|
|
|
$return_string .= $k . '=' . $this->fieldEncapsulate . $v . $this->fieldEncapsulate . ',';
|
|
}
|
|
}
|
|
}
|
|
|
|
$return_string = rtrim( $return_string, "," );
|
|
|
|
return $return_string;
|
|
}
|
|
|
|
/**
|
|
* Remove quotes from a DB query
|
|
*
|
|
* @param string Raw text
|
|
* @return @e string
|
|
*/
|
|
protected function _removeAllQuotes( $t )
|
|
{
|
|
//-----------------------------------------
|
|
// Remove quotes
|
|
//-----------------------------------------
|
|
|
|
$t = preg_replace( "#\\\{1,}[\"']#s", "", $t );
|
|
$t = preg_replace( "#'[^']*'#s" , "", $t );
|
|
$t = preg_replace( "#\"[^\"]*\"#s" , "", $t );
|
|
$t = preg_replace( "#\"\"#s" , "", $t );
|
|
$t = preg_replace( "#''#s" , "", $t );
|
|
|
|
return $t;
|
|
}
|
|
|
|
/**
|
|
* Build order by clause
|
|
*
|
|
* @param string Order by clause
|
|
* @return @e void
|
|
*/
|
|
abstract protected function _buildOrderBy( $order );
|
|
|
|
/**
|
|
* Build having clause
|
|
*
|
|
* @param string Having clause
|
|
* @return @e void
|
|
*/
|
|
abstract protected function _buildHaving( $having_clause );
|
|
|
|
/**
|
|
* Build group by clause
|
|
*
|
|
* @param string Group by clause
|
|
* @return @e void
|
|
*/
|
|
abstract protected function _buildGroupBy( $group );
|
|
|
|
/**
|
|
* Build limit clause
|
|
*
|
|
* @param integer Start offset
|
|
* @param integer [Optional] Number of records
|
|
* @return @e void
|
|
*/
|
|
abstract protected function _buildLimit( $offset, $limit=0 );
|
|
|
|
/**
|
|
* Build select statement
|
|
*
|
|
* @param string Columns to retrieve
|
|
* @param string Table name
|
|
* @param string [Optional] Where clause
|
|
* @param array [Optional] Joined table data
|
|
* @param array [Optional] Force index
|
|
* @return @e void
|
|
*/
|
|
abstract protected function _buildSelect( $get, $table, $where, $add_join=array(), $calcRows=FALSE, $forceIndex=array() );
|
|
|
|
/**
|
|
* Generates calc rows in the query if supported / runs count(*) if not
|
|
*
|
|
* @return @e void Sets $this->_calcRows
|
|
*/
|
|
abstract protected function _buildCalcRows();
|
|
|
|
/**
|
|
* Prints SQL error message
|
|
*
|
|
* @param string Additional error message
|
|
* @return @e mixed
|
|
*/
|
|
public function throwFatalError( $the_error='' )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$this->error = $this->_getErrorString();
|
|
$this->error_no = $this->_getErrorNumber();
|
|
$errTemplate = 'ipsDriverError';
|
|
$nonIPSErrors = array( '1012-1021', '1023-1027', '1030-1031', '1034-1043', '1129-1131', '1150-1153', 1194, 1195, '1203-1207' );
|
|
|
|
/* MySQL: Is this non IPS error? */
|
|
if ( $this->usingClass == 'db_driver_mysql' )
|
|
{
|
|
if ( stristr( $this->error, 'has gone away') OR stristr( $this->error, 'connect to local mysql server through socket') )
|
|
{
|
|
$errTemplate = 'ipsServerError';
|
|
}
|
|
else if ( $this->error_no )
|
|
{
|
|
foreach( $nonIPSErrors as $id )
|
|
{
|
|
if ( strstr( $id, '-' ) )
|
|
{
|
|
list( $a, $b ) = explode( '-', $id );
|
|
|
|
if ( $a AND $b )
|
|
{
|
|
if ( $this->error_no >= $a AND $this->error_no <= $b )
|
|
{
|
|
$errTemplate = 'ipsServerError';
|
|
}
|
|
}
|
|
}
|
|
else if ( $this->error_no == intval( $id ) )
|
|
{
|
|
$errTemplate = 'ipsServerError';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Fetch debug information */
|
|
$_debug = debug_backtrace();
|
|
$_dString = '';
|
|
|
|
if ( is_array( $_debug ) and count( $_debug ) )
|
|
{
|
|
foreach( $_debug as $idx => $data )
|
|
{
|
|
/* Remove non-essential items */
|
|
if ( $data['class'] == 'dbMain' OR $data['class'] == 'ips_DBRegistry' OR $data['class'] == 'ipsRegistry' OR $data['class'] == 'ipsController' OR $data['class'] == 'ipsCommand' OR $data['class'] == 'db_driver_mysql' )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$_dbString[ $idx ] = array( 'file' => $data['file'],
|
|
'line' => $data['line'],
|
|
'function' => $data['function'],
|
|
'class' => $data['class'] );
|
|
}
|
|
}
|
|
|
|
$_error_string = "\n ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
|
|
$_error_string .= "\n Date: ". date( 'r' );
|
|
$_error_string .= "\n Error: " . $this->error_no . ' - ' . $this->error;
|
|
$_error_string .= "\n IP Address: " . $_SERVER['REMOTE_ADDR'] . ' - ' . $_SERVER['REQUEST_URI'];
|
|
$_error_string .= "\n ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
|
|
$_error_string .= "\n " . $the_error;
|
|
$_error_string .= "\n .--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------.";
|
|
|
|
if ( count( $_dbString ) )
|
|
{
|
|
$_error_string .= "\n | File | Function | Line No. |";
|
|
$_error_string .= "\n |----------------------------------------------------------------------------+-------------------------------------------------------------------------------+-------------------|";
|
|
|
|
foreach( $_dbString as $i => $data )
|
|
{
|
|
if ( defined('DOC_IPS_ROOT_PATH') )
|
|
{
|
|
$data['file'] = str_replace( DOC_IPS_ROOT_PATH, '', $data['file'] );
|
|
}
|
|
|
|
/* Reset */
|
|
$data['func'] = "[" . $data['class'] . '].' . $data['function'];
|
|
|
|
/* Pad right */
|
|
$data['file'] = str_pad( $data['file'], 75 );
|
|
$data['func'] = str_pad( $data['func'], 78 );
|
|
$data['line'] = str_pad( $data['line'], 18 );
|
|
|
|
$_error_string .= "\n | " . $data['file'] . "| " . $data['func'] . '| ' . $data['line'] . '|';
|
|
$_error_string .= "\n '----------------------------------------------------------------------------+-------------------------------------------------------------------------------+-------------------'";
|
|
}
|
|
}
|
|
|
|
if ( $this->return_die == true )
|
|
{
|
|
$this->error = ( $this->error == "" ? $the_error : $this->error );
|
|
$this->failed = true;
|
|
return;
|
|
}
|
|
else if ( $this->obj['use_error_log'] AND $this->obj['error_log'] )
|
|
{
|
|
if ( $FH = @fopen( $this->obj['error_log'], 'a' ) )
|
|
{
|
|
@fwrite( $FH, $_error_string );
|
|
@fclose( $FH );
|
|
}
|
|
|
|
/* Write to latest log also */
|
|
if ( is_dir( IPS_CACHE_PATH . 'cache' ) )
|
|
{
|
|
@file_put_contents( IPS_CACHE_PATH . 'cache/sql_error_latest.cgi', trim( $_error_string ) );
|
|
}
|
|
else if ( is_dir( DOC_IPS_ROOT_PATH . 'cache' ) )
|
|
{
|
|
@file_put_contents( DOC_IPS_ROOT_PATH . 'cache/sql_error_latest.cgi', trim( $_error_string ) );
|
|
}
|
|
|
|
if ( isset( $_SERVER['SERVER_PROTOCOL'] ) AND strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) )
|
|
{
|
|
@header( "HTTP/1.0 503 Service Unavailable" );
|
|
}
|
|
else
|
|
{
|
|
@header( "HTTP/1.1 503 Service Unavailable" );
|
|
}
|
|
|
|
if( $this->use_template )
|
|
{
|
|
require_once IPS_ROOT_PATH . 'sources/classes/output/systemTemplates.php';
|
|
$systemTemplates = new systemTemplates();
|
|
$template = $systemTemplates->getClass( $errTemplate );
|
|
|
|
$errorBlock = '';
|
|
|
|
if( $errTemplate == 'ipsServerError' and $the_error )
|
|
{
|
|
$_errorMessage = htmlspecialchars( $the_error );
|
|
$errorBlock = <<<EOF
|
|
<div class='database-error'>
|
|
<form name='mysql'>
|
|
<textarea rows="15" cols="60">{$the_error}</textarea>
|
|
</form>
|
|
</div>
|
|
EOF;
|
|
}
|
|
|
|
print $template->getTemplate( $_SERVER['HTTP_HOST'], nl2br( trim( $the_error ) ), $errorBlock );
|
|
}
|
|
else
|
|
{
|
|
print "<html><head><title>IPS Driver Error</title>
|
|
<style>P,BODY{ font-family:arial,sans-serif; font-size:11px; }</style></head><body>
|
|
<blockquote><h1>IPS Driver Error</h1><b>There appears to be an error with the database.</b><br>
|
|
You can try to refresh the page by clicking <a href=\"javascript:window.location=window.location;\">here</a>
|
|
</body></html>";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$the_error .= "\n\nSQL error: ".$this->error."\n";
|
|
$the_error .= "SQL error code: ".$this->error_no."\n";
|
|
$the_error .= "Date: ".date("l dS F Y h:i:s A");
|
|
$the_error .= "\n\n" . $_error_string;
|
|
|
|
if ( isset( $_SERVER['SERVER_PROTOCOL'] ) AND strstr( $_SERVER['SERVER_PROTOCOL'], '/1.0' ) )
|
|
{
|
|
@header( "HTTP/1.0 503 Service Unavailable" );
|
|
}
|
|
else
|
|
{
|
|
@header( "HTTP/1.1 503 Service Unavailable" );
|
|
}
|
|
|
|
if( $this->use_template )
|
|
{
|
|
require_once IPS_ROOT_PATH . 'sources/classes/output/systemTemplates.php';
|
|
$systemTemplates = new systemTemplates();
|
|
$template = $systemTemplates->getClass( $errTemplate );
|
|
|
|
$errorBlock = '';
|
|
if( $the_error )
|
|
{
|
|
$_errorMessage = htmlspecialchars( $the_error );
|
|
$errorBlock = <<<EOF
|
|
<div class='database-error'>
|
|
<form name='mysql'>
|
|
<textarea rows="15" cols="60">{$the_error}</textarea>
|
|
</form>
|
|
</div>
|
|
EOF;
|
|
}
|
|
|
|
print $template->getTemplate( $_SERVER['HTTP_HOST'], nl2br( trim( $the_error ) ), $errorBlock, ipsRegistry::$settings );
|
|
}
|
|
else
|
|
{
|
|
print "<html><head><title>IPS Driver Error</title>
|
|
<style>P,BODY{ font-family:arial,sans-serif; font-size:11px; }</style></head><body>
|
|
<blockquote><h1>IPS Driver Error</h1><b>There appears to be an error with the database.</b><br>
|
|
You can try to refresh the page by clicking <a href=\"javascript:window.location=window.location;\">here</a>.
|
|
<br><br><b>Error Returned</b><br>
|
|
<form name='mysql'><textarea rows=\"15\" cols=\"60\">".htmlspecialchars($the_error)."</textarea></form><br>We apologise for any inconvenience</blockquote></body></html>";
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Need to clear this for shutdown queries
|
|
//-----------------------------------------
|
|
|
|
$this->cur_query = '';
|
|
|
|
exit();
|
|
}
|
|
|
|
/**
|
|
* Logs SQL error message to log file
|
|
*
|
|
* @param string SQL Query
|
|
* @param string Data to log (i.e. error message)
|
|
* @param integer Timestamp for log
|
|
* @return @e void
|
|
*/
|
|
public function writeDebugLog( $query, $data, $endtime, $fileToWrite='', $backTrace=FALSE )
|
|
{
|
|
$fileToWrite = ( $fileToWrite ) ? $fileToWrite : $this->obj['debug_log'];
|
|
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
if ( ( $this->obj['use_debug_log'] AND $this->obj['debug_log'] ) OR ( $this->obj['use_bad_log'] AND $this->obj['bad_log'] ) OR ( $this->obj['use_slow_log'] AND $this->obj['slow_log'] ) )
|
|
{
|
|
if ( $query == '{start}' AND ( $this->obj['use_debug_log'] AND $this->obj['debug_log'] ) )
|
|
{
|
|
$_string = "\n\n\n\n\n==============================================================================";
|
|
$_string .= "\n========================= START ===================================";
|
|
$_string .= "\n========================= " . $_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING'] . " ===================================";
|
|
$_string .= "\n==============================================================================";
|
|
}
|
|
else if ( $query == '{end}' AND ( $this->obj['use_debug_log'] AND $this->obj['debug_log'] ) )
|
|
{
|
|
$_string = "\n==============================================================================";
|
|
$_string .= "\n========================= END ===================================";
|
|
$_string .= "\n========================= " . $_SERVER['PHP_SELF'] . '?' . $_SERVER['QUERY_STRING'] . " ===================================";
|
|
$_string .= "\n==============================================================================";
|
|
}
|
|
else if ( $query != '{start}' AND $query != '{end}' )
|
|
{
|
|
$_string = "\n==============================================================================";
|
|
$_string .= "\n URL: ". $_SERVER['PHP_SELF'] . $_SERVER['REQUEST_URI'];
|
|
$_string .= "\n Date: ". date( 'r' );
|
|
$_string .= "\n IP Address: " . $_SERVER['REMOTE_ADDR'];
|
|
$_string .= "\n Time Taken: ".$endtime;
|
|
$_string .= "\n ".$query;
|
|
$_string .= "\n".$data;
|
|
$_string .= "\n==============================================================================";
|
|
}
|
|
|
|
if ( $_string AND $FH = @fopen( $fileToWrite, 'a' ) )
|
|
{
|
|
@fwrite( $FH, $_string );
|
|
@fclose( $FH );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return an object handle for a loaded class
|
|
*
|
|
* @param string Class to return
|
|
* @return @e object
|
|
*/
|
|
public function fetchLoadedClass( $class )
|
|
{
|
|
return ( is_object( $this->loaded_classes[ $class ] ) ) ? $this->loaded_classes[ $class ] : NULL;
|
|
}
|
|
|
|
/**
|
|
* Get SQL error number
|
|
*
|
|
* @return @e mixed
|
|
*/
|
|
abstract protected function _getErrorNumber();
|
|
|
|
/**
|
|
* Get SQL error message
|
|
*
|
|
* @return @e string
|
|
*/
|
|
abstract protected function _getErrorString();
|
|
|
|
/**
|
|
* db_driver destructor: Runs shutdown queries and closes connection
|
|
*
|
|
* @return @e void
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
$this->return_die = true;
|
|
$this->_isShutDown = true;
|
|
|
|
if ( count( $this->obj['shutdown_queries'] ) )
|
|
{
|
|
foreach( $this->obj['shutdown_queries'] as $q )
|
|
{
|
|
$this->query( $q );
|
|
}
|
|
}
|
|
|
|
$this->writeDebugLog( '{end}', '', '' );
|
|
|
|
$this->obj['shutdown_queries'] = array();
|
|
|
|
$this->disconnect();
|
|
}
|
|
} |