<?phpif(!defined('BASEPATH'))exit('No direct script access allowed');/** * CodeIgniter * * An open source application development framework for PHP 5.1.6 or newer * * @package CodeIgniter * @author ExpressionEngine Dev Team * @copyright Copyright (c) 2008 - 2011, EllisLab, Inc. * @license http://codeigniter.com/user_guide/license.html * @link http://codeigniter.com * @since Version 1.0 * @filesource */// ------------------------------------------------------------------------/** * Database Driver Class * * This is the platform-independent base DB implementation class. * This class will not be called directly. Rather, the adapter * class for the specific database will extend and instantiate it. * * @package CodeIgniter * @subpackage Drivers * @category Database * @author ExpressionEngine Dev Team * @link http://codeigniter.com/user_guide/database/ */classCI_DB_driver{var$username;var$password;var$hostname;var$database;var$dbdriver='mysql';var$dbprefix='';var$char_set='utf8';var$dbcollat='utf8_general_ci';var$autoinit=TRUE;// Whether to automatically initialize the DBvar$swap_pre='';var$port='';var$pconnect=FALSE;var$conn_id=FALSE;var$result_id=FALSE;var$db_debug=FALSE;var$benchmark=0;var$query_count=0;var$bind_marker='?';var$save_queries=TRUE;var$queries=array();var$query_times=array();var$data_cache=array();var$trans_enabled=TRUE;var$trans_strict=TRUE;var$_trans_depth=0;var$_trans_status=TRUE;// Used with transactions to determine if a rollback should occurvar$cache_on=FALSE;var$cachedir='';var$cache_autodel=FALSE;var$CACHE;// The cache class object// Private variablesvar$_protect_identifiers=TRUE;var$_reserved_identifiers=array('*');// Identifiers that should NOT be escaped// These are use with Oraclevar$stmt_id;var$curs_id;var$limit_used;/** * Constructor. Accepts one parameter containing the database * connection settings. * * @param array */functionCI_DB_driver($params){if(is_array($params)){foreach($paramsas$key=>$val){$this->$key=$val;}}log_message('debug','Database Driver Class Initialized');}// --------------------------------------------------------------------/** * Initialize Database Settings * * @access private Called by the constructor * @param mixed * @return void */functioninitialize(){// If an existing connection resource is available// there is no need to connect and select the databaseif(is_resource($this->conn_id)ORis_object($this->conn_id)){returnTRUE;}// ----------------------------------------------------------------// Connect to the database and set the connection ID$this->conn_id=($this->pconnect==FALSE)?$this->db_connect():$this->db_pconnect();// No connection resource? Throw an errorif(!$this->conn_id){log_message('error','Unable to connect to the database');if($this->db_debug){$this->display_error('db_unable_to_connect');}returnFALSE;}// ----------------------------------------------------------------// Select the DB... assuming a database name is specified in the config fileif($this->database!=''){if(!$this->db_select()){log_message('error','Unable to select database: '.$this->database);if($this->db_debug){$this->display_error('db_unable_to_select',$this->database);}returnFALSE;}else{// We've selected the DB. Now we set the character setif(!$this->db_set_charset($this->char_set,$this->dbcollat)){returnFALSE;}returnTRUE;}}returnTRUE;}// --------------------------------------------------------------------/** * Set client character set * * @access public * @param string * @param string * @return resource */functiondb_set_charset($charset,$collation){if(!$this->_db_set_charset($this->char_set,$this->dbcollat)){log_message('error','Unable to set database connection charset: '.$this->char_set);if($this->db_debug){$this->display_error('db_unable_to_set_charset',$this->char_set);}returnFALSE;}returnTRUE;}// --------------------------------------------------------------------/** * The name of the platform in use (mysql, mssql, etc...) * * @access public * @return string */functionplatform(){return$this->dbdriver;}// --------------------------------------------------------------------/** * Database Version Number. Returns a string containing the * version of the database being used * * @access public * @return string */functionversion(){if(FALSE===($sql=$this->_version())){if($this->db_debug){return$this->display_error('db_unsupported_function');}returnFALSE;}// Some DBs have functions that return the version, and don't run special// SQL queries per se. In these instances, just return the result.$driver_version_exceptions=array('oci8','sqlite');if(in_array($this->dbdriver,$driver_version_exceptions)){return$sql;}else{$query=$this->query($sql);return$query->row('ver');}}// --------------------------------------------------------------------/** * Execute the query * * Accepts an SQL string as input and returns a result object upon * successful execution of a "read" type query. Returns boolean TRUE * upon successful execution of a "write" type query. Returns boolean * FALSE upon failure, and if the $db_debug variable is set to TRUE * will raise an error. * * @access public * @param string An SQL query string * @param array An array of binding data * @return mixed */functionquery($sql,$binds=FALSE,$return_object=TRUE){if($sql==''){if($this->db_debug){log_message('error','Invalid query: '.$sql);return$this->display_error('db_invalid_query');}returnFALSE;}// Verify table prefix and replace if necessaryif(($this->dbprefix!=''AND$this->swap_pre!='')AND($this->dbprefix!=$this->swap_pre)){$sql=preg_replace("/(\W)".$this->swap_pre."(\S+?)/","\\1".$this->dbprefix."\\2",$sql);}// Is query caching enabled? If the query is a "read type"// we will load the caching class and return the previously// cached query if it existsif($this->cache_on==TRUEANDstristr($sql,'SELECT')){if($this->_cache_init()){$this->load_rdriver();if(FALSE!==($cache=$this->CACHE->read($sql))){return$cache;}}}// Compile binds if neededif($binds!==FALSE){$sql=$this->compile_binds($sql,$binds);}// Save the query for debuggingif($this->save_queries==TRUE){$this->queries[]=$sql;}// Start the Query Timer$time_start=list($sm,$ss)=explode(' ',microtime());// Run the Queryif(FALSE===($this->result_id=$this->simple_query($sql))){if($this->save_queries==TRUE){$this->query_times[]=0;}// This will trigger a rollback if transactions are being used$this->_trans_status=FALSE;if($this->db_debug){// grab the error number and message now, as we might run some// additional queries before displaying the error$error_no=$this->_error_number();$error_msg=$this->_error_message();// We call this function in order to roll-back queries// if transactions are enabled. If we don't call this here// the error message will trigger an exit, causing the// transactions to remain in limbo.$this->trans_complete();// Log and display errorslog_message('error','Query error: '.$error_msg);return$this->display_error(array('Error Number: '.$error_no,$error_msg,$sql));}returnFALSE;}// Stop and aggregate the query time results$time_end=list($em,$es)=explode(' ',microtime());$this->benchmark+=($em+$es)-($sm+$ss);if($this->save_queries==TRUE){$this->query_times[]=($em+$es)-($sm+$ss);}// Increment the query counter$this->query_count++;// Was the query a "write" type?// If so we'll simply return trueif($this->is_write_type($sql)===TRUE){// If caching is enabled we'll auto-cleanup any// existing files related to this particular URIif($this->cache_on==TRUEAND$this->cache_autodel==TRUEAND$this->_cache_init()){$this->CACHE->delete();}returnTRUE;}// Return TRUE if we don't need to create a result object// Currently only the Oracle driver uses this when stored// procedures are usedif($return_object!==TRUE){returnTRUE;}// Load and instantiate the result driver$driver=$this->load_rdriver();$RES=new$driver();$RES->conn_id=$this->conn_id;$RES->result_id=$this->result_id;if($this->dbdriver=='oci8'){$RES->stmt_id=$this->stmt_id;$RES->curs_id=NULL;$RES->limit_used=$this->limit_used;$this->stmt_id=FALSE;}// oci8 vars must be set before calling this$RES->num_rows=$RES->num_rows();// Is query caching enabled? If so, we'll serialize the// result object and save it to a cache file.if($this->cache_on==TRUEAND$this->_cache_init()){// We'll create a new instance of the result object// only without the platform specific driver since// we can't use it with cached data (the query result// resource ID won't be any good once we've cached the// result object, so we'll have to compile the data// and save it)$CR=newCI_DB_result();$CR->num_rows=$RES->num_rows();$CR->result_object=$RES->result_object();$CR->result_array=$RES->result_array();// Reset these since cached objects can not utilize resource IDs.$CR->conn_id=NULL;$CR->result_id=NULL;$this->CACHE->write($sql,$CR);}return$RES;}// --------------------------------------------------------------------/** * Load the result drivers * * @access public * @return string the name of the result class */functionload_rdriver(){$driver='CI_DB_'.$this->dbdriver.'_result';if(!class_exists($driver)){include_once(BASEPATH.'database/DB_result.php');include_once(BASEPATH.'database/drivers/'.$this->dbdriver.'/'.$this->dbdriver.'_result.php');}return$driver;}// --------------------------------------------------------------------/** * Simple Query * This is a simplified version of the query() function. Internally * we only use it when running transaction commands since they do * not require all the features of the main query() function. * * @access public * @param string the sql query * @return mixed */functionsimple_query($sql){if(!$this->conn_id){$this->initialize();}return$this->_execute($sql);}// --------------------------------------------------------------------/** * Disable Transactions * This permits transactions to be disabled at run-time. * * @access public * @return void */functiontrans_off(){$this->trans_enabled=FALSE;}// --------------------------------------------------------------------/** * Enable/disable Transaction Strict Mode * When strict mode is enabled, if you are running multiple groups of * transactions, if one group fails all groups will be rolled back. * If strict mode is disabled, each group is treated autonomously, meaning * a failure of one group will not affect any others * * @access public * @return void */functiontrans_strict($mode=TRUE){$this->trans_strict=is_bool($mode)?$mode:TRUE;}// --------------------------------------------------------------------/** * Start Transaction * * @access public * @return void */functiontrans_start($test_mode=FALSE){if(!$this->trans_enabled){returnFALSE;}// When transactions are nested we only begin/commit/rollback the outermost onesif($this->_trans_depth>0){$this->_trans_depth+=1;return;}$this->trans_begin($test_mode);}// --------------------------------------------------------------------/** * Complete Transaction * * @access public * @return bool */functiontrans_complete(){if(!$this->trans_enabled){returnFALSE;}// When transactions are nested we only begin/commit/rollback the outermost onesif($this->_trans_depth>1){$this->_trans_depth-=1;returnTRUE;}// The query() function will set this flag to FALSE in the event that a query failedif($this->_trans_status===FALSE){$this->trans_rollback();// If we are NOT running in strict mode, we will reset// the _trans_status flag so that subsequent groups of transactions// will be permitted.if($this->trans_strict===FALSE){$this->_trans_status=TRUE;}log_message('debug','DB Transaction Failure');returnFALSE;}$this->trans_commit();returnTRUE;}// --------------------------------------------------------------------/** * Lets you retrieve the transaction flag to determine if it has failed * * @access public * @return bool */functiontrans_status(){return$this->_trans_status;}// --------------------------------------------------------------------/** * Compile Bindings * * @access public * @param string the sql statement * @param array an array of bind data * @return string */functioncompile_binds($sql,$binds){if(strpos($sql,$this->bind_marker)===FALSE){return$sql;}if(!is_array($binds)){$binds=array($binds);}// Get the sql segments around the bind markers$segments=explode($this->bind_marker,$sql);// The count of bind should be 1 less then the count of segments// If there are more bind arguments trim it downif(count($binds)>=count($segments)){$binds=array_slice($binds,0,count($segments)-1);}// Construct the binded query$result=$segments[0];$i=0;foreach($bindsas$bind){$result.=$this->escape($bind);$result.=$segments[++$i];}return$result;}// --------------------------------------------------------------------/** * Determines if a query is a "write" type. * * @access public * @param string An SQL query string * @return boolean */functionis_write_type($sql){if(!preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD DATA|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK)\s+/i',$sql)){returnFALSE;}returnTRUE;}// --------------------------------------------------------------------/** * Calculate the aggregate query elapsed time * * @access public * @param integer The number of decimal places * @return integer */functionelapsed_time($decimals=6){returnnumber_format($this->benchmark,$decimals);}// --------------------------------------------------------------------/** * Returns the total number of queries * * @access public * @return integer */functiontotal_queries(){return$this->query_count;}// --------------------------------------------------------------------/** * Returns the last query that was executed * * @access public * @return void */functionlast_query(){returnend($this->queries);}// --------------------------------------------------------------------/** * "Smart" Escape String * * Escapes data based on type * Sets boolean and null types * * @access public * @param string * @return mixed */functionescape($str){if(is_string($str)){$str="'".$this->escape_str($str)."'";}elseif(is_bool($str)){$str=($str===FALSE)?0:1;}elseif(is_null($str)){$str='NULL';}return$str;}// --------------------------------------------------------------------/** * Escape LIKE String * * Calls the individual driver for platform * specific escaping for LIKE conditions * * @access public * @param string * @return mixed */functionescape_like_str($str){return$this->escape_str($str,TRUE);}// --------------------------------------------------------------------/** * Primary * * Retrieves the primary key. It assumes that the row in the first * position is the primary key * * @access public * @param string the table name * @return string */functionprimary($table=''){$fields=$this->list_fields($table);if(!is_array($fields)){returnFALSE;}returncurrent($fields);}// --------------------------------------------------------------------/** * Returns an array of table names * * @access public * @return array */functionlist_tables($constrain_by_prefix=FALSE){// Is there a cached result?if(isset($this->data_cache['table_names'])){return$this->data_cache['table_names'];}if(FALSE===($sql=$this->_list_tables($constrain_by_prefix))){if($this->db_debug){return$this->display_error('db_unsupported_function');}returnFALSE;}$retval=array();$query=$this->query($sql);if($query->num_rows()>0){foreach($query->result_array()as$row){if(isset($row['TABLE_NAME'])){$retval[]=$row['TABLE_NAME'];}else{$retval[]=array_shift($row);}}}$this->data_cache['table_names']=$retval;return$this->data_cache['table_names'];}// --------------------------------------------------------------------/** * Determine if a particular table exists * @access public * @return boolean */functiontable_exists($table_name){return(!in_array($this->_protect_identifiers($table_name,TRUE,FALSE,FALSE),$this->list_tables()))?FALSE:TRUE;}// --------------------------------------------------------------------/** * Fetch MySQL Field Names * * @access public * @param string the table name * @return array */functionlist_fields($table=''){// Is there a cached result?if(isset($this->data_cache['field_names'][$table])){return$this->data_cache['field_names'][$table];}if($table==''){if($this->db_debug){return$this->display_error('db_field_param_missing');}returnFALSE;}if(FALSE===($sql=$this->_list_columns($table))){if($this->db_debug){return$this->display_error('db_unsupported_function');}returnFALSE;}$query=$this->query($sql);$retval=array();foreach($query->result_array()as$row){if(isset($row['COLUMN_NAME'])){$retval[]=$row['COLUMN_NAME'];}else{$retval[]=current($row);}}$this->data_cache['field_names'][$table]=$retval;return$this->data_cache['field_names'][$table];}// --------------------------------------------------------------------/** * Determine if a particular field exists * @access public * @param string * @param string * @return boolean */functionfield_exists($field_name,$table_name){return(!in_array($field_name,$this->list_fields($table_name)))?FALSE:TRUE;}// --------------------------------------------------------------------/** * Returns an object with field data * * @access public * @param string the table name * @return object */functionfield_data($table=''){if($table==''){if($this->db_debug){return$this->display_error('db_field_param_missing');}returnFALSE;}$query=$this->query($this->_field_data($this->_protect_identifiers($table,TRUE,NULL,FALSE)));return$query->field_data();}// --------------------------------------------------------------------/** * Generate an insert string * * @access public * @param string the table upon which the query will be performed * @param array an associative array data of key/values * @return string */functioninsert_string($table,$data){$fields=array();$values=array();foreach($dataas$key=>$val){$fields[]=$this->_escape_identifiers($key);$values[]=$this->escape($val);}return$this->_insert($this->_protect_identifiers($table,TRUE,NULL,FALSE),$fields,$values);}// --------------------------------------------------------------------/** * Generate an update string * * @access public * @param string the table upon which the query will be performed * @param array an associative array data of key/values * @param mixed the "where" statement * @return string */functionupdate_string($table,$data,$where){if($where==''){returnfalse;}$fields=array();foreach($dataas$key=>$val){$fields[$this->_protect_identifiers($key)]=$this->escape($val);}if(!is_array($where)){$dest=array($where);}else{$dest=array();foreach($whereas$key=>$val){$prefix=(count($dest)==0)?'':' AND ';if($val!==''){if(!$this->_has_operator($key)){$key.=' =';}$val=' '.$this->escape($val);}$dest[]=$prefix.$key.$val;}}return$this->_update($this->_protect_identifiers($table,TRUE,NULL,FALSE),$fields,$dest);}// --------------------------------------------------------------------/** * Tests whether the string has an SQL operator * * @access private * @param string * @return bool */function_has_operator($str){$str=trim($str);if(!preg_match("/(\s|<|>|!|=|is null|is not null)/i",$str)){returnFALSE;}returnTRUE;}// --------------------------------------------------------------------/** * Enables a native PHP function to be run, using a platform agnostic wrapper. * * @access public * @param string the function name * @param mixed any parameters needed by the function * @return mixed */functioncall_function($function){$driver=($this->dbdriver=='postgre')?'pg_':$this->dbdriver.'_';if(FALSE===strpos($driver,$function)){$function=$driver.$function;}if(!function_exists($function)){if($this->db_debug){return$this->display_error('db_unsupported_function');}returnFALSE;}else{$args=(func_num_args()>1)?array_splice(func_get_args(),1):null;returncall_user_func_array($function,$args);}}// --------------------------------------------------------------------/** * Set Cache Directory Path * * @access public * @param string the path to the cache directory * @return void */functioncache_set_path($path=''){$this->cachedir=$path;}// --------------------------------------------------------------------/** * Enable Query Caching * * @access public * @return void */functioncache_on(){$this->cache_on=TRUE;returnTRUE;}// --------------------------------------------------------------------/** * Disable Query Caching * * @access public * @return void */functioncache_off(){$this->cache_on=FALSE;returnFALSE;}// --------------------------------------------------------------------/** * Delete the cache files associated with a particular URI * * @access public * @return void */functioncache_delete($segment_one='',$segment_two=''){if(!$this->_cache_init()){returnFALSE;}return$this->CACHE->delete($segment_one,$segment_two);}// --------------------------------------------------------------------/** * Delete All cache files * * @access public * @return void */functioncache_delete_all(){if(!$this->_cache_init()){returnFALSE;}return$this->CACHE->delete_all();}// --------------------------------------------------------------------/** * Initialize the Cache Class * * @access private * @return void */function_cache_init(){if(is_object($this->CACHE)ANDclass_exists('CI_DB_Cache')){returnTRUE;}if(!class_exists('CI_DB_Cache')){if(!@include(BASEPATH.'database/DB_cache.php')){return$this->cache_off();}}$this->CACHE=newCI_DB_Cache($this);// pass db object to support multiple db connections and returned db objectsreturnTRUE;}// --------------------------------------------------------------------/** * Close DB Connection * * @access public * @return void */functionclose(){if(is_resource($this->conn_id)ORis_object($this->conn_id)){$this->_close($this->conn_id);}$this->conn_id=FALSE;}// --------------------------------------------------------------------/** * Display an error message * * @access public * @param string the error message * @param string any "swap" values * @param boolean whether to localize the message * @return string sends the application/error_db.php template */functiondisplay_error($error='',$swap='',$native=FALSE){$LANG=&load_class('Lang','core');$LANG->load('db');$heading=$LANG->line('db_error_heading');if($native==TRUE){$message=$error;}else{$message=(!is_array($error))?array(str_replace('%s',$swap,$LANG->line($error))):$error;}// Find the most likely culprit of the error by going through// the backtrace until the source file is no longer in the// database folder.$trace=debug_backtrace();foreach($traceas$call){if(isset($call['file'])&&strpos($call['file'],BASEPATH.'database')===FALSE){// Found it - use a relative path for safety$message[]='Filename: '.str_replace(array(BASEPATH,APPPATH),'',$call['file']);$message[]='Line Number: '.$call['line'];break;}}$error=&load_class('Exceptions','core');echo$error->show_error($heading,$message,'error_db');exit;}// --------------------------------------------------------------------/** * Protect Identifiers * * This function adds backticks if appropriate based on db type * * @access private * @param mixed the item to escape * @return mixed the item with backticks */functionprotect_identifiers($item,$prefix_single=FALSE){return$this->_protect_identifiers($item,$prefix_single);}// --------------------------------------------------------------------/** * Protect Identifiers * * This function is used extensively by the Active Record class, and by * a couple functions in this class. * It takes a column or table name (optionally with an alias) and inserts * the table prefix onto it. Some logic is necessary in order to deal with * column names that include the path. Consider a query like this: * * SELECT * FROM hostname.database.table.column AS c FROM hostname.database.table * * Or a query with aliasing: * * SELECT m.member_id, m.member_name FROM members AS m * * Since the column name can include up to four segments (host, DB, table, column) * or also have an alias prefix, we need to do a bit of work to figure this out and * insert the table prefix (if it exists) in the proper position, and escape only * the correct identifiers. * * @access private * @param string * @param bool * @param mixed * @param bool * @return string */function_protect_identifiers($item,$prefix_single=FALSE,$protect_identifiers=NULL,$field_exists=TRUE){if(!is_bool($protect_identifiers)){$protect_identifiers=$this->_protect_identifiers;}if(is_array($item)){$escaped_array=array();foreach($itemas$k=>$v){$escaped_array[$this->_protect_identifiers($k)]=$this->_protect_identifiers($v);}return$escaped_array;}// Convert tabs or multiple spaces into single spaces$item=preg_replace('/[\t ]+/',' ',$item);// If the item has an alias declaration we remove it and set it aside.// Basically we remove everything to the right of the first space$alias='';if(strpos($item,' ')!==FALSE){$alias=strstr($item," ");$item=substr($item,0,-strlen($alias));}// This is basically a bug fix for queries that use MAX, MIN, etc.// If a parenthesis is found we know that we do not need to// escape the data or add a prefix. There's probably a more graceful// way to deal with this, but I'm not thinking of it -- Rickif(strpos($item,'(')!==FALSE){return$item.$alias;}// Break the string apart if it contains periods, then insert the table prefix// in the correct location, assuming the period doesn't indicate that we're dealing// with an alias. While we're at it, we will escape the componentsif(strpos($item,'.')!==FALSE){$parts=explode('.',$item);// Does the first segment of the exploded item match// one of the aliases previously identified? If so,// we have nothing more to do other than escape the itemif(in_array($parts[0],$this->ar_aliased_tables)){if($protect_identifiers===TRUE){foreach($partsas$key=>$val){if(!in_array($val,$this->_reserved_identifiers)){$parts[$key]=$this->_escape_identifiers($val);}}$item=implode('.',$parts);}return$item.$alias;}// Is there a table prefix defined in the config file? If not, no need to do anythingif($this->dbprefix!=''){// We now add the table prefix based on some logic.// Do we have 4 segments (hostname.database.table.column)?// If so, we add the table prefix to the column name in the 3rd segment.if(isset($parts[3])){$i=2;}// Do we have 3 segments (database.table.column)?// If so, we add the table prefix to the column name in 2nd positionelseif(isset($parts[2])){$i=1;}// Do we have 2 segments (table.column)?// If so, we add the table prefix to the column name in 1st segmentelse{$i=0;}// This flag is set when the supplied $item does not contain a field name.// This can happen when this function is being called from a JOIN.if($field_exists==FALSE){$i++;}// Verify table prefix and replace if necessaryif($this->swap_pre!=''&&strncmp($parts[$i],$this->swap_pre,strlen($this->swap_pre))===0){$parts[$i]=preg_replace("/^".$this->swap_pre."(\S+?)/",$this->dbprefix."\\1",$parts[$i]);}// We only add the table prefix if it does not already existif(substr($parts[$i],0,strlen($this->dbprefix))!=$this->dbprefix){$parts[$i]=$this->dbprefix.$parts[$i];}// Put the parts back together$item=implode('.',$parts);}if($protect_identifiers===TRUE){$item=$this->_escape_identifiers($item);}return$item.$alias;}// Is there a table prefix? If not, no need to insert itif($this->dbprefix!=''){// Verify table prefix and replace if necessaryif($this->swap_pre!=''&&strncmp($item,$this->swap_pre,strlen($this->swap_pre))===0){$item=preg_replace("/^".$this->swap_pre."(\S+?)/",$this->dbprefix."\\1",$item);}// Do we prefix an item with no segments?if($prefix_single==TRUEANDsubstr($item,0,strlen($this->dbprefix))!=$this->dbprefix){$item=$this->dbprefix.$item;}}if($protect_identifiers===TRUEAND!in_array($item,$this->_reserved_identifiers)){$item=$this->_escape_identifiers($item);}return$item.$alias;}}/* End of file DB_driver.php *//* Location: ./system/database/DB_driver.php */