diff --git a/core/base.php b/core/base.php index 1af1e329..28de4b51 100644 --- a/core/base.php +++ b/core/base.php @@ -57,5 +57,5 @@ if (is_file(ROOT_PATH . 'env' . EXT)) { // 注册错误和异常处理机制 \think\Error::register(); -// 加载模式配置文件 +// 加载惯例配置文件 \think\Config::set(include THINK_PATH . 'convention' . EXT); diff --git a/core/helper.php b/core/helper.php index 5c5f8442..1b8def16 100644 --- a/core/helper.php +++ b/core/helper.php @@ -187,11 +187,12 @@ if (!function_exists('db')) { * 实例化数据库类 * @param string $name 操作的数据表名称(不含前缀) * @param array|string $config 数据库配置参数 + * @param bool $force 是否强制重新连接 * @return \think\db\Query */ - function db($name = '', $config = []) + function db($name = '', $config = [], $force = true) { - return Db::connect($config, true)->name($name); + return Db::connect($config, $force)->name($name); } } @@ -510,3 +511,28 @@ if (!function_exists('abort')) { } } } + +if (!function_exists('halt')) { + /** + * 调试变量并且中断输出 + * @param mixed $var 调试变量或者信息 + */ + function halt($var) + { + dump($var); + throw new \think\exception\HttpResponseException(new Response); + } +} + +if (!function_exists('token')) { + /** + * 生成表单令牌 + * @param string $name 令牌名称 + * @param mixed $type 令牌生成方法 + */ + function token($name = '__token__', $type = 'md5') + { + $token = Request::instance()->token($name, $type); + return ''; + } +} diff --git a/core/lang/zh-cn.php b/core/lang/zh-cn.php index 98abf7a0..2e1247f9 100644 --- a/core/lang/zh-cn.php +++ b/core/lang/zh-cn.php @@ -17,6 +17,7 @@ return [ 'Parse error' => '语法解析错误', 'Type error' => '类型错误', 'Fatal error' => '致命错误', + 'syntax error' => '语法错误', // 框架核心错误提示 'dispatch type not support' => '不支持的调度类型', diff --git a/core/library/think/Build.php b/core/library/think/Build.php index 76d82609..dd2bd550 100644 --- a/core/library/think/Build.php +++ b/core/library/think/Build.php @@ -198,7 +198,7 @@ class Build } $filename = APP_PATH . ($module ? $module . DS : '') . 'common.php'; if (!is_file($filename)) { - file_put_contents($filename, "field)) { + if (true === $this->field) { + $type = $this->db()->getTableInfo('', 'type'); + } else { + $type = []; + foreach ((array) $this->field as $key => $val) { + if (is_int($key)) { + $key = $val; + $val = 'varchar'; + } + $type[$key] = $val; + } + } + $query->setFieldType($type); + $this->field = array_keys($type); $query->allowField($this->field); } - if (!empty($this->fieldType)) { - $query->setFieldType($this->fieldType); - } - if (!empty($this->pk)) { $query->pk($this->pk); } @@ -594,11 +606,10 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * @access public * @param array $data 数据 * @param array $where 更新条件 - * @param bool $getId 新增的时候是否获取id - * @param bool $replace 是否replace + * @param string $sequence 自增序列名 * @return integer */ - public function save($data = [], $where = [], $getId = true, $replace = false) + public function save($data = [], $where = [], $sequence = null) { if (!empty($data)) { // 数据自动验证 @@ -616,9 +627,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 检测字段 if (!empty($this->field)) { - if (true === $this->field) { - $this->field = $this->db()->getTableInfo('', 'fields'); - } foreach ($this->data as $key => $val) { if (!in_array($key, $this->field)) { unset($this->data[$key]); @@ -656,6 +664,15 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } } + if (!empty($this->readonly)) { + // 只读字段不允许更新 + foreach ($this->readonly as $key => $field) { + if (isset($data[$field])) { + unset($data[$field]); + } + } + } + if (empty($where) && !empty($this->updateWhere)) { $where = $this->updateWhere; } @@ -685,16 +702,15 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return false; } - $result = $this->db()->insert($this->data, $replace); + $result = $this->db()->insert($this->data); // 获取自动增长主键 - if ($result && $getId) { - $insertId = $this->db()->getLastInsID(); + if ($result) { + $insertId = $this->db()->getLastInsID($sequence); $pk = $this->getPk(); if (is_string($pk) && $insertId) { $this->data[$pk] = $insertId; } - $result = $insertId; } // 标记为更新 $this->isUpdate = true; @@ -713,17 +729,16 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * 保存多个数据到当前数据对象 * @access public * @param array $dataSet 数据 - * @param bool $replace 是否replace * @return array|false */ - public function saveAll($dataSet, $replace = false) + public function saveAll($dataSet) { $result = []; $db = $this->db(); $db->startTrans(); try { foreach ($dataSet as $key => $data) { - $result[$key] = self::create($data, $replace); + $result[$key] = self::create($data); } $db->commit(); return $result; @@ -741,6 +756,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ public function allowField($field) { + if (true === $field) { + $field = $this->db()->getTableInfo('', 'type'); + $this->db()->setFieldType($field); + $field = array_keys($field); + } $this->field = $field; return $this; } @@ -931,13 +951,12 @@ abstract class Model implements \JsonSerializable, \ArrayAccess * 写入数据 * @access public * @param array $data 数据数组 - * @param bool $replace 是否replace * @return $this */ - public static function create($data = [], $replace = false) + public static function create($data = []) { $model = new static(); - $model->isUpdate(false)->save($data, [], true, $replace); + $model->isUpdate(false)->save($data, []); return $model; } @@ -1068,6 +1087,19 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return $model; } + /** + * 设置是否使用全局查询范围 + * @param bool $use 是否启用全局查询范围 + * @access public + * @return Model + */ + public static function useGlobalScope($use) + { + $model = new static(); + static::$useGlobalScope = $use; + return $model; + } + /** * 根据关联条件查询当前模型 * @access public @@ -1105,6 +1137,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $model = new static(); $info = $model->$relation()->getRelationInfo(); switch ($info['type']) { + case Relation::HAS_ONE: case Relation::HAS_MANY: $table = $info['model']::getTable(); if (is_array($where)) { @@ -1287,7 +1320,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess { $query = $this->db(); // 全局作用域 - if (method_exists($this, 'base')) { + if (static::$useGlobalScope && method_exists($this, 'base')) { call_user_func_array('static::base', [ & $query]); } if (method_exists($this, 'scope' . $method)) { @@ -1309,7 +1342,7 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } $query = self::$links[$model]; // 全局作用域 - if (method_exists($model, 'base')) { + if (static::$useGlobalScope && method_exists($model, 'base')) { call_user_func_array('static::base', [ & $query]); } return call_user_func_array([$query, $method], $params); diff --git a/core/library/think/Request.php b/core/library/think/Request.php index 4edf5083..4449b97f 100644 --- a/core/library/think/Request.php +++ b/core/library/think/Request.php @@ -599,11 +599,6 @@ class Request */ public function param($name = '', $default = null, $filter = null) { - if (is_array($name)) { - // 设置param - $this->param = array_merge($this->param, $name); - return; - } if (empty($this->param)) { $method = $this->method(true); // 自动获取请求变量 @@ -642,6 +637,7 @@ class Request public function route($name = '', $default = null, $filter = null) { if (is_array($name)) { + $this->param = []; return $this->route = array_merge($this->route, $name); } return $this->input($this->route, $name, $default, $filter); @@ -658,6 +654,7 @@ class Request public function get($name = '', $default = null, $filter = null) { if (is_array($name)) { + $this->param = []; return $this->get = array_merge($this->get, $name); } elseif (empty($this->get)) { $this->get = $_GET; @@ -676,6 +673,7 @@ class Request public function post($name = '', $default = null, $filter = null) { if (is_array($name)) { + $this->param = []; return $this->post = array_merge($this->post, $name); } elseif (empty($this->post)) { $this->post = $_POST; @@ -694,6 +692,7 @@ class Request public function put($name = '', $default = null, $filter = null) { if (is_array($name)) { + $this->param = []; return $this->put = is_null($this->put) ? $name : array_merge($this->put, $name); } if (is_null($this->put)) { @@ -743,6 +742,7 @@ class Request public function request($name = '', $default = null, $filter = null) { if (is_array($name)) { + $this->param = []; return $this->request = array_merge($this->request, $name); } elseif (empty($this->request)) { $this->request = $_REQUEST; @@ -1228,7 +1228,7 @@ class Request { if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) { return true; - } elseif (strpos(strtoupper($_SERVER['HTTP_ACCEPT']), "VND.WAP.WML")) { + } elseif (isset($_SERVER['HTTP_ACCEPT']) && strpos(strtoupper($_SERVER['HTTP_ACCEPT']), "VND.WAP.WML")) { return true; } elseif (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE'])) { return true; @@ -1404,4 +1404,22 @@ class Request } return $this->content; } + + /** + * 生成请求令牌 + * @access public + * @param string $name 令牌名称 + * @param mixed $type 令牌生成方法 + * @return string + */ + public function token($name = '__token__', $type = 'md5') + { + $type = is_callable($type) ? $type : 'md5'; + $token = call_user_func($type, $_SERVER['REQUEST_TIME_FLOAT']); + if ($this->isAjax()) { + header($name . ': ' . $token); + } + Session::set($name, $token); + return $token; + } } diff --git a/core/library/think/Route.php b/core/library/think/Route.php index 2ada5acf..95904ee0 100644 --- a/core/library/think/Route.php +++ b/core/library/think/Route.php @@ -401,8 +401,16 @@ class Route } else { $route = $val; } + + $options = isset($option1) ? $option1 : $option; + $patterns = isset($pattern1) ? $pattern1 : $pattern; + if ('$' == substr($key, -1, 1)) { + // 是否完整匹配 + $options['complete_match'] = true; + $key = substr($key, 0, -1); + } $vars = self::parseVar($key); - $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => isset($option1) ? $option1 : $option, 'pattern' => isset($pattern1) ? $pattern1 : $pattern]; + $item[] = ['rule' => $key, 'route' => $route, 'var' => $vars, 'option' => $options, 'pattern' => $patterns]; } self::$rules['*'][$name] = ['rule' => $item, 'route' => '', 'var' => [], 'option' => $option, 'pattern' => $pattern]; } diff --git a/core/library/think/Validate.php b/core/library/think/Validate.php index 857a9933..475edbc9 100644 --- a/core/library/think/Validate.php +++ b/core/library/think/Validate.php @@ -12,6 +12,7 @@ namespace think; use think\Request; +use think\Session; class Validate { @@ -479,9 +480,10 @@ class Validate * @access protected * @param mixed $value 字段值 * @param string $rule 验证规则 + * @param array $data 验证数据 * @return bool */ - protected function is($value, $rule) + protected function is($value, $rule, $data = []) { switch ($rule) { case 'require': @@ -541,6 +543,8 @@ class Validate $result = $this->filter($value, FILTER_VALIDATE_FLOAT); break; case 'number': + $result = is_numeric($value); + break; case 'integer': // 是否为整形 $result = $this->filter($value, FILTER_VALIDATE_INT); @@ -563,6 +567,9 @@ class Validate case 'image': $result = $value instanceof \think\File && in_array($this->getImageType($value->getRealPath()), [1, 2, 3, 6]); break; + case 'token': + $result = $this->token($value, '__token__', $data); + break; default: if (isset(self::$type[$rule])) { // 注册的验证规则 @@ -1083,6 +1090,33 @@ class Validate return 1 === preg_match($rule, (string) $value); } + /** + * 验证表单令牌 + * @access protected + * @param mixed $value 字段值 + * @param mixed $rule 验证规则 + * @param array $data 数据 + * @return bool + */ + protected function token($value, $rule, $data) + { + $rule = !empty($rule) ? $rule : '__token__'; + if (!isset($data[$rule]) || !Session::has($rule)) { + // 令牌数据无效 + return false; + } + + // 令牌验证 + if (isset($data[$rule]) && Session::get($rule) === $data[$rule]) { + // 防止重复提交 + Session::delete($rule); // 验证完成销毁session + return true; + } + // 开启TOKEN重置 + Session::delete($rule); + return false; + } + // 获取错误信息 public function getError() { diff --git a/core/library/think/cache/driver/File.php b/core/library/think/cache/driver/File.php index 97ee2bf6..1f4b91f8 100644 --- a/core/library/think/cache/driver/File.php +++ b/core/library/think/cache/driver/File.php @@ -17,11 +17,9 @@ namespace think\cache\driver; */ class File { - protected $options = [ 'expire' => 0, 'cache_subdir' => false, - 'path_level' => 1, 'prefix' => '', 'path' => CACHE_PATH, 'data_compress' => false, diff --git a/core/library/think/db/Builder.php b/core/library/think/db/Builder.php index 3ebdb692..24d20d49 100644 --- a/core/library/think/db/Builder.php +++ b/core/library/think/db/Builder.php @@ -24,9 +24,6 @@ abstract class Builder // 查询对象实例 protected $query; - // 查询参数 - protected $options = []; - // 数据库表达式 protected $exp = ['eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'exp' => 'EXP', 'notin' => 'NOT IN', 'not in' => 'NOT IN', 'between' => 'BETWEEN', 'not between' => 'NOT BETWEEN', 'notbetween' => 'NOT BETWEEN', 'exists' => 'EXISTS', 'notexists' => 'NOT EXISTS', 'not exists' => 'NOT EXISTS', 'null' => 'NULL', 'notnull' => 'NOT NULL', 'not null' => 'NOT NULL', '> time' => '> TIME', '< time' => '< TIME', '>= time' => '>= TIME', '<= time' => '<= TIME', 'between time' => 'BETWEEN TIME', 'not between time' => 'NOT BETWEEN TIME', 'notbetween time' => 'NOT BETWEEN TIME']; @@ -606,7 +603,7 @@ abstract class Builder { // 获取合法的字段 if ('*' == $options['field']) { - $fields = $this->query->getFieldsType($options); + $fields = array_keys($this->query->getFieldsType($options)); } else { $fields = $options['field']; } @@ -687,7 +684,7 @@ abstract class Builder $this->parseWhere($options['where'], $options), $this->parseOrder($options['order']), $this->parseLimit($options['limit']), - $this->parseLimit($options['lock']), + $this->parseLock($options['lock']), $this->parseComment($options['comment']), ], $this->updateSql); @@ -711,7 +708,7 @@ abstract class Builder $this->parseWhere($options['where'], $options), $this->parseOrder($options['order']), $this->parseLimit($options['limit']), - $this->parseLimit($options['lock']), + $this->parseLock($options['lock']), $this->parseComment($options['comment']), ], $this->deleteSql); diff --git a/core/library/think/db/Connection.php b/core/library/think/db/Connection.php index 6712e0d9..bbdbdc6a 100644 --- a/core/library/think/db/Connection.php +++ b/core/library/think/db/Connection.php @@ -13,7 +13,6 @@ namespace think\db; use PDO; use PDOStatement; -use think\App; use think\Collection; use think\Db; use think\db\exception\BindParamException; @@ -255,6 +254,8 @@ abstract class Connection if (!isset($this->links[$linkNum])) { if (!$config) { $config = $this->config; + } else { + $config = array_merge($this->config, $config); } // 连接参数 if (isset($config['params']) && is_array($config['params'])) { @@ -272,15 +273,20 @@ abstract class Connection if (empty($config['dsn'])) { $config['dsn'] = $this->parseDsn($config); } + if ($config['debug']) { + $startTime = microtime(true); + } $this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params); - // 记录数据库连接信息 - App::$debug && Log::record('[ DB ] CONNECT: ' . $config['dsn'], 'info'); + if ($config['debug']) { + // 记录数据库连接信息 + Log::record('[ DB ] CONNECT:[ UseTime:' . number_format(microtime(true) - $startTime, 6) . 's ] ' . $config['dsn'], 'sql'); + } } catch (\PDOException $e) { if ($autoConnection) { Log::record($e->getMessage(), 'error'); return $this->connect($autoConnection, $linkNum); } else { - throw new Exception($e->getMessage()); + throw $e; } } } @@ -359,13 +365,11 @@ abstract class Connection * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 - * @param boolean $getLastInsID 是否获取自增ID - * @param string $sequence 自增序列名 * @return int * @throws BindParamException * @throws PDOException */ - public function execute($sql, $bind = [], $getLastInsID = false, $sequence = null) + public function execute($sql, $bind = []) { $this->initConnect(true); if (!$this->linkID) { @@ -393,12 +397,6 @@ abstract class Connection $this->debug(false); $this->numRows = $this->PDOStatement->rowCount(); - if (preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $sql)) { - $this->lastInsID = $this->linkID->lastInsertId($sequence); - if ($getLastInsID) { - return $this->lastInsID; - } - } return $this->numRows; } catch (\PDOException $e) { throw new PDOException($e, $this->config, $this->queryStr); @@ -696,10 +694,14 @@ abstract class Connection /** * 获取最近插入的ID * @access public + * @param string $sequence 自增序列名 * @return string */ - public function getLastInsID() + public function getLastInsID($sequence = null) { + if (is_null($this->lastInsID)) { + $this->lastInsID = $this->linkID->lastInsertId($sequence); + } return $this->lastInsID; } @@ -738,9 +740,10 @@ abstract class Connection * 数据库调试 记录当前SQL及分析性能 * @access protected * @param boolean $start 调试开始标记 true 开始 false 结束 + * @param string $sql 执行的SQL语句 留空自动获取 * @return void */ - protected function debug($start) + protected function debug($start, $sql = '') { if (!empty($this->config['debug'])) { // 开启数据库调试模式 @@ -750,14 +753,15 @@ abstract class Connection // 记录操作结束时间 Debug::remark('queryEndTime', 'time'); $runtime = Debug::getRangeTime('queryStartTime', 'queryEndTime'); - $log = $this->queryStr . ' [ RunTime:' . $runtime . 's ]'; + $sql = $sql ?: $this->queryStr; + $log = $sql . ' [ RunTime:' . $runtime . 's ]'; $result = []; // SQL性能分析 - if ($this->config['sql_explain'] && 0 === stripos(trim($this->queryStr), 'select')) { - $result = $this->getExplain($this->queryStr); + if ($this->config['sql_explain'] && 0 === stripos(trim($sql), 'select')) { + $result = $this->getExplain($sql); } // SQL监听 - $this->trigger($this->queryStr, $runtime, $result); + $this->trigger($sql, $runtime, $result); } } } @@ -791,7 +795,7 @@ abstract class Connection } } else { // 未注册监听则记录到日志中 - Log::record('[ SQL ] ' . $this->queryStr . ' [ RunTime:' . $runtime . 's ]', 'sql'); + Log::record('[ SQL ] ' . $sql . ' [ RunTime:' . $runtime . 's ]', 'sql'); if (!empty($explain)) { Log::record('[ EXPLAIN : ' . var_export($explain, true) . ' ]', 'sql'); } diff --git a/core/library/think/db/Query.php b/core/library/think/db/Query.php index 816d8d48..3a687f13 100644 --- a/core/library/think/db/Query.php +++ b/core/library/think/db/Query.php @@ -194,25 +194,24 @@ class Query * @access public * @param string $sql sql指令 * @param array $bind 参数绑定 - * @param boolean $getLastInsID 是否获取自增ID - * @param boolean $sequence 自增序列名 * @return int * @throws BindParamException * @throws PDOException */ - public function execute($sql, $bind = [], $getLastInsID = false, $sequence = null) + public function execute($sql, $bind = []) { - return $this->connection->execute($sql, $bind, $getLastInsID, $sequence); + return $this->connection->execute($sql, $bind); } /** * 获取最近插入的ID * @access public + * @param string $sequence 自增序列名 * @return string */ - public function getLastInsID() + public function getLastInsID($sequence = null) { - return $this->connection->getLastInsID(); + return $this->connection->getLastInsID($sequence); } /** @@ -728,11 +727,11 @@ class Query } if (true === $field) { // 获取全部字段 - $fields = isset($this->options['allow_field']) ? $this->options['allow_field'] : $this->getTableInfo($tableName, 'fields'); + $fields = isset($this->options['allow_field']) ? $this->options['allow_field'] : $this->getTableInfo($tableName ?: (isset($this->options['table']) ? $this->options['table'] : ''), 'fields'); $field = $fields ?: ['*']; } elseif ($except) { // 字段排除 - $fields = isset($this->options['allow_field']) ? $this->options['allow_field'] : $this->getTableInfo($tableName, 'fields'); + $fields = isset($this->options['allow_field']) ? $this->options['allow_field'] : $this->getTableInfo($tableName ?: (isset($this->options['table']) ? $this->options['table'] : ''), 'fields'); $field = $fields ? array_diff($fields, $field) : $field; } if ($tableName) { @@ -749,7 +748,7 @@ class Query if (isset($this->options['field'])) { $field = array_merge($this->options['field'], $field); } - $this->options['field'] = $field; + $this->options['field'] = array_unique($field); return $this; } @@ -1415,8 +1414,10 @@ class Query { $types = $this->getFieldsType($options); $bind = []; - foreach ($types as $key => $type) { - $bind[$key] = $this->getFieldBindType($type); + if ($types) { + foreach ($types as $key => $type) { + $bind[$key] = $this->getFieldBindType($type); + } } return $bind; } @@ -1665,7 +1666,7 @@ class Query * @access public * @param mixed $data 数据 * @param boolean $replace 是否replace - * @param boolean $getLastInsID 是否获取自增ID + * @param boolean $getLastInsID 返回自增主键 * @param string $sequence 自增序列名 * @return integer|string */ @@ -1681,9 +1682,14 @@ class Query // 获取实际执行的SQL语句 return $this->connection->getRealSql($sql, $bind); } - $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); + // 执行操作 - return $this->execute($sql, $bind, $getLastInsID, $sequence); + $result = $this->execute($sql, $bind); + if ($getLastInsID) { + $sequence = $sequence ?: (isset($options['sequence']) ? $options['sequence'] : null); + return $this->getLastInsID($sequence); + } + return $result; } /** @@ -2031,7 +2037,7 @@ class Query public function chunk($count, $callback, $column = null) { $options = $this->getOptions(); - $column = $column ?: ($options['pk'] ?: $this->getPk()); + $column = $column ?: $this->getPk(); $bind = $this->bind; $resultSet = $this->limit($count)->order($column, 'asc')->select(); diff --git a/core/library/think/db/connector/Mysql.php b/core/library/think/db/connector/Mysql.php index 5f83f496..42a6376b 100644 --- a/core/library/think/db/connector/Mysql.php +++ b/core/library/think/db/connector/Mysql.php @@ -54,8 +54,12 @@ class Mysql extends Connection if (strpos($tableName, '.')) { $tableName = str_replace('.', '`.`', $tableName); } - $sql = 'SHOW COLUMNS FROM `' . $tableName . '`'; - $pdo = $this->linkID->query($sql); + $sql = 'SHOW COLUMNS FROM `' . $tableName . '`'; + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; if ($result) { @@ -82,8 +86,12 @@ class Mysql extends Connection */ public function getTables($dbName = '') { - $sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES '; - $pdo = $this->linkID->query($sql); + $sql = !empty($dbName) ? 'SHOW TABLES FROM ' . $dbName : 'SHOW TABLES '; + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; foreach ($result as $key => $val) { @@ -110,8 +118,9 @@ class Mysql extends Connection } return $result; } - - protected function supportSavepoint(){ + + protected function supportSavepoint() + { return true; } } diff --git a/core/library/think/db/connector/Pgsql.php b/core/library/think/db/connector/Pgsql.php index 161165ac..06e08f54 100644 --- a/core/library/think/db/connector/Pgsql.php +++ b/core/library/think/db/connector/Pgsql.php @@ -46,9 +46,13 @@ class Pgsql extends Connection $this->initConnect(true); list($tableName) = explode(' ', $tableName); $sql = 'select fields_name as "field",fields_type as "type",fields_not_null as "null",fields_key_name as "key",fields_default as "default",fields_default as "extra" from table_msg(\'' . $tableName . '\');'; - $pdo = $this->linkID->query($sql); - $result = $pdo->fetchAll(PDO::FETCH_ASSOC); - $info = []; + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; if ($result) { foreach ($result as $key => $val) { $val = array_change_key_case($val); @@ -73,8 +77,12 @@ class Pgsql extends Connection */ public function getTables($dbName = '') { - $sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'"; - $pdo = $this->linkID->query($sql); + $sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'"; + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; foreach ($result as $key => $val) { @@ -94,7 +102,8 @@ class Pgsql extends Connection return []; } - protected function supportSavepoint(){ + protected function supportSavepoint() + { return true; } } diff --git a/core/library/think/db/connector/Sqlite.php b/core/library/think/db/connector/Sqlite.php index d8f63f81..1a52905e 100644 --- a/core/library/think/db/connector/Sqlite.php +++ b/core/library/think/db/connector/Sqlite.php @@ -43,9 +43,13 @@ class Sqlite extends Connection $this->initConnect(true); list($tableName) = explode(' ', $tableName); $sql = 'PRAGMA table_info( ' . $tableName . ' )'; - $pdo = $this->linkID->query($sql); - $result = $pdo->fetchAll(PDO::FETCH_ASSOC); - $info = []; + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); + $result = $pdo->fetchAll(PDO::FETCH_ASSOC); + $info = []; if ($result) { foreach ($result as $key => $val) { $val = array_change_key_case($val); @@ -73,7 +77,11 @@ class Sqlite extends Connection $sql = "SELECT name FROM sqlite_master WHERE type='table' " . "UNION ALL SELECT name FROM sqlite_temp_master " . "WHERE type='table' ORDER BY name"; - $pdo = $this->linkID->query($sql); + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; foreach ($result as $key => $val) { @@ -93,7 +101,8 @@ class Sqlite extends Connection return []; } - protected function supportSavepoint(){ + protected function supportSavepoint() + { return true; } } diff --git a/core/library/think/db/connector/Sqlsrv.php b/core/library/think/db/connector/Sqlsrv.php index cce0c6c8..1100f5dd 100644 --- a/core/library/think/db/connector/Sqlsrv.php +++ b/core/library/think/db/connector/Sqlsrv.php @@ -58,7 +58,11 @@ class Sqlsrv extends Connection AND t.table_schema = c.table_schema AND t.table_name = c.table_name WHERE t.table_name = '$tableName'"; - $pdo = $this->linkID->query($sql); + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; if ($result) { @@ -74,8 +78,12 @@ class Sqlsrv extends Connection ]; } } - $sql = "SELECT column_name FROM information_schema.key_column_usage WHERE table_name='$tableName'"; - $pdo = $this->linkID->query($sql); + $sql = "SELECT column_name FROM information_schema.key_column_usage WHERE table_name='$tableName'"; + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); $result = $pdo->fetch(PDO::FETCH_ASSOC); if ($result) { $info[$result['column_name']]['primary'] = true; @@ -95,7 +103,11 @@ class Sqlsrv extends Connection FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' "; - $pdo = $this->linkID->query($sql); + // 调试开始 + $this->debug(true); + $pdo = $this->linkID->query($sql); + // 调试结束 + $this->debug(false, $sql); $result = $pdo->fetchAll(PDO::FETCH_ASSOC); $info = []; foreach ($result as $key => $val) { diff --git a/core/library/think/exception/Handle.php b/core/library/think/exception/Handle.php index 7b3d0ff1..0b1f6bc0 100644 --- a/core/library/think/exception/Handle.php +++ b/core/library/think/exception/Handle.php @@ -14,7 +14,6 @@ namespace think\exception; use Exception; use think\App; use think\Config; -use think\Console; use think\console\Output; use think\Lang; use think\Log; @@ -91,7 +90,7 @@ class Handle if (App::$debug) { $output->setVerbosity(Output::VERBOSITY_DEBUG); } - (new Console)->renderException($e, $output); + $output->renderException($e); } /** @@ -210,11 +209,15 @@ class Handle } if (strpos($message, ':')) { - $name = strstr($message, ':', true); - return Lang::has($name) ? Lang::get($name) . ' ' . strstr($message, ':') : $message; - } else { - return Lang::has($message) ? Lang::get($message) : $message; + $name = strstr($message, ':', true); + $message = Lang::has($name) ? Lang::get($name) . strstr($message, ':') : $message; + } elseif (strpos($message, ',')) { + $name = strstr($message, ',', true); + $message = Lang::has($name) ? Lang::get($name) . ':' . substr(strstr($message, ','), 1) : $message; + } elseif (Lang::has($message)) { + $message = Lang::get($message); } + return $message; } /** diff --git a/core/library/think/log/driver/File.php b/core/library/think/log/driver/File.php index be6e1d0f..11b265a2 100644 --- a/core/library/think/log/driver/File.php +++ b/core/library/think/log/driver/File.php @@ -20,6 +20,7 @@ class File 'time_format' => ' c ', 'file_size' => 2097152, 'path' => LOG_PATH, + 'apart_level' => [], ]; // 实例化并传入参数 @@ -63,20 +64,27 @@ class File $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; $file_load = ' [文件加载:' . count(get_included_files()) . ']'; - $info = '[ log ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n"; - foreach ($log as $type => $val) { - foreach ($val as $msg) { - if (!is_string($msg)) { - $msg = var_export($msg, true); - } - $info .= '[ ' . $type . ' ] ' . $msg . "\r\n"; - } - } - + $info = '[ log ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n"; $server = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '0.0.0.0'; $remote = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '0.0.0.0'; $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI'; $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + foreach ($log as $type => $val) { + $level = ''; + foreach ($val as $msg) { + if (!is_string($msg)) { + $msg = var_export($msg, true); + } + $level .= '[ ' . $type . ' ] ' . $msg . "\r\n"; + } + if (in_array($type, $this->config['apart_level'])) { + // 独立记录的日志级别 + $filename = $path . DS . $type . '.log'; + error_log("[{$now}] {$server} {$remote} {$method} {$uri}\r\n{$level}\r\n", 3, $filename); + } else { + $info .= $level; + } + } return error_log("[{$now}] {$server} {$remote} {$method} {$uri}\r\n{$info}\r\n", 3, $destination); } diff --git a/core/library/think/model/Relation.php b/core/library/think/model/Relation.php index 6b1faa32..0a18d1f1 100644 --- a/core/library/think/model/Relation.php +++ b/core/library/think/model/Relation.php @@ -45,6 +45,8 @@ class Relation protected $joinType; // 关联模型查询对象 protected $query; + // 关联查询条件 + protected $where; /** * 架构函数 @@ -93,7 +95,7 @@ class Relation $result = $relation->where($localKey, $this->parent->$foreignKey)->find(); break; case self::HAS_MANY: - $result = $relation->where($foreignKey, $this->parent->$localKey)->select(); + $result = $relation->select(); break; case self::HAS_MANY_THROUGH: $result = $relation->select(); @@ -170,7 +172,8 @@ class Relation } if (!empty($range)) { - $data = $this->eagerlyOneToMany($model, [ + $this->where[$foreignKey] = ['in', $range]; + $data = $this->eagerlyOneToMany($model, [ $foreignKey => [ 'in', $range, @@ -659,6 +662,14 @@ class Relation { if ($this->query) { switch ($this->type) { + case self::HAS_MANY: + if (isset($this->where)) { + $this->query->where($this->where); + } elseif (isset($this->parent->{$this->localKey})) { + // 关联查询带入关联条件 + $this->query->where($this->foreignKey, $this->parent->{$this->localKey}); + } + break; case self::HAS_MANY_THROUGH: $through = $this->middle; $model = $this->model; diff --git a/core/library/traits/controller/Jump.php b/core/library/traits/controller/Jump.php index b8b2b573..a867548e 100644 --- a/core/library/traits/controller/Jump.php +++ b/core/library/traits/controller/Jump.php @@ -31,9 +31,10 @@ trait Jump * @param string $url 跳转的URL地址 * @param mixed $data 返回的数据 * @param integer $wait 跳转等待时间 + * @param array $header 发送的Header信息 * @return void */ - protected function success($msg = '', $url = null, $data = '', $wait = 3) + protected function success($msg = '', $url = null, $data = '', $wait = 3, array $header = []) { $code = 1; if (is_numeric($msg)) { @@ -58,7 +59,7 @@ trait Jump $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) ->fetch(Config::get('dispatch_success_tmpl'), $result); } - $response = Response::create($result, $type); + $response = Response::create($result, $type)->header($header); throw new HttpResponseException($response); } @@ -69,9 +70,10 @@ trait Jump * @param string $url 跳转的URL地址 * @param mixed $data 返回的数据 * @param integer $wait 跳转等待时间 + * @param array $header 发送的Header信息 * @return void */ - protected function error($msg = '', $url = null, $data = '', $wait = 3) + protected function error($msg = '', $url = null, $data = '', $wait = 3, array $header = []) { $code = 0; if (is_numeric($msg)) { @@ -96,7 +98,7 @@ trait Jump $result = ViewTemplate::instance(Config::get('template'), Config::get('view_replace_str')) ->fetch(Config::get('dispatch_error_tmpl'), $result); } - $response = Response::create($result, $type); + $response = Response::create($result, $type)->header($header); throw new HttpResponseException($response); } @@ -107,9 +109,10 @@ trait Jump * @param integer $code 返回的code * @param mixed $msg 提示信息 * @param string $type 返回数据格式 + * @param array $header 发送的Header信息 * @return void */ - protected function result($data, $code = 0, $msg = '', $type = '') + protected function result($data, $code = 0, $msg = '', $type = '', array $header = []) { $result = [ 'code' => $code, @@ -118,7 +121,7 @@ trait Jump 'data' => $data, ]; $type = $type ?: $this->getResponseType(); - $response = Response::create($result, $type); + $response = Response::create($result, $type)->header($header); throw new HttpResponseException($response); } diff --git a/core/library/traits/model/SoftDelete.php b/core/library/traits/model/SoftDelete.php index f580243a..c2d56f1e 100644 --- a/core/library/traits/model/SoftDelete.php +++ b/core/library/traits/model/SoftDelete.php @@ -4,6 +4,20 @@ namespace traits\model; trait SoftDelete { + + /** + * 判断当前实例是否被软删除 + * @access public + * @return boolean + */ + public function trashed() + { + if (!empty($this->data[static::$deleteTime])) { + return true; + } + return false; + } + /** * 查询软删除数据 * @access public diff --git a/core/tpl/page_trace.tpl b/core/tpl/page_trace.tpl index c1c2f248..7c5df6fb 100644 --- a/core/tpl/page_trace.tpl +++ b/core/tpl/page_trace.tpl @@ -12,7 +12,7 @@ $val) { - echo '