国内流行的内容管理系统(CMS)多端全媒体解决方案 https://www.dedebiz.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

746 lines
22KB

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