diff --git a/library/think/db/driver.php b/library/think/db/driver.php index 23ebe391..e3f3239b 100644 --- a/library/think/db/driver.php +++ b/library/think/db/driver.php @@ -379,7 +379,7 @@ abstract class Driver // 记录错误日志 Log::record($this->error, 'ERR'); if ($this->config['debug']) { -// 开启数据库调试模式 + // 开启数据库调试模式 throw new Exception($this->error); } else { return $this->error; @@ -410,7 +410,7 @@ abstract class Driver } elseif (is_null($val)) { $set[] = $this->parseKey($key) . '=NULL'; } elseif (is_scalar($val)) { -// 过滤非标量数据 + // 过滤非标量数据 if (0 === strpos($val, ':') && in_array($val, array_keys($this->bind))) { $set[] = $this->parseKey($key) . '=' . $this->escapeString($val); } else { @@ -510,7 +510,7 @@ abstract class Driver protected function parseTable($tables) { if (is_array($tables)) { -// 支持别名定义 + // 支持别名定义 $array = []; foreach ($tables as $table => $alias) { if (!is_numeric($table)) { @@ -601,7 +601,7 @@ abstract class Driver // 比较运算 $whereStr .= $key . ' ' . $this->exp[$exp] . ' ' . $this->parseValue($val[1]); } elseif (preg_match('/^(notlike|like)$/', $exp)) { -// 模糊查找 + // 模糊查找 if (is_array($val[1])) { $likeLogic = isset($val[2]) ? strtoupper($val[2]) : 'OR'; if (in_array($likeLogic, ['AND', 'OR', 'XOR'])) { @@ -741,17 +741,18 @@ abstract class Driver */ protected function parseOrder($order) { - if (is_array($order)) { - $array = []; - foreach ($order as $key => $val) { - if (is_numeric($key)) { + $array = []; + foreach ($order as $key => $val) { + if (is_numeric($key)) { + if (false === strpos($val, '(')) { $array[] = $this->parseKey($val); - } else { - $array[] = $this->parseKey($key) . ' ' . $val; } + } else { + $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; + $array[] = $this->parseKey($key) . ' ' . $sort; } - $order = implode(',', $array); } + $order = implode(',', $array); return !empty($order) ? ' ORDER BY ' . $order : ''; } @@ -981,7 +982,7 @@ abstract class Driver $table = $this->parseTable($options['table']); $sql = 'UPDATE ' . $table . $this->parseSet($data); if (strpos($table, ',')) { -// 多表更新支持JOIN操作 + // 多表更新支持JOIN操作 $sql .= $this->parseJoin(!empty($options['join']) ? $options['join'] : ''); } $sql .= $this->parseWhere(!empty($options['where']) ? $options['where'] : ''); @@ -1007,7 +1008,7 @@ abstract class Driver $table = $this->parseTable($options['table']); $sql = 'DELETE FROM ' . $table; if (strpos($table, ',')) { -// 多表删除支持USING和JOIN操作 + // 多表删除支持USING和JOIN操作 if (!empty($options['using'])) { $sql .= ' USING ' . $this->parseTable($options['using']) . ' '; } @@ -1125,7 +1126,7 @@ abstract class Driver */ public function escapeString($str) { - return addslashes($str); + return $this->_linkID->quote($str); } /** @@ -1147,7 +1148,7 @@ abstract class Driver protected function debug($start) { if ($this->config['debug']) { -// 开启数据库调试模式 + // 开启数据库调试模式 if ($start) { Debug::remark('queryStartTime', 'time'); } else { @@ -1207,7 +1208,7 @@ abstract class Driver $r = $m; } else { if (is_numeric($this->config['slave_no'])) { -// 指定服务器读 + // 指定服务器读 $r = $this->config['slave_no']; } else { // 读操作连接从服务器 diff --git a/library/think/db/driver/mysql.php b/library/think/db/driver/mysql.php index 0aec656e..83a1c8da 100644 --- a/library/think/db/driver/mysql.php +++ b/library/think/db/driver/mysql.php @@ -89,6 +89,11 @@ class Mysql extends Driver protected function parseKey(&$key) { $key = trim($key); + if (strpos($key, '$.') && false === strpos($key, '(')) { + // JSON字段支持 + list($field, $name) = explode($key, '$.'); + $key = 'jsn_extract(' . $field . ', \'$.\'.' . $name . ')'; + } if (!preg_match('/[,\'\"\*\(\)`.\s]/', $key)) { $key = '`' . $key . '`'; } diff --git a/library/think/db/driver/oracle.php b/library/think/db/driver/oracle.php index 68b46219..0c9fe229 100644 --- a/library/think/db/driver/oracle.php +++ b/library/think/db/driver/oracle.php @@ -132,17 +132,6 @@ class Oracle extends Driver return $info; } - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL指令 - * @return string - */ - public function escapeString($str) - { - return str_ireplace("'", "''", $str); - } - /** * limit * @access public @@ -176,4 +165,21 @@ class Oracle extends Driver return ' FOR UPDATE NOWAIT '; } + + /** + * 字段和表名处理 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) + { + $key = trim($key); + if (strpos($key, '$.') && false === strpos($key, '(')) { + // JSON字段支持 + list($field, $name) = explode($key, '$.'); + $key = $field . '."' . $name . '"'; + } + return $key; + } } diff --git a/library/think/db/driver/pgsql.php b/library/think/db/driver/pgsql.php index 70a21dcb..b980bf1d 100644 --- a/library/think/db/driver/pgsql.php +++ b/library/think/db/driver/pgsql.php @@ -94,4 +94,20 @@ class Pgsql extends Driver return $limitStr; } + /** + * 字段和表名处理 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) + { + $key = trim($key); + if (strpos($key, '$.') && false === strpos($key, '(')) { + // JSON字段支持 + list($field, $name) = explode($key, '$.'); + $key = $field . '->>\'' . $name . '\''; + } + return $key; + } } diff --git a/library/think/db/driver/sqlite.php b/library/think/db/driver/sqlite.php index 991242e0..fb70c959 100644 --- a/library/think/db/driver/sqlite.php +++ b/library/think/db/driver/sqlite.php @@ -73,17 +73,6 @@ class Sqlite extends Driver return $info; } - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL指令 - * @return string - */ - public function escapeString($str) - { - return str_ireplace("'", "''", $str); - } - /** * limit * @access public diff --git a/library/think/db/driver/sqlsrv.php b/library/think/db/driver/sqlsrv.php index 62377421..7bffeef8 100644 --- a/library/think/db/driver/sqlsrv.php +++ b/library/think/db/driver/sqlsrv.php @@ -100,6 +100,16 @@ class Sqlsrv extends Driver */ protected function parseOrder($order) { + $array = []; + foreach ($order as $key => $val) { + if (is_numeric($key)) { + $array[] = $this->parseKey($val); + } else { + $sort = in_array(strtolower(trim($val)), ['asc', 'desc']) ? ' ' . $val : ''; + $array[] = $this->parseKey($key) . ' ' . $sort; + } + } + $order = implode(',', $array); return !empty($order) ? ' ORDER BY ' . $order : ' ORDER BY rand()'; } diff --git a/library/think/model.php b/library/think/model.php index dc279bfe..e5a0a9cb 100644 --- a/library/think/model.php +++ b/library/think/model.php @@ -18,7 +18,7 @@ class Model const MODEL_UPDATE = 2; // 更新 const MODEL_BOTH = 3; // 全部 // 当前数据库操作对象 - protected $db = null; + protected $db = null; // 数据库对象池 private $_db = []; // 主键名称 @@ -546,7 +546,7 @@ class Model $options['model'] = $this->name; if (isset($options['table'])) { -// 动态指定表名 + // 动态指定表名 $fields = $this->db->getFields($options['table']); $fields = $fields ? array_keys($fields) : false; } else { @@ -596,6 +596,8 @@ class Model $data[$key] = floatval($data[$key]); } elseif (false !== strpos($fieldType, 'bool')) { $data[$key] = (bool) $data[$key]; + } elseif (false !== strpos($fieldType, 'json') && is_array($data[$key])) { + $data[$key] = json_encode($data[$key]); } } } @@ -653,7 +655,7 @@ class Model return false; } if (empty($resultSet)) { -// 查询结果为空 + // 查询结果为空 return null; } if (is_string($resultSet)) { @@ -917,16 +919,11 @@ class Model * SQL查询 * @access public * @param string $sql SQL指令 - * @param mixed $parse 是否需要解析SQL * @return mixed */ - public function query($sql, $parse = false) + public function query($sql) { - if (!is_bool($parse) && !is_array($parse)) { - $parse = func_get_args(); - array_shift($parse); - } - $sql = $this->parseSql($sql, $parse); + $sql = $this->parseSql($sql); return $this->db->query($sql); } @@ -934,16 +931,11 @@ class Model * 执行SQL语句 * @access public * @param string $sql SQL指令 - * @param mixed $parse 是否需要解析SQL * @return false | integer */ - public function execute($sql, $parse = false) + public function execute($sql) { - if (!is_bool($parse) && !is_array($parse)) { - $parse = func_get_args(); - array_shift($parse); - } - $sql = $this->parseSql($sql, $parse); + $sql = $this->parseSql($sql); return $this->db->execute($sql); } @@ -951,24 +943,14 @@ class Model * 解析SQL语句 * @access public * @param string $sql SQL指令 - * @param boolean $parse 是否需要解析SQL * @return string */ - protected function parseSql($sql, $parse) + protected function parseSql($sql) { // 分析表达式 - if (true === $parse) { - $options = $this->_parseOptions(); - $sql = $this->db->parseSql($sql, $options); - } elseif (is_array($parse)) { - // SQL预处理 - $parse = array_map([$this->db, 'escapeString'], $parse); - $sql = vsprintf($sql, $parse); - } else { - $sql = strtr($sql, ['__TABLE__' => $this->getTableName(), '__PREFIX__' => $this->tablePrefix]); - $prefix = $this->tablePrefix; - $sql = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $sql); - } + $sql = strtr($sql, ['__TABLE__' => $this->getTableName(), '__PREFIX__' => $this->tablePrefix]); + $prefix = $this->tablePrefix; + $sql = preg_replace_callback("/__([A-Z0-9_-]+)__/sU", function ($match) use ($prefix) {return $prefix . strtolower($match[1]);}, $sql); $this->db->setModel($this->name); return $sql; } @@ -1088,11 +1070,11 @@ class Model public function field($field, $except = false) { if (true === $field) { -// 获取全部字段 + // 获取全部字段 $fields = $this->getDbFields(); $field = $fields ?: '*'; } elseif ($except) { -// 字段排除 + // 字段排除 if (is_string($field)) { $field = explode(',', $field); } @@ -1247,14 +1229,23 @@ class Model } /** - * 指定排序 + * 指定排序 order('id','desc') 或者 order(['id'=>'desc','create_time'=>'desc']) * @access public + * @param string|array $field 排序字段 * @param string $order 排序 * @return Model */ - public function order($order) + public function order($field, $order = '') { - $this->options['order'] = $order; + if (is_array($field)) { + $this->options['order'] = $field; + } else { + if (!empty($order)) { + $this->options['order'][$field] = $order; + } else { + $this->options['order'][] = $field; + } + } return $this; }