| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 |
- <?php
- /**
- * [Discuz!] (C)2001-2099 Discuz! Team
- * This is NOT a freeware, use is subject to license terms
- * https://license.discuz.vip
- */
- if(!defined('IN_DISCUZ')) {
- exit('Access Denied');
- }
- class discuz_database {
- public static $db;
- public static $driver;
- public static function init($driver, $config) {
- self::$driver = $driver;
- self::$db = new $driver;
- self::$db->set_config($config);
- self::$db->connect();
- }
- public static function object() {
- return self::$db;
- }
- public static function table($table) {
- return self::$db->table_name($table);
- }
- public static function delete($table, $condition, $limit = 0, $unbuffered = true) {
- $arg = null;
- if(empty($condition)) {
- return false;
- } elseif(is_array($condition)) {
- if(count($condition) == 2 && isset($condition['where']) && isset($condition['arg'])) {
- if(!self::is_pdo()) {
- $where = self::format($condition['where'], $condition['arg']);
- } else {
- $where = self::format_prepared($condition['where'], $condition['arg']);
- }
- } else {
- if(!self::is_pdo()) {
- $where = self::implode_field_value($condition, ' AND ');
- } else {
- $where = self::implode_field_value_prepared($condition, $arg, ' AND ');
- }
- }
- } else {
- $where = $condition;
- }
- $limit = dintval($limit);
- $sql = 'DELETE FROM '.self::table($table)." WHERE $where ".($limit > 0 ? "LIMIT $limit" : '');
- return self::query($sql, $arg, false, $unbuffered);
- }
- public static function insert($table, $data, $return_insert_id = false, $replace = false, $silent = false) {
- if(!self::is_pdo()) {
- $sql = 'SET '.self::implode($data);
- $arg = null;
- } else {
- $arg = [];
- $sql = self::implode_prepared_insert($data, $arg);
- }
- $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
- $table = self::table($table);
- $silent = $silent ? 'SILENT' : '';
- return self::query("$cmd $table $sql", $arg, $silent, !$return_insert_id);
- }
- public static function update($table, $data, $condition = '', $unbuffered = false, $low_priority = false) {
- if(!self::is_pdo()) {
- $sql = self::implode($data);
- $arg = null;
- } else {
- $arg = [];
- $sql = self::implode_prepared($data, $arg);
- }
- if(empty($sql)) {
- return false;
- }
- $cmd = 'UPDATE '.($low_priority ? 'LOW_PRIORITY' : '');
- $table = self::table($table);
- $where = '';
- if(empty($condition)) {
- $where = '1';
- } elseif(is_array($condition)) {
- if(!self::is_pdo()) {
- $where = self::implode($condition, ' AND ');
- } else {
- $where = self::implode_prepared($condition, $arg, ' AND ');
- }
- } else {
- $where = $condition;
- }
- $res = self::query("$cmd $table SET $sql WHERE $where", $arg, false, $unbuffered);
- return $res;
- }
- public static function insert_id() {
- return self::$db->insert_id();
- }
- public static function fetch($resourceid, $type = null) {
- if(!isset($type)) {
- $type = constant('MYSQLI_ASSOC');
- }
- return self::$db->fetch_array($resourceid, $type);
- }
- public static function fetch_first($sql, $arg = [], $silent = false) {
- $res = self::query($sql, $arg, $silent, false);
- if($res === 0) {
- return [];
- }
- $ret = self::$db->fetch_array($res);
- self::$db->free_result($res);
- return $ret ? $ret : [];
- }
- public static function fetch_all($sql, $arg = [], $keyfield = '', $silent = false) {
- $data = [];
- $query = self::query($sql, $arg, $silent, false);
- while($row = self::$db->fetch_array($query)) {
- if($keyfield && isset($row[$keyfield])) {
- $data[$row[$keyfield]] = $row;
- } else {
- $data[] = $row;
- }
- }
- self::$db->free_result($query);
- return $data;
- }
- public static function result($resourceid, $row = 0) {
- return self::$db->result($resourceid, $row);
- }
- public static function result_first($sql, $arg = [], $silent = false) {
- $res = self::query($sql, $arg, $silent, false);
- $ret = self::$db->result($res, 0);
- self::$db->free_result($res);
- return $ret;
- }
- public static function query($sql, $arg = [], $silent = false, $unbuffered = false) {
- if(!empty($arg)) {
- if(is_array($arg)) {
- if(!self::is_pdo()) {
- $sql = self::format($sql, $arg);
- } else {
- $sql = self::format_prepared($sql, $arg);
- }
- } elseif($arg === 'SILENT') {
- $silent = true;
- $arg = [];
- } elseif($arg === 'UNBUFFERED') {
- $unbuffered = true;
- $arg = [];
- }
- }
- self::checkquery($sql);
- $ret = self::$db->query(!self::is_pdo() ? $sql : [$sql, $arg], $silent, $unbuffered);
- if(!$unbuffered && $ret) {
- $cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' '))));
- if($cmd === 'SELECT') {
- } elseif($cmd === 'UPDATE' || $cmd === 'DELETE') {
- $ret = self::$db->affected_rows();
- } elseif($cmd === 'INSERT') {
- $ret = self::$db->insert_id();
- }
- }
- return $ret;
- }
- public static function num_rows($resourceid) {
- return self::$db->num_rows($resourceid);
- }
- public static function affected_rows() {
- return self::$db->affected_rows();
- }
- public static function free_result($query) {
- return self::$db->free_result($query);
- }
- public static function error() {
- return self::$db->error();
- }
- public static function errno() {
- return self::$db->errno();
- }
- public static function checkquery($sql) {
- return discuz_database_safecheck::checkquery($sql);
- }
- public static function quote($str, $noarray = false) {
- if(is_string($str))
- return '\''.self::$db->escape_string($str).'\'';
- if(is_int($str) or is_float($str))
- return '\''.$str.'\'';
- if(is_array($str)) {
- if($noarray === false) {
- foreach($str as &$v) {
- $v = self::quote($v, true);
- }
- return $str;
- } else {
- return '\'\'';
- }
- }
- if(is_bool($str))
- return $str ? '1' : '0';
- return '\'\'';
- }
- public static function quote_field($field) {
- if(is_array($field)) {
- foreach($field as $k => $v) {
- $field[$k] = self::quote_field($v);
- }
- } else {
- if(str_contains($field, '`'))
- $field = str_replace('`', '', $field);
- $field = '`'.$field.'`';
- }
- return $field;
- }
- public static function limit($start, $limit = 0) {
- $limit = intval($limit > 0 ? $limit : 0);
- $start = intval($start > 0 ? $start : 0);
- if($start > 0 && $limit > 0) {
- return " LIMIT $start, $limit";
- } elseif($limit) {
- return " LIMIT $limit";
- } elseif($start) {
- return " LIMIT $start";
- } else {
- return '';
- }
- }
- public static function order($field, $order = 'ASC') {
- if(empty($field)) {
- return '';
- }
- $order = strtoupper($order) == 'ASC' || empty($order) ? 'ASC' : 'DESC';
- return self::quote_field($field).' '.$order;
- }
- public static function field($field, $val, $glue = '=') {
- $field = self::quote_field($field);
- if(is_array($val)) {
- $glue = $glue == 'notin' ? 'notin' : 'in';
- } elseif($glue == 'in') {
- $glue = '=';
- }
- switch($glue) {
- case '>=':
- case '=':
- return $field.$glue.self::quote($val);
- break;
- case '-':
- case '+':
- return $field.'='.$field.$glue.self::quote((string)$val);
- break;
- case '|':
- case '&':
- case '^':
- case '&~':
- return $field.'='.$field.$glue.self::quote($val);
- break;
- case '>':
- case '<':
- case '<>':
- case '<=':
- return $field.$glue.self::quote($val);
- break;
- case 'like':
- return $field.' LIKE('.self::quote($val).')';
- break;
- case 'in':
- case 'notin':
- $val = $val ? implode(',', self::quote($val)) : '\'\'';
- return $field.($glue == 'notin' ? ' NOT' : '').' IN('.$val.')';
- break;
- default:
- throw new DbException('Not allow this glue between field and value: "'.$glue.'"');
- }
- }
- public static function is_pdo() {
- return getglobal('db_driver') == 'pdo';
- }
- public static function implode($array, $glue = ',') {
- $sql = $comma = '';
- $glue = ' '.trim($glue).' ';
- foreach($array as $k => $v) {
- $sql .= $comma.self::quote_field($k).'='.self::quote($v);
- $comma = $glue;
- }
- return $sql;
- }
- public static function implode_prepared_insert($array, &$arg, $glue = ',') {
- $sql1 = $sql2 = $comma1 = $comma2 = '';
- $glue = ' '.trim($glue).' ';
- foreach($array as $k => $v) {
- $sql1 .= $comma1.self::quote_field($k);
- $sql2 .= $comma2.'?';
- $arg[] = !is_object($v) ? $v : '';
- $comma1 = $glue;
- $comma2 = $glue;
- }
- return '('.$sql1.') VALUES ('.$sql2.')';
- }
- public static function implode_prepared($array, &$arg, $glue = ',') {
- $sql = $comma = '';
- $glue = ' '.trim($glue).' ';
- foreach($array as $k => $v) {
- $sql .= $comma.self::quote_field($k).'=?';
- $arg[] = !is_object($v) ? $v : '';
- $comma = $glue;
- }
- return $sql;
- }
- public static function implode_field_value($array, $glue = ',') {
- return self::implode($array, $glue);
- }
- public static function implode_field_value_prepared($array, &$arg, $glue = ',') {
- return self::implode_prepared($array, $arg, $glue);
- }
- public static function format($sql, $arg) {
- $count = substr_count($sql, '%');
- if(!$count) {
- return $sql;
- } elseif($count > count($arg)) {
- throw new DbException('SQL string format error! This SQL need "'.$count.'" vars to replace into.', 0, $sql);
- }
- $len = strlen($sql);
- $i = $find = 0;
- $ret = '';
- while($i <= $len && $find < $count) {
- if($sql[$i] == '%') {
- $next = $sql[$i + 1];
- if($next == 't') {
- $ret .= self::table($arg[$find]);
- } elseif($next == 's') {
- $ret .= self::quote(is_array($arg[$find]) ? serialize($arg[$find]) : (string)$arg[$find]);
- } elseif($next == 'f') {
- $ret .= sprintf('%F', $arg[$find]);
- } elseif($next == 'd') {
- $ret .= dintval($arg[$find]);
- } elseif($next == 'i') {
- $ret .= $arg[$find];
- } elseif($next == 'n') {
- if(!empty($arg[$find])) {
- $ret .= is_array($arg[$find]) ? implode(',', self::quote($arg[$find])) : self::quote($arg[$find]);
- } else {
- $ret .= '0';
- }
- } else {
- $ret .= self::quote($arg[$find]);
- }
- $i++;
- $find++;
- } else {
- $ret .= $sql[$i];
- }
- $i++;
- }
- if($i < $len) {
- $ret .= substr($sql, $i);
- }
- return $ret;
- }
- public static function format_prepared($sql, &$arg) {
- $params = [];
- $count = substr_count($sql, '%');
- if(!$count) {
- return $sql;
- } elseif($count > count($arg)) {
- throw new DbException('SQL string format error! This SQL need "'.$count.'" vars to replace into.', 0, $sql);
- }
- $len = strlen($sql);
- $i = $find = 0;
- $ret = '';
- while($i <= $len && $find < $count) {
- if($sql[$i] == '%') {
- $next = $sql[$i + 1];
- $v = $arg[$find];
- if($next == 't') {
- $ret .= self::table($v);
- } elseif($next == 's') {
- $v = is_array($v) ? serialize($v) : (string)$v;
- $ret .= '?';
- $params[] = $v;
- } elseif($next == 'f') {
- $ret .= sprintf('%F', $v);
- } elseif($next == 'd') {
- $ret .= dintval($v);
- } elseif($next == 'i') {
- $ret .= $v;
- } elseif($next == 'n') {
- if(!empty($v)) {
- if(is_array($v)) {
- $_ret = [];
- foreach($v as $_v) {
- $_ret[] = '?';
- $params[] = $_v;
- }
- $ret .= implode(',', $_ret);
- } else {
- $ret .= '?';
- $params[] = $v;
- }
- } else {
- $ret .= '0';
- }
- } else {
- $ret .= '?';
- $params[] = $v;
- }
- $i++;
- $find++;
- } else {
- $ret .= $sql[$i];
- }
- $i++;
- }
- if($i < $len) {
- $ret .= substr($sql, $i);
- }
- $arg = $params;
- return $ret;
- }
- public static function begin_transaction() {
- return self::$db->begin_transaction();
- }
- public static function commit() {
- return self::$db->commit();
- }
- public static function rollback() {
- return self::$db->rollback();
- }
- }
- class discuz_database_safecheck {
- protected static $checkcmd = ['SEL' => 1, 'UPD' => 1, 'INS' => 1, 'REP' => 1, 'DEL' => 1];
- protected static $config;
- public static function checkquery($sql) {
- if(is_array($sql)) {
- $sql = $sql[0];
- }
- if(self::$config === null) {
- self::$config = getglobal('config/security/querysafe');
- }
- if(self::$config['status']) {
- $check = 1;
- $cmd = strtoupper(substr(trim($sql), 0, 3));
- if(isset(self::$checkcmd[$cmd])) {
- $check = self::_do_query_safe($sql);
- } elseif(str_starts_with($cmd, '/*')) {
- $check = -1;
- }
- if($check < 1) {
- throw new DbException('It is not safe to do this query', 0, $sql);
- }
- }
- return true;
- }
- private static function _do_query_safe($sql) {
- $sql = str_replace(['\\\\', '\\\'', '\\"', '\'\''], '', $sql);
- $mark = $clean = '';
- if(!str_contains($sql, '/') && !str_contains($sql, '#') && !str_contains($sql, '-- ') && !str_contains($sql, '@') && !str_contains($sql, '`') && !str_contains($sql, '"')) {
- $clean = preg_replace("/'(.+?)'/s", '', $sql);
- } else {
- $len = strlen($sql);
- $mark = $clean = '';
- for($i = 0; $i < $len; $i++) {
- $str = $sql[$i];
- switch($str) {
- case '`':
- if(!$mark) {
- $mark = '`';
- $clean .= $str;
- } elseif($mark == '`') {
- $mark = '';
- }
- break;
- case '\'':
- if(!$mark) {
- $mark = '\'';
- $clean .= $str;
- } elseif($mark == '\'') {
- $mark = '';
- }
- break;
- case '/':
- if(empty($mark) && $sql[$i + 1] == '*') {
- $mark = '/*';
- $clean .= $mark;
- $i++;
- } elseif($mark == '/*' && $sql[$i - 1] == '*') {
- $mark = '';
- $clean .= '*';
- }
- break;
- case '#':
- if(empty($mark)) {
- $mark = $str;
- $clean .= $str;
- }
- break;
- case "\n":
- if($mark == '#' || $mark == '--') {
- $mark = '';
- }
- break;
- case '-':
- if(empty($mark) && substr($sql, $i, 3) == '-- ') {
- $mark = '-- ';
- $clean .= $mark;
- }
- break;
- default:
- break;
- }
- $clean .= $mark ? '' : $str;
- }
- }
- if(str_contains($clean, '@')) {
- return '-3';
- }
- $clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", '', strtolower($clean));
- if(self::$config['afullnote']) {
- $clean = str_replace('/**/', '', $clean);
- }
- if(is_array(self::$config['dfunction'])) {
- foreach(self::$config['dfunction'] as $fun) {
- if(str_contains($clean, $fun.'('))
- return '-1';
- }
- }
- if(is_array(self::$config['daction'])) {
- foreach(self::$config['daction'] as $action) {
- if(str_contains($clean, $action))
- return '-3';
- }
- }
- if(self::$config['dlikehex'] && strpos($clean, 'like0x')) {
- return '-2';
- }
- if(is_array(self::$config['dnote'])) {
- foreach(self::$config['dnote'] as $note) {
- if(str_contains($clean, $note))
- return '-4';
- }
- }
- return 1;
- }
- public static function setconfigstatus($data) {
- self::$config['status'] = $data ? 1 : 0;
- }
- }
- class discuz_database_prepared {
- }
|