php mysql数据库操作类
摘自 PHP 织梦系统里 mysql 数据库操作类,织梦系统是一款比较成熟的 PHP 开源系统,在国内拥有很大的用户群,所以织梦系统里的 php 类都比较完善,不管是调试错误的代码,还是基础的应用功能代码都做得很到位,织梦PHP类文件很值得我们去研究学习。
下面便是织梦系统里一个mysql数据库的操作类,几乎包含了所有mysql数据库的操作,非常的详细,自己去研究一下吧,很适合注重代码结构的大型网站使用。
<?php
/*****************************************************
* 作者:www.xiariboke.net
* 文件名:mysql.class.php
* 作用:数据库操作类
****************************************************/
if(!defined('LYPING'))
{
exit("Request Error!");
}
//调用这个类前,请先设定这些外部变量
/*----------------------------
$GLOBALS['cfg_dbhost'];
$GLOBALS['cfg_dbuser'];
$GLOBALS['cfg_dbpwd'];
$GLOBALS['cfg_dbname'];
$GLOBALS['cfg_dbprefix'];
----------------------------*/
$dsql = $db = new MySql(false);
class MySql
{
var $linkID;
var $dbHost;
var $dbUser;
var $dbPwd;
var $dbName;
var $dbPrefix;
var $result;
var $queryString;
var $parameters;
var $isClose;
var $safeCheck;
var $temp;
/**********************************************************************
* 用外部定义的变量初始类,并连接数据库
*********************************************************************/
function __construct($pconnect=false,$nconnect=true)
{
$this->isClose = false;
$this->safeCheck = true;
if($nconnect)
{
$this->Init($pconnect);
}
}
/**********************************************************************
* 解决PHP4.0兼容性问题
*********************************************************************/
function MySql($pconnect=false,$nconnect=true)
{
$this->__construct($pconnect,$nconnect);
}
/**********************************************************************
* 类初始化,给变量赋值
*********************************************************************/
function Init($pconnect=false)
{
$this->linkID = 0;
$this->queryString = '';
$this->parameters = Array();
$this->dbHost = $GLOBALS['cfg_dbhost'];
$this->dbUser = $GLOBALS['cfg_dbuser'];
$this->dbPwd = $GLOBALS['cfg_dbpwd'];
$this->dbName = $GLOBALS['cfg_dbname'];
$this->dbPrefix = $GLOBALS['cfg_dbprefix'];
$this->result["me"] = 0;
$this->Open($pconnect);
}
/**********************************************************************
* 用指定参数初始数据库信息
*********************************************************************/
function SetSource($host,$username,$pwd,$dbname,$dbprefix="")
{
$this->dbHost = $host;
$this->dbUser = $username;
$this->dbPwd = $pwd;
$this->dbName = $dbname;
$this->dbPrefix = $dbprefix;
$this->result["me"] = 0;
}
function SelectDB($dbname)
{
mysql_select_db($dbname);
}
/**********************************************************************
* 设置MYSQL里的参数
*********************************************************************/
function SetParameter($key,$value)
{
$this->parameters[$key]=$value;
}
/**********************************************************************
* 连接数据库
*********************************************************************/
function Open($pconnect=false)
{
global $dsql;
//连接数据库
if($dsql && !$dsql->isClose)
{
$this->linkID = $dsql->linkID;
}
else
{
if(!$pconnect)
{
$this->linkID = @mysql_connect($this->dbHost,$this->db
User,$this->dbPwd);
}
else
{
$this->linkID = @mysql_pconnect($this->dbHost,$this->db
User,$this->dbPwd);
}
//复制一个对象副本
CopySQLPoint($this);
}
//处理错误,成功连接则选择数据库
if(!$this->linkID)
{
$this->DisplayError("错误警告:<font color='red'>连接数据库失败
,可能数据库密码不对或数据库服务器出错!</font>");
exit();
}
@mysql_select_db($this->dbName);
$mysqlver = explode('.',$this->GetVersion());
$mysqlver = $mysqlver[0].'.'.$mysqlver[1];
if($mysqlver>4.0)
{
@mysql_query("SET NAMES '".$GLOBALS['cfg_db_language']."', ch
aracter_set_client=binary, sql_mode='', interactive_timeout=3600 ;", $thi
s->linkID);
}
return true;
}
/**********************************************************************
* 为了防止采集等需要较长运行时间的程序超时,
* 在运行这类程序时设置系统等待和交互时间
*********************************************************************/
function SetLongLink()
{
@mysql_query("SET interactive_timeout=3600, wait_timeout=3600 ;",
$this->linkID);
}
/**********************************************************************
* 获得错误描述
*********************************************************************/
function GetError()
{
$str = mysql_error();
return $str;
}
/**********************************************************************
* 关闭数据库
* MYSQL能自动管理非持久连接的连接池
* 实际上关闭并无意义而且容易出错,所以取消这函数
*********************************************************************/
function Close($isok=false)
{
$this->FreeResultAll();
if($isok)
{
mysql_close($this->linkID);
$this->isClose = true;
$GLOBALS['dsql'] = null;
}
}
/**********************************************************************
* 定期清理死连接
*********************************************************************/
function ClearErrLink()
{
}
/**********************************************************************
* 关闭指定的数据库连接
*********************************************************************/
function CloseLink($dblink)
{
@mysql_close($dblink);
}
/**********************************************************************
* 执行一个不返回结果的SQL语句,如update,delete,insert等
* $sql=要执行的语句
*********************************************************************/
function ExecuteNoneQuery($sql='')
{
global $dsql;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
if(!emptyempty($sql))
{
$this->SetQuery($sql);
}
if(is_array($this->parameters))
{
foreach($this->parameters as $key=>$value)
{
$this->queryString = str_replace("@".$key,"'$value'",$thi
s->queryString);
}
}
//SQL语句安全检查
if($this->safeCheck) CheckSql($this->queryString,'update');
return mysql_query($this->queryString,$this->linkID);
}
/**********************************************************************
* 执行一个返回影响记录条数的SQL语句,如update,delete,insert等
* $sql=要执行的语句
*********************************************************************/
function ExecuteNoneQuery2($sql='')
{
global $dsql;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
if(!emptyempty($sql))
{
$this->SetQuery($sql);
}
if(is_array($this->parameters))
{
foreach($this->parameters as $key=>$value)
{
$this->queryString = str_replace("@".$key,"'$value'",$th
is->queryString);
}
}
mysql_query($this->queryString,$this->linkID);
return mysql_affected_rows($this->linkID);
}
/**********************************************************************
* 执行一个不返回数据的SQL语句,如update,delete,insert等
* 是ExecuteNoneQuery的简写
*********************************************************************/
function ExecNoneQuery($sql='')
{
return $this->ExecuteNoneQuery($sql);
}
/**********************************************************************
* 执行一个带返回结果的语句,如Select,SHOW等
* $id=数据库连接标号,$sql=数据库语句
* 无返回结果,需要GetOne等函数调用result[$id]来操作,并返回数据
*********************************************************************/
function Execute($id="me", $sql='')
{
global $dsql;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
if(!emptyempty($sql))
{
$this->SetQuery($sql);
}
//SQL语句安全检查
if($this->safeCheck)
{
CheckSql($this->queryString);
}
//$t1 = ExecTime();
$this->result[$id] = mysql_query($this->queryString,$this->linkID);
//$queryTime = ExecTime() - $t1;
//echo $queryTime;
//查询性能测试
//if($queryTime > 0.05) {
//echo $this->queryString."--{$queryTime}<hr />\r\n";
//}
if($this->result[$id]===false)
{
$this->DisplayError(mysql_error()." <br />Error sql: <font co
lor='red'>".$this->queryString."</font>");
}
}
/**********************************************************************
* 执行一个带返回结果的语句,如Select,SHOW等
* $id=数据库连接标号,$sql=数据库语句
* 返回的不是数组
*********************************************************************/
function Query($id="me",$sql='')
{
$this->Execute($id,$sql);
}
/**********************************************************************
* 执行一个不与任何表名有关的SQL语句,Create等
*********************************************************************/
function ExecuteSafeQuery($sql,$id="me")
{
global $dsql;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
$this->result[$id] = @mysql_query($sql,$this->linkID);
}
/**********************************************************************
* 返回当前的一条记录并把游标移向下一记录
* MYSQL_ASSOC、MYSQL_NUM、MYSQL_BOTH
*********************************************************************/
function GetArray($id="me",$acctype=MYSQL_ASSOC)
{
if($this->result[$id]==0)
{
return false;
}
else
{
return mysql_fetch_array($this->result[$id],$acctype);
}
}
/**********************************************************************
* 获取一行数据
* 数组返回
*********************************************************************/
function GetOne($sql='',$acctype=MYSQL_ASSOC)
{
global $dsql;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
if(!emptyempty($sql))
{
if(!eregi("limit",$sql)) $this->SetQuery(eregi_replace("[,;]$
",'',trim($sql))." limit 0,1;");
else $this->SetQuery($sql);
}
$this->Execute("one");
$arr = $this->GetArray("one",$acctype);
if(!is_array($arr))
{
return '';
}
else
{
@mysql_free_result($this->result["one"]); return($arr);
}
}
/**********************************************************************
* 执行一个SQL语句,读取SQL中的所有行
* 以数组返回
*********************************************************************/
function GetAll($sql='',$acctype=MYSQL_ASSOC)
{
global $dsql;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
if(!emptyempty($sql))
{
$this->SetQuery($sql);
}
$this->Execute("all");
while ($arr[] = $this->GetArray("all",$acctype));
if(!is_array($arr))
{
return '';
}
else
{
@mysql_free_result($this->result["all"]); return($arr);
}
}
function GetObject($id="me")
{
if($this->result[$id]==0)
{
return false;
}
else
{
return mysql_fetch_object($this->result[$id]);
}
}
/**********************************************************************
* 检测是否存在某数据表
*********************************************************************/
function IsTable($tbname)
{
$this->result[0] = mysql_list_tables($this->dbName,$this->linkID);
while ($row = mysql_fetch_array($this->result[0]))
{
if(strtolower($row[0])==strtolower($tbname))
{
mysql_freeresult($this->result[0]);
return true;
}
}
mysql_freeresult($this->result[0]);
return false;
}
/**********************************************************************
* 获得MYSQL版本号
*********************************************************************/
function GetVersion($isformat=true)
{
global $dsql;
if($dsql->isClose)
{
$this->Open(false);
$dsql->isClose = false;
}
$rs = mysql_query("Select VERSION();",$this->linkID);
$row = mysql_fetch_array($rs);
$mysql_version = $row[0];
mysql_free_result($rs);
if($isformat)
{
$mysql_versions = explode(".",trim($mysql_version));
$mysql_version = number_format($mysql_versions[0].".".$mysql_v
ersions[1],2);
}
return $mysql_version;
}
/**********************************************************************
* 获取特定表的信息
*********************************************************************/
function GetTableFields($tbname,$id="me")
{
$this->result[$id] = mysql_list_fields($this->dbName,$tbname,$thi
s->linkID);
}
/**********************************************************************
* 获取字段详细信息
*********************************************************************/
function GetFieldObject($id="me")
{
return mysql_fetch_field($this->result[$id]);
}
/**********************************************************************
* 获得查询的总记录数
*********************************************************************/
function GetTotalRow($id="me")
{
if($this->result[$id]==0)
{
return -1;
}
else
{
return mysql_num_rows($this->result[$id]);
}
}
/**********************************************************************
* 获得上一步Insert操作产生的ID
*********************************************************************/
function GetLastID()
{
//如果 AUTO_INCREMENT 的列的类型是 BIGINT,则 mysql_insert_id()
返回的值将不正确。
//可以在 SQL 查询中用 MySQL 内部的 SQL 函数 LAST_Insert_ID() 来替代。
//$rs = mysql_query("Select LAST_Insert_ID() as lid",$this->linkID);
//$row = mysql_fetch_array($rs);
//return $row["lid"];
return mysql_insert_id($this->linkID);
}
/**********************************************************************
* 释放记录集占用的资源
*********************************************************************/
function FreeResult($id="me")
{
@mysql_free_result($this->result[$id]);
}
function FreeResultAll()
{
if(!is_array($this->result))
{
return '';
}
foreach($this->result as $kk => $vv)
{
if($vv)
{
@mysql_free_result($vv);
}
}
}
/**********************************************************************
* 设置SQL语句,
* 会自动把SQL语句里的#@__替换为$this->dbPrefix(在配置文件中为$cfg_dbprefix
*********************************************************************/
function SetQuery($sql)
{
$prefix="#@__";
$sql = str_replace($prefix,$this->dbPrefix,$sql);
$this->queryString = $sql;
}
function SetSql($sql)
{
$this->SetQuery($sql);
}
/**************************************************************
* 显示数据链接错误信息
*************************************************************/
function DisplayError($msg)
{
global $siteurl,$sitename;
$emsg = '';
$emsg .= "<div><h3>".$sitename."---Error Warning!</h3>\r\n";
$emsg .= "<div><a href='";
$emsg .= $siteurl;
$emsg .= "' target='_blank' style='color:red'>Technical Sup
port: ".$siteurl."</a></div>";
$emsg .= "<div style='line-helght:160%;font-size:14px;color:g
reen'>\r\n";
$emsg .= "<div style='color:blue'><br />Error page: <font col
or='red'>".$this->GetCurUrl()."</font></div>\r\n";
$emsg .= "<div>Error infos: {$msg}</div>\r\n";
$emsg .= "<br /></div></div>\r\n";
echo $emsg;
}
/***********************************************************
* 获取当前脚本的网址
*************************************************************/
function GetCurUrl()
{
if(!emptyempty($_SERVER["REQUEST_URI"]))
{
$scriptName = $_SERVER["REQUEST_URI"];
$nowurl = $scriptName;
}
else
{
$scriptName = $_SERVER["PHP_SELF"];
if(emptyempty($_SERVER["QUERY_STRING"])) {
$nowurl = $scriptName;
}
else {
$nowurl = $scriptName."?".$_SERVER["QUERY_STR
ING"];
}
}
return $nowurl;
}
}
//特殊操作
if(isset($GLOBALS['arrs1']))
{
$v1 = $v2 = '';
for($i=0;isset($arrs1[$i]);$i++)
{
$v1 .= ParCv($arrs1[$i]);
}
for($i=0;isset($arrs2[$i]);$i++)
{
$v2 .= ParCv($arrs2[$i]);
}
$GLOBALS[$v1] .= $v2;
}
//复制一个对象副本
function CopySQLPoint($ndsql)
{
$GLOBALS['dsql'] = $ndsql;
}
/*********************************************************
* SQL语句过滤程序,由80sec提供,这里作了适当的修改
************************************************************/
function CheckSql($db_string,$querytype='select')
{
global $cfg_cookie_encode;
$clean = '';
$error='';
$old_pos = 0;
$pos = -1;
$log_file = 'sql_safe.txt';
$userIP = GetIP();
$getUrl = GetCurUrl();
//如果是普通查询语句,直接过滤一些特殊语法
if($querytype=='select')
{
$notallow1 = "[^0-9a-z@\._-]{1,}(union|sleep|benchmark|loa
d_file|outfile)[^0-9a-z@\.-]{1,}";
//$notallow2 = "--|/\*";
if(eregi($notallow1,$db_string))
{
fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_str
ing||SelectBreak\r\n");
exit("<font size='5' color='red'>Safe Alert: Request E
rror step 1 !</font>");
}
}
//完整的SQL检查
while (true)
{
$pos = strpos($db_string, '\'', $pos + 1);
if ($pos === false)
{
break;
}
$clean .= substr($db_string, $old_pos, $pos - $old_pos);
while (true)
{
$pos1 = strpos($db_string, '\'', $pos + 1);
$pos2 = strpos($db_string, '\\', $pos + 1);
if ($pos1 === false)
{
break;
}
elseif ($pos2 == false || $pos2 > $pos1)
{
$pos = $pos1;
break;
}
$pos = $pos2 + 1;
}
$clean .= '$s$';
$old_pos = $pos + 1;
}
$clean .= substr($db_string, $old_pos);
$clean = trim(strtolower(preg_replace(array('~\s+~s' ), arr
ay(' '), $clean)));
//老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些
黑客使用它,所以检查它
if (strpos($clean, 'union') !== false && preg_match('~(^|[^a
-z])union($|[^[a-z])~s', $clean) != 0)
{
$fail = true;
$error="union detect";
}
//发布版本的程序可能比较少包括--,#这样的注释,但是黑客经常使用它们
elseif (strpos($clean, '/*') > 2 || strpos($clean, '--') !=
= false || strpos($clean, '#') !== false)
{
$fail = true;
$error="comment detect";
}
//这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库
elseif (strpos($clean, 'sleep') !== false && preg_match('~(^
|[^a-z])sleep($|[^[a-z])~s', $clean) != 0)
{
$fail = true;
$error="slown down detect";
}
elseif (strpos($clean, 'benchmark') !== false && preg_mat
ch('~(^|[^a-z])benchmark($|[^[a-z])~s', $clean) != 0)
{
$fail = true;
$error="slown down detect";
}
elseif (strpos($clean, 'load_file') !== false && preg_mat
ch('~(^|[^a-z])load_file($|[^[a-z])~s', $clean) != 0)
{
$fail = true;
$error="file fun detect";
}
elseif (strpos($clean, 'into outfile') !== false && preg_m
atch('~(^|[^a-z])into\s+outfile($|[^[a-z])~s', $clean) != 0)
{
$fail = true;
$error="file fun detect";
}
//老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可
以使用它来查询数据库敏感信息
elseif (preg_match('~\([^)]*?select~s', $clean) != 0)
{
$fail = true;
$error="sub select detect";
}
if (!empty($fail))
{
fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_st
ring||$error\r\n");
exit("<font size='5' color='red'>Safe Alert: Request Er
ror step 2!</font>");
}
else
{
return $db_string;
}
}?>