diff --git a/thinkphp/convention.php b/thinkphp/convention.php index fbce075e7..c1753afca 100644 --- a/thinkphp/convention.php +++ b/thinkphp/convention.php @@ -186,6 +186,8 @@ return [ 'level' => [], // 是否记录trace信息到日志 'record_trace' => false, + // 是否JSON格式记录 + 'json' => false, ], // +---------------------------------------------------------------------- diff --git a/thinkphp/library/think/App.php b/thinkphp/library/think/App.php index e704658d2..34b677af5 100644 --- a/thinkphp/library/think/App.php +++ b/thinkphp/library/think/App.php @@ -20,7 +20,7 @@ use think\route\Dispatch; */ class App extends Container { - const VERSION = '5.1.14'; + const VERSION = '5.1.15'; /** * 当前模块路径 @@ -382,7 +382,7 @@ class App extends Container $this->lang->load($this->appPath . $module . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR . $this->request->langset() . '.php'); // 模块请求缓存检查 - $this->request->cache( + $this->checkRequestCache( $config['app']['request_cache'], $config['app']['request_cache_expire'], $config['app']['request_cache_except'] @@ -419,7 +419,7 @@ class App extends Container if (empty($dispatch)) { // 路由检测 - $dispatch = $this->routeCheck(); + $dispatch = $this->routeCheck()->init(); } // 记录当前调度信息 @@ -436,7 +436,7 @@ class App extends Container $this->hook->listen('app_begin'); // 请求缓存检查 - $this->request->cache( + $this->checkRequestCache( $this->config('request_cache'), $this->config('request_cache_expire'), $this->config('request_cache_except') @@ -468,7 +468,9 @@ class App extends Container $response = Response::create($data, $type); } else { - $response = Response::create(); + $data = ob_get_clean(); + $status = empty($data) ? 204 : 200; + $response = Response::create($data, '', $status); } return $response; }); @@ -512,6 +514,34 @@ class App extends Container ]); } + /** + * 设置当前地址的请求缓存 + * @access public + * @param string $key 缓存标识,支持变量规则 ,例如 item/:name/:id + * @param mixed $expire 缓存有效期 + * @param array $except 缓存排除 + * @param string $tag 缓存标签 + * @return void + */ + public function checkRequestCache($key, $expire = null, $except = [], $tag = null) + { + $cache = $this->request->cache($key, $expire, $except, $tag); + + if ($cache) { + list($key, $expire, $tag) = $cache; + if (strtotime($this->request->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $this->request->server('REQUEST_TIME')) { + // 读取缓存 + $response = Response::create()->code(304); + throw new HttpResponseException($response); + } elseif ($this->cache->has($key)) { + list($content, $header) = $this->cache->get($key); + + $response = Response::create($content)->header($header); + throw new HttpResponseException($response); + } + } + } + /** * 设置当前请求的调度信息 * @access public @@ -554,15 +584,17 @@ class App extends Container */ public function routeCheck() { - // 获取应用调度信息 + // 检测路由缓存 if (!$this->appDebug && $this->config->get('route_check_cache')) { $routeKey = $this->getRouteCacheKey(); + $option = $this->config->get('route_cache_option') ?: $this->cache->getConfig(); - if ($this->cache->has($routeKey)) { - return $this->cache->get($routeKey); + if ($this->cache->connect($option)->has($routeKey)) { + return $this->cache->connect($option)->get($routeKey); } } + // 获取应用调度信息 $path = $this->request->path(); // 路由检测 @@ -591,10 +623,6 @@ class App extends Container } } - if (is_file($this->runtimePath . 'rule_regex.php')) { - $this->route->setRuleRegexs(include $this->runtimePath . 'rule_regex.php'); - } - // 是否强制路由模式 $must = !is_null($this->routeMust) ? $this->routeMust : $this->route->config('url_route_must'); @@ -604,6 +632,7 @@ class App extends Container if (!empty($routeKey)) { try { $this->cache + ->connect($option) ->tag('route_cache') ->set($routeKey, $dispatch); } catch (\Exception $e) { diff --git a/thinkphp/library/think/Build.php b/thinkphp/library/think/Build.php index 6de014023..0c3244da8 100644 --- a/thinkphp/library/think/Build.php +++ b/thinkphp/library/think/Build.php @@ -239,7 +239,7 @@ class Build $class = new \ReflectionClass($namespace . '\\' . $module . '\\' . $layer . '\\' . $controller); - if (strpos($layer, DIRECTORY_SEPARATOR)) { + if (strpos($layer, '\\')) { // 多级控制器 $level = str_replace(DIRECTORY_SEPARATOR, '.', substr($layer, 11)); $controller = $level . '.' . $controller; diff --git a/thinkphp/library/think/Cache.php b/thinkphp/library/think/Cache.php index c7a7aa6e2..162cb6d3b 100644 --- a/thinkphp/library/think/Cache.php +++ b/thinkphp/library/think/Cache.php @@ -100,6 +100,11 @@ class Cache return new static($config->pull('cache')); } + public function getConfig() + { + return $this->config; + } + public function setConfig(array $config) { $this->config = array_merge($this->config, $config); diff --git a/thinkphp/library/think/Config.php b/thinkphp/library/think/Config.php index 3fa9b136b..1e60ac9d0 100644 --- a/thinkphp/library/think/Config.php +++ b/thinkphp/library/think/Config.php @@ -25,17 +25,6 @@ class Config implements \ArrayAccess */ private $prefix = 'app'; - /** - * 应用对象 - * @var App - */ - protected $app; - - public function __construct(App $app) - { - $this->app = $app; - } - /** * 设置配置参数默认前缀 * @access public @@ -90,30 +79,6 @@ class Config implements \ArrayAccess return $this->config; } - /** - * 自动加载配置文件(PHP格式) - * @access public - * @param string $name 配置名 - * @return void - */ - protected function autoLoad($name) - { - // 如果尚未载入 则动态加载配置文件 - $module = $this->app->request->module(); - $module = $module ? $module . DIRECTORY_SEPARATOR : ''; - $path = $this->app->getAppPath() . $module; - - if (is_dir($path . 'config')) { - $file = $path . 'config' . DIRECTORY_SEPARATOR . $name . $this->app->getConfigExt(); - } elseif (is_dir($this->app->getConfigPath() . $module)) { - $file = $this->app->getConfigPath() . $module . $name . $this->app->getConfigExt(); - } - - if (isset($file) && is_file($file)) { - $this->load($file, $name); - } - } - /** * 检测配置是否存在 * @access public @@ -139,21 +104,17 @@ class Config implements \ArrayAccess { $name = strtolower($name); - if (!isset($this->config[$name])) { - // 如果尚未载入 则动态加载配置文件 - $this->autoLoad($name); - } - return isset($this->config[$name]) ? $this->config[$name] : []; } /** * 获取配置参数 为空则获取所有配置 * @access public - * @param string $name 配置参数名(支持多级配置 .号分割) + * @param string $name 配置参数名(支持多级配置 .号分割) + * @param mixed $default 默认值 * @return mixed */ - public function get($name = null) + public function get($name = null, $default = null) { // 无参数时获取所有 if (empty($name)) { @@ -170,17 +131,12 @@ class Config implements \ArrayAccess $name[0] = strtolower($name[0]); $config = $this->config; - if (!isset($config[$name[0]])) { - // 如果尚未载入 则动态加载配置文件 - $this->autoLoad($name[0]); - } - // 按.拆分成多维数组进行判断 foreach ($name as $val) { if (isset($config[$val])) { $config = $config[$val]; } else { - return; + return $default; } } diff --git a/thinkphp/library/think/Console.php b/thinkphp/library/think/Console.php index 8782aa92e..9757e4766 100644 --- a/thinkphp/library/think/Console.php +++ b/thinkphp/library/think/Console.php @@ -42,6 +42,7 @@ class Console "think\\console\\command\\make\\Controller", "think\\console\\command\\make\\Model", "think\\console\\command\\make\\Middleware", + "think\\console\\command\\make\\Validate", "think\\console\\command\\optimize\\Autoload", "think\\console\\command\\optimize\\Config", "think\\console\\command\\optimize\\Schema", diff --git a/thinkphp/library/think/Container.php b/thinkphp/library/think/Container.php index 94cf449e3..743a88d3f 100644 --- a/thinkphp/library/think/Container.php +++ b/thinkphp/library/think/Container.php @@ -178,6 +178,21 @@ class Container implements \ArrayAccess return isset($this->bind[$abstract]) || isset($this->instances[$abstract]); } + /** + * 判断容器中是否存在对象实例 + * @access public + * @param string $abstract 类名或者标识 + * @return bool + */ + public function exists($abstract) + { + if (isset($this->bind[$abstract])) { + $abstract = $this->bind[$abstract]; + } + + return isset($this->instances[$abstract]); + } + /** * 判断容器中是否存在类及标识 * @access public @@ -420,12 +435,13 @@ class Container implements \ArrayAccess */ protected function getObjectParam($className, &$vars) { - $value = array_shift($vars); + $array = $vars; + $value = array_shift($array); if ($value instanceof $className) { $result = $value; + array_shift($vars); } else { - array_unshift($vars, $value); $result = $this->make($className); } diff --git a/thinkphp/library/think/Db.php b/thinkphp/library/think/Db.php index e86e6e034..f72c0f1d1 100644 --- a/thinkphp/library/think/Db.php +++ b/thinkphp/library/think/Db.php @@ -101,11 +101,16 @@ class Db /** * 获取数据库配置 * @access public - * @return array + * @param string $config 配置名称 + * @return mixed */ - public static function getConfig() + public static function getConfig($name = '') { - return self::$config; + if ('' === $name) { + return self::$config; + } + + return isset(self::$config[$name]) ? self::$config[$name] : null; } /** @@ -121,7 +126,8 @@ class Db { // 解析配置参数 $options = self::parseConfig($config ?: self::$config); - $query = $query ?: self::$config['query']; + + $query = $query ?: $options['query']; // 创建数据库连接对象实例 self::$connection = Connection::instance($options, $name); @@ -142,11 +148,13 @@ class Db $config = isset(self::$config[$config]) ? self::$config[$config] : self::$config; } - if (is_string($config)) { - return self::parseDsnConfig($config); - } else { - return $config; + $result = is_string($config) ? self::parseDsnConfig($config) : $config; + + if (empty($result['query'])) { + $result['query'] = self::$config['query']; } + + return $result; } /** diff --git a/thinkphp/library/think/Log.php b/thinkphp/library/think/Log.php index 1c2e9d5c8..5cc98b008 100644 --- a/thinkphp/library/think/Log.php +++ b/thinkphp/library/think/Log.php @@ -126,11 +126,11 @@ class Log implements LoggerInterface $msg = strtr($msg, $replace); } - $this->log[$type][] = $msg; - if (PHP_SAPI == 'cli') { // 命令行日志实时写入 - $this->save(); + $this->write($msg, $type, true); + } else { + $this->log[$type][] = $msg; } return $this; @@ -196,7 +196,7 @@ class Log implements LoggerInterface */ public function save() { - if (empty($this->log) || !$this->allowWrite || !$this->driver) { + if (empty($this->log) || !$this->allowWrite) { return true; } @@ -221,7 +221,8 @@ class Log implements LoggerInterface } } - $result = $this->driver->save($log); + $result = $this->driver->save($log, true); + if ($result) { $this->log = []; } @@ -240,11 +241,11 @@ class Log implements LoggerInterface public function write($msg, $type = 'info', $force = false) { // 封装日志信息 - $log = $this->log; + if (empty($this->config['level'])) { + $force = true; + } - if (true === $force || empty($this->config['level'])) { - $log[$type][] = $msg; - } elseif (in_array($type, $this->config['level'])) { + if (true === $force || in_array($type, $this->config['level'])) { $log[$type][] = $msg; } else { return false; @@ -254,13 +255,7 @@ class Log implements LoggerInterface $this->app['hook']->listen('log_write', $log); // 写入日志 - $result = $this->driver->save($log); - - if ($result) { - $this->log = []; - } - - return $result; + return $this->driver->save($log, false); } /** diff --git a/thinkphp/library/think/Model.php b/thinkphp/library/think/Model.php index d2baf9995..124635508 100644 --- a/thinkphp/library/think/Model.php +++ b/thinkphp/library/think/Model.php @@ -11,6 +11,7 @@ namespace think; +use InvalidArgumentException; use think\db\Query; /** @@ -173,11 +174,6 @@ abstract class Model implements \JsonSerializable, \ArrayAccess $this->resultSetType = $config['resultset_type']; } - if (is_null($this->query)) { - // 设置查询对象 - $this->query = $config['query']; - } - if (!empty($this->connection) && is_array($this->connection)) { // 设置模型的数据库连接 $this->connection = array_merge($config, $this->connection); @@ -542,17 +538,30 @@ abstract class Model implements \JsonSerializable, \ArrayAccess } // 模型更新 - $result = $this->db(false)->where($where)->strict(false)->field($allowFields)->update($data); + $db = $this->db(false); + $db->startTrans(); - // 关联更新 - if (!empty($this->relationWrite)) { - $this->autoRelationUpdate(); + try { + $result = $db->where($where) + ->strict(false) + ->field($allowFields) + ->update($data); + + // 关联更新 + if (!empty($this->relationWrite)) { + $this->autoRelationUpdate(); + } + + $db->commit(); + + // 更新回调 + $this->trigger('after_update'); + + return $result; + } catch (\Exception $e) { + $db->rollback(); + throw $e; } - - // 更新回调 - $this->trigger('after_update'); - - return $result; } /** @@ -576,31 +585,43 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 检查允许字段 $allowFields = $this->checkAllowFields(array_merge($this->auto, $this->insert)); - $result = $this->db(false)->strict(false)->field($allowFields)->insert($this->data, $this->replace, false, $sequence); + $db = $this->db(false); + $db->startTrans(); - // 获取自动增长主键 - if ($result && $insertId = $this->db(false)->getLastInsID($sequence)) { - $pk = $this->getPk(); + try { + $result = $db->strict(false) + ->field($allowFields) + ->insert($this->data, $this->replace, false, $sequence); - foreach ((array) $pk as $key) { - if (!isset($this->data[$key]) || '' == $this->data[$key]) { - $this->data[$key] = $insertId; + // 获取自动增长主键 + if ($result && $insertId = $db->getLastInsID($sequence)) { + $pk = $this->getPk(); + + foreach ((array) $pk as $key) { + if (!isset($this->data[$key]) || '' == $this->data[$key]) { + $this->data[$key] = $insertId; + } } } + + // 关联写入 + if (!empty($this->relationWrite)) { + $this->autoRelationInsert(); + } + + $db->commit(); + + // 标记为更新 + $this->isUpdate = true; + + // 新增回调 + $this->trigger('after_insert'); + + return $result; + } catch (\Exception $e) { + $db->rollback(); + throw $e; } - - // 关联写入 - if (!empty($this->relationWrite)) { - $this->autoRelationInsert(); - } - - // 标记为更新 - $this->isUpdate = true; - - // 新增回调 - $this->trigger('after_insert'); - - return $result; } /** @@ -622,7 +643,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return false; } - $result = $this->db(false)->where($where)->setInc($field, $step, $lazyTime); + $result = $this->db(false) + ->where($where) + ->setInc($field, $step, $lazyTime); if (true !== $result) { $this->data[$field] += $step; @@ -653,7 +676,9 @@ abstract class Model implements \JsonSerializable, \ArrayAccess return false; } - $result = $this->db(false)->where($where)->setDec($field, $step, $lazyTime); + $result = $this->db(false) + ->where($where) + ->setDec($field, $step, $lazyTime); if (true !== $result) { $this->data[$field] -= $step; @@ -762,21 +787,31 @@ abstract class Model implements \JsonSerializable, \ArrayAccess // 读取更新条件 $where = $this->getWhere(); - // 删除当前模型数据 - $result = $this->db(false)->where($where)->delete(); + $db = $this->db(false); + $db->startTrans(); - // 关联删除 - if (!empty($this->relationWrite)) { - $this->autoRelationDelete(); + try { + // 删除当前模型数据 + $result = $db->where($where)->delete(); + + // 关联删除 + if (!empty($this->relationWrite)) { + $this->autoRelationDelete(); + } + + $db->commit(); + + $this->trigger('after_delete'); + + // 清空数据 + $this->data = []; + $this->origin = []; + + return $result; + } catch (\Exception $e) { + $db->rollback(); + throw $e; } - - $this->trigger('after_delete'); - - // 清空数据 - $this->data = []; - $this->origin = []; - - return $result; } /** @@ -1015,11 +1050,11 @@ abstract class Model implements \JsonSerializable, \ArrayAccess */ public function __isset($name) { - if (array_key_exists($name, $this->data) || array_key_exists($name, $this->relation)) { - return true; + try { + return !is_null($this->getAttr($name)); + } catch (InvalidArgumentException $e) { + return false; } - - return false; } /** diff --git a/thinkphp/library/think/Request.php b/thinkphp/library/think/Request.php index 6a25c99f1..925e2148d 100644 --- a/thinkphp/library/think/Request.php +++ b/thinkphp/library/think/Request.php @@ -11,8 +11,6 @@ namespace think; -use think\exception\HttpResponseException; - class Request { /** @@ -21,17 +19,32 @@ class Request */ protected $instance; - /** - * 应用对象实例 - * @var App - */ - protected $app; - /** * 配置参数 * @var array */ - protected $config = []; + protected $config = [ + // 表单请求类型伪装变量 + 'var_method' => '_method', + // 表单ajax伪装变量 + 'var_ajax' => '_ajax', + // 表单pjax伪装变量 + 'var_pjax' => '_pjax', + // PATHINFO变量名 用于兼容模式 + 'var_pathinfo' => 's', + // 兼容PATH_INFO获取 + 'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'], + // 默认全局过滤方法 用逗号分隔多个 + 'default_filter' => '', + // 域名根,如thinkphp.cn + 'url_domain_root' => '', + // HTTPS代理标识 + 'https_agent_name' => '', + // IP代理获取标识 + 'http_agent_ip' => 'X-REAL-IP', + // URL伪静态后缀 + 'url_html_suffix' => 'html', + ]; /** * 请求类型 @@ -268,9 +281,8 @@ class Request * @access public * @param array $options 参数 */ - public function __construct(App $app, array $options = []) + public function __construct(array $options = []) { - $this->app = $app; $this->init($options); // 保存 php://input @@ -296,7 +308,13 @@ class Request public static function __make(App $app, Config $config) { - return new static($app, $config->pull('app')); + $request = new static($config->pull('app')); + $request->session($app['session']->get()); + $request->cookie($app['cookie']->get()); + $request->server($_SERVER); + $request->env($app['env']->get()); + + return $request; } public function __call($method, $args) @@ -411,13 +429,14 @@ class Request $options['domain'] = isset($info['scheme']) ? $info['scheme'] . '://' . $server['HTTP_HOST'] : ''; $options['content'] = $content; + $request = new static(); foreach ($options as $name => $item) { - if (property_exists($this, $name)) { - $this->$name = $item; + if (property_exists($request, $name)) { + $request->$name = $item; } } - return $this; + return $request; } /** @@ -514,13 +533,13 @@ class Request return $this; } elseif (!$this->url) { if ($this->isCli()) { - $this->url = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; - } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { - $this->url = $_SERVER['HTTP_X_REWRITE_URL']; - } elseif (isset($_SERVER['REQUEST_URI'])) { - $this->url = $_SERVER['REQUEST_URI']; - } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { - $this->url = $_SERVER['ORIG_PATH_INFO'] . (!empty($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : ''); + $this->url = $this->server('argv')[1] ?: ''; + } elseif ($this->server('HTTP_X_REWRITE_URL')) { + $this->url = $this->server('HTTP_X_REWRITE_URL'); + } elseif ($this->server('REQUEST_URI')) { + $this->url = $this->server('REQUEST_URI'); + } elseif ($this->server('ORIG_PATH_INFO')) { + $this->url = $this->server('ORIG_PATH_INFO') . (!empty($this->server('QUERY_STRING')) ? '?' . $this->server('QUERY_STRING') : ''); } else { $this->url = ''; } @@ -562,17 +581,17 @@ class Request } elseif (!$this->baseFile) { $url = ''; if (!$this->isCli()) { - $script_name = basename($_SERVER['SCRIPT_FILENAME']); - if (basename($_SERVER['SCRIPT_NAME']) === $script_name) { - $url = $_SERVER['SCRIPT_NAME']; - } elseif (basename($_SERVER['PHP_SELF']) === $script_name) { - $url = $_SERVER['PHP_SELF']; - } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $script_name) { - $url = $_SERVER['ORIG_SCRIPT_NAME']; - } elseif (($pos = strpos($_SERVER['PHP_SELF'], '/' . $script_name)) !== false) { - $url = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $script_name; - } elseif (isset($_SERVER['DOCUMENT_ROOT']) && strpos($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT']) === 0) { - $url = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME'])); + $script_name = basename($this->server('SCRIPT_FILENAME')); + if (basename($this->server('SCRIPT_NAME')) === $script_name) { + $url = $this->server('SCRIPT_NAME'); + } elseif (basename($this->server('PHP_SELF')) === $script_name) { + $url = $this->server('PHP_SELF'); + } elseif (basename($this->server('ORIG_SCRIPT_NAME')) === $script_name) { + $url = $this->server('ORIG_SCRIPT_NAME'); + } elseif (($pos = strpos($this->server('PHP_SELF'), '/' . $script_name)) !== false) { + $url = substr($this->server('SCRIPT_NAME'), 0, $pos) . '/' . $script_name; + } elseif ($this->server('DOCUMENT_ROOT') && strpos($this->server('SCRIPT_FILENAME'), $this->server('DOCUMENT_ROOT')) === 0) { + $url = str_replace('\\', '/', str_replace($this->server('DOCUMENT_ROOT'), '', $this->server('SCRIPT_FILENAME'))); } } $this->baseFile = $url; @@ -630,27 +649,29 @@ class Request if (is_null($this->pathinfo)) { if (isset($_GET[$this->config['var_pathinfo']])) { // 判断URL里面是否有兼容模式参数 - $_SERVER['PATH_INFO'] = $_GET[$this->config['var_pathinfo']]; + $pathinfo = $_GET[$this->config['var_pathinfo']]; unset($_GET[$this->config['var_pathinfo']]); } elseif ($this->isCli()) { // CLI模式下 index.php module/controller/action/params/... - $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; + $pathinfo = isset($this->server('argv')[1]) ? $this->server('argv')[1] : ''; } elseif ('cli-server' == PHP_SAPI) { - $_SERVER['PATH_INFO'] = strpos($_SERVER['REQUEST_URI'], '?') ? strstr($_SERVER['REQUEST_URI'], '?', true) : $_SERVER['REQUEST_URI']; + $pathinfo = strpos($this->server('REQUEST_URI'), '?') ? strstr($this->server('REQUEST_URI'), '?', true) : $this->server('REQUEST_URI'); + } elseif ($this->server('PATH_INFO')) { + $pathinfo = $this->server('PATH_INFO'); } // 分析PATHINFO信息 - if (!isset($_SERVER['PATH_INFO'])) { + if (!isset($pathinfo)) { foreach ($this->config['pathinfo_fetch'] as $type) { - if (!empty($_SERVER[$type])) { - $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ? - substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type]; + if ($this->server($type)) { + $pathinfo = (0 === strpos($this->server($type), $this->server('SCRIPT_NAME'))) ? + substr($this->server($type), strlen($this->server('SCRIPT_NAME'))) : $this->server($type); break; } } } - $this->pathinfo = empty($_SERVER['PATH_INFO']) || '/' == $_SERVER['PATH_INFO'] ? '' : ltrim($_SERVER['PATH_INFO'], '/'); + $this->pathinfo = empty($pathinfo) || '/' == $pathinfo ? '' : ltrim($pathinfo, '/'); } return $this->pathinfo; @@ -699,7 +720,7 @@ class Request */ public function time($float = false) { - return $float ? $_SERVER['REQUEST_TIME_FLOAT'] : $_SERVER['REQUEST_TIME']; + return $float ? $this->server('REQUEST_TIME_FLOAT') : $this->server('REQUEST_TIME'); } /** @@ -753,15 +774,15 @@ class Request { if (true === $method) { // 获取原始请求类型 - return $this->isCli() ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']); + return $this->isCli() ? 'GET' : $this->server('REQUEST_METHOD'); } elseif (!$this->method) { if (isset($_POST[$this->config['var_method']])) { $this->method = strtoupper($_POST[$this->config['var_method']]); $this->{$this->method}($_POST); - } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { - $this->method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); + } elseif ($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')) { + $this->method = strtoupper($this->server('HTTP_X_HTTP_METHOD_OVERRIDE')); } else { - $this->method = $this->isCli() ? 'GET' : (isset($this->server['REQUEST_METHOD']) ? $this->server['REQUEST_METHOD'] : $_SERVER['REQUEST_METHOD']); + $this->method = $this->isCli() ? 'GET' : $this->server('REQUEST_METHOD'); } } @@ -1051,10 +1072,6 @@ class Request */ public function session($name = '', $default = null, $filter = '') { - if (empty($this->session)) { - $this->session = $this->app['session']->get(); - } - if (is_array($name)) { return $this->session = array_merge($this->session, $name); } @@ -1072,16 +1089,10 @@ class Request */ public function cookie($name = '', $default = null, $filter = '') { - $cookie = $this->app['cookie']; - - if (empty($this->cookie)) { - $this->cookie = $cookie->get(); - } - if (is_array($name)) { return $this->cookie = array_merge($this->cookie, $name); } elseif (!empty($name)) { - $data = $cookie->has($name) ? $cookie->get($name) : $default; + $data = isset($this->cookie[$name]) ? $this->cookie[$name] : $default; } else { $data = $this->cookie; } @@ -1109,10 +1120,6 @@ class Request */ public function server($name = '', $default = null, $filter = '') { - if (empty($this->server)) { - $this->server = $_SERVER; - } - if (is_array($name)) { return $this->server = array_merge($this->server, $name); } @@ -1208,10 +1215,6 @@ class Request */ public function env($name = '', $default = null, $filter = '') { - if (empty($this->env)) { - $this->env = $this->app['env']->get(); - } - if (is_array($name)) { return $this->env = array_merge($this->env, $name); } @@ -1523,17 +1526,15 @@ class Request */ public function isSsl() { - $server = array_merge($_SERVER, $this->server); - - if (isset($server['HTTPS']) && ('1' == $server['HTTPS'] || 'on' == strtolower($server['HTTPS']))) { + if ($this->server('HTTPS') && ('1' == $this->server('HTTPS') || 'on' == strtolower($this->server('HTTPS')))) { return true; - } elseif (isset($server['REQUEST_SCHEME']) && 'https' == $server['REQUEST_SCHEME']) { + } elseif ('https' == $this->server('REQUEST_SCHEME')) { return true; - } elseif (isset($server['SERVER_PORT']) && ('443' == $server['SERVER_PORT'])) { + } elseif ('443' == $this->server('SERVER_PORT')) { return true; - } elseif (isset($server['HTTP_X_FORWARDED_PROTO']) && 'https' == $server['HTTP_X_FORWARDED_PROTO']) { + } elseif ('https' == $this->server('HTTP_X_FORWARDED_PROTO')) { return true; - } elseif ($this->config['https_agent_name'] && isset($server[$this->config['https_agent_name']])) { + } elseif ($this->config['https_agent_name'] && $this->server($this->config['https_agent_name'])) { return true; } @@ -1593,23 +1594,23 @@ class Request $httpAgentIp = $this->config['http_agent_ip']; - if ($httpAgentIp && isset($_SERVER[$httpAgentIp])) { - $ip = $_SERVER[$httpAgentIp]; + if ($httpAgentIp && $this->server($httpAgentIp)) { + $ip = $this->server($httpAgentIp); } elseif ($adv) { - if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + if ($this->server('HTTP_X_FORWARDED_FOR')) { + $arr = explode(',', $this->server('HTTP_X_FORWARDED_FOR')); $pos = array_search('unknown', $arr); if (false !== $pos) { unset($arr[$pos]); } $ip = trim(current($arr)); - } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { - $ip = $_SERVER['HTTP_CLIENT_IP']; - } elseif (isset($_SERVER['REMOTE_ADDR'])) { - $ip = $_SERVER['REMOTE_ADDR']; + } elseif ($this->server('HTTP_CLIENT_IP')) { + $ip = $this->server('HTTP_CLIENT_IP'); + } elseif ($this->server('REMOTE_ADDR')) { + $ip = $this->server('REMOTE_ADDR'); } - } elseif (isset($_SERVER['REMOTE_ADDR'])) { - $ip = $_SERVER['REMOTE_ADDR']; + } elseif ($this->server('REMOTE_ADDR')) { + $ip = $this->server('REMOTE_ADDR'); } // IP地址类型 @@ -1635,13 +1636,13 @@ class Request */ public function isMobile() { - if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) { + if ($this->server('HTTP_VIA') && stristr($this->server('HTTP_VIA'), "wap")) { return true; - } elseif (isset($_SERVER['HTTP_ACCEPT']) && strpos(strtoupper($_SERVER['HTTP_ACCEPT']), "VND.WAP.WML")) { + } elseif ($this->server('HTTP_ACCEPT') && strpos(strtoupper($this->server('HTTP_ACCEPT')), "VND.WAP.WML")) { return true; - } elseif (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE'])) { + } elseif ($this->server('HTTP_X_WAP_PROFILE') || $this->server('HTTP_PROFILE')) { return true; - } elseif (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $_SERVER['HTTP_USER_AGENT'])) { + } elseif ($this->server('HTTP_USER_AGENT') && preg_match('/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $this->server('HTTP_USER_AGENT'))) { return true; } @@ -1676,11 +1677,7 @@ class Request */ public function host($strict = false) { - if (isset($_SERVER['HTTP_X_REAL_HOST'])) { - $host = $_SERVER['HTTP_X_REAL_HOST']; - } else { - $host = $this->server('HTTP_HOST'); - } + $host = $this->server('HTTP_X_REAL_HOST') ?: $this->server('HTTP_HOST'); return true === $strict && strpos($host, ':') ? strstr($host, ':', true) : $host; } @@ -1879,13 +1876,13 @@ class Request public function token($name = '__token__', $type = 'md5') { $type = is_callable($type) ? $type : 'md5'; - $token = call_user_func($type, $_SERVER['REQUEST_TIME_FLOAT']); + $token = call_user_func($type, $this->server('REQUEST_TIME_FLOAT')); if ($this->isAjax()) { header($name . ': ' . $token); } - $this->app['session']->set($name, $token); + facade\Session::set($name, $token); return $token; } @@ -1897,7 +1894,7 @@ class Request * @param mixed $expire 缓存有效期 * @param array $except 缓存排除 * @param string $tag 缓存标签 - * @return void + * @return mixed */ public function cache($key, $expire = null, $except = [], $tag = null) { @@ -1953,20 +1950,9 @@ class Request if (isset($fun)) { $key = $fun($key); } - $cache = $this->app['cache']; - - if (strtotime($this->server('HTTP_IF_MODIFIED_SINCE')) + $expire > $_SERVER['REQUEST_TIME']) { - // 读取缓存 - $response = Response::create()->code(304); - throw new HttpResponseException($response); - } elseif ($cache->has($key)) { - list($content, $header) = $cache->get($key); - - $response = Response::create($content)->header($header); - throw new HttpResponseException($response); - } $this->cache = [$key, $expire, $tag]; + return $this->cache; } /** diff --git a/thinkphp/library/think/Route.php b/thinkphp/library/think/Route.php index 4b403a15f..af5d2191c 100644 --- a/thinkphp/library/think/Route.php +++ b/thinkphp/library/think/Route.php @@ -818,9 +818,9 @@ class Route } // 默认路由解析 - $ruleItem = new RuleItem($this, $this->group, '', '', $url); - - return new UrlDispatch($this->request, $ruleItem, $url, ['auto_search' => $this->autoSearchController]); + return new UrlDispatch($this->request, $this->group, $url, [ + 'auto_search' => $this->autoSearchController, + ]); } /** diff --git a/thinkphp/library/think/cache/driver/File.php b/thinkphp/library/think/cache/driver/File.php index 5f10200bf..7c5661e3d 100644 --- a/thinkphp/library/think/cache/driver/File.php +++ b/thinkphp/library/think/cache/driver/File.php @@ -110,7 +110,7 @@ class File extends Driver */ public function has($name) { - return $this->get($name) ? true : false; + return false !== $this->get($name) ? true : false; } /** diff --git a/thinkphp/library/think/console/command/make/Validate.php b/thinkphp/library/think/console/command/make/Validate.php new file mode 100644 index 000000000..e7e39e635 --- /dev/null +++ b/thinkphp/library/think/console/command/make/Validate.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- + +namespace think\console\command\make; + +use think\console\command\Make; + +class Validate extends Make +{ + + protected $type = "Validate"; + + protected function configure() + { + parent::configure(); + $this->setName('make:validate') + ->setDescription('Create a validate class'); + } + + protected function getStub() + { + $stubPath = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR; + + return $stubPath . 'validate.stub'; + } + + protected function getNamespace($appNamespace, $module) + { + return parent::getNamespace($appNamespace, $module) . '\validate'; + } + +} diff --git a/thinkphp/library/think/console/command/make/stubs/validate.stub b/thinkphp/library/think/console/command/make/stubs/validate.stub new file mode 100644 index 000000000..0775bfa44 --- /dev/null +++ b/thinkphp/library/think/console/command/make/stubs/validate.stub @@ -0,0 +1,24 @@ + ['规则1','规则2'...] + * + * @var array + */ + protected $rule = []; + + /** + * 定义错误信息 + * 格式:'字段名.规则名' => '错误信息' + * + * @var array + */ + protected $message = []; +} diff --git a/thinkphp/library/think/console/command/optimize/Config.php b/thinkphp/library/think/console/command/optimize/Config.php index 9b692b33b..1be4e3a2d 100644 --- a/thinkphp/library/think/console/command/optimize/Config.php +++ b/thinkphp/library/think/console/command/optimize/Config.php @@ -99,7 +99,7 @@ class Config extends Command if (is_file($path . 'provider.php')) { $provider = include $path . 'provider.php'; if (is_array($provider)) { - $content .= PHP_EOL . '\think\Container::getInstance()->bind(' . var_export($provider, true) . ');' . PHP_EOL; + $content .= PHP_EOL . '\think\Container::getInstance()->bindTo(' . var_export($provider, true) . ');' . PHP_EOL; } } diff --git a/thinkphp/library/think/db/Builder.php b/thinkphp/library/think/db/Builder.php index e7dfb475e..0d30267b1 100644 --- a/thinkphp/library/think/db/Builder.php +++ b/thinkphp/library/think/db/Builder.php @@ -951,7 +951,7 @@ abstract class Builder protected function parseComment(Query $query, $comment) { if (false !== strpos($comment, '*/')) { - $comment = strstr($coment, '*/', true); + $comment = strstr($comment, '*/', true); } return !empty($comment) ? ' /* ' . $comment . ' */' : ''; diff --git a/thinkphp/library/think/db/Query.php b/thinkphp/library/think/db/Query.php index 2860359ea..23476a32f 100644 --- a/thinkphp/library/think/db/Query.php +++ b/thinkphp/library/think/db/Query.php @@ -2450,10 +2450,19 @@ class Query if ($relation instanceof \Closure) { $closure = $relation; $relation = $key; + } elseif (!is_int($key)) { + $aggregateField = $relation; + $relation = $key; } + + if (!isset($aggregateField)) { + $aggregateField = Loader::parseName($relation) . '_' . $aggregate; + } + $relation = Loader::parseName($relation, 1, false); $count = '(' . $this->model->$relation()->getRelationCountQuery($closure, $aggregate, $field) . ')'; - $this->field([$count => Loader::parseName($relation) . '_' . $aggregate]); + + $this->field([$count => $aggregateField]); } } diff --git a/thinkphp/library/think/facade/Route.php b/thinkphp/library/think/facade/Route.php index ac458e0b3..3e4dcaaee 100644 --- a/thinkphp/library/think/facade/Route.php +++ b/thinkphp/library/think/facade/Route.php @@ -27,7 +27,7 @@ use think\Facade; * @method void import(array $rules, string $type = '*') static 导入配置文件的路由规则 * @method \think\route\RuleItem rule(string $rule, mixed $route, string $method = '*', array $option = [], array $pattern = []) static 注册路由规则 * @method void rules(string $rules, string $method = '*', array $option = [], array $pattern = []) static 批量注册路由规则 - * @method \think\route\RuleGroup group(string $name, mixed $route, string $method = '*', array $option = [], array $pattern = []) static 注册路由分组 + * @method \think\route\RuleGroup group(string|array $name, mixed $route, string $method = '*', array $option = [], array $pattern = []) static 注册路由分组 * @method \think\route\RuleItem any(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 * @method \think\route\RuleItem get(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 * @method \think\route\RuleItem post(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由 diff --git a/thinkphp/library/think/log/driver/File.php b/thinkphp/library/think/log/driver/File.php index 1db14925b..ff3225907 100644 --- a/thinkphp/library/think/log/driver/File.php +++ b/thinkphp/library/think/log/driver/File.php @@ -11,7 +11,7 @@ namespace think\log\driver; -use think\Container; +use think\App; /** * 本地化调试输出到文件 @@ -25,19 +25,22 @@ class File 'path' => '', 'apart_level' => [], 'max_files' => 0, + 'json' => false, ]; - protected $writed = []; + protected $app; // 实例化并传入参数 - public function __construct($config = []) + public function __construct(App $app, $config = []) { + $this->app = $app; + if (is_array($config)) { $this->config = array_merge($this->config, $config); } if (empty($this->config['path'])) { - $this->config['path'] = Container::get('app')->getRuntimePath() . 'log' . DIRECTORY_SEPARATOR; + $this->config['path'] = $this->app->getRuntimePath() . 'log' . DIRECTORY_SEPARATOR; } elseif (substr($this->config['path'], -1) != DIRECTORY_SEPARATOR) { $this->config['path'] .= DIRECTORY_SEPARATOR; } @@ -46,13 +49,89 @@ class File /** * 日志写入接口 * @access public - * @param array $log 日志信息 + * @param array $log 日志信息 + * @param bool $append 是否追加请求信息 * @return bool */ - public function save(array $log = []) + public function save(array $log = [], $append = false) + { + $destination = $this->getMasterLogFile(); + + $path = dirname($destination); + !is_dir($path) && mkdir($path, 0755, true); + + $info = []; + + foreach ($log as $type => $val) { + + foreach ($val as $msg) { + if (!is_string($msg)) { + $msg = var_export($msg, true); + } + + $info[$type][] = $this->config['json'] ? $msg : '[ ' . $type . ' ] ' . $msg; + } + + if (!$this->config['json'] && in_array($type, $this->config['apart_level'])) { + // 独立记录的日志级别 + $filename = $this->getApartLevelFile($path, $type); + + $this->write($info[$type], $filename, true, $append); + + unset($info[$type]); + } + } + + if ($info) { + return $this->write($info, $destination, false, $append); + } + + return true; + } + + /** + * 日志写入 + * @access protected + * @param array $message 日志信息 + * @param string $destination 日志文件 + * @param bool $apart 是否独立文件写入 + * @param bool $append 是否追加请求信息 + * @return bool + */ + protected function write($message, $destination, $apart = false, $append = false) + { + // 检测日志文件大小,超过配置大小则备份日志文件重新生成 + $this->checkLogSize($destination); + + // 日志信息封装 + $info['timestamp'] = date($this->config['time_format']); + + foreach ($message as $type => $msg) { + $info[$type] = is_array($msg) ? implode("\r\n", $msg) : $msg; + } + + if (PHP_SAPI == 'cli') { + $message = $this->parseCliLog($info); + } else { + // 添加调试日志 + $this->getDebugLog($info, $append, $apart); + + $message = $this->parseLog($info); + } + + return error_log($message, 3, $destination); + } + + /** + * 获取主日志文件名 + * @access public + * @return string + */ + protected function getMasterLogFile() { if ($this->config['single']) { - $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; + $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; + $destination = $this->config['path'] . $name . '.log'; } else { $cli = PHP_SAPI == 'cli' ? '_cli' : ''; @@ -74,90 +153,128 @@ class File $destination = $this->config['path'] . $filename; } - $path = dirname($destination); - !is_dir($path) && mkdir($path, 0755, true); - - $info = ''; - 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'])) { - // 独立记录的日志级别 - if ($this->config['single']) { - $filename = $path . DIRECTORY_SEPARATOR . $name . '_' . $type . '.log'; - } elseif ($this->config['max_files']) { - $filename = $path . DIRECTORY_SEPARATOR . date('Ymd') . '_' . $type . $cli . '.log'; - } else { - $filename = $path . DIRECTORY_SEPARATOR . date('d') . '_' . $type . $cli . '.log'; - } - - $this->write($level, $filename, true); - } else { - $info .= $level; - } - } - - if ($info) { - return $this->write($info, $destination); - } - - return true; + return $destination; } /** - * 日志写入 - * @access protected - * @param array $message 日志信息 - * @param string $destination 日志文件 - * @param bool $apart 是否独立文件写入 - * @return bool + * 获取独立日志文件名 + * @access public + * @param string $path 日志目录 + * @param string $type 日志类型 + * @return string */ - protected function write($message, $destination, $apart = false) + protected function getApartLevelFile($path, $type) + { + $cli = PHP_SAPI == 'cli' ? '_cli' : ''; + + if ($this->config['single']) { + $name = is_string($this->config['single']) ? $this->config['single'] : 'single'; + + $name .= '_' . $type; + } elseif ($this->config['max_files']) { + $name = date('Ymd') . '_' . $type . $cli; + } else { + $name = date('d') . '_' . $type . $cli; + } + + return $path . DIRECTORY_SEPARATOR . $name . '.log'; + } + + /** + * 检查日志文件大小并自动生成备份文件 + * @access protected + * @param string $destination 日志文件 + * @return void + */ + protected function checkLogSize($destination) { - // 检测日志文件大小,超过配置大小则备份日志文件重新生成 if (is_file($destination) && floor($this->config['file_size']) <= filesize($destination)) { try { rename($destination, dirname($destination) . DIRECTORY_SEPARATOR . time() . '-' . basename($destination)); } catch (\Exception $e) { } - - $this->writed[$destination] = false; } - - if (empty($this->writed[$destination]) && PHP_SAPI != 'cli') { - if (Container::get('app')->isDebug() && !$apart) { - // 获取基本信息 - $current_uri = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; - $runtime = round(microtime(true) - Container::get('app')->getBeginTime(), 10); - $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; - $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; - $memory_use = number_format((memory_get_usage() - Container::get('app')->getBeginMem()) / 1024, 2); - $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; - $file_load = ' [文件加载:' . count(get_included_files()) . ']'; - $message = '[ info ] ' . $current_uri . $time_str . $memory_str . $file_load . "\r\n" . $message; - } - - $now = date($this->config['time_format']); - $ip = Container::get('request')->ip(); - $method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'CLI'; - $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; - $message = "---------------------------------------------------------------\r\n[{$now}] {$ip} {$method} {$uri}\r\n" . $message; - - $this->writed[$destination] = true; - } - - if (PHP_SAPI == 'cli') { - $now = date($this->config['time_format']); - $message = "[{$now}]" . $message; - } - - return error_log($message, 3, $destination); } + /** + * CLI日志解析 + * @access protected + * @param array $info 日志信息 + * @return string + */ + protected function parseCliLog($info) + { + if ($this->config['json']) { + $message = json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n"; + } else { + $now = $info['timestamp']; + unset($info['timestamp']); + + $message = implode("\r\n", $info); + + $message = "[{$now}]" . $message . "\r\n"; + } + + return $message; + } + + /** + * 解析日志 + * @access protected + * @param array $info 日志信息 + * @return string + */ + protected function parseLog($info) + { + $requestInfo = [ + 'ip' => $this->app['request']->ip(), + 'method' => $this->app['request']->method(), + 'host' => $this->app['request']->host(), + 'uri' => $this->app['request']->url(), + ]; + + if ($this->config['json']) { + $info = $requestInfo + $info; + return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\r\n"; + } + + array_unshift($info, "---------------------------------------------------------------\r\n[{$info['timestamp']}] {$requestInfo['ip']} {$requestInfo['method']} {$requestInfo['host']}{$requestInfo['uri']}"); + unset($info['timestamp']); + + return implode("\r\n", $info) . "\r\n"; + } + + protected function getDebugLog(&$info, $append, $apart) + { + if ($this->app->isDebug() && $append) { + + if ($this->config['json']) { + // 获取基本信息 + $runtime = round(microtime(true) - $this->app->getBeginTime(), 10); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; + + $memory_use = number_format((memory_get_usage() - $this->app->getBeginMem()) / 1024, 2); + + $info = [ + 'runtime' => number_format($runtime, 6) . 's', + 'reqs' => $reqs . 'req/s', + 'memory' => $memory_use . 'kb', + 'file' => count(get_included_files()), + ] + $info; + + } elseif (!$apart) { + // 增加额外的调试信息 + $runtime = round(microtime(true) - $this->app->getBeginTime(), 10); + $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; + + $memory_use = number_format((memory_get_usage() - $this->app->getBeginMem()) / 1024, 2); + + $time_str = '[运行时间:' . number_format($runtime, 6) . 's] [吞吐率:' . $reqs . 'req/s]'; + $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; + $file_load = ' [文件加载:' . count(get_included_files()) . ']'; + + array_unshift($info, $time_str . $memory_str . $file_load); + } + } + } } diff --git a/thinkphp/library/think/log/driver/Socket.php b/thinkphp/library/think/log/driver/Socket.php index d3e717fe3..b4a2cadc7 100644 --- a/thinkphp/library/think/log/driver/Socket.php +++ b/thinkphp/library/think/log/driver/Socket.php @@ -11,7 +11,7 @@ namespace think\log\driver; -use think\Container; +use think\App; /** * github: https://github.com/luofei614/SocketLog @@ -41,14 +41,17 @@ class Socket ]; protected $allowForceClientIds = []; //配置强制推送且被授权的client_id + protected $app; /** * 架构函数 * @access public * @param array $config 缓存参数 */ - public function __construct(array $config = []) + public function __construct(App $app, array $config = []) { + $this->app = $app; + if (!empty($config)) { $this->config = array_merge($this->config, $config); } @@ -60,7 +63,7 @@ class Socket * @param array $log 日志信息 * @return bool */ - public function save(array $log = []) + public function save(array $log = [], $append = false) { if (!$this->check()) { return false; @@ -68,11 +71,11 @@ class Socket $trace = []; - if (Container::get('app')->isDebug()) { - $runtime = round(microtime(true) - Container::get('app')->getBeginTime(), 10); + if ($this->app->isDebug()) { + $runtime = round(microtime(true) - $this->app->getBeginTime(), 10); $reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞'; $time_str = ' [运行时间:' . number_format($runtime, 6) . 's][吞吐率:' . $reqs . 'req/s]'; - $memory_use = number_format((memory_get_usage() - Container::get('app')->getBeginMem()) / 1024, 2); + $memory_use = number_format((memory_get_usage() - $this->app->getBeginMem()) / 1024, 2); $memory_str = ' [内存消耗:' . $memory_use . 'kb]'; $file_load = ' [文件加载:' . count(get_included_files()) . ']'; diff --git a/thinkphp/library/think/model/concern/SoftDelete.php b/thinkphp/library/think/model/concern/SoftDelete.php index da774b823..2aaa5319d 100644 --- a/thinkphp/library/think/model/concern/SoftDelete.php +++ b/thinkphp/library/think/model/concern/SoftDelete.php @@ -86,7 +86,9 @@ trait SoftDelete // 软删除 $this->data($name, $this->autoWriteTimestamp($name)); - $result = $this->isUpdate()->save(); + $result = $this->isUpdate()->withEvent(false)->save(); + + $this->withEvent = true; } else { // 读取更新条件 $where = $this->getWhere(); diff --git a/thinkphp/library/think/route/Dispatch.php b/thinkphp/library/think/route/Dispatch.php index 4106c0da4..059839786 100644 --- a/thinkphp/library/think/route/Dispatch.php +++ b/thinkphp/library/think/route/Dispatch.php @@ -72,10 +72,16 @@ abstract class Dispatch if (isset($param['convert'])) { $this->convert = $param['convert']; } + } + public function init() + { // 执行路由后置操作 if ($this->rule->doAfter()) { // 设置请求的路由信息 + + // 设置当前请求的参数 + $this->request->route($this->rule->getVars()); $this->request->routeInfo([ 'rule' => $this->rule->getRule(), 'route' => $this->rule->getRoute(), @@ -86,13 +92,9 @@ abstract class Dispatch $this->doRouteAfter(); } - // 初始化 - $this->init(); + return $this; } - protected function init() - {} - /** * 检查路由后置操作 * @access protected @@ -316,4 +318,14 @@ abstract class Dispatch abstract public function exec(); + public function __sleep() + { + return ['rule', 'dispatch', 'convert', 'param', 'code', 'controller', 'actionName']; + } + + public function __wakeup() + { + $this->app = Container::get('app'); + $this->request = $this->app['request']; + } } diff --git a/thinkphp/library/think/route/Resource.php b/thinkphp/library/think/route/Resource.php index 0d2f4dabf..5d0d34a08 100644 --- a/thinkphp/library/think/route/Resource.php +++ b/thinkphp/library/think/route/Resource.php @@ -80,6 +80,8 @@ class Resource extends RuleGroup $rule = implode('/', $item) . '/' . $last; } + $prefix = substr($rule, strlen($this->name) + 1); + // 注册资源路由 foreach ($this->rest as $key => $val) { if ((isset($option['only']) && !in_array($key, $option['only'])) @@ -93,9 +95,7 @@ class Resource extends RuleGroup $val[1] = str_replace('', '<' . $option['var'][$rule] . '>', $val[1]); } - $option['rest'] = $key; - - $this->addRule(trim($val[1], '/'), $this->route . '/' . $val[2], $val[0], $option); + $this->addRule(trim($prefix . $val[1], '/'), $this->route . '/' . $val[2], $val[0]); } $this->router->setGroup($origin); diff --git a/thinkphp/library/think/route/Rule.php b/thinkphp/library/think/route/Rule.php index 430f95944..affd328f2 100644 --- a/thinkphp/library/think/route/Rule.php +++ b/thinkphp/library/think/route/Rule.php @@ -89,7 +89,7 @@ abstract class Rule */ protected $doAfter; - abstract public function check($request, $url, $depr = '/'); + abstract public function check($request, $url, $completeMatch = false); /** * 获取Name @@ -261,6 +261,19 @@ abstract class Rule return $this; } + /** + * 设置变量 + * @access public + * @param array $vars 变量 + * @return $this + */ + public function vars($vars) + { + $this->vars = $vars; + + return $this; + } + /** * 设置路由请求类型 * @access public @@ -879,9 +892,6 @@ abstract class Rule }, $url); } } - - // 设置当前请求的参数 - $request->route($var); } /** @@ -1041,4 +1051,14 @@ abstract class Rule return call_user_func_array([$this, 'option'], $args); } + + public function __sleep() + { + return ['name', 'rule', 'route', 'method', 'vars', 'option', 'pattern', 'doAfter']; + } + + public function __wakeup() + { + $this->router = Container::get('route'); + } } diff --git a/thinkphp/library/think/route/RuleItem.php b/thinkphp/library/think/route/RuleItem.php index 6a7855774..31b584087 100644 --- a/thinkphp/library/think/route/RuleItem.php +++ b/thinkphp/library/think/route/RuleItem.php @@ -125,7 +125,7 @@ class RuleItem extends Rule $suffix = null; } - $value = [$this->rule, $vars, $this->parent->getDomain(), $suffix]; + $value = [$this->rule, $vars, $this->parent->getDomain(), $suffix, $this->method]; Container::get('rule_name')->set($name, $value, $first); } @@ -226,6 +226,7 @@ class RuleItem extends Rule } $pattern = array_merge($this->parent->getPattern(), $this->pattern); + $depr = $this->router->config('pathinfo_depr'); // 检查完整规则定义 if (isset($pattern['__url__']) && !preg_match(0 === strpos($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . '/', str_replace('|', $depr, $url))) { @@ -233,7 +234,6 @@ class RuleItem extends Rule } $var = []; - $depr = $this->router->config('pathinfo_depr'); $url = $depr . str_replace('|', $depr, $url); $rule = $depr . str_replace('/', $depr, $this->rule); diff --git a/thinkphp/library/think/route/dispatch/Module.php b/thinkphp/library/think/route/dispatch/Module.php index acbfff24e..091f2f6e9 100644 --- a/thinkphp/library/think/route/dispatch/Module.php +++ b/thinkphp/library/think/route/dispatch/Module.php @@ -22,8 +22,10 @@ class Module extends Dispatch protected $controller; protected $actionName; - protected function init() + public function init() { + parent::init(); + $result = $this->dispatch; if (is_string($result)) { @@ -72,6 +74,7 @@ class Module extends Dispatch // 设置当前请求的控制器、操作 $this->request->controller(Loader::parseName($this->controller, 1))->action($this->actionName); + return $this; } public function exec() diff --git a/thinkphp/library/think/route/dispatch/Url.php b/thinkphp/library/think/route/dispatch/Url.php index 8d5c85d69..1329cb4c0 100644 --- a/thinkphp/library/think/route/dispatch/Url.php +++ b/thinkphp/library/think/route/dispatch/Url.php @@ -17,29 +17,26 @@ use think\route\Dispatch; class Url extends Dispatch { - protected function init() + public function init() { // 解析默认的URL规则 - $depr = $this->rule->getConfig('pathinfo_depr'); - $result = $this->parseUrl($this->dispatch, $depr); + $result = $this->parseUrl($this->dispatch); - $this->dispatch = new Module($this->request, $this->rule, $result); + return (new Module($this->request, $this->rule, $result))->init(); } public function exec() - { - return $this->dispatch->exec(); - } + {} /** * 解析URL地址 * @access protected * @param string $url URL - * @param string $depr 分隔符 * @return array */ - protected function parseUrl($url, $depr) + protected function parseUrl($url) { + $depr = $this->rule->getConfig('pathinfo_depr'); $bind = $this->rule->getRouter()->getBind(); if (!empty($bind) && preg_match('/^[a-z]/is', $bind)) { diff --git a/vendor/autoload.php b/vendor/autoload.php index b5fb5f223..df648040b 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit4b011dbaeb8d413f22cc4a85f342d3db::getLoader(); +return ComposerAutoloaderInit3b653bd8f42dcddd1a5ffaa4b92dcf0f::getLoader(); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 936553986..6de2029a7 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit4b011dbaeb8d413f22cc4a85f342d3db +class ComposerAutoloaderInit3b653bd8f42dcddd1a5ffaa4b92dcf0f { private static $loader; @@ -19,15 +19,15 @@ class ComposerAutoloaderInit4b011dbaeb8d413f22cc4a85f342d3db return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit4b011dbaeb8d413f22cc4a85f342d3db', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInit3b653bd8f42dcddd1a5ffaa4b92dcf0f', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit4b011dbaeb8d413f22cc4a85f342d3db', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInit3b653bd8f42dcddd1a5ffaa4b92dcf0f', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit4b011dbaeb8d413f22cc4a85f342d3db::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInit3b653bd8f42dcddd1a5ffaa4b92dcf0f::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { @@ -48,19 +48,19 @@ class ComposerAutoloaderInit4b011dbaeb8d413f22cc4a85f342d3db $loader->register(true); if ($useStaticLoader) { - $includeFiles = Composer\Autoload\ComposerStaticInit4b011dbaeb8d413f22cc4a85f342d3db::$files; + $includeFiles = Composer\Autoload\ComposerStaticInit3b653bd8f42dcddd1a5ffaa4b92dcf0f::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { - composerRequire4b011dbaeb8d413f22cc4a85f342d3db($fileIdentifier, $file); + composerRequire3b653bd8f42dcddd1a5ffaa4b92dcf0f($fileIdentifier, $file); } return $loader; } } -function composerRequire4b011dbaeb8d413f22cc4a85f342d3db($fileIdentifier, $file) +function composerRequire3b653bd8f42dcddd1a5ffaa4b92dcf0f($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { require $file; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 8e04adc08..23ffc756a 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,7 +4,7 @@ namespace Composer\Autoload; -class ComposerStaticInit4b011dbaeb8d413f22cc4a85f342d3db +class ComposerStaticInit3b653bd8f42dcddd1a5ffaa4b92dcf0f { public static $files = array ( '1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php', @@ -302,9 +302,9 @@ class ComposerStaticInit4b011dbaeb8d413f22cc4a85f342d3db public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit4b011dbaeb8d413f22cc4a85f342d3db::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit4b011dbaeb8d413f22cc4a85f342d3db::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit4b011dbaeb8d413f22cc4a85f342d3db::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInit3b653bd8f42dcddd1a5ffaa4b92dcf0f::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit3b653bd8f42dcddd1a5ffaa4b92dcf0f::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit3b653bd8f42dcddd1a5ffaa4b92dcf0f::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 5eb9cb105..736ef4eae 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -49,18 +49,18 @@ "source": { "type": "git", "url": "https://github.com/zoujingli/ip2region.git", - "reference": "5d981fbf3b574bad7fe9652e7aecba0920f54325" + "reference": "0a55d6c1ab6b4cbaa204824557aa950aaaefda0e" }, "dist": { "type": "zip", - "url": "https://files.phpcomposer.com/files/zoujingli/ip2region/5d981fbf3b574bad7fe9652e7aecba0920f54325.zip", - "reference": "5d981fbf3b574bad7fe9652e7aecba0920f54325", + "url": "https://files.phpcomposer.com/files/zoujingli/ip2region/0a55d6c1ab6b4cbaa204824557aa950aaaefda0e.zip", + "reference": "0a55d6c1ab6b4cbaa204824557aa950aaaefda0e", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3" }, - "time": "2017-11-09T03:36:17+00:00", + "time": "2018-06-01T02:21:05+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -70,9 +70,16 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache 2.0" + "Apache-2.0" ], - "description": "Ip2Region", + "authors": [ + { + "name": "Anyon", + "email": "zoujingli@qq.com", + "homepage": "http://ctolog.com" + } + ], + "description": "Ip2Region for PHP", "homepage": "https://github.com/zoujingli/Ip2Region", "keywords": [ "Ip2Region" @@ -184,17 +191,17 @@ }, { "name": "topthink/framework", - "version": "v5.1.14", - "version_normalized": "5.1.14.0", + "version": "v5.1.15", + "version_normalized": "5.1.15.0", "source": { "type": "git", "url": "https://github.com/top-think/framework.git", - "reference": "6448c4b42599d58125ba1307aa6d3defa044aeb9" + "reference": "04d8180148fe11610a9601ed6a7d7320998d21f1" }, "dist": { "type": "zip", - "url": "https://files.phpcomposer.com/files/top-think/framework/6448c4b42599d58125ba1307aa6d3defa044aeb9.zip", - "reference": "6448c4b42599d58125ba1307aa6d3defa044aeb9", + "url": "https://files.phpcomposer.com/files/top-think/framework/04d8180148fe11610a9601ed6a7d7320998d21f1.zip", + "reference": "04d8180148fe11610a9601ed6a7d7320998d21f1", "shasum": "" }, "require": { @@ -210,7 +217,7 @@ "sebastian/phpcpd": "2.*", "squizlabs/php_codesniffer": "2.*" }, - "time": "2018-05-19T13:37:11+00:00", + "time": "2018-06-01T03:56:50+00:00", "type": "think-framework", "installation-source": "dist", "notification-url": "https://packagist.org/downloads/", diff --git a/vendor/zoujingli/ip2region/.gitignore b/vendor/zoujingli/ip2region/.gitignore new file mode 100644 index 000000000..12a35faed --- /dev/null +++ b/vendor/zoujingli/ip2region/.gitignore @@ -0,0 +1,2 @@ +# Created by .ignore support plugin (hsz.mobi) +/.idea diff --git a/vendor/zoujingli/ip2region/composer.json b/vendor/zoujingli/ip2region/composer.json index 936363e55..a64046ed0 100644 --- a/vendor/zoujingli/ip2region/composer.json +++ b/vendor/zoujingli/ip2region/composer.json @@ -2,13 +2,20 @@ "type": "library", "name": "zoujingli/ip2region", "homepage": "https://github.com/zoujingli/Ip2Region", - "description": "Ip2Region", - "license": "Apache 2.0", + "description": "Ip2Region for PHP", + "license": "Apache-2.0", + "authors": [ + { + "name": "Anyon", + "email": "zoujingli@qq.com", + "homepage": "http://ctolog.com" + } + ], "keywords": [ "Ip2Region" ], "require": { - "php": ">=5.3.3" + "php": ">=5.3" }, "autoload": { "classmap": [ diff --git a/vendor/zoujingli/ip2region/ip2region.db b/vendor/zoujingli/ip2region/ip2region.db index cfdc900ba..ecd01a6f2 100644 Binary files a/vendor/zoujingli/ip2region/ip2region.db and b/vendor/zoujingli/ip2region/ip2region.db differ diff --git a/vendor/zoujingli/ip2region/test.php b/vendor/zoujingli/ip2region/test.php index 45981c3db..61bc599be 100644 --- a/vendor/zoujingli/ip2region/test.php +++ b/vendor/zoujingli/ip2region/test.php @@ -7,7 +7,7 @@ $ip = '101.105.35.57'; $info = $ip2region->btreeSearch($ip); -var_export($info, true); +var_export($info); // array ( // 'city_id' => 2163,