<?
/*
The Next BBS - Forums Software
Copyright (C) 2004 Chris F. Ravenscroft
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Questions? We can be reached at http://forums.sf.net
*/
require_once "tidbit.php";
function factoryGetDriver($dblayer="peardb")
{
if($dblayer=="peardb")
{
$dbdriver = new peardbdriver();
}
else if($dblayer=="adodb")
{
$dbdriver = new adodbdriver();
}
else
{
die("Error! Wrong db abstraction layer specified: ".$dblayer);
}
return $dbdriver;
}
class basicdbdriver
{
var $db;
var $total_queries;
var $total_time;
var $start;
var $queries;
var $report_next_error;
/**
* @return mixed: current database handler
*/
function db()
{
return $this->db;
}
/**
* An alias for db()
*/
function current()
{
return $this->db();
}
function prequery($qry, $db=null)
{
global $DB, $CONFIG, $COMMON;
if($CONFIG->debuglevel>=2)
{
$this->total_queries++;
$this->start = $COMMON->microtime_float();
}
if($CONFIG->debuglevel>=5)
$this->queries[] = $qry;
}
function postquery($qry, $db=null)
{
global $DB, $CONFIG, $COMMON;
if($CONFIG->debuglevel>=2)
$this->total_time += ($COMMON->microtime_float()-$this->start);
}
/**
* Create and execute an 'update' query
* @param table String name of a table to query
* @param keys_and_alues An associative array of keys and values
* @param condition String a 'where' condition
* @param db database to query
* @return mixed: a result set
*/
function update($table, $keys_and_values, $condition=null, $db=null)
{
$qry = "UPDATE `".$table."` SET ";
$bMore = true;
foreach($keys_and_values as $key=>$value)
{
if($bMore)
$qry .= ", ";
else
$bMore = true;
$qry .= "`".$key."`='".$value."'";
}
if($condition!=null)
{
$qry .= " WHERE ".$condition;
}
return $this->query($qry, $db);
}
/**
* Create and execute an 'insert' query
* @param table String name of a table to query
* @param keys_and_alues An associative array of keys and values
* @param db database to query
* @return mixed: a result set
*/
function insert($table, $keys_and_values, $db=null)
{
$qry = "INSERT INTO `".$table."` (";
$qry2 = ") VALUES (";
$bMore = true;
foreach($keys_and_values as $key=>$value)
{
if($bMore)
{
$qry .= ", ";
$qry2 .= ", ";
}
else
$bMore = true;
$qry .= "`".$key."`";
$qry2 .= "'".$value."'";
}
$qry .= $qry2 . ")";
return $this->query($qry, $db);
}
function report_next_error()
{
$this->report_next_error = true;
}
/**
* Renders a string harmless, thus avoiding SQL Injection
* @param str string to neuter
* @param forceescape if true, escape string even if magic quotes are enabled
* @return string: neutered string
*/
function neuter($str,$forceescape=false)
{
if(!$forceescape && get_magic_quotes_gpc())
return $str;
else
return addslashes($str);
# return DB_common::escapesimple($str);
}
/**
* Revert a string to its old pre-neutering state
* @param str string to de-neuter
* @return de-neutered string
*/
function undoneuter($str)
{
return stripslashes($str);
}
/**
* @return integer: total query time since this object was instantiated
*/
function getTotalTime()
{
return $this->total_time;
}
/**
* For profiling purpose
* @return string: various information regarding this session's queries
*/
function getDebug()
{
global $CONFIG;
$debug = "";
if($CONFIG->debuglevel>=2)
$debug .= "<br />Total DB [{$CONFIG->dblayer}:{$CONFIG->dbengine}] queries: {$this->total_queries}";
if($CONFIG->debuglevel>=5)
{
$debug .="<br />Queries List:";
for($i=0;$i<count($this->queries);$i++)
$debug .= "<br />[ ".$this->queries[$i]." ]";
}
return $debug;
}
/**
* For debugging purpose
* @param row a result set
* @return string: keys and associated values
*/
function dumpResult($row)
{
$s="";
foreach($row as $key=>$value)
$s.=$key." => ".$value."<br />";
return $s;
}
}
class peardbdriver extends basicdbdriver
{
function peardbdriver()
{
require_once "DB.php";
$this->total_queries = 0;
$this->total_time = 0;
$this->queries = array();
$this->report_next_error = false;
set_magic_quotes_runtime(0);
}
/**
* Connect to a SQL Database.
* @param dbengine Database engine; for instance: 'mysql'
* @param dbhost Host where the database is located
* @param dbname Database name
* @param dbuser Username to use when connecting...
* @param dbpass User password
*/
function connect($dbengine, $dbhost, $dbname, $dbuser, $dbpass)
{
global $COMMON;
$this->db = DB::connect( "$dbengine://$dbuser:$dbpass@$dbhost/$dbname" );
if(DB::isError($this->db))
{
if($this->report_next_error == true)
{
$this->report_next_error = false;
return null;
}
$err = &$this->db;
die("Unable to open database: ".DB::errorMessage($err->code));
}
$this->report_next_error = false;
return $this->db;
}
/**
* Cleanup current connection
*/
function cleanup()
{
$this->db->disconnect();
}
/**
* Run an SQL Query
* @param qry the query
* @param db database to query
* @return mixed: a result set
*/
function query($qry, $db=null)
{
global $DB, $CONFIG, $COMMON;
$this->prequery($qry, $db);
if($db==null)
$db = &$this->db; // Use current
$res = $db->query($qry);
$this->postquery($qry, $db);
if(DB::isError($res))
{
if($this->report_next_error == true)
{
$this->report_next_error = false;
return null;
}
// Database error handling
die("SQL Layer Error: ".$res->getMessage()." (".$res->getCode().")<br />Debug Info:<br />".$res->getDebugInfo()."<br />Query [".$qry."]");
}
$this->report_next_error = false;
return $res;
}
/**
* Similar to mySQL's lastInsertId()
* Careful! This method's implementation must use a switch() statement to adapt to each db's specifics
* ALSO:
* Beware of dbs that will actualy return the ID of the _next_ insert; this is bad for various reasons such as:
* - they do not return the ID of the latest insert (duh!)
* - when returning a future ID, it seems difficult to maintain the DB's integrity as opposed to getting the latest ID,
* which can be understood as 'the latest ID for this connection' as opposed to 'all concurrent connections'
* @param tableName name of the table where we had an insert whose id we want to get
* @return integer: last insert's id
*/
function getLastInsertId($tableName, $db=null)
{
if($db==null)
$db = &$this->db; // Use current
$qry = "SELECT LAST_INSERT_ID() FROM {$tableName}";
$res = $this->query($qry, $db);
$row = $res->fetchRow(DB_FETCHMODE_ORDERED);
return $row[0];
}
/**
* @return integer: Number of rows affected by last INSERT or DELETE statement
*/
function affectedRows($db=null)
{
if($db==null)
$db = &$this->db; // Use current
return $db->affectedRows();
}
}
class adodbdriver extends basicdbdriver
{
function adodbdriver()
{
require_once "adodb/adodb.inc.php";
$this->total_queries = 0;
$this->total_time = 0;
$this->queries = array();
$this->report_next_error = false;
set_magic_quotes_runtime(0);
}
/**
* Connect to a SQL Database.
* @param dbengine Database engine; for instance: 'mysql'
* @param dbhost Host where the database is located
* @param dbname Database name
* @param dbuser Username to use when connecting...
* @param dbpass User password
*/
function connect($dbengine, $dbhost, $dbname, $dbuser, $dbpass)
{
global $CONFIG, $COMMON;
$this->db = &ADONewConnection($dbengine);
if(!$this->db->Connect($dbhost,$dbuser,$dbpass,$dbname))
{
if($this->report_next_error == true)
{
$this->report_next_error = false;
return null;
}
$err = &$this->db;
die("Unable to open database.");
}
$this->report_next_error = false;
return $this->db;
}
/**
* Cleanup current connection
*/
function cleanup()
{
$this->db->Close();
}
/**
* Run an SQL Query
* @param qry the query
* @param db database to query
* @return mixed: a result set
*/
function query($qry, $db=null)
{
global $DB, $CONFIG, $COMMON;
$this->prequery($qry, $db);
if($db==null)
$db = &$this->db; // Use current
$res = $db->query($qry);
$this->postquery($qry, $db);
if(!$res)
{
if($this->report_next_error == true)
{
$this->report_next_error = false;
return null;
}
// Database error handling
die("SQL Layer Error: ".$db->ErrorMsg()."<br />Query [".$qry."]");
}
$this->report_next_error = false;
return $res;
}
/**
* Similar to mySQL's lastInsertId()
* Careful! This method's implementation must use a switch() statement to adapt to each db's specifics
* ALSO:
* Beware of dbs that will actualy return the ID of the _next_ insert; this is bad for various reasons such as:
* - they do not return the ID of the latest insert (duh!)
* - when returning a future ID, it seems difficult to maintain the DB's integrity as opposed to getting the latest ID,
* which can be understood as 'the latest ID for this connection' as opposed to 'all concurrent connections'
* @param tableName name of the table where we had an insert whose id we want to get
* @return integer: last insert's id
*/
function getLastInsertId($tableName, $db=null)
{
if($db==null)
$db = &$this->db; // Use current
$qry = "SELECT LAST_INSERT_ID() FROM {$tableName}";
$res = $this->query($qry, $db);
$row = $res->fetchRow(DB_FETCHMODE_ORDERED);
return $row[0];
}
/**
* @return integer: Number of rows affected by last INSERT or DELETE statement
*/
function affectedRows($db=null)
{
if($db==null)
$db = &$this->db; // Use current
return $db->Affected_Rows();
}
}
?>