国内流行的内容管理系统(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.

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