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

686 line
23KB

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