discuz_database.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. <?php
  2. /**
  3. * [Discuz!] (C)2001-2099 Comsenz Inc.
  4. * This is NOT a freeware, use is subject to license terms
  5. *
  6. * $Id: discuz_database.php 36294 2016-12-14 03:11:30Z nemohou $
  7. */
  8. if(!defined('IN_DISCUZ')) {
  9. exit('Access Denied');
  10. }
  11. class discuz_database {
  12. public static $db;
  13. public static $driver;
  14. public static function init($driver, $config) {
  15. self::$driver = $driver;
  16. self::$db = new $driver;
  17. self::$db->set_config($config);
  18. self::$db->connect();
  19. }
  20. public static function object() {
  21. return self::$db;
  22. }
  23. public static function table($table) {
  24. return self::$db->table_name($table);
  25. }
  26. public static function delete($table, $condition, $limit = 0, $unbuffered = true) {
  27. if (empty($condition)) {
  28. return false;
  29. } elseif (is_array($condition)) {
  30. if (count($condition) == 2 && isset($condition['where']) && isset($condition['arg'])) {
  31. $where = self::format($condition['where'], $condition['arg']);
  32. } else {
  33. $where = self::implode_field_value($condition, ' AND ');
  34. }
  35. } else {
  36. $where = $condition;
  37. }
  38. $limit = dintval($limit);
  39. $sql = "DELETE FROM " . self::table($table) . " WHERE $where " . ($limit > 0 ? "LIMIT $limit" : '');
  40. return self::query($sql, ($unbuffered ? 'UNBUFFERED' : ''));
  41. }
  42. public static function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {
  43. $sql = self::implode($data);
  44. $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
  45. $table = self::table($table);
  46. $silent = $silent ? 'SILENT' : '';
  47. return self::query("$cmd $table SET $sql", null, $silent, !$return_insert_id);
  48. }
  49. public static function update($table, $data, $condition = '', $unbuffered = false, $low_priority = false) {
  50. $sql = self::implode($data);
  51. if(empty($sql)) {
  52. return false;
  53. }
  54. $cmd = "UPDATE " . ($low_priority ? 'LOW_PRIORITY' : '');
  55. $table = self::table($table);
  56. $where = '';
  57. if (empty($condition)) {
  58. $where = '1';
  59. } elseif (is_array($condition)) {
  60. $where = self::implode($condition, ' AND ');
  61. } else {
  62. $where = $condition;
  63. }
  64. $res = self::query("$cmd $table SET $sql WHERE $where", $unbuffered ? 'UNBUFFERED' : '');
  65. return $res;
  66. }
  67. public static function insert_id() {
  68. return self::$db->insert_id();
  69. }
  70. public static function fetch($resourceid, $type = MYSQL_ASSOC) {
  71. if(self::$db->drivertype == 'mysqli') $type = MYSQLI_ASSOC;
  72. return self::$db->fetch_array($resourceid, $type);
  73. }
  74. public static function fetch_first($sql, $arg = array(), $silent = false) {
  75. $res = self::query($sql, $arg, $silent, false);
  76. $ret = self::$db->fetch_array($res);
  77. self::$db->free_result($res);
  78. return $ret ? $ret : array();
  79. }
  80. public static function fetch_all($sql, $arg = array(), $keyfield = '', $silent=false) {
  81. $data = array();
  82. $query = self::query($sql, $arg, $silent, false);
  83. while ($row = self::$db->fetch_array($query)) {
  84. if ($keyfield && isset($row[$keyfield])) {
  85. $data[$row[$keyfield]] = $row;
  86. } else {
  87. $data[] = $row;
  88. }
  89. }
  90. self::$db->free_result($query);
  91. return $data;
  92. }
  93. public static function result($resourceid, $row = 0) {
  94. return self::$db->result($resourceid, $row);
  95. }
  96. public static function result_first($sql, $arg = array(), $silent = false) {
  97. $res = self::query($sql, $arg, $silent, false);
  98. $ret = self::$db->result($res, 0);
  99. self::$db->free_result($res);
  100. return $ret;
  101. }
  102. public static function query($sql, $arg = array(), $silent = false, $unbuffered = false) {
  103. if (!empty($arg)) {
  104. if (is_array($arg)) {
  105. $sql = self::format($sql, $arg);
  106. } elseif ($arg === 'SILENT') {
  107. $silent = true;
  108. } elseif ($arg === 'UNBUFFERED') {
  109. $unbuffered = true;
  110. }
  111. }
  112. self::checkquery($sql);
  113. $ret = self::$db->query($sql, $silent, $unbuffered);
  114. if (!$unbuffered && $ret) {
  115. $cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));
  116. if ($cmd === 'SELECT') {
  117. } elseif ($cmd === 'UPDATE' || $cmd === 'DELETE') {
  118. $ret = self::$db->affected_rows();
  119. } elseif ($cmd === 'INSERT') {
  120. $ret = self::$db->insert_id();
  121. }
  122. }
  123. return $ret;
  124. }
  125. public static function num_rows($resourceid) {
  126. return self::$db->num_rows($resourceid);
  127. }
  128. public static function affected_rows() {
  129. return self::$db->affected_rows();
  130. }
  131. public static function free_result($query) {
  132. return self::$db->free_result($query);
  133. }
  134. public static function error() {
  135. return self::$db->error();
  136. }
  137. public static function errno() {
  138. return self::$db->errno();
  139. }
  140. public static function checkquery($sql) {
  141. return discuz_database_safecheck::checkquery($sql);
  142. }
  143. public static function quote($str, $noarray = false) {
  144. if (is_string($str))
  145. return '\'' . self::$db->escape_string($str) . '\'';
  146. if (is_int($str) or is_float($str))
  147. return '\'' . $str . '\'';
  148. if (is_array($str)) {
  149. if($noarray === false) {
  150. foreach ($str as &$v) {
  151. $v = self::quote($v, true);
  152. }
  153. return $str;
  154. } else {
  155. return '\'\'';
  156. }
  157. }
  158. if (is_bool($str))
  159. return $str ? '1' : '0';
  160. return '\'\'';
  161. }
  162. public static function quote_field($field) {
  163. if (is_array($field)) {
  164. foreach ($field as $k => $v) {
  165. $field[$k] = self::quote_field($v);
  166. }
  167. } else {
  168. if (strpos($field, '`') !== false)
  169. $field = str_replace('`', '', $field);
  170. $field = '`' . $field . '`';
  171. }
  172. return $field;
  173. }
  174. public static function limit($start, $limit = 0) {
  175. $limit = intval($limit > 0 ? $limit : 0);
  176. $start = intval($start > 0 ? $start : 0);
  177. if ($start > 0 && $limit > 0) {
  178. return " LIMIT $start, $limit";
  179. } elseif ($limit) {
  180. return " LIMIT $limit";
  181. } elseif ($start) {
  182. return " LIMIT $start";
  183. } else {
  184. return '';
  185. }
  186. }
  187. public static function order($field, $order = 'ASC') {
  188. if(empty($field)) {
  189. return '';
  190. }
  191. $order = strtoupper($order) == 'ASC' || empty($order) ? 'ASC' : 'DESC';
  192. return self::quote_field($field) . ' ' . $order;
  193. }
  194. public static function field($field, $val, $glue = '=') {
  195. $field = self::quote_field($field);
  196. if (is_array($val)) {
  197. $glue = $glue == 'notin' ? 'notin' : 'in';
  198. } elseif ($glue == 'in') {
  199. $glue = '=';
  200. }
  201. switch ($glue) {
  202. case '=':
  203. return $field . $glue . self::quote($val);
  204. break;
  205. case '-':
  206. case '+':
  207. return $field . '=' . $field . $glue . self::quote((string) $val);
  208. break;
  209. case '|':
  210. case '&':
  211. case '^':
  212. return $field . '=' . $field . $glue . self::quote($val);
  213. break;
  214. case '>':
  215. case '<':
  216. case '<>':
  217. case '<=':
  218. case '>=':
  219. return $field . $glue . self::quote($val);
  220. break;
  221. case 'like':
  222. return $field . ' LIKE(' . self::quote($val) . ')';
  223. break;
  224. case 'in':
  225. case 'notin':
  226. $val = $val ? implode(',', self::quote($val)) : '\'\'';
  227. return $field . ($glue == 'notin' ? ' NOT' : '') . ' IN(' . $val . ')';
  228. break;
  229. default:
  230. throw new DbException('Not allow this glue between field and value: "' . $glue . '"');
  231. }
  232. }
  233. public static function implode($array, $glue = ',') {
  234. $sql = $comma = '';
  235. $glue = ' ' . trim($glue) . ' ';
  236. foreach ($array as $k => $v) {
  237. $sql .= $comma . self::quote_field($k) . '=' . self::quote($v);
  238. $comma = $glue;
  239. }
  240. return $sql;
  241. }
  242. public static function implode_field_value($array, $glue = ',') {
  243. return self::implode($array, $glue);
  244. }
  245. public static function format($sql, $arg) {
  246. $count = substr_count($sql, '%');
  247. if (!$count) {
  248. return $sql;
  249. } elseif ($count > count($arg)) {
  250. throw new DbException('SQL string format error! This SQL need "' . $count . '" vars to replace into.', 0, $sql);
  251. }
  252. $len = strlen($sql);
  253. $i = $find = 0;
  254. $ret = '';
  255. while ($i <= $len && $find < $count) {
  256. if ($sql{$i} == '%') {
  257. $next = $sql{$i + 1};
  258. if ($next == 't') {
  259. $ret .= self::table($arg[$find]);
  260. } elseif ($next == 's') {
  261. $ret .= self::quote(is_array($arg[$find]) ? serialize($arg[$find]) : (string) $arg[$find]);
  262. } elseif ($next == 'f') {
  263. $ret .= sprintf('%F', $arg[$find]);
  264. } elseif ($next == 'd') {
  265. $ret .= dintval($arg[$find]);
  266. } elseif ($next == 'i') {
  267. $ret .= $arg[$find];
  268. } elseif ($next == 'n') {
  269. if (!empty($arg[$find])) {
  270. $ret .= is_array($arg[$find]) ? implode(',', self::quote($arg[$find])) : self::quote($arg[$find]);
  271. } else {
  272. $ret .= '0';
  273. }
  274. } else {
  275. $ret .= self::quote($arg[$find]);
  276. }
  277. $i++;
  278. $find++;
  279. } else {
  280. $ret .= $sql{$i};
  281. }
  282. $i++;
  283. }
  284. if ($i < $len) {
  285. $ret .= substr($sql, $i);
  286. }
  287. return $ret;
  288. }
  289. }
  290. class discuz_database_safecheck {
  291. protected static $checkcmd = array('SEL'=>1, 'UPD'=>1, 'INS'=>1, 'REP'=>1, 'DEL'=>1);
  292. protected static $config;
  293. public static function checkquery($sql) {
  294. if (self::$config === null) {
  295. self::$config = getglobal('config/security/querysafe');
  296. }
  297. if (self::$config['status']) {
  298. $check = 1;
  299. $cmd = strtoupper(substr(trim($sql), 0, 3));
  300. if(isset(self::$checkcmd[$cmd])) {
  301. $check = self::_do_query_safe($sql);
  302. } elseif(substr($cmd, 0, 2) === '/*') {
  303. $check = -1;
  304. }
  305. if ($check < 1) {
  306. throw new DbException('It is not safe to do this query', 0, $sql);
  307. }
  308. }
  309. return true;
  310. }
  311. private static function _do_query_safe($sql) {
  312. $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql);
  313. $mark = $clean = '';
  314. if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false && strpos($sql, '@') === false && strpos($sql, '`') === false) {
  315. $clean = preg_replace("/'(.+?)'/s", '', $sql);
  316. } else {
  317. $len = strlen($sql);
  318. $mark = $clean = '';
  319. for ($i = 0; $i < $len; $i++) {
  320. $str = $sql[$i];
  321. switch ($str) {
  322. case '`':
  323. if(!$mark) {
  324. $mark = '`';
  325. $clean .= $str;
  326. } elseif ($mark == '`') {
  327. $mark = '';
  328. }
  329. break;
  330. case '\'':
  331. if (!$mark) {
  332. $mark = '\'';
  333. $clean .= $str;
  334. } elseif ($mark == '\'') {
  335. $mark = '';
  336. }
  337. break;
  338. case '/':
  339. if (empty($mark) && $sql[$i + 1] == '*') {
  340. $mark = '/*';
  341. $clean .= $mark;
  342. $i++;
  343. } elseif ($mark == '/*' && $sql[$i - 1] == '*') {
  344. $mark = '';
  345. $clean .= '*';
  346. }
  347. break;
  348. case '#':
  349. if (empty($mark)) {
  350. $mark = $str;
  351. $clean .= $str;
  352. }
  353. break;
  354. case "\n":
  355. if ($mark == '#' || $mark == '--') {
  356. $mark = '';
  357. }
  358. break;
  359. case '-':
  360. if (empty($mark) && substr($sql, $i, 3) == '-- ') {
  361. $mark = '-- ';
  362. $clean .= $mark;
  363. }
  364. break;
  365. default:
  366. break;
  367. }
  368. $clean .= $mark ? '' : $str;
  369. }
  370. }
  371. if(strpos($clean, '@') !== false) {
  372. return '-3';
  373. }
  374. $clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean));
  375. if (self::$config['afullnote']) {
  376. $clean = str_replace('/**/', '', $clean);
  377. }
  378. if (is_array(self::$config['dfunction'])) {
  379. foreach (self::$config['dfunction'] as $fun) {
  380. if (strpos($clean, $fun . '(') !== false)
  381. return '-1';
  382. }
  383. }
  384. if (is_array(self::$config['daction'])) {
  385. foreach (self::$config['daction'] as $action) {
  386. if (strpos($clean, $action) !== false)
  387. return '-3';
  388. }
  389. }
  390. if (self::$config['dlikehex'] && strpos($clean, 'like0x')) {
  391. return '-2';
  392. }
  393. if (is_array(self::$config['dnote'])) {
  394. foreach (self::$config['dnote'] as $note) {
  395. if (strpos($clean, $note) !== false)
  396. return '-4';
  397. }
  398. }
  399. return 1;
  400. }
  401. public static function setconfigstatus($data) {
  402. self::$config['status'] = $data ? 1 : 0;
  403. }
  404. }
  405. ?>