diff --git a/Server/.user.ini b/Server/.user.ini
new file mode 100644
index 00000000..74c9614a
--- /dev/null
+++ b/Server/.user.ini
@@ -0,0 +1 @@
+open_basedir="E:/WorkSpace/Maokaka/Server/;C:/Windows/Temp/;C:/Temp/;D:/Application/BtSoft/temp/session/"
\ No newline at end of file
diff --git a/Server/index.html b/Server/index.html
index 132e44fb..40e91ccf 100644
--- a/Server/index.html
+++ b/Server/index.html
@@ -1,40 +1,40 @@
-
-
-
-
- 恭喜,站点创建成功!
-
-
-
-
-
恭喜, 站点创建成功!
-
这是默认index.html,本页面由系统自动生成
-
- - 本页面在FTP根目录下的index.html
- - 您可以修改、删除或覆盖本页面
- - FTP相关信息,请到“面板系统后台 > FTP” 查看
-
-
-
+
+
+
+
+ 恭喜,站点创建成功!
+
+
+
+
+
恭喜, 站点创建成功!
+
这是默认index.html,本页面由系统自动生成
+
+ - 本页面在FTP根目录下的index.html
+ - 您可以修改、删除或覆盖本页面
+ - FTP相关信息,请到“面板系统后台 > FTP” 查看
+
+
+
\ No newline at end of file
diff --git a/Server/thinkphp/library/think/Container.php b/Server/thinkphp/library/think/Container.php
new file mode 100644
index 00000000..91b32aa6
--- /dev/null
+++ b/Server/thinkphp/library/think/Container.php
@@ -0,0 +1,618 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use ArrayAccess;
+use ArrayIterator;
+use Closure;
+use Countable;
+use InvalidArgumentException;
+use IteratorAggregate;
+use ReflectionClass;
+use ReflectionException;
+use ReflectionFunction;
+use ReflectionMethod;
+use think\exception\ClassNotFoundException;
+
+/**
+ * @package think
+ * @property Build $build
+ * @property Cache $cache
+ * @property Config $config
+ * @property Cookie $cookie
+ * @property Debug $debug
+ * @property Env $env
+ * @property Hook $hook
+ * @property Lang $lang
+ * @property Middleware $middleware
+ * @property Request $request
+ * @property Response $response
+ * @property Route $route
+ * @property Session $session
+ * @property Template $template
+ * @property Url $url
+ * @property Validate $validate
+ * @property View $view
+ * @property route\RuleName $rule_name
+ * @property Log $log
+ */
+class Container implements ArrayAccess, IteratorAggregate, Countable
+{
+ /**
+ * 容器对象实例
+ * @var Container
+ */
+ protected static $instance;
+
+ /**
+ * 容器中的对象实例
+ * @var array
+ */
+ protected $instances = [];
+
+ /**
+ * 容器绑定标识
+ * @var array
+ */
+ protected $bind = [
+ 'app' => App::class,
+ 'build' => Build::class,
+ 'cache' => Cache::class,
+ 'config' => Config::class,
+ 'cookie' => Cookie::class,
+ 'debug' => Debug::class,
+ 'env' => Env::class,
+ 'hook' => Hook::class,
+ 'lang' => Lang::class,
+ 'log' => Log::class,
+ 'middleware' => Middleware::class,
+ 'request' => Request::class,
+ 'response' => Response::class,
+ 'route' => Route::class,
+ 'session' => Session::class,
+ 'template' => Template::class,
+ 'url' => Url::class,
+ 'validate' => Validate::class,
+ 'view' => View::class,
+ 'rule_name' => route\RuleName::class,
+ // 接口依赖注入
+ 'think\LoggerInterface' => Log::class,
+ ];
+
+ /**
+ * 容器标识别名
+ * @var array
+ */
+ protected $name = [];
+
+ /**
+ * 获取当前容器的实例(单例)
+ * @access public
+ * @return static
+ */
+ public static function getInstance()
+ {
+ if (is_null(static::$instance)) {
+ static::$instance = new static;
+ }
+
+ return static::$instance;
+ }
+
+ /**
+ * 设置当前容器的实例
+ * @access public
+ * @param object $instance
+ * @return void
+ */
+ public static function setInstance($instance)
+ {
+ static::$instance = $instance;
+ }
+
+ /**
+ * 获取容器中的对象实例
+ * @access public
+ * @param string $abstract 类名或者标识
+ * @param array|true $vars 变量
+ * @param bool $newInstance 是否每次创建新的实例
+ * @return object
+ */
+ public static function get($abstract, $vars = [], $newInstance = false)
+ {
+ return static::getInstance()->make($abstract, $vars, $newInstance);
+ }
+
+ /**
+ * 绑定一个类、闭包、实例、接口实现到容器
+ * @access public
+ * @param string $abstract 类标识、接口
+ * @param mixed $concrete 要绑定的类、闭包或者实例
+ * @return Container
+ */
+ public static function set($abstract, $concrete = null)
+ {
+ return static::getInstance()->bindTo($abstract, $concrete);
+ }
+
+ /**
+ * 移除容器中的对象实例
+ * @access public
+ * @param string $abstract 类标识、接口
+ * @return void
+ */
+ public static function remove($abstract)
+ {
+ return static::getInstance()->delete($abstract);
+ }
+
+ /**
+ * 清除容器中的对象实例
+ * @access public
+ * @return void
+ */
+ public static function clear()
+ {
+ return static::getInstance()->flush();
+ }
+
+ /**
+ * 绑定一个类、闭包、实例、接口实现到容器
+ * @access public
+ * @param string|array $abstract 类标识、接口
+ * @param mixed $concrete 要绑定的类、闭包或者实例
+ * @return $this
+ */
+ public function bindTo($abstract, $concrete = null)
+ {
+ if (is_array($abstract)) {
+ $this->bind = array_merge($this->bind, $abstract);
+ } elseif ($concrete instanceof Closure) {
+ $this->bind[$abstract] = $concrete;
+ } elseif (is_object($concrete)) {
+ if (isset($this->bind[$abstract])) {
+ $abstract = $this->bind[$abstract];
+ }
+ $this->instances[$abstract] = $concrete;
+ } else {
+ $this->bind[$abstract] = $concrete;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 绑定一个类实例当容器
+ * @access public
+ * @param string $abstract 类名或者标识
+ * @param object|\Closure $instance 类的实例
+ * @return $this
+ */
+ public function instance($abstract, $instance)
+ {
+ if ($instance instanceof \Closure) {
+ $this->bind[$abstract] = $instance;
+ } else {
+ if (isset($this->bind[$abstract])) {
+ $abstract = $this->bind[$abstract];
+ }
+
+ $this->instances[$abstract] = $instance;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 判断容器中是否存在类及标识
+ * @access public
+ * @param string $abstract 类名或者标识
+ * @return bool
+ */
+ public function bound($abstract)
+ {
+ 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
+ * @param string $name 类名或者标识
+ * @return bool
+ */
+ public function has($name)
+ {
+ return $this->bound($name);
+ }
+
+ /**
+ * 创建类的实例
+ * @access public
+ * @param string $abstract 类名或者标识
+ * @param array|true $vars 变量
+ * @param bool $newInstance 是否每次创建新的实例
+ * @return object
+ */
+ public function make($abstract, $vars = [], $newInstance = false)
+ {
+ if (true === $vars) {
+ // 总是创建新的实例化对象
+ $newInstance = true;
+ $vars = [];
+ }
+
+ $abstract = isset($this->name[$abstract]) ? $this->name[$abstract] : $abstract;
+
+ if (isset($this->instances[$abstract]) && !$newInstance) {
+ return $this->instances[$abstract];
+ }
+
+ if (isset($this->bind[$abstract])) {
+ $concrete = $this->bind[$abstract];
+
+ if ($concrete instanceof Closure) {
+ $object = $this->invokeFunction($concrete, $vars);
+ } else {
+ $this->name[$abstract] = $concrete;
+ return $this->make($concrete, $vars, $newInstance);
+ }
+ } else {
+ $object = $this->invokeClass($abstract, $vars);
+ }
+
+ if (!$newInstance) {
+ $this->instances[$abstract] = $object;
+ }
+
+ return $object;
+ }
+
+ /**
+ * 删除容器中的对象实例
+ * @access public
+ * @param string|array $abstract 类名或者标识
+ * @return void
+ */
+ public function delete($abstract)
+ {
+ foreach ((array) $abstract as $name) {
+ $name = isset($this->name[$name]) ? $this->name[$name] : $name;
+
+ if (isset($this->instances[$name])) {
+ unset($this->instances[$name]);
+ }
+ }
+ }
+
+ /**
+ * 获取容器中的对象实例
+ * @access public
+ * @return array
+ */
+ public function all()
+ {
+ return $this->instances;
+ }
+
+ /**
+ * 清除容器中的对象实例
+ * @access public
+ * @return void
+ */
+ public function flush()
+ {
+ $this->instances = [];
+ $this->bind = [];
+ $this->name = [];
+ }
+
+ /**
+ * 执行函数或者闭包方法 支持参数调用
+ * @access public
+ * @param mixed $function 函数或者闭包
+ * @param array $vars 参数
+ * @return mixed
+ */
+ public function invokeFunction($function, $vars = [])
+ {
+ try {
+ $reflect = new ReflectionFunction($function);
+
+ $args = $this->bindParams($reflect, $vars);
+
+ return call_user_func_array($function, $args);
+ } catch (ReflectionException $e) {
+ throw new Exception('function not exists: ' . $function . '()');
+ }
+ }
+
+ /**
+ * 调用反射执行类的方法 支持参数绑定
+ * @access public
+ * @param mixed $method 方法
+ * @param array $vars 参数
+ * @return mixed
+ */
+ public function invokeMethod($method, $vars = [])
+ {
+ try {
+ if (is_array($method)) {
+ $class = is_object($method[0]) ? $method[0] : $this->invokeClass($method[0]);
+ $reflect = new ReflectionMethod($class, $method[1]);
+ } else {
+ // 静态方法
+ $reflect = new ReflectionMethod($method);
+ }
+
+ $args = $this->bindParams($reflect, $vars);
+
+ return $reflect->invokeArgs(isset($class) ? $class : null, $args);
+ } catch (ReflectionException $e) {
+ if (is_array($method) && is_object($method[0])) {
+ $method[0] = get_class($method[0]);
+ }
+
+ throw new Exception('method not exists: ' . (is_array($method) ? $method[0] . '::' . $method[1] : $method) . '()');
+ }
+ }
+
+ /**
+ * 调用反射执行类的方法 支持参数绑定
+ * @access public
+ * @param object $instance 对象实例
+ * @param mixed $reflect 反射类
+ * @param array $vars 参数
+ * @return mixed
+ */
+ public function invokeReflectMethod($instance, $reflect, $vars = [])
+ {
+ $args = $this->bindParams($reflect, $vars);
+
+ return $reflect->invokeArgs($instance, $args);
+ }
+
+ /**
+ * 调用反射执行callable 支持参数绑定
+ * @access public
+ * @param mixed $callable
+ * @param array $vars 参数
+ * @return mixed
+ */
+ public function invoke($callable, $vars = [])
+ {
+ if ($callable instanceof Closure) {
+ return $this->invokeFunction($callable, $vars);
+ }
+
+ return $this->invokeMethod($callable, $vars);
+ }
+
+ /**
+ * 调用反射执行类的实例化 支持依赖注入
+ * @access public
+ * @param string $class 类名
+ * @param array $vars 参数
+ * @return mixed
+ */
+ public function invokeClass($class, $vars = [])
+ {
+ try {
+ $reflect = new ReflectionClass($class);
+
+ if ($reflect->hasMethod('__make')) {
+ $method = new ReflectionMethod($class, '__make');
+
+ if ($method->isPublic() && $method->isStatic()) {
+ $args = $this->bindParams($method, $vars);
+ return $method->invokeArgs(null, $args);
+ }
+ }
+
+ $constructor = $reflect->getConstructor();
+
+ $args = $constructor ? $this->bindParams($constructor, $vars) : [];
+
+ return $reflect->newInstanceArgs($args);
+
+ } catch (ReflectionException $e) {
+ throw new ClassNotFoundException('class not exists: ' . $class, $class);
+ }
+ }
+
+ /**
+ * 绑定参数
+ * @access protected
+ * @param \ReflectionMethod|\ReflectionFunction $reflect 反射类
+ * @param array $vars 参数
+ * @return array
+ */
+ protected function bindParams($reflect, $vars = [])
+ {
+ if ($reflect->getNumberOfParameters() == 0) {
+ return [];
+ }
+
+ // 判断数组类型 数字数组时按顺序绑定参数
+ reset($vars);
+ $type = key($vars) === 0 ? 1 : 0;
+ $params = $reflect->getParameters();
+
+ if (PHP_VERSION > 8.0) {
+ $args = $this->parseParamsForPHP8($params, $vars, $type);
+ } else {
+ $args = $this->parseParams($params, $vars, $type);
+ }
+
+ return $args;
+ }
+
+ /**
+ * 解析参数
+ * @access protected
+ * @param array $params 参数列表
+ * @param array $vars 参数数据
+ * @param int $type 参数类别
+ * @return array
+ */
+ protected function parseParams($params, $vars, $type)
+ {
+ foreach ($params as $param) {
+ $name = $param->getName();
+ $lowerName = Loader::parseName($name);
+ $class = $param->getClass();
+
+ if ($class) {
+ $args[] = $this->getObjectParam($class->getName(), $vars);
+ } elseif (1 == $type && !empty($vars)) {
+ $args[] = array_shift($vars);
+ } elseif (0 == $type && isset($vars[$name])) {
+ $args[] = $vars[$name];
+ } elseif (0 == $type && isset($vars[$lowerName])) {
+ $args[] = $vars[$lowerName];
+ } elseif ($param->isDefaultValueAvailable()) {
+ $args[] = $param->getDefaultValue();
+ } else {
+ throw new InvalidArgumentException('method param miss:' . $name);
+ }
+ }
+ return $args;
+ }
+
+ /**
+ * 解析参数
+ * @access protected
+ * @param array $params 参数列表
+ * @param array $vars 参数数据
+ * @param int $type 参数类别
+ * @return array
+ */
+ protected function parseParamsForPHP8($params, $vars, $type)
+ {
+ foreach ($params as $param) {
+ $name = $param->getName();
+ $lowerName = Loader::parseName($name);
+ $reflectionType = $param->getType();
+
+ if ($reflectionType && $reflectionType->isBuiltin() === false) {
+ $args[] = $this->getObjectParam($reflectionType->getName(), $vars);
+ } elseif (1 == $type && !empty($vars)) {
+ $args[] = array_shift($vars);
+ } elseif (0 == $type && array_key_exists($name, $vars)) {
+ $args[] = $vars[$name];
+ } elseif (0 == $type && array_key_exists($lowerName, $vars)) {
+ $args[] = $vars[$lowerName];
+ } elseif ($param->isDefaultValueAvailable()) {
+ $args[] = $param->getDefaultValue();
+ } else {
+ throw new InvalidArgumentException('method param miss:' . $name);
+ }
+ }
+ return $args;
+ }
+
+ /**
+ * 获取对象类型的参数值
+ * @access protected
+ * @param string $className 类名
+ * @param array $vars 参数
+ * @return mixed
+ */
+ protected function getObjectParam($className, &$vars)
+ {
+ $array = $vars;
+ $value = array_shift($array);
+
+ if ($value instanceof $className) {
+ $result = $value;
+ array_shift($vars);
+ } else {
+ $result = $this->make($className);
+ }
+
+ return $result;
+ }
+
+ public function __set($name, $value)
+ {
+ $this->bindTo($name, $value);
+ }
+
+ public function __get($name)
+ {
+ return $this->make($name);
+ }
+
+ public function __isset($name)
+ {
+ return $this->bound($name);
+ }
+
+ public function __unset($name)
+ {
+ $this->delete($name);
+ }
+
+ public function offsetExists($key)
+ {
+ return $this->__isset($key);
+ }
+
+ public function offsetGet($key)
+ {
+ return $this->__get($key);
+ }
+
+ public function offsetSet($key, $value)
+ {
+ $this->__set($key, $value);
+ }
+
+ public function offsetUnset($key)
+ {
+ $this->__unset($key);
+ }
+
+ //Countable
+ public function count()
+ {
+ return count($this->instances);
+ }
+
+ //IteratorAggregate
+ public function getIterator()
+ {
+ return new ArrayIterator($this->instances);
+ }
+
+ public function __debugInfo()
+ {
+ $data = get_object_vars($this);
+ unset($data['instances'], $data['instance']);
+
+ return $data;
+ }
+}
diff --git a/Server/thinkphp/library/think/Facade.php b/Server/thinkphp/library/think/Facade.php
new file mode 100644
index 00000000..ac5ae28b
--- /dev/null
+++ b/Server/thinkphp/library/think/Facade.php
@@ -0,0 +1,125 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+class Facade
+{
+ /**
+ * 绑定对象
+ * @var array
+ */
+ protected static $bind = [];
+
+ /**
+ * 始终创建新的对象实例
+ * @var bool
+ */
+ protected static $alwaysNewInstance;
+
+ /**
+ * 绑定类的静态代理
+ * @static
+ * @access public
+ * @param string|array $name 类标识
+ * @param string $class 类名
+ * @return object
+ */
+ public static function bind($name, $class = null)
+ {
+ if (__CLASS__ != static::class) {
+ return self::__callStatic('bind', func_get_args());
+ }
+
+ if (is_array($name)) {
+ self::$bind = array_merge(self::$bind, $name);
+ } else {
+ self::$bind[$name] = $class;
+ }
+ }
+
+ /**
+ * 创建Facade实例
+ * @static
+ * @access protected
+ * @param string $class 类名或标识
+ * @param array $args 变量
+ * @param bool $newInstance 是否每次创建新的实例
+ * @return object
+ */
+ protected static function createFacade($class = '', $args = [], $newInstance = false)
+ {
+ $class = $class ?: static::class;
+
+ $facadeClass = static::getFacadeClass();
+
+ if ($facadeClass) {
+ $class = $facadeClass;
+ } elseif (isset(self::$bind[$class])) {
+ $class = self::$bind[$class];
+ }
+
+ if (static::$alwaysNewInstance) {
+ $newInstance = true;
+ }
+
+ return Container::getInstance()->make($class, $args, $newInstance);
+ }
+
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {}
+
+ /**
+ * 带参数实例化当前Facade类
+ * @access public
+ * @return mixed
+ */
+ public static function instance(...$args)
+ {
+ if (__CLASS__ != static::class) {
+ return self::createFacade('', $args);
+ }
+ }
+
+ /**
+ * 调用类的实例
+ * @access public
+ * @param string $class 类名或者标识
+ * @param array|true $args 变量
+ * @param bool $newInstance 是否每次创建新的实例
+ * @return mixed
+ */
+ public static function make($class, $args = [], $newInstance = false)
+ {
+ if (__CLASS__ != static::class) {
+ return self::__callStatic('make', func_get_args());
+ }
+
+ if (true === $args) {
+ // 总是创建新的实例化对象
+ $newInstance = true;
+ $args = [];
+ }
+
+ return self::createFacade($class, $args, $newInstance);
+ }
+
+ // 调用实际类的方法
+ public static function __callStatic($method, $params)
+ {
+ return call_user_func_array([static::createFacade(), $method], $params);
+ }
+}
diff --git a/Server/thinkphp/library/think/Middleware.php b/Server/thinkphp/library/think/Middleware.php
new file mode 100644
index 00000000..d3f43606
--- /dev/null
+++ b/Server/thinkphp/library/think/Middleware.php
@@ -0,0 +1,205 @@
+
+// +----------------------------------------------------------------------
+
+namespace think;
+
+use InvalidArgumentException;
+use LogicException;
+use think\exception\HttpResponseException;
+
+class Middleware
+{
+ protected $queue = [];
+ protected $app;
+ protected $config = [
+ 'default_namespace' => 'app\\http\\middleware\\',
+ ];
+
+ public function __construct(App $app, array $config = [])
+ {
+ $this->app = $app;
+ $this->config = array_merge($this->config, $config);
+ }
+
+ public static function __make(App $app, Config $config)
+ {
+ return new static($app, $config->pull('middleware'));
+ }
+
+ public function setConfig(array $config)
+ {
+ $this->config = array_merge($this->config, $config);
+ }
+
+ /**
+ * 导入中间件
+ * @access public
+ * @param array $middlewares
+ * @param string $type 中间件类型
+ */
+ public function import(array $middlewares = [], $type = 'route')
+ {
+ foreach ($middlewares as $middleware) {
+ $this->add($middleware, $type);
+ }
+ }
+
+ /**
+ * 注册中间件
+ * @access public
+ * @param mixed $middleware
+ * @param string $type 中间件类型
+ */
+ public function add($middleware, $type = 'route')
+ {
+ if (is_null($middleware)) {
+ return;
+ }
+
+ $middleware = $this->buildMiddleware($middleware, $type);
+
+ if ($middleware) {
+ $this->queue[$type][] = $middleware;
+ }
+ }
+
+ /**
+ * 注册控制器中间件
+ * @access public
+ * @param mixed $middleware
+ */
+ public function controller($middleware)
+ {
+ return $this->add($middleware, 'controller');
+ }
+
+ /**
+ * 移除中间件
+ * @access public
+ * @param mixed $middleware
+ * @param string $type 中间件类型
+ */
+ public function unshift($middleware, $type = 'route')
+ {
+ if (is_null($middleware)) {
+ return;
+ }
+
+ $middleware = $this->buildMiddleware($middleware, $type);
+
+ if ($middleware) {
+ array_unshift($this->queue[$type], $middleware);
+ }
+ }
+
+ /**
+ * 获取注册的中间件
+ * @access public
+ * @param string $type 中间件类型
+ */
+ public function all($type = 'route')
+ {
+ return $this->queue[$type] ?: [];
+ }
+
+ /**
+ * 清除中间件
+ * @access public
+ */
+ public function clear()
+ {
+ $this->queue = [];
+ }
+
+ /**
+ * 中间件调度
+ * @access public
+ * @param Request $request
+ * @param string $type 中间件类型
+ */
+ public function dispatch(Request $request, $type = 'route')
+ {
+ return call_user_func($this->resolve($type), $request);
+ }
+
+ /**
+ * 解析中间件
+ * @access protected
+ * @param mixed $middleware
+ * @param string $type 中间件类型
+ */
+ protected function buildMiddleware($middleware, $type = 'route')
+ {
+ if (is_array($middleware)) {
+ list($middleware, $param) = $middleware;
+ }
+
+ if ($middleware instanceof \Closure) {
+ return [$middleware, isset($param) ? $param : null];
+ }
+
+ if (!is_string($middleware)) {
+ throw new InvalidArgumentException('The middleware is invalid');
+ }
+
+ if (false === strpos($middleware, '\\')) {
+ if (isset($this->config[$middleware])) {
+ $middleware = $this->config[$middleware];
+ } else {
+ $middleware = $this->config['default_namespace'] . $middleware;
+ }
+ }
+
+ if (is_array($middleware)) {
+ return $this->import($middleware, $type);
+ }
+
+ if (strpos($middleware, ':')) {
+ list($middleware, $param) = explode(':', $middleware, 2);
+ }
+
+ return [[$this->app->make($middleware), 'handle'], isset($param) ? $param : null];
+ }
+
+ protected function resolve($type = 'route')
+ {
+ return function (Request $request) use ($type) {
+
+ $middleware = array_shift($this->queue[$type]);
+
+ if (null === $middleware) {
+ throw new InvalidArgumentException('The queue was exhausted, with no response returned');
+ }
+
+ list($call, $param) = $middleware;
+
+ try {
+ $response = call_user_func_array($call, [$request, $this->resolve($type), $param]);
+ } catch (HttpResponseException $exception) {
+ $response = $exception->getResponse();
+ }
+
+ if (!$response instanceof Response) {
+ throw new LogicException('The middleware must return Response instance');
+ }
+
+ return $response;
+ };
+ }
+
+ public function __debugInfo()
+ {
+ $data = get_object_vars($this);
+ unset($data['app']);
+
+ return $data;
+ }
+}
diff --git a/Server/thinkphp/library/think/console/Table.php b/Server/thinkphp/library/think/console/Table.php
new file mode 100644
index 00000000..9e28e266
--- /dev/null
+++ b/Server/thinkphp/library/think/console/Table.php
@@ -0,0 +1,281 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\console;
+
+class Table
+{
+ const ALIGN_LEFT = 1;
+ const ALIGN_RIGHT = 0;
+ const ALIGN_CENTER = 2;
+
+ /**
+ * 头信息数据
+ * @var array
+ */
+ protected $header = [];
+
+ /**
+ * 头部对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+ * @var int
+ */
+ protected $headerAlign = 1;
+
+ /**
+ * 表格数据(二维数组)
+ * @var array
+ */
+ protected $rows = [];
+
+ /**
+ * 单元格对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+ * @var int
+ */
+ protected $cellAlign = 1;
+
+ /**
+ * 单元格宽度信息
+ * @var array
+ */
+ protected $colWidth = [];
+
+ /**
+ * 表格输出样式
+ * @var string
+ */
+ protected $style = 'default';
+
+ /**
+ * 表格样式定义
+ * @var array
+ */
+ protected $format = [
+ 'compact' => [],
+ 'default' => [
+ 'top' => ['+', '-', '+', '+'],
+ 'cell' => ['|', ' ', '|', '|'],
+ 'middle' => ['+', '-', '+', '+'],
+ 'bottom' => ['+', '-', '+', '+'],
+ 'cross-top' => ['+', '-', '-', '+'],
+ 'cross-bottom' => ['+', '-', '-', '+'],
+ ],
+ 'markdown' => [
+ 'top' => [' ', ' ', ' ', ' '],
+ 'cell' => ['|', ' ', '|', '|'],
+ 'middle' => ['|', '-', '|', '|'],
+ 'bottom' => [' ', ' ', ' ', ' '],
+ 'cross-top' => ['|', ' ', ' ', '|'],
+ 'cross-bottom' => ['|', ' ', ' ', '|'],
+ ],
+ 'borderless' => [
+ 'top' => ['=', '=', ' ', '='],
+ 'cell' => [' ', ' ', ' ', ' '],
+ 'middle' => ['=', '=', ' ', '='],
+ 'bottom' => ['=', '=', ' ', '='],
+ 'cross-top' => ['=', '=', ' ', '='],
+ 'cross-bottom' => ['=', '=', ' ', '='],
+ ],
+ 'box' => [
+ 'top' => ['┌', '─', '┬', '┐'],
+ 'cell' => ['│', ' ', '│', '│'],
+ 'middle' => ['├', '─', '┼', '┤'],
+ 'bottom' => ['└', '─', '┴', '┘'],
+ 'cross-top' => ['├', '─', '┴', '┤'],
+ 'cross-bottom' => ['├', '─', '┬', '┤'],
+ ],
+ 'box-double' => [
+ 'top' => ['╔', '═', '╤', '╗'],
+ 'cell' => ['║', ' ', '│', '║'],
+ 'middle' => ['╠', '─', '╪', '╣'],
+ 'bottom' => ['╚', '═', '╧', '╝'],
+ 'cross-top' => ['╠', '═', '╧', '╣'],
+ 'cross-bottom' => ['╠', '═', '╤', '╣'],
+ ],
+ ];
+
+ /**
+ * 设置表格头信息 以及对齐方式
+ * @access public
+ * @param array $header 要输出的Header信息
+ * @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+ * @return void
+ */
+ public function setHeader(array $header, $align = self::ALIGN_LEFT)
+ {
+ $this->header = $header;
+ $this->headerAlign = $align;
+
+ $this->checkColWidth($header);
+ }
+
+ /**
+ * 设置输出表格数据 及对齐方式
+ * @access public
+ * @param array $rows 要输出的表格数据(二维数组)
+ * @param int $align 对齐方式 默认1 ALGIN_LEFT 0 ALIGN_RIGHT 2 ALIGN_CENTER
+ * @return void
+ */
+ public function setRows(array $rows, $align = self::ALIGN_LEFT)
+ {
+ $this->rows = $rows;
+ $this->cellAlign = $align;
+
+ foreach ($rows as $row) {
+ $this->checkColWidth($row);
+ }
+ }
+
+ /**
+ * 检查列数据的显示宽度
+ * @access public
+ * @param mixed $row 行数据
+ * @return void
+ */
+ protected function checkColWidth($row)
+ {
+ if (is_array($row)) {
+ foreach ($row as $key => $cell) {
+ if (!isset($this->colWidth[$key]) || strlen($cell) > $this->colWidth[$key]) {
+ $this->colWidth[$key] = strlen($cell);
+ }
+ }
+ }
+ }
+
+ /**
+ * 增加一行表格数据
+ * @access public
+ * @param mixed $row 行数据
+ * @param bool $first 是否在开头插入
+ * @return void
+ */
+ public function addRow($row, $first = false)
+ {
+ if ($first) {
+ array_unshift($this->rows, $row);
+ } else {
+ $this->rows[] = $row;
+ }
+
+ $this->checkColWidth($row);
+ }
+
+ /**
+ * 设置输出表格的样式
+ * @access public
+ * @param string $style 样式名
+ * @return void
+ */
+ public function setStyle($style)
+ {
+ $this->style = isset($this->format[$style]) ? $style : 'default';
+ }
+
+ /**
+ * 输出分隔行
+ * @access public
+ * @param string $pos 位置
+ * @return string
+ */
+ protected function renderSeparator($pos)
+ {
+ $style = $this->getStyle($pos);
+ $array = [];
+
+ foreach ($this->colWidth as $width) {
+ $array[] = str_repeat($style[1], $width + 2);
+ }
+
+ return $style[0] . implode($style[2], $array) . $style[3] . PHP_EOL;
+ }
+
+ /**
+ * 输出表格头部
+ * @access public
+ * @return string
+ */
+ protected function renderHeader()
+ {
+ $style = $this->getStyle('cell');
+ $content = $this->renderSeparator('top');
+
+ foreach ($this->header as $key => $header) {
+ $array[] = ' ' . str_pad($header, $this->colWidth[$key], $style[1], $this->headerAlign);
+ }
+
+ if (!empty($array)) {
+ $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
+
+ if ($this->rows) {
+ $content .= $this->renderSeparator('middle');
+ }
+ }
+
+ return $content;
+ }
+
+ protected function getStyle($style)
+ {
+ if ($this->format[$this->style]) {
+ $style = $this->format[$this->style][$style];
+ } else {
+ $style = [' ', ' ', ' ', ' '];
+ }
+
+ return $style;
+ }
+
+ /**
+ * 输出表格
+ * @access public
+ * @param array $dataList 表格数据
+ * @return string
+ */
+ public function render($dataList = [])
+ {
+ if ($dataList) {
+ $this->setRows($dataList);
+ }
+
+ // 输出头部
+ $content = $this->renderHeader();
+ $style = $this->getStyle('cell');
+
+ if ($this->rows) {
+ foreach ($this->rows as $row) {
+ if (is_string($row) && '-' === $row) {
+ $content .= $this->renderSeparator('middle');
+ } elseif (is_scalar($row)) {
+ $content .= $this->renderSeparator('cross-top');
+ $array = str_pad($row, 3 * (count($this->colWidth) - 1) + array_reduce($this->colWidth, function ($a, $b) {
+ return $a + $b;
+ }));
+
+ $content .= $style[0] . ' ' . $array . ' ' . $style[3] . PHP_EOL;
+ $content .= $this->renderSeparator('cross-bottom');
+ } else {
+ $array = [];
+
+ foreach ($row as $key => $val) {
+ $array[] = ' ' . str_pad($val, $this->colWidth[$key], ' ', $this->cellAlign);
+ }
+
+ $content .= $style[0] . implode(' ' . $style[2], $array) . ' ' . $style[3] . PHP_EOL;
+
+ }
+ }
+ }
+
+ $content .= $this->renderSeparator('bottom');
+
+ return $content;
+ }
+}
diff --git a/Server/thinkphp/library/think/console/command/RouteList.php b/Server/thinkphp/library/think/console/command/RouteList.php
new file mode 100644
index 00000000..0405c31b
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/RouteList.php
@@ -0,0 +1,130 @@
+
+// +----------------------------------------------------------------------
+namespace think\console\command;
+
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Argument;
+use think\console\input\Option;
+use think\console\Output;
+use think\console\Table;
+use think\Container;
+
+class RouteList extends Command
+{
+ protected $sortBy = [
+ 'rule' => 0,
+ 'route' => 1,
+ 'method' => 2,
+ 'name' => 3,
+ 'domain' => 4,
+ ];
+
+ protected function configure()
+ {
+ $this->setName('route:list')
+ ->addArgument('style', Argument::OPTIONAL, "the style of the table.", 'default')
+ ->addOption('sort', 's', Option::VALUE_OPTIONAL, 'order by rule name.', 0)
+ ->addOption('more', 'm', Option::VALUE_NONE, 'show route options.')
+ ->setDescription('show route list.');
+ }
+
+ protected function execute(Input $input, Output $output)
+ {
+ $filename = Container::get('app')->getRuntimePath() . 'route_list.php';
+
+ if (is_file($filename)) {
+ unlink($filename);
+ }
+
+ $content = $this->getRouteList();
+ file_put_contents($filename, 'Route List' . PHP_EOL . $content);
+ }
+
+ protected function getRouteList()
+ {
+ Container::get('route')->setTestMode(true);
+ // 路由检测
+ $path = Container::get('app')->getRoutePath();
+
+ $files = is_dir($path) ? scandir($path) : [];
+
+ foreach ($files as $file) {
+ if (strpos($file, '.php')) {
+ $filename = $path . DIRECTORY_SEPARATOR . $file;
+ // 导入路由配置
+ $rules = include $filename;
+
+ if (is_array($rules)) {
+ Container::get('route')->import($rules);
+ }
+ }
+ }
+
+ if (Container::get('config')->get('route_annotation')) {
+ $suffix = Container::get('config')->get('controller_suffix') || Container::get('config')->get('class_suffix');
+
+ include Container::get('build')->buildRoute($suffix);
+ }
+
+ $table = new Table();
+
+ if ($this->input->hasOption('more')) {
+ $header = ['Rule', 'Route', 'Method', 'Name', 'Domain', 'Option', 'Pattern'];
+ } else {
+ $header = ['Rule', 'Route', 'Method', 'Name', 'Domain'];
+ }
+
+ $table->setHeader($header);
+
+ $routeList = Container::get('route')->getRuleList();
+ $rows = [];
+
+ foreach ($routeList as $domain => $items) {
+ foreach ($items as $item) {
+ $item['route'] = $item['route'] instanceof \Closure ? '' : $item['route'];
+
+ if ($this->input->hasOption('more')) {
+ $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $domain, json_encode($item['option']), json_encode($item['pattern'])];
+ } else {
+ $item = [$item['rule'], $item['route'], $item['method'], $item['name'], $domain];
+ }
+
+ $rows[] = $item;
+ }
+ }
+
+ if ($this->input->getOption('sort')) {
+ $sort = $this->input->getOption('sort');
+
+ if (isset($this->sortBy[$sort])) {
+ $sort = $this->sortBy[$sort];
+ }
+
+ uasort($rows, function ($a, $b) use ($sort) {
+ $itemA = isset($a[$sort]) ? $a[$sort] : null;
+ $itemB = isset($b[$sort]) ? $b[$sort] : null;
+
+ return strcasecmp($itemA, $itemB);
+ });
+ }
+
+ $table->setRows($rows);
+
+ if ($this->input->getArgument('style')) {
+ $style = $this->input->getArgument('style');
+ $table->setStyle($style);
+ }
+
+ return $this->table($table);
+ }
+
+}
diff --git a/Server/thinkphp/library/think/console/command/RunServer.php b/Server/thinkphp/library/think/console/command/RunServer.php
new file mode 100644
index 00000000..2e028dc6
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/RunServer.php
@@ -0,0 +1,53 @@
+
+// +----------------------------------------------------------------------
+namespace think\console\command;
+
+use think\console\Command;
+use think\console\Input;
+use think\console\input\Option;
+use think\console\Output;
+use think\facade\App;
+
+class RunServer extends Command
+{
+ public function configure()
+ {
+ $this->setName('run')
+ ->addOption('host', 'H', Option::VALUE_OPTIONAL,
+ 'The host to server the application on', '127.0.0.1')
+ ->addOption('port', 'p', Option::VALUE_OPTIONAL,
+ 'The port to server the application on', 8000)
+ ->addOption('root', 'r', Option::VALUE_OPTIONAL,
+ 'The document root of the application', App::getRootPath() . 'public')
+ ->setDescription('PHP Built-in Server for ThinkPHP');
+ }
+
+ public function execute(Input $input, Output $output)
+ {
+ $host = $input->getOption('host');
+ $port = $input->getOption('port');
+ $root = $input->getOption('root');
+
+ $command = sprintf(
+ 'php -S %s:%d -t %s %s',
+ $host,
+ $port,
+ escapeshellarg($root),
+ escapeshellarg($root . DIRECTORY_SEPARATOR . 'router.php')
+ );
+
+ $output->writeln(sprintf('ThinkPHP Development server is started On ', $host, $port));
+ $output->writeln(sprintf('You can exit with `CTRL-C`'));
+ $output->writeln(sprintf('Document root is: %s', $root));
+ passthru($command);
+ }
+
+}
diff --git a/Server/thinkphp/library/think/console/command/Version.php b/Server/thinkphp/library/think/console/command/Version.php
new file mode 100644
index 00000000..ee7eca9c
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/Version.php
@@ -0,0 +1,31 @@
+
+// +----------------------------------------------------------------------
+namespace think\console\command;
+
+use think\console\Command;
+use think\console\Input;
+use think\console\Output;
+use think\facade\App;
+
+class Version extends Command
+{
+ protected function configure()
+ {
+ // 指令配置
+ $this->setName('version')
+ ->setDescription('show thinkphp framework version');
+ }
+
+ protected function execute(Input $input, Output $output)
+ {
+ $output->writeln('v' . App::version());
+ }
+}
diff --git a/Server/thinkphp/library/think/console/command/make/Command.php b/Server/thinkphp/library/think/console/command/make/Command.php
new file mode 100644
index 00000000..b539eb23
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/make/Command.php
@@ -0,0 +1,56 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\console\command\make;
+
+use think\console\command\Make;
+use think\console\input\Argument;
+use think\facade\App;
+
+class Command extends Make
+{
+ protected $type = "Command";
+
+ protected function configure()
+ {
+ parent::configure();
+ $this->setName('make:command')
+ ->addArgument('commandName', Argument::OPTIONAL, "The name of the command")
+ ->setDescription('Create a new command class');
+ }
+
+ protected function buildClass($name)
+ {
+ $commandName = $this->input->getArgument('commandName') ?: strtolower(basename($name));
+ $namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
+
+ $class = str_replace($namespace . '\\', '', $name);
+ $stub = file_get_contents($this->getStub());
+
+ return str_replace(['{%commandName%}', '{%className%}', '{%namespace%}', '{%app_namespace%}'], [
+ $commandName,
+ $class,
+ $namespace,
+ App::getNamespace(),
+ ], $stub);
+ }
+
+ protected function getStub()
+ {
+ return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'command.stub';
+ }
+
+ protected function getNamespace($appNamespace, $module)
+ {
+ return $appNamespace . '\\command';
+ }
+
+}
diff --git a/Server/thinkphp/library/think/console/command/make/Middleware.php b/Server/thinkphp/library/think/console/command/make/Middleware.php
new file mode 100644
index 00000000..bfe821b0
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/make/Middleware.php
@@ -0,0 +1,36 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\console\command\make;
+
+use think\console\command\Make;
+
+class Middleware extends Make
+{
+ protected $type = "Middleware";
+
+ protected function configure()
+ {
+ parent::configure();
+ $this->setName('make:middleware')
+ ->setDescription('Create a new middleware class');
+ }
+
+ protected function getStub()
+ {
+ return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'middleware.stub';
+ }
+
+ protected function getNamespace($appNamespace, $module)
+ {
+ return parent::getNamespace($appNamespace, 'http') . '\middleware';
+ }
+}
diff --git a/Server/thinkphp/library/think/console/command/make/Validate.php b/Server/thinkphp/library/think/console/command/make/Validate.php
new file mode 100644
index 00000000..89830ad1
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/make/Validate.php
@@ -0,0 +1,39 @@
+
+// +----------------------------------------------------------------------
+
+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/Server/thinkphp/library/think/console/command/make/stubs/command.stub b/Server/thinkphp/library/think/console/command/make/stubs/command.stub
new file mode 100644
index 00000000..d2c7c1e7
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/make/stubs/command.stub
@@ -0,0 +1,24 @@
+setName('{%commandName%}');
+ // 设置参数
+
+ }
+
+ protected function execute(Input $input, Output $output)
+ {
+ // 指令输出
+ $output->writeln('{%commandName%}');
+ }
+}
diff --git a/Server/thinkphp/library/think/console/command/make/stubs/controller.api.stub b/Server/thinkphp/library/think/console/command/make/stubs/controller.api.stub
new file mode 100644
index 00000000..54ec0594
--- /dev/null
+++ b/Server/thinkphp/library/think/console/command/make/stubs/controller.api.stub
@@ -0,0 +1,64 @@
+ ['规则1','规则2'...]
+ *
+ * @var array
+ */
+ protected $rule = [];
+
+ /**
+ * 定义错误信息
+ * 格式:'字段名.规则名' => '错误信息'
+ *
+ * @var array
+ */
+ protected $message = [];
+}
diff --git a/Server/thinkphp/library/think/db/Where.php b/Server/thinkphp/library/think/db/Where.php
new file mode 100644
index 00000000..9132e546
--- /dev/null
+++ b/Server/thinkphp/library/think/db/Where.php
@@ -0,0 +1,178 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\db;
+
+use ArrayAccess;
+
+class Where implements ArrayAccess
+{
+ /**
+ * 查询表达式
+ * @var array
+ */
+ protected $where = [];
+
+ /**
+ * 是否需要增加括号
+ * @var bool
+ */
+ protected $enclose = false;
+
+ /**
+ * 创建一个查询表达式
+ *
+ * @param array $where 查询条件数组
+ * @param bool $enclose 是否增加括号
+ */
+ public function __construct(array $where = [], $enclose = false)
+ {
+ $this->where = $where;
+ $this->enclose = $enclose;
+ }
+
+ /**
+ * 设置是否添加括号
+ * @access public
+ * @param bool $enclose
+ * @return $this
+ */
+ public function enclose($enclose = true)
+ {
+ $this->enclose = $enclose;
+ return $this;
+ }
+
+ /**
+ * 解析为Query对象可识别的查询条件数组
+ * @access public
+ * @return array
+ */
+ public function parse()
+ {
+ $where = [];
+
+ foreach ($this->where as $key => $val) {
+ if ($val instanceof Expression) {
+ $where[] = [$key, 'exp', $val];
+ } elseif (is_null($val)) {
+ $where[] = [$key, 'NULL', ''];
+ } elseif (is_array($val)) {
+ $where[] = $this->parseItem($key, $val);
+ } else {
+ $where[] = [$key, '=', $val];
+ }
+ }
+
+ return $this->enclose ? [$where] : $where;
+ }
+
+ /**
+ * 分析查询表达式
+ * @access protected
+ * @param string $field 查询字段
+ * @param array $where 查询条件
+ * @return array
+ */
+ protected function parseItem($field, $where = [])
+ {
+ $op = $where[0];
+ $condition = isset($where[1]) ? $where[1] : null;
+
+ if (is_array($op)) {
+ // 同一字段多条件查询
+ array_unshift($where, $field);
+ } elseif (is_null($condition)) {
+ if (in_array(strtoupper($op), ['NULL', 'NOTNULL', 'NOT NULL'], true)) {
+ // null查询
+ $where = [$field, $op, ''];
+ } elseif (in_array($op, ['=', 'eq', 'EQ', null], true)) {
+ $where = [$field, 'NULL', ''];
+ } elseif (in_array($op, ['<>', 'neq', 'NEQ'], true)) {
+ $where = [$field, 'NOTNULL', ''];
+ } else {
+ // 字段相等查询
+ $where = [$field, '=', $op];
+ }
+ } else {
+ $where = [$field, $op, $condition];
+ }
+
+ return $where;
+ }
+
+ /**
+ * 修改器 设置数据对象的值
+ * @access public
+ * @param string $name 名称
+ * @param mixed $value 值
+ * @return void
+ */
+ public function __set($name, $value)
+ {
+ $this->where[$name] = $value;
+ }
+
+ /**
+ * 获取器 获取数据对象的值
+ * @access public
+ * @param string $name 名称
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ return isset($this->where[$name]) ? $this->where[$name] : null;
+ }
+
+ /**
+ * 检测数据对象的值
+ * @access public
+ * @param string $name 名称
+ * @return boolean
+ */
+ public function __isset($name)
+ {
+ return isset($this->where[$name]);
+ }
+
+ /**
+ * 销毁数据对象的值
+ * @access public
+ * @param string $name 名称
+ * @return void
+ */
+ public function __unset($name)
+ {
+ unset($this->where[$name]);
+ }
+
+ // ArrayAccess
+ public function offsetSet($name, $value)
+ {
+ $this->__set($name, $value);
+ }
+
+ public function offsetExists($name)
+ {
+ return $this->__isset($name);
+ }
+
+ public function offsetUnset($name)
+ {
+ $this->__unset($name);
+ }
+
+ public function offsetGet($name)
+ {
+ return $this->__get($name);
+ }
+
+}
diff --git a/Server/thinkphp/library/think/facade/App.php b/Server/thinkphp/library/think/facade/App.php
new file mode 100644
index 00000000..b375aa09
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/App.php
@@ -0,0 +1,63 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\App
+ * @mixin \think\App
+ * @method \think\App bind(string $bind) static 绑定模块或者控制器
+ * @method void initialize() static 初始化应用
+ * @method void init(string $module='') static 初始化模块
+ * @method \think\Response run() static 执行应用
+ * @method \think\App dispatch(\think\route\Dispatch $dispatch) static 设置当前请求的调度信息
+ * @method void log(mixed $log, string $type = 'info') static 记录调试信息
+ * @method mixed config(string $name='') static 获取配置参数
+ * @method \think\route\Dispatch routeCheck() static URL路由检测(根据PATH_INFO)
+ * @method \think\App routeMust(bool $must = false) static 设置应用的路由检测机制
+ * @method \think\Model model(string $name = '', string $layer = 'model', bool $appendSuffix = false, string $common = 'common') static 实例化模型
+ * @method object controller(string $name, string $layer = 'controller', bool $appendSuffix = false, string $empty = '') static 实例化控制器
+ * @method \think\Validate validate(string $name = '', string $layer = 'validate', bool $appendSuffix = false, string $common = 'common') static 实例化验证器类
+ * @method \think\db\Query db(mixed $config = [], mixed $name = false) static 数据库初始化
+ * @method mixed action(string $url, $vars = [], $layer = 'controller', $appendSuffix = false) static 调用模块的操作方法
+ * @method string parseClass(string $module, string $layer, string $name, bool $appendSuffix = false) static 解析应用类的类名
+ * @method string version() static 获取框架版本
+ * @method bool isDebug() static 是否为调试模式
+ * @method string getModulePath() static 获取当前模块路径
+ * @method void setModulePath(string $path) static 设置当前模块路径
+ * @method string getRootPath() static 获取应用根目录
+ * @method string getAppPath() static 获取应用类库目录
+ * @method string getRuntimePath() static 获取应用运行时目录
+ * @method string getThinkPath() static 获取核心框架目录
+ * @method string getRoutePath() static 获取路由目录
+ * @method string getConfigPath() static 获取应用配置目录
+ * @method string getConfigExt() static 获取配置后缀
+ * @method string setNamespace(string $namespace) static 设置应用类库命名空间
+ * @method string getNamespace() static 获取应用类库命名空间
+ * @method string getSuffix() static 是否启用类库后缀
+ * @method float getBeginTime() static 获取应用开启时间
+ * @method integer getBeginMem() static 获取应用初始内存占用
+ * @method \think\Container container() static 获取容器实例
+ */
+class App extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'app';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Build.php b/Server/thinkphp/library/think/facade/Build.php
new file mode 100644
index 00000000..c051bea1
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Build.php
@@ -0,0 +1,33 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Build
+ * @mixin \think\Build
+ * @method void run(array $build = [], string $namespace = 'app', bool $suffix = false) static 根据传入的build资料创建目录和文件
+ * @method void module(string $module = '', array $list = [], string $namespace = 'app', bool $suffix = false) static 创建模块
+ */
+class Build extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'build';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Cache.php b/Server/thinkphp/library/think/facade/Cache.php
new file mode 100644
index 00000000..9743486e
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Cache.php
@@ -0,0 +1,45 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Cache
+ * @mixin \think\Cache
+ * @method \think\cache\Driver connect(array $options = [], mixed $name = false) static 连接缓存
+ * @method \think\cache\Driver init(array $options = []) static 初始化缓存
+ * @method \think\cache\Driver store(string $name = '') static 切换缓存类型
+ * @method bool has(string $name) static 判断缓存是否存在
+ * @method mixed get(string $name, mixed $default = false) static 读取缓存
+ * @method mixed pull(string $name) static 读取缓存并删除
+ * @method mixed set(string $name, mixed $value, int $expire = null) static 设置缓存
+ * @method mixed remember(string $name, mixed $value, int $expire = null) static 如果不存在则写入缓存
+ * @method mixed inc(string $name, int $step = 1) static 自增缓存(针对数值缓存)
+ * @method mixed dec(string $name, int $step = 1) static 自减缓存(针对数值缓存)
+ * @method bool rm(string $name) static 删除缓存
+ * @method bool clear(string $tag = null) static 清除缓存
+ * @method mixed tag(string $name, mixed $keys = null, bool $overlay = false) static 缓存标签
+ * @method object handler() static 返回句柄对象,可执行其它高级方法
+ */
+class Cache extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'cache';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Config.php b/Server/thinkphp/library/think/facade/Config.php
new file mode 100644
index 00000000..824d2b6a
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Config.php
@@ -0,0 +1,39 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Config
+ * @mixin \think\Config
+ * @method array load(string $file, string $name = '') static 加载配置文件
+ * @method bool has(string $name) static 检测配置是否存在
+ * @method array pull(string $name) static 获取一级配置参数
+ * @method mixed get(string $name,mixed $default = null) static 获取配置参数
+ * @method array set(mixed $name, mixed $value = null) static 设置配置参数
+ * @method array reset(string $name ='') static 重置配置参数
+ * @method void remove(string $name = '') static 移除配置
+ * @method void setYaconf(mixed $yaconf) static 设置开启Yaconf 或者指定配置文件名
+ */
+class Config extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'config';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Cookie.php b/Server/thinkphp/library/think/facade/Cookie.php
new file mode 100644
index 00000000..4d7cea25
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Cookie.php
@@ -0,0 +1,39 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Cookie
+ * @mixin \think\Cookie
+ * @method void init(array $config = []) static 初始化
+ * @method bool has(string $name,string $prefix = null) static 判断Cookie数据
+ * @method mixed prefix(string $prefix = '') static 设置或者获取cookie作用域(前缀)
+ * @method mixed get(string $name,string $prefix = null) static Cookie获取
+ * @method mixed set(string $name, mixed $value = null, mixed $option = null) static 设置Cookie
+ * @method void forever(string $name, mixed $value = null, mixed $option = null) static 永久保存Cookie数据
+ * @method void delete(string $name, string $prefix = null) static Cookie删除
+ * @method void clear($prefix = null) static Cookie清空
+ */
+class Cookie extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'cookie';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Debug.php b/Server/thinkphp/library/think/facade/Debug.php
new file mode 100644
index 00000000..df20086d
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Debug.php
@@ -0,0 +1,40 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Debug
+ * @mixin \think\Debug
+ * @method void remark(string $name, mixed $value = '') static 记录时间(微秒)和内存使用情况
+ * @method int getRangeTime(string $start, string $end, mixed $dec = 6) static 统计某个区间的时间(微秒)使用情况
+ * @method int getUseTime(int $dec = 6) static 统计从开始到统计时的时间(微秒)使用情况
+ * @method string getThroughputRate(string $start, string $end, mixed $dec = 6) static 获取当前访问的吞吐率情况
+ * @method string getRangeMem(string $start, string $end, mixed $dec = 2) static 记录区间的内存使用情况
+ * @method int getUseMem(int $dec = 2) static 统计从开始到统计时的内存使用情况
+ * @method string getMemPeak(string $start, string $end, mixed $dec = 2) static 统计区间的内存峰值情况
+ * @method mixed getFile(bool $detail = false) static 获取文件加载信息
+ * @method mixed dump(mixed $var, bool $echo = true, string $label = null, int $flags = ENT_SUBSTITUTE) static 浏览器友好的变量输出
+ */
+class Debug extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'debug';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Env.php b/Server/thinkphp/library/think/facade/Env.php
new file mode 100644
index 00000000..5d047244
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Env.php
@@ -0,0 +1,34 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Env
+ * @mixin \think\Env
+ * @method void load(string $file) static 读取环境变量定义文件
+ * @method mixed get(string $name = null, mixed $default = null) static 获取环境变量值
+ * @method void set(mixed $env, string $value = null) static 设置环境变量值
+ */
+class Env extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'env';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Hook.php b/Server/thinkphp/library/think/facade/Hook.php
new file mode 100644
index 00000000..e9e12083
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Hook.php
@@ -0,0 +1,37 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Hook
+ * @mixin \think\Hook
+ * @method \think\Hook alias(mixed $name, mixed $behavior = null) static 指定行为标识
+ * @method void add(string $tag, mixed $behavior, bool $first = false) static 动态添加行为扩展到某个标签
+ * @method void import(array $tags, bool $recursive = true) static 批量导入插件
+ * @method array get(string $tag = '') static 获取插件信息
+ * @method mixed listen(string $tag, mixed $params = null, bool $once = false) static 监听标签的行为
+ * @method mixed exec(mixed $class, mixed $params = null) static 执行行为
+ */
+class Hook extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'hook';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Lang.php b/Server/thinkphp/library/think/facade/Lang.php
new file mode 100644
index 00000000..56c4777d
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Lang.php
@@ -0,0 +1,41 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Lang
+ * @mixin \think\Lang
+ * @method mixed range($range = '') static 设定当前的语言
+ * @method mixed set(mixed $name, string $value = null, string $range = '') static 设置语言定义
+ * @method array load(mixed $file, string $range = '') static 加载语言定义
+ * @method mixed get(string $name = null, array $vars = [], string $range = '') static 获取语言定义
+ * @method mixed has(string $name, string $range = '') static 获取语言定义
+ * @method string detect() static 自动侦测设置获取语言选择
+ * @method void saveToCookie(string $lang = null) static 设置当前语言到Cookie
+ * @method void setLangDetectVar(string $var) static 设置语言自动侦测的变量
+ * @method void setLangCookieVar(string $var) static 设置语言的cookie保存变量
+ * @method void setAllowLangList(array $list) static 设置允许的语言列表
+ */
+class Lang extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'lang';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Log.php b/Server/thinkphp/library/think/facade/Log.php
new file mode 100644
index 00000000..ae627a5c
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Log.php
@@ -0,0 +1,50 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Log
+ * @mixin \think\Log
+ * @method \think\Log init(array $config = []) static 日志初始化
+ * @method mixed getLog(string $type = '') static 获取日志信息
+ * @method \think\Log record(mixed $msg, string $type = 'info', array $context = []) static 记录日志信息
+ * @method \think\Log clear() static 清空日志信息
+ * @method \think\Log key(string $key) static 当前日志记录的授权key
+ * @method \think\Log close() static 关闭本次请求日志写入
+ * @method bool check(array $config) static 检查日志写入权限
+ * @method bool save() static 保存调试信息
+ * @method void write(mixed $msg, string $type = 'info', bool $force = false) static 实时写入日志信息
+ * @method void log(string $level,mixed $message, array $context = []) static 记录日志信息
+ * @method void emergency(mixed $message, array $context = []) static 记录emergency信息
+ * @method void alert(mixed $message, array $context = []) static 记录alert信息
+ * @method void critical(mixed $message, array $context = []) static 记录critical信息
+ * @method void error(mixed $message, array $context = []) static 记录error信息
+ * @method void warning(mixed $message, array $context = []) static 记录warning信息
+ * @method void notice(mixed $message, array $context = []) static 记录notice信息
+ * @method void info(mixed $message, array $context = []) static 记录info信息
+ * @method void debug(mixed $message, array $context = []) static 记录debug信息
+ * @method void sql(mixed $message, array $context = []) static 记录sql信息
+ */
+class Log extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'log';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Middleware.php b/Server/thinkphp/library/think/facade/Middleware.php
new file mode 100644
index 00000000..5e4cac74
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Middleware.php
@@ -0,0 +1,36 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Middleware
+ * @mixin \think\Middleware
+ * @method void import(array $middlewares = []) static 批量设置中间件
+ * @method void add(mixed $middleware) static 添加中间件到队列
+ * @method void unshift(mixed $middleware) static 添加中间件到队列开头
+ * @method array all() static 获取中间件队列
+ * @method \think\Response dispatch(\think\Request $request) static 执行中间件调度
+ */
+class Middleware extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'middleware';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Request.php b/Server/thinkphp/library/think/facade/Request.php
new file mode 100644
index 00000000..0989253f
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Request.php
@@ -0,0 +1,97 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Request
+ * @mixin \think\Request
+ * @method void hook(mixed $method, mixed $callback = null) static Hook 方法注入
+ * @method \think\Request create(string $uri, string $method = 'GET', array $params = [], array $cookie = [], array $files = [], array $server = [], string $content = null) static 创建一个URL请求
+ * @method mixed domain(bool $port = false) static 获取当前包含协议、端口的域名
+ * @method mixed url(bool $domain = false) static 获取当前完整URL
+ * @method mixed baseUrl(bool $domain = false) static 获取当前URL
+ * @method mixed baseFile(bool $domain = false) static 获取当前执行的文件
+ * @method mixed root(bool $domain = false) static 获取URL访问根地址
+ * @method string rootUrl() static 获取URL访问根目录
+ * @method string pathinfo() static 获取当前请求URL的pathinfo信息(含URL后缀)
+ * @method string path() static 获取当前请求URL的pathinfo信息(不含URL后缀)
+ * @method string ext() static 当前URL的访问后缀
+ * @method float time(bool $float = false) static 获取当前请求的时间
+ * @method mixed type() static 当前请求的资源类型
+ * @method void mimeType(mixed $type, string $val = '') static 设置资源类型
+ * @method string method(bool $method = false) static 当前的请求类型
+ * @method bool isGet() static 是否为GET请求
+ * @method bool isPost() static 是否为POST请求
+ * @method bool isPut() static 是否为PUT请求
+ * @method bool isDelete() static 是否为DELTE请求
+ * @method bool isHead() static 是否为HEAD请求
+ * @method bool isPatch() static 是否为PATCH请求
+ * @method bool isOptions() static 是否为OPTIONS请求
+ * @method bool isCli() static 是否为cli
+ * @method bool isCgi() static 是否为cgi
+ * @method mixed param(string $name = '', mixed $default = null, mixed $filter = '') static 获取当前请求的参数
+ * @method mixed route(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取路由参数
+ * @method mixed get(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取GET参数
+ * @method mixed post(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取POST参数
+ * @method mixed put(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取PUT参数
+ * @method mixed delete(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取DELETE参数
+ * @method mixed patch(string $name = '', mixed $default = null, mixed $filter = '') static 设置获取PATCH参数
+ * @method mixed request(string $name = '', mixed $default = null, mixed $filter = '') static 获取request变量
+ * @method mixed session(string $name = '', mixed $default = null, mixed $filter = '') static 获取session数据
+ * @method mixed cookie(string $name = '', mixed $default = null, mixed $filter = '') static 获取cookie参数
+ * @method mixed server(string $name = '', mixed $default = null, mixed $filter = '') static 获取server参数
+ * @method mixed env(string $name = '', mixed $default = null, mixed $filter = '') static 获取环境变量
+ * @method mixed file(string $name = '') static 获取上传的文件信息
+ * @method mixed header(string $name = '', mixed $default = null) static 设置或者获取当前的Header
+ * @method mixed input(array $data,mixed $name = '', mixed $default = null, mixed $filter = '') static 获取变量 支持过滤和默认值
+ * @method mixed filter(mixed $filter = null) static 设置或获取当前的过滤规则
+ * @method mixed has(string $name, string $type = 'param', bool $checkEmpty = false) static 是否存在某个请求参数
+ * @method mixed only(mixed $name, string $type = 'param') static 获取指定的参数
+ * @method mixed except(mixed $name, string $type = 'param') static 排除指定参数获取
+ * @method bool isSsl() static 当前是否ssl
+ * @method bool isAjax(bool $ajax = false) static 当前是否Ajax请求
+ * @method bool isPjax(bool $pjax = false) static 当前是否Pjax请求
+ * @method mixed ip(int $type = 0, bool $adv = true) static 获取客户端IP地址
+ * @method bool isMobile() static 检测是否使用手机访问
+ * @method string scheme() static 当前URL地址中的scheme参数
+ * @method string query() static 当前请求URL地址中的query参数
+ * @method string host(bool $stric = false) static 当前请求的host
+ * @method string port() static 当前请求URL地址中的port参数
+ * @method string protocol() static 当前请求 SERVER_PROTOCOL
+ * @method string remotePort() static 当前请求 REMOTE_PORT
+ * @method string contentType() static 当前请求 HTTP_CONTENT_TYPE
+ * @method array routeInfo() static 获取当前请求的路由信息
+ * @method array dispatch() static 获取当前请求的调度信息
+ * @method string module() static 获取当前的模块名
+ * @method string controller(bool $convert = false) static 获取当前的控制器名
+ * @method string action(bool $convert = false) static 获取当前的操作名
+ * @method string langset() static 获取当前的语言
+ * @method string getContent() static 设置或者获取当前请求的content
+ * @method string getInput() static 获取当前请求的php://input
+ * @method string token(string $name = '__token__', mixed $type = 'md5') static 生成请求令牌
+ * @method string cache(string $key, mixed $expire = null, array $except = [], string $tag = null) static 设置当前地址的请求缓存
+ * @method string getCache() static 读取请求缓存设置
+ */
+class Request extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'request';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Response.php b/Server/thinkphp/library/think/facade/Response.php
new file mode 100644
index 00000000..d7de142f
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Response.php
@@ -0,0 +1,47 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Response
+ * @mixin \think\Response
+ * @method \think\response create(mixed $data = '', string $type = '', int $code = 200, array $header = [], array $options = []) static 创建Response对象
+ * @method void send() static 发送数据到客户端
+ * @method \think\Response options(mixed $options = []) static 输出的参数
+ * @method \think\Response data(mixed $data) static 输出数据设置
+ * @method \think\Response header(mixed $name, string $value = null) static 设置响应头
+ * @method \think\Response content(mixed $content) static 设置页面输出内容
+ * @method \think\Response code(int $code) static 发送HTTP状态
+ * @method \think\Response lastModified(string $time) static LastModified
+ * @method \think\Response expires(string $time) static expires
+ * @method \think\Response eTag(string $eTag) static eTag
+ * @method \think\Response cacheControl(string $cache) static 页面缓存控制
+ * @method \think\Response contentType(string $contentType, string $charset = 'utf-8') static 页面输出类型
+ * @method mixed getHeader(string $name) static 获取头部信息
+ * @method mixed getData() static 获取原始数据
+ * @method mixed getContent() static 获取输出数据
+ * @method int getCode() static 获取状态码
+ */
+class Response extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'response';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Route.php b/Server/thinkphp/library/think/facade/Route.php
new file mode 100644
index 00000000..6457ba4b
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Route.php
@@ -0,0 +1,57 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Route
+ * @mixin \think\Route
+ * @method \think\route\Domain domain(mixed $name, mixed $rule = '', array $option = [], array $pattern = []) static 注册域名路由
+ * @method \think\Route pattern(mixed $name, string $rule = '') static 注册变量规则
+ * @method \think\Route option(mixed $name, mixed $value = '') static 注册路由参数
+ * @method \think\Route bind(string $bind) static 设置路由绑定
+ * @method mixed getBind(string $bind) static 读取路由绑定
+ * @method \think\Route name(string $name) static 设置当前路由标识
+ * @method mixed getName(string $name) static 读取路由标识
+ * @method void setName(string $name) static 批量导入路由标识
+ * @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(array $rules, string $method = '*', array $option = [], array $pattern = []) static 批量注册路由规则
+ * @method \think\route\RuleGroup group(string|array $name, array|\Closure $route, array $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 注册路由
+ * @method \think\route\RuleItem put(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由
+ * @method \think\route\RuleItem delete(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由
+ * @method \think\route\RuleItem patch(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册路由
+ * @method \think\route\Resource resource(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册资源路由
+ * @method \think\Route controller(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册控制器路由
+ * @method \think\Route alias(string $rule, mixed $route, array $option = [], array $pattern = []) static 注册别名路由
+ * @method \think\Route setMethodPrefix(mixed $method, string $prefix = '') static 设置不同请求类型下面的方法前缀
+ * @method \think\Route rest(string $name, array $resource = []) static rest方法定义和修改
+ * @method \think\Route\RuleItem miss(string $route, string $method = '*', array $option = []) static 注册未匹配路由规则后的处理
+ * @method \think\Route\RuleItem auto(string $route) static 注册一个自动解析的URL路由
+ * @method \think\Route\Dispatch check(string $url, string $depr = '/', bool $must = false, bool $completeMatch = false) static 检测URL路由
+ */
+class Route extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'route';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Session.php b/Server/thinkphp/library/think/facade/Session.php
new file mode 100644
index 00000000..fb9206af
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Session.php
@@ -0,0 +1,46 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Session
+ * @mixin \think\Session
+ * @method void init(array $config = []) static session初始化
+ * @method bool has(string $name,string $prefix = null) static 判断session数据
+ * @method mixed prefix(string $prefix = '') static 设置或者获取session作用域(前缀)
+ * @method mixed get(string $name = '',string $prefix = null) static session获取
+ * @method mixed pull(string $name,string $prefix = null) static session获取并删除
+ * @method void push(string $key, mixed $value) static 添加数据到一个session数组
+ * @method void set(string $name, mixed $value , string $prefix = null) static 设置session数据
+ * @method void flash(string $name, mixed $value = null) static session设置 下一次请求有效
+ * @method void flush() static 清空当前请求的session数据
+ * @method void delete(string $name, string $prefix = null) static 删除session数据
+ * @method void clear($prefix = null) static 清空session数据
+ * @method void start() static 启动session
+ * @method void destroy() static 销毁session
+ * @method void pause() static 暂停session
+ * @method void regenerate(bool $delete = false) static 重新生成session_id
+ */
+class Session extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'session';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Template.php b/Server/thinkphp/library/think/facade/Template.php
new file mode 100644
index 00000000..f91b1182
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Template.php
@@ -0,0 +1,36 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Template
+ * @mixin \think\Template
+ * @method void assign(mixed $name, mixed $value = '') static 模板变量赋值
+ * @method mixed get(string $name = '') static 获取模板变量
+ * @method void fetch(string $template, array $vars = [], array $config = []) static 渲染模板文件
+ * @method void display(string $content, array $vars = [], array $config = []) static 渲染模板内容
+ * @method mixed layout(string $name, string $replace = '') static 设置模板布局
+ */
+class Template extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'template';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Url.php b/Server/thinkphp/library/think/facade/Url.php
new file mode 100644
index 00000000..639591ac
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Url.php
@@ -0,0 +1,33 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Url
+ * @mixin \think\Url
+ * @method string build(string $url = '', mixed $vars = '', mixed $suffix = true, mixed $domain = false) static URL生成 支持路由反射
+ * @method void root(string $root) static 指定当前生成URL地址的root
+ */
+class Url extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'url';
+ }
+}
diff --git a/Server/thinkphp/library/think/facade/Validate.php b/Server/thinkphp/library/think/facade/Validate.php
new file mode 100644
index 00000000..a6eec23e
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/Validate.php
@@ -0,0 +1,75 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\Validate
+ * @mixin \think\Validate
+ * @method \think\Validate make(array $rules = [], array $message = [], array $field = []) static 创建一个验证器类
+ * @method \think\Validate rule(mixed $name, mixed $rule = '') static 添加字段验证规则
+ * @method void extend(string $type, mixed $callback = null) static 注册扩展验证(类型)规则
+ * @method void setTypeMsg(mixed $type, string $msg = null) static 设置验证规则的默认提示信息
+ * @method \think\Validate message(mixed $name, string $message = '') static 设置提示信息
+ * @method \think\Validate scene(string $name) static 设置验证场景
+ * @method bool hasScene(string $name) static 判断是否存在某个验证场景
+ * @method \think\Validate batch(bool $batch = true) static 设置批量验证
+ * @method \think\Validate only(array $fields) static 指定需要验证的字段列表
+ * @method \think\Validate remove(mixed $field, mixed $rule = true) static 移除某个字段的验证规则
+ * @method \think\Validate append(mixed $field, mixed $rule = null) static 追加某个字段的验证规则
+ * @method bool confirm(mixed $value, mixed $rule, array $data = [], string $field = '') static 验证是否和某个字段的值一致
+ * @method bool different(mixed $value, mixed $rule, array $data = []) static 验证是否和某个字段的值是否不同
+ * @method bool egt(mixed $value, mixed $rule, array $data = []) static 验证是否大于等于某个值
+ * @method bool gt(mixed $value, mixed $rule, array $data = []) static 验证是否大于某个值
+ * @method bool elt(mixed $value, mixed $rule, array $data = []) static 验证是否小于等于某个值
+ * @method bool lt(mixed $value, mixed $rule, array $data = []) static 验证是否小于某个值
+ * @method bool eq(mixed $value, mixed $rule) static 验证是否等于某个值
+ * @method bool must(mixed $value, mixed $rule) static 必须验证
+ * @method bool is(mixed $value, mixed $rule, array $data = []) static 验证字段值是否为有效格式
+ * @method bool ip(mixed $value, mixed $rule) static 验证是否有效IP
+ * @method bool requireIf(mixed $value, mixed $rule) static 验证某个字段等于某个值的时候必须
+ * @method bool requireCallback(mixed $value, mixed $rule,array $data) static 通过回调方法验证某个字段是否必须
+ * @method bool requireWith(mixed $value, mixed $rule, array $data) static 验证某个字段有值的情况下必须
+ * @method bool filter(mixed $value, mixed $rule) static 使用filter_var方式验证
+ * @method bool in(mixed $value, mixed $rule) static 验证是否在范围内
+ * @method bool notIn(mixed $value, mixed $rule) static 验证是否不在范围内
+ * @method bool between(mixed $value, mixed $rule) static between验证数据
+ * @method bool notBetween(mixed $value, mixed $rule) static 使用notbetween验证数据
+ * @method bool length(mixed $value, mixed $rule) static 验证数据长度
+ * @method bool max(mixed $value, mixed $rule) static 验证数据最大长度
+ * @method bool min(mixed $value, mixed $rule) static 验证数据最小长度
+ * @method bool after(mixed $value, mixed $rule) static 验证日期
+ * @method bool before(mixed $value, mixed $rule) static 验证日期
+ * @method bool expire(mixed $value, mixed $rule) static 验证有效期
+ * @method bool allowIp(mixed $value, mixed $rule) static 验证IP许可
+ * @method bool denyIp(mixed $value, mixed $rule) static 验证IP禁用
+ * @method bool regex(mixed $value, mixed $rule) static 使用正则验证数据
+ * @method bool token(mixed $value, mixed $rule) static 验证表单令牌
+ * @method bool dateFormat(mixed $value, mixed $rule) static 验证时间和日期是否符合指定格式
+ * @method bool unique(mixed $value, mixed $rule, array $data = [], string $field = '') static 验证是否唯一
+ * @method bool check(array $data, mixed $rules = [], string $scene = '') static 数据自动验证
+ * @method mixed getError(mixed $value, mixed $rule) static 获取错误信息
+ */
+class Validate extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'validate';
+ }
+
+}
diff --git a/Server/thinkphp/library/think/facade/View.php b/Server/thinkphp/library/think/facade/View.php
new file mode 100644
index 00000000..08433917
--- /dev/null
+++ b/Server/thinkphp/library/think/facade/View.php
@@ -0,0 +1,40 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\facade;
+
+use think\Facade;
+
+/**
+ * @see \think\View
+ * @mixin \think\View
+ * @method \think\View init(mixed $engine = [], array $replace = []) static 初始化
+ * @method \think\View share(mixed $name, mixed $value = '') static 模板变量静态赋值
+ * @method \think\View assign(mixed $name, mixed $value = '') static 模板变量赋值
+ * @method \think\View config(mixed $name, mixed $value = '') static 配置模板引擎
+ * @method \think\View exists(mixed $name) static 检查模板是否存在
+ * @method \think\View filter(Callable $filter) static 视图内容过滤
+ * @method \think\View engine(mixed $engine = []) static 设置当前模板解析的引擎
+ * @method string fetch(string $template = '', array $vars = [], array $config = [], bool $renderContent = false) static 解析和获取模板内容
+ * @method string display(string $content = '', array $vars = [], array $config = []) static 渲染内容输出
+ */
+class View extends Facade
+{
+ /**
+ * 获取当前Facade对应类名(或者已经绑定的容器对象标识)
+ * @access protected
+ * @return string
+ */
+ protected static function getFacadeClass()
+ {
+ return 'view';
+ }
+}
diff --git a/Server/thinkphp/library/think/model/concern/Attribute.php b/Server/thinkphp/library/think/model/concern/Attribute.php
new file mode 100644
index 00000000..66627b38
--- /dev/null
+++ b/Server/thinkphp/library/think/model/concern/Attribute.php
@@ -0,0 +1,656 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\model\concern;
+
+use InvalidArgumentException;
+use think\db\Expression;
+use think\Exception;
+use think\Loader;
+use think\model\Relation;
+
+trait Attribute
+{
+ /**
+ * 数据表主键 复合主键使用数组定义
+ * @var string|array
+ */
+ protected $pk = 'id';
+
+ /**
+ * 数据表字段信息 留空则自动获取
+ * @var array
+ */
+ protected $field = [];
+
+ /**
+ * JSON数据表字段
+ * @var array
+ */
+ protected $json = [];
+
+ /**
+ * JSON数据取出是否需要转换为数组
+ * @var bool
+ */
+ protected $jsonAssoc = false;
+
+ /**
+ * JSON数据表字段类型
+ * @var array
+ */
+ protected $jsonType = [];
+
+ /**
+ * 数据表废弃字段
+ * @var array
+ */
+ protected $disuse = [];
+
+ /**
+ * 数据表只读字段
+ * @var array
+ */
+ protected $readonly = [];
+
+ /**
+ * 数据表字段类型
+ * @var array
+ */
+ protected $type = [];
+
+ /**
+ * 当前模型数据
+ * @var array
+ */
+ private $data = [];
+
+ /**
+ * 修改器执行记录
+ * @var array
+ */
+ private $set = [];
+
+ /**
+ * 原始数据
+ * @var array
+ */
+ private $origin = [];
+
+ /**
+ * 动态获取器
+ * @var array
+ */
+ private $withAttr = [];
+
+ /**
+ * 获取模型对象的主键
+ * @access public
+ * @return string|array
+ */
+ public function getPk()
+ {
+ return $this->pk;
+ }
+
+ /**
+ * 判断一个字段名是否为主键字段
+ * @access public
+ * @param string $key 名称
+ * @return bool
+ */
+ protected function isPk($key)
+ {
+ $pk = $this->getPk();
+ if (is_string($pk) && $pk == $key) {
+ return true;
+ } elseif (is_array($pk) && in_array($key, $pk)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 获取模型对象的主键值
+ * @access public
+ * @return integer
+ */
+ public function getKey()
+ {
+ $pk = $this->getPk();
+ if (is_string($pk) && array_key_exists($pk, $this->data)) {
+ return $this->data[$pk];
+ }
+
+ return;
+ }
+
+ /**
+ * 设置允许写入的字段
+ * @access public
+ * @param array|string|true $field 允许写入的字段 如果为true只允许写入数据表字段
+ * @return $this
+ */
+ public function allowField($field)
+ {
+ if (is_string($field)) {
+ $field = explode(',', $field);
+ }
+
+ $this->field = $field;
+
+ return $this;
+ }
+
+ /**
+ * 设置只读字段
+ * @access public
+ * @param array|string $field 只读字段
+ * @return $this
+ */
+ public function readonly($field)
+ {
+ if (is_string($field)) {
+ $field = explode(',', $field);
+ }
+
+ $this->readonly = $field;
+
+ return $this;
+ }
+
+ /**
+ * 设置数据对象值
+ * @access public
+ * @param mixed $data 数据或者属性名
+ * @param mixed $value 值
+ * @return $this
+ */
+ public function data($data, $value = null)
+ {
+ if (is_string($data)) {
+ $this->data[$data] = $value;
+ return $this;
+ }
+
+ // 清空数据
+ $this->data = [];
+
+ if (is_object($data)) {
+ $data = get_object_vars($data);
+ }
+
+ if ($this->disuse) {
+ // 废弃字段
+ foreach ((array) $this->disuse as $key) {
+ if (array_key_exists($key, $data)) {
+ unset($data[$key]);
+ }
+ }
+ }
+
+ if (true === $value) {
+ // 数据对象赋值
+ foreach ($data as $key => $value) {
+ $this->setAttr($key, $value, $data);
+ }
+ } elseif (is_array($value)) {
+ foreach ($value as $name) {
+ if (isset($data[$name])) {
+ $this->data[$name] = $data[$name];
+ }
+ }
+ } else {
+ $this->data = $data;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 批量设置数据对象值
+ * @access public
+ * @param mixed $data 数据
+ * @param bool $set 是否需要进行数据处理
+ * @return $this
+ */
+ public function appendData($data, $set = false)
+ {
+ if ($set) {
+ // 进行数据处理
+ foreach ($data as $key => $value) {
+ $this->setAttr($key, $value, $data);
+ }
+ } else {
+ if (is_object($data)) {
+ $data = get_object_vars($data);
+ }
+
+ $this->data = array_merge($this->data, $data);
+ }
+
+ return $this;
+ }
+
+ /**
+ * 获取对象原始数据 如果不存在指定字段返回null
+ * @access public
+ * @param string $name 字段名 留空获取全部
+ * @return mixed
+ */
+ public function getOrigin($name = null)
+ {
+ if (is_null($name)) {
+ return $this->origin;
+ }
+ return array_key_exists($name, $this->origin) ? $this->origin[$name] : null;
+ }
+
+ /**
+ * 获取对象原始数据 如果不存在指定字段返回false
+ * @access public
+ * @param string $name 字段名 留空获取全部
+ * @return mixed
+ * @throws InvalidArgumentException
+ */
+ public function getData($name = null)
+ {
+ if (is_null($name)) {
+ return $this->data;
+ } elseif (array_key_exists($name, $this->data)) {
+ return $this->data[$name];
+ } elseif (array_key_exists($name, $this->relation)) {
+ return $this->relation[$name];
+ }
+ throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);
+ }
+
+ /**
+ * 获取变化的数据 并排除只读数据
+ * @access public
+ * @return array
+ */
+ public function getChangedData()
+ {
+ if ($this->force) {
+ $data = $this->data;
+ } else {
+ $data = array_udiff_assoc($this->data, $this->origin, function ($a, $b) {
+ if ((empty($a) || empty($b)) && $a !== $b) {
+ return 1;
+ }
+
+ return is_object($a) || $a != $b ? 1 : 0;
+ });
+ }
+
+ if (!empty($this->readonly)) {
+ // 只读字段不允许更新
+ foreach ($this->readonly as $key => $field) {
+ if (isset($data[$field])) {
+ unset($data[$field]);
+ }
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * 修改器 设置数据对象值
+ * @access public
+ * @param string $name 属性名
+ * @param mixed $value 属性值
+ * @param array $data 数据
+ * @return void
+ */
+ public function setAttr($name, $value, $data = [])
+ {
+ if (isset($this->set[$name])) {
+ return;
+ }
+
+ if (is_null($value) && $this->autoWriteTimestamp && in_array($name, [$this->createTime, $this->updateTime])) {
+ // 自动写入的时间戳字段
+ $value = $this->autoWriteTimestamp($name);
+ } else {
+ // 检测修改器
+ $method = 'set' . Loader::parseName($name, 1) . 'Attr';
+
+ if (method_exists($this, $method)) {
+ $origin = $this->data;
+ $value = $this->$method($value, array_merge($this->data, $data));
+
+ $this->set[$name] = true;
+ if (is_null($value) && $origin !== $this->data) {
+ return;
+ }
+ } elseif (isset($this->type[$name])) {
+ // 类型转换
+ $value = $this->writeTransform($value, $this->type[$name]);
+ }
+ }
+
+ // 设置数据对象属性
+ $this->data[$name] = $value;
+ }
+
+ /**
+ * 是否需要自动写入时间字段
+ * @access public
+ * @param bool $auto
+ * @return $this
+ */
+ public function isAutoWriteTimestamp($auto)
+ {
+ $this->autoWriteTimestamp = $auto;
+
+ return $this;
+ }
+
+ /**
+ * 自动写入时间戳
+ * @access protected
+ * @param string $name 时间戳字段
+ * @return mixed
+ */
+ protected function autoWriteTimestamp($name)
+ {
+ if (isset($this->type[$name])) {
+ $type = $this->type[$name];
+
+ if (strpos($type, ':')) {
+ list($type, $param) = explode(':', $type, 2);
+ }
+
+ switch ($type) {
+ case 'datetime':
+ case 'date':
+ $value = $this->formatDateTime('Y-m-d H:i:s.u');
+ break;
+ case 'timestamp':
+ case 'integer':
+ default:
+ $value = time();
+ break;
+ }
+ } elseif (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
+ 'datetime',
+ 'date',
+ 'timestamp',
+ ])) {
+ $value = $this->formatDateTime('Y-m-d H:i:s.u');
+ } else {
+ $value = time();
+ }
+
+ return $value;
+ }
+
+ /**
+ * 数据写入 类型转换
+ * @access protected
+ * @param mixed $value 值
+ * @param string|array $type 要转换的类型
+ * @return mixed
+ */
+ protected function writeTransform($value, $type)
+ {
+ if (is_null($value)) {
+ return;
+ }
+
+ if ($value instanceof Expression) {
+ return $value;
+ }
+
+ if (is_array($type)) {
+ list($type, $param) = $type;
+ } elseif (strpos($type, ':')) {
+ list($type, $param) = explode(':', $type, 2);
+ }
+
+ switch ($type) {
+ case 'integer':
+ $value = (int) $value;
+ break;
+ case 'float':
+ if (empty($param)) {
+ $value = (float) $value;
+ } else {
+ $value = (float) number_format($value, $param, '.', '');
+ }
+ break;
+ case 'boolean':
+ $value = (bool) $value;
+ break;
+ case 'timestamp':
+ if (!is_numeric($value)) {
+ $value = strtotime($value);
+ }
+ break;
+ case 'datetime':
+ $value = is_numeric($value) ? $value : strtotime($value);
+ $value = $this->formatDateTime('Y-m-d H:i:s.u', $value);
+ break;
+ case 'object':
+ if (is_object($value)) {
+ $value = json_encode($value, JSON_FORCE_OBJECT);
+ }
+ break;
+ case 'array':
+ $value = (array) $value;
+ case 'json':
+ $option = !empty($param) ? (int) $param : JSON_UNESCAPED_UNICODE;
+ $value = json_encode($value, $option);
+ break;
+ case 'serialize':
+ $value = serialize($value);
+ break;
+ }
+
+ return $value;
+ }
+
+ /**
+ * 获取器 获取数据对象的值
+ * @access public
+ * @param string $name 名称
+ * @param array $item 数据
+ * @return mixed
+ * @throws InvalidArgumentException
+ */
+ public function getAttr($name, &$item = null)
+ {
+ try {
+ $notFound = false;
+ $value = $this->getData($name);
+ } catch (InvalidArgumentException $e) {
+ $notFound = true;
+ $value = null;
+ }
+
+ // 检测属性获取器
+ $fieldName = Loader::parseName($name);
+ $method = 'get' . Loader::parseName($name, 1) . 'Attr';
+
+ if (isset($this->withAttr[$fieldName])) {
+ if ($notFound && $relation = $this->isRelationAttr($name)) {
+ $modelRelation = $this->$relation();
+ $value = $this->getRelationData($modelRelation);
+ }
+
+ $closure = $this->withAttr[$fieldName];
+ $value = $closure($value, $this->data);
+ } elseif (method_exists($this, $method)) {
+ if ($notFound && $relation = $this->isRelationAttr($name)) {
+ $modelRelation = $this->$relation();
+ $value = $this->getRelationData($modelRelation);
+ }
+
+ $value = $this->$method($value, $this->data);
+ } elseif (isset($this->type[$name])) {
+ // 类型转换
+ $value = $this->readTransform($value, $this->type[$name]);
+ } elseif ($this->autoWriteTimestamp && in_array($name, [$this->createTime, $this->updateTime])) {
+ if (is_string($this->autoWriteTimestamp) && in_array(strtolower($this->autoWriteTimestamp), [
+ 'datetime',
+ 'date',
+ 'timestamp',
+ ])) {
+ $value = $this->formatDateTime($this->dateFormat, $value);
+ } else {
+ $value = $this->formatDateTime($this->dateFormat, $value, true);
+ }
+ } elseif ($notFound) {
+ $value = $this->getRelationAttribute($name, $item);
+ }
+
+ return $value;
+ }
+
+ /**
+ * 获取关联属性值
+ * @access protected
+ * @param string $name 属性名
+ * @param array $item 数据
+ * @return mixed
+ */
+ protected function getRelationAttribute($name, &$item)
+ {
+ $relation = $this->isRelationAttr($name);
+
+ if ($relation) {
+ $modelRelation = $this->$relation();
+ if ($modelRelation instanceof Relation) {
+ $value = $this->getRelationData($modelRelation);
+
+ if ($item && method_exists($modelRelation, 'getBindAttr') && $bindAttr = $modelRelation->getBindAttr()) {
+
+ foreach ($bindAttr as $key => $attr) {
+ $key = is_numeric($key) ? $attr : $key;
+
+ if (isset($item[$key])) {
+ throw new Exception('bind attr has exists:' . $key);
+ } else {
+ $item[$key] = $value ? $value->getAttr($attr) : null;
+ }
+ }
+
+ return false;
+ }
+
+ // 保存关联对象值
+ $this->relation[$name] = $value;
+
+ return $value;
+ }
+ }
+
+ throw new InvalidArgumentException('property not exists:' . static::class . '->' . $name);
+ }
+
+ /**
+ * 数据读取 类型转换
+ * @access protected
+ * @param mixed $value 值
+ * @param string|array $type 要转换的类型
+ * @return mixed
+ */
+ protected function readTransform($value, $type)
+ {
+ if (is_null($value)) {
+ return;
+ }
+
+ if (is_array($type)) {
+ list($type, $param) = $type;
+ } elseif (strpos($type, ':')) {
+ list($type, $param) = explode(':', $type, 2);
+ }
+
+ switch ($type) {
+ case 'integer':
+ $value = (int) $value;
+ break;
+ case 'float':
+ if (empty($param)) {
+ $value = (float) $value;
+ } else {
+ $value = (float) number_format($value, $param, '.', '');
+ }
+ break;
+ case 'boolean':
+ $value = (bool) $value;
+ break;
+ case 'timestamp':
+ if (!is_null($value)) {
+ $format = !empty($param) ? $param : $this->dateFormat;
+ $value = $this->formatDateTime($format, $value, true);
+ }
+ break;
+ case 'datetime':
+ if (!is_null($value)) {
+ $format = !empty($param) ? $param : $this->dateFormat;
+ $value = $this->formatDateTime($format, $value);
+ }
+ break;
+ case 'json':
+ $value = json_decode($value, true);
+ break;
+ case 'array':
+ $value = empty($value) ? [] : json_decode($value, true);
+ break;
+ case 'object':
+ $value = empty($value) ? new \stdClass() : json_decode($value);
+ break;
+ case 'serialize':
+ try {
+ $value = unserialize($value);
+ } catch (\Exception $e) {
+ $value = null;
+ }
+ break;
+ default:
+ if (false !== strpos($type, '\\')) {
+ // 对象类型
+ $value = new $type($value);
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * 设置数据字段获取器
+ * @access public
+ * @param string|array $name 字段名
+ * @param callable $callback 闭包获取器
+ * @return $this
+ */
+ public function withAttribute($name, $callback = null)
+ {
+ if (is_array($name)) {
+ foreach ($name as $key => $val) {
+ $key = Loader::parseName($key);
+
+ $this->withAttr[$key] = $val;
+ }
+ } else {
+ $name = Loader::parseName($name);
+
+ $this->withAttr[$name] = $callback;
+ }
+
+ return $this;
+ }
+}
diff --git a/Server/thinkphp/library/think/model/concern/Conversion.php b/Server/thinkphp/library/think/model/concern/Conversion.php
new file mode 100644
index 00000000..de4db931
--- /dev/null
+++ b/Server/thinkphp/library/think/model/concern/Conversion.php
@@ -0,0 +1,273 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\model\concern;
+
+use think\Collection;
+use think\Exception;
+use think\Loader;
+use think\Model;
+use think\model\Collection as ModelCollection;
+
+/**
+ * 模型数据转换处理
+ */
+trait Conversion
+{
+ /**
+ * 数据输出显示的属性
+ * @var array
+ */
+ protected $visible = [];
+
+ /**
+ * 数据输出隐藏的属性
+ * @var array
+ */
+ protected $hidden = [];
+
+ /**
+ * 数据输出需要追加的属性
+ * @var array
+ */
+ protected $append = [];
+
+ /**
+ * 数据集对象名
+ * @var string
+ */
+ protected $resultSetType;
+
+ /**
+ * 设置需要附加的输出属性
+ * @access public
+ * @param array $append 属性列表
+ * @param bool $override 是否覆盖
+ * @return $this
+ */
+ public function append(array $append = [], $override = false)
+ {
+ $this->append = $override ? $append : array_merge($this->append, $append);
+
+ return $this;
+ }
+
+ /**
+ * 设置附加关联对象的属性
+ * @access public
+ * @param string $attr 关联属性
+ * @param string|array $append 追加属性名
+ * @return $this
+ * @throws Exception
+ */
+ public function appendRelationAttr($attr, $append)
+ {
+ if (is_string($append)) {
+ $append = explode(',', $append);
+ }
+
+ $relation = Loader::parseName($attr, 1, false);
+ if (isset($this->relation[$relation])) {
+ $model = $this->relation[$relation];
+ } else {
+ $model = $this->getRelationData($this->$relation());
+ }
+
+ if ($model instanceof Model) {
+ foreach ($append as $key => $attr) {
+ $key = is_numeric($key) ? $attr : $key;
+ if (isset($this->data[$key])) {
+ throw new Exception('bind attr has exists:' . $key);
+ } else {
+ $this->data[$key] = $model->getAttr($attr);
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * 设置需要隐藏的输出属性
+ * @access public
+ * @param array $hidden 属性列表
+ * @param bool $override 是否覆盖
+ * @return $this
+ */
+ public function hidden(array $hidden = [], $override = false)
+ {
+ $this->hidden = $override ? $hidden : array_merge($this->hidden, $hidden);
+
+ return $this;
+ }
+
+ /**
+ * 设置需要输出的属性
+ * @access public
+ * @param array $visible
+ * @param bool $override 是否覆盖
+ * @return $this
+ */
+ public function visible(array $visible = [], $override = false)
+ {
+ $this->visible = $override ? $visible : array_merge($this->visible, $visible);
+
+ return $this;
+ }
+
+ /**
+ * 转换当前模型对象为数组
+ * @access public
+ * @return array
+ */
+ public function toArray()
+ {
+ $item = [];
+ $hasVisible = false;
+
+ foreach ($this->visible as $key => $val) {
+ if (is_string($val)) {
+ if (strpos($val, '.')) {
+ list($relation, $name) = explode('.', $val);
+ $this->visible[$relation][] = $name;
+ } else {
+ $this->visible[$val] = true;
+ $hasVisible = true;
+ }
+ unset($this->visible[$key]);
+ }
+ }
+
+ foreach ($this->hidden as $key => $val) {
+ if (is_string($val)) {
+ if (strpos($val, '.')) {
+ list($relation, $name) = explode('.', $val);
+ $this->hidden[$relation][] = $name;
+ } else {
+ $this->hidden[$val] = true;
+ }
+ unset($this->hidden[$key]);
+ }
+ }
+
+ // 合并关联数据
+ $data = array_merge($this->data, $this->relation);
+
+ foreach ($data as $key => $val) {
+ if ($val instanceof Model || $val instanceof ModelCollection) {
+ // 关联模型对象
+ if (isset($this->visible[$key]) && is_array($this->visible[$key])) {
+ $val->visible($this->visible[$key]);
+ } elseif (isset($this->hidden[$key]) && is_array($this->hidden[$key])) {
+ $val->hidden($this->hidden[$key]);
+ }
+ // 关联模型对象
+ if (!isset($this->hidden[$key]) || true !== $this->hidden[$key]) {
+ $item[$key] = $val->toArray();
+ }
+ } elseif (isset($this->visible[$key])) {
+ $item[$key] = $this->getAttr($key);
+ } elseif (!isset($this->hidden[$key]) && !$hasVisible) {
+ $item[$key] = $this->getAttr($key);
+ }
+ }
+
+ // 追加属性(必须定义获取器)
+ if (!empty($this->append)) {
+ foreach ($this->append as $key => $name) {
+ if (is_array($name)) {
+ // 追加关联对象属性
+ $relation = $this->getRelation($key);
+
+ if (!$relation) {
+ $relation = $this->getAttr($key);
+ if ($relation) {
+ $relation->visible($name);
+ }
+ }
+
+ $item[$key] = $relation ? $relation->append($name)->toArray() : [];
+ } elseif (strpos($name, '.')) {
+ list($key, $attr) = explode('.', $name);
+ // 追加关联对象属性
+ $relation = $this->getRelation($key);
+
+ if (!$relation) {
+ $relation = $this->getAttr($key);
+ if ($relation) {
+ $relation->visible([$attr]);
+ }
+ }
+
+ $item[$key] = $relation ? $relation->append([$attr])->toArray() : [];
+ } else {
+ $item[$name] = $this->getAttr($name, $item);
+ }
+ }
+ }
+
+ return $item;
+ }
+
+ /**
+ * 转换当前模型对象为JSON字符串
+ * @access public
+ * @param integer $options json参数
+ * @return string
+ */
+ public function toJson($options = JSON_UNESCAPED_UNICODE)
+ {
+ return json_encode($this->toArray(), $options);
+ }
+
+ /**
+ * 移除当前模型的关联属性
+ * @access public
+ * @return $this
+ */
+ public function removeRelation()
+ {
+ $this->relation = [];
+ return $this;
+ }
+
+ public function __toString()
+ {
+ return $this->toJson();
+ }
+
+ // JsonSerializable
+ public function jsonSerialize()
+ {
+ return $this->toArray();
+ }
+
+ /**
+ * 转换数据集为数据集对象
+ * @access public
+ * @param array|Collection $collection 数据集
+ * @param string $resultSetType 数据集类
+ * @return Collection
+ */
+ public function toCollection($collection, $resultSetType = null)
+ {
+ $resultSetType = $resultSetType ?: $this->resultSetType;
+
+ if ($resultSetType && false !== strpos($resultSetType, '\\')) {
+ $collection = new $resultSetType($collection);
+ } else {
+ $collection = new ModelCollection($collection);
+ }
+
+ return $collection;
+ }
+
+}
diff --git a/Server/thinkphp/library/think/model/concern/ModelEvent.php b/Server/thinkphp/library/think/model/concern/ModelEvent.php
new file mode 100644
index 00000000..3a874846
--- /dev/null
+++ b/Server/thinkphp/library/think/model/concern/ModelEvent.php
@@ -0,0 +1,238 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\model\concern;
+
+use think\Container;
+use think\Loader;
+
+/**
+ * 模型事件处理
+ */
+trait ModelEvent
+{
+ /**
+ * 模型回调
+ * @var array
+ */
+ private static $event = [];
+
+ /**
+ * 模型事件观察
+ * @var array
+ */
+ protected static $observe = ['before_write', 'after_write', 'before_insert', 'after_insert', 'before_update', 'after_update', 'before_delete', 'after_delete', 'before_restore', 'after_restore'];
+
+ /**
+ * 绑定模型事件观察者类
+ * @var array
+ */
+ protected $observerClass;
+
+ /**
+ * 是否需要事件响应
+ * @var bool
+ */
+ private $withEvent = true;
+
+ /**
+ * 注册回调方法
+ * @access public
+ * @param string $event 事件名
+ * @param callable $callback 回调方法
+ * @param bool $override 是否覆盖
+ * @return void
+ */
+ public static function event($event, $callback, $override = false)
+ {
+ $class = static::class;
+
+ if ($override) {
+ self::$event[$class][$event] = [];
+ }
+
+ self::$event[$class][$event][] = $callback;
+ }
+
+ /**
+ * 清除回调方法
+ * @access public
+ * @return void
+ */
+ public static function flushEvent()
+ {
+ self::$event[static::class] = [];
+ }
+
+ /**
+ * 注册一个模型观察者
+ *
+ * @param object|string $class
+ * @return void
+ */
+ public static function observe($class)
+ {
+ self::flushEvent();
+
+ foreach (static::$observe as $event) {
+ $eventFuncName = Loader::parseName($event, 1, false);
+
+ if (method_exists($class, $eventFuncName)) {
+ static::event($event, [$class, $eventFuncName]);
+ }
+ }
+ }
+
+ /**
+ * 当前操作的事件响应
+ * @access protected
+ * @param bool $event 是否需要事件响应
+ * @return $this
+ */
+ public function withEvent($event)
+ {
+ $this->withEvent = $event;
+ return $this;
+ }
+
+ /**
+ * 触发事件
+ * @access protected
+ * @param string $event 事件名
+ * @return bool
+ */
+ protected function trigger($event)
+ {
+ $class = static::class;
+
+ if ($this->withEvent && isset(self::$event[$class][$event])) {
+ foreach (self::$event[$class][$event] as $callback) {
+ $result = Container::getInstance()->invoke($callback, [$this]);
+
+ if (false === $result) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 模型before_insert事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function beforeInsert($callback, $override = false)
+ {
+ self::event('before_insert', $callback, $override);
+ }
+
+ /**
+ * 模型after_insert事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function afterInsert($callback, $override = false)
+ {
+ self::event('after_insert', $callback, $override);
+ }
+
+ /**
+ * 模型before_update事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function beforeUpdate($callback, $override = false)
+ {
+ self::event('before_update', $callback, $override);
+ }
+
+ /**
+ * 模型after_update事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function afterUpdate($callback, $override = false)
+ {
+ self::event('after_update', $callback, $override);
+ }
+
+ /**
+ * 模型before_write事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function beforeWrite($callback, $override = false)
+ {
+ self::event('before_write', $callback, $override);
+ }
+
+ /**
+ * 模型after_write事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function afterWrite($callback, $override = false)
+ {
+ self::event('after_write', $callback, $override);
+ }
+
+ /**
+ * 模型before_delete事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function beforeDelete($callback, $override = false)
+ {
+ self::event('before_delete', $callback, $override);
+ }
+
+ /**
+ * 模型after_delete事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function afterDelete($callback, $override = false)
+ {
+ self::event('after_delete', $callback, $override);
+ }
+
+ /**
+ * 模型before_restore事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function beforeRestore($callback, $override = false)
+ {
+ self::event('before_restore', $callback, $override);
+ }
+
+ /**
+ * 模型after_restore事件快捷方法
+ * @access protected
+ * @param callable $callback
+ * @param bool $override
+ */
+ protected static function afterRestore($callback, $override = false)
+ {
+ self::event('after_restore', $callback, $override);
+ }
+}
diff --git a/Server/thinkphp/library/think/model/concern/RelationShip.php b/Server/thinkphp/library/think/model/concern/RelationShip.php
new file mode 100644
index 00000000..48579b70
--- /dev/null
+++ b/Server/thinkphp/library/think/model/concern/RelationShip.php
@@ -0,0 +1,697 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\model\concern;
+
+use think\Collection;
+use think\db\Query;
+use think\Exception;
+use think\Loader;
+use think\Model;
+use think\model\Relation;
+use think\model\relation\BelongsTo;
+use think\model\relation\BelongsToMany;
+use think\model\relation\HasMany;
+use think\model\relation\HasManyThrough;
+use think\model\relation\HasOne;
+use think\model\relation\MorphMany;
+use think\model\relation\MorphOne;
+use think\model\relation\MorphTo;
+
+/**
+ * 模型关联处理
+ */
+trait RelationShip
+{
+ /**
+ * 父关联模型对象
+ * @var object
+ */
+ private $parent;
+
+ /**
+ * 模型关联数据
+ * @var array
+ */
+ private $relation = [];
+
+ /**
+ * 关联写入定义信息
+ * @var array
+ */
+ private $together;
+
+ /**
+ * 关联自动写入信息
+ * @var array
+ */
+ protected $relationWrite;
+
+ /**
+ * 设置父关联对象
+ * @access public
+ * @param Model $model 模型对象
+ * @return $this
+ */
+ public function setParent($model)
+ {
+ $this->parent = $model;
+
+ return $this;
+ }
+
+ /**
+ * 获取父关联对象
+ * @access public
+ * @return Model
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * 获取当前模型的关联模型数据
+ * @access public
+ * @param string $name 关联方法名
+ * @return mixed
+ */
+ public function getRelation($name = null)
+ {
+ if (is_null($name)) {
+ return $this->relation;
+ } elseif (array_key_exists($name, $this->relation)) {
+ return $this->relation[$name];
+ }
+ return;
+ }
+
+ /**
+ * 设置关联数据对象值
+ * @access public
+ * @param string $name 属性名
+ * @param mixed $value 属性值
+ * @param array $data 数据
+ * @return $this
+ */
+ public function setRelation($name, $value, $data = [])
+ {
+ // 检测修改器
+ $method = 'set' . Loader::parseName($name, 1) . 'Attr';
+
+ if (method_exists($this, $method)) {
+ $value = $this->$method($value, array_merge($this->data, $data));
+ }
+
+ $this->relation[$name] = $value;
+
+ return $this;
+ }
+
+ /**
+ * 绑定(一对一)关联属性到当前模型
+ * @access protected
+ * @param string $relation 关联名称
+ * @param array $attrs 绑定属性
+ * @return $this
+ * @throws Exception
+ */
+ public function bindAttr($relation, array $attrs = [])
+ {
+ $relation = $this->getRelation($relation);
+
+ foreach ($attrs as $key => $attr) {
+ $key = is_numeric($key) ? $attr : $key;
+ $value = $this->getOrigin($key);
+
+ if (!is_null($value)) {
+ throw new Exception('bind attr has exists:' . $key);
+ }
+
+ $this->setAttr($key, $relation ? $relation->getAttr($attr) : null);
+ }
+
+ return $this;
+ }
+
+ /**
+ * 关联数据写入
+ * @access public
+ * @param array|string $relation 关联
+ * @return $this
+ */
+ public function together($relation)
+ {
+ if (is_string($relation)) {
+ $relation = explode(',', $relation);
+ }
+
+ $this->together = $relation;
+
+ $this->checkAutoRelationWrite();
+
+ return $this;
+ }
+
+ /**
+ * 根据关联条件查询当前模型
+ * @access public
+ * @param string $relation 关联方法名
+ * @param mixed $operator 比较操作符
+ * @param integer $count 个数
+ * @param string $id 关联表的统计字段
+ * @param string $joinType JOIN类型
+ * @return Query
+ */
+ public static function has($relation, $operator = '>=', $count = 1, $id = '*', $joinType = 'INNER')
+ {
+ $relation = (new static())->$relation();
+
+ if (is_array($operator) || $operator instanceof \Closure) {
+ return $relation->hasWhere($operator);
+ }
+
+ return $relation->has($operator, $count, $id, $joinType);
+ }
+
+ /**
+ * 根据关联条件查询当前模型
+ * @access public
+ * @param string $relation 关联方法名
+ * @param mixed $where 查询条件(数组或者闭包)
+ * @param mixed $fields 字段
+ * @return Query
+ */
+ public static function hasWhere($relation, $where = [], $fields = '*')
+ {
+ return (new static())->$relation()->hasWhere($where, $fields);
+ }
+
+ /**
+ * 查询当前模型的关联数据
+ * @access public
+ * @param string|array $relations 关联名
+ * @param array $withRelationAttr 关联获取器
+ * @return $this
+ */
+ public function relationQuery($relations, $withRelationAttr = [])
+ {
+ if (is_string($relations)) {
+ $relations = explode(',', $relations);
+ }
+
+ foreach ($relations as $key => $relation) {
+ $subRelation = '';
+ $closure = null;
+
+ if ($relation instanceof \Closure) {
+ // 支持闭包查询过滤关联条件
+ $closure = $relation;
+ $relation = $key;
+ }
+
+ if (is_array($relation)) {
+ $subRelation = $relation;
+ $relation = $key;
+ } elseif (strpos($relation, '.')) {
+ list($relation, $subRelation) = explode('.', $relation, 2);
+ }
+
+ $method = Loader::parseName($relation, 1, false);
+ $relationName = Loader::parseName($relation);
+
+ $relationResult = $this->$method();
+
+ if (isset($withRelationAttr[$relationName])) {
+ $relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
+ }
+
+ $this->relation[$relation] = $relationResult->getRelation($subRelation, $closure);
+ }
+
+ return $this;
+ }
+
+ /**
+ * 预载入关联查询 返回数据集
+ * @access public
+ * @param array $resultSet 数据集
+ * @param string $relation 关联名
+ * @param array $withRelationAttr 关联获取器
+ * @param bool $join 是否为JOIN方式
+ * @return array
+ */
+ public function eagerlyResultSet(&$resultSet, $relation, $withRelationAttr = [], $join = false)
+ {
+ $relations = is_string($relation) ? explode(',', $relation) : $relation;
+
+ foreach ($relations as $key => $relation) {
+ $subRelation = '';
+ $closure = null;
+
+ if ($relation instanceof \Closure) {
+ $closure = $relation;
+ $relation = $key;
+ }
+
+ if (is_array($relation)) {
+ $subRelation = $relation;
+ $relation = $key;
+ } elseif (strpos($relation, '.')) {
+ list($relation, $subRelation) = explode('.', $relation, 2);
+ }
+
+ $relation = Loader::parseName($relation, 1, false);
+ $relationName = Loader::parseName($relation);
+
+ $relationResult = $this->$relation();
+
+ if (isset($withRelationAttr[$relationName])) {
+ $relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
+ }
+
+ $relationResult->eagerlyResultSet($resultSet, $relation, $subRelation, $closure, $join);
+ }
+ }
+
+ /**
+ * 预载入关联查询 返回模型对象
+ * @access public
+ * @param Model $result 数据对象
+ * @param string $relation 关联名
+ * @param array $withRelationAttr 关联获取器
+ * @param bool $join 是否为JOIN方式
+ * @return Model
+ */
+ public function eagerlyResult(&$result, $relation, $withRelationAttr = [], $join = false)
+ {
+ $relations = is_string($relation) ? explode(',', $relation) : $relation;
+
+ foreach ($relations as $key => $relation) {
+ $subRelation = '';
+ $closure = null;
+
+ if ($relation instanceof \Closure) {
+ $closure = $relation;
+ $relation = $key;
+ }
+
+ if (is_array($relation)) {
+ $subRelation = $relation;
+ $relation = $key;
+ } elseif (strpos($relation, '.')) {
+ list($relation, $subRelation) = explode('.', $relation, 2);
+ }
+
+ $relation = Loader::parseName($relation, 1, false);
+ $relationName = Loader::parseName($relation);
+
+ $relationResult = $this->$relation();
+
+ if (isset($withRelationAttr[$relationName])) {
+ $relationResult->getQuery()->withAttr($withRelationAttr[$relationName]);
+ }
+
+ $relationResult->eagerlyResult($result, $relation, $subRelation, $closure, $join);
+ }
+ }
+
+ /**
+ * 关联统计
+ * @access public
+ * @param Model $result 数据对象
+ * @param array $relations 关联名
+ * @param string $aggregate 聚合查询方法
+ * @param string $field 字段
+ * @return void
+ */
+ public function relationCount(&$result, $relations, $aggregate = 'sum', $field = '*')
+ {
+ foreach ($relations as $key => $relation) {
+ $closure = $name = null;
+
+ if ($relation instanceof \Closure) {
+ $closure = $relation;
+ $relation = $key;
+ } elseif (is_string($key)) {
+ $name = $relation;
+ $relation = $key;
+ }
+
+ $relation = Loader::parseName($relation, 1, false);
+
+ $count = $this->$relation()->relationCount($result, $closure, $aggregate, $field, $name);
+
+ if (empty($name)) {
+ $name = Loader::parseName($relation) . '_' . $aggregate;
+ }
+
+ $result->setAttr($name, $count);
+ }
+ }
+
+ /**
+ * HAS ONE 关联定义
+ * @access public
+ * @param string $model 模型名
+ * @param string $foreignKey 关联外键
+ * @param string $localKey 当前主键
+ * @return HasOne
+ */
+ public function hasOne($model, $foreignKey = '', $localKey = '')
+ {
+ // 记录当前关联信息
+ $model = $this->parseModel($model);
+ $localKey = $localKey ?: $this->getPk();
+ $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
+
+ return new HasOne($this, $model, $foreignKey, $localKey);
+ }
+
+ /**
+ * BELONGS TO 关联定义
+ * @access public
+ * @param string $model 模型名
+ * @param string $foreignKey 关联外键
+ * @param string $localKey 关联主键
+ * @return BelongsTo
+ */
+ public function belongsTo($model, $foreignKey = '', $localKey = '')
+ {
+ // 记录当前关联信息
+ $model = $this->parseModel($model);
+ $foreignKey = $foreignKey ?: $this->getForeignKey((new $model)->getName());
+ $localKey = $localKey ?: (new $model)->getPk();
+ $trace = debug_backtrace(false, 2);
+ $relation = Loader::parseName($trace[1]['function']);
+
+ return new BelongsTo($this, $model, $foreignKey, $localKey, $relation);
+ }
+
+ /**
+ * HAS MANY 关联定义
+ * @access public
+ * @param string $model 模型名
+ * @param string $foreignKey 关联外键
+ * @param string $localKey 当前主键
+ * @return HasMany
+ */
+ public function hasMany($model, $foreignKey = '', $localKey = '')
+ {
+ // 记录当前关联信息
+ $model = $this->parseModel($model);
+ $localKey = $localKey ?: $this->getPk();
+ $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
+
+ return new HasMany($this, $model, $foreignKey, $localKey);
+ }
+
+ /**
+ * HAS MANY 远程关联定义
+ * @access public
+ * @param string $model 模型名
+ * @param string $through 中间模型名
+ * @param string $foreignKey 关联外键
+ * @param string $throughKey 关联外键
+ * @param string $localKey 当前主键
+ * @return HasManyThrough
+ */
+ public function hasManyThrough($model, $through, $foreignKey = '', $throughKey = '', $localKey = '')
+ {
+ // 记录当前关联信息
+ $model = $this->parseModel($model);
+ $through = $this->parseModel($through);
+ $localKey = $localKey ?: $this->getPk();
+ $foreignKey = $foreignKey ?: $this->getForeignKey($this->name);
+ $throughKey = $throughKey ?: $this->getForeignKey((new $through)->getName());
+
+ return new HasManyThrough($this, $model, $through, $foreignKey, $throughKey, $localKey);
+ }
+
+ /**
+ * BELONGS TO MANY 关联定义
+ * @access public
+ * @param string $model 模型名
+ * @param string $table 中间表名
+ * @param string $foreignKey 关联外键
+ * @param string $localKey 当前模型关联键
+ * @return BelongsToMany
+ */
+ public function belongsToMany($model, $table = '', $foreignKey = '', $localKey = '')
+ {
+ // 记录当前关联信息
+ $model = $this->parseModel($model);
+ $name = Loader::parseName(basename(str_replace('\\', '/', $model)));
+ $table = $table ?: Loader::parseName($this->name) . '_' . $name;
+ $foreignKey = $foreignKey ?: $name . '_id';
+ $localKey = $localKey ?: $this->getForeignKey($this->name);
+
+ return new BelongsToMany($this, $model, $table, $foreignKey, $localKey);
+ }
+
+ /**
+ * MORPH One 关联定义
+ * @access public
+ * @param string $model 模型名
+ * @param string|array $morph 多态字段信息
+ * @param string $type 多态类型
+ * @return MorphOne
+ */
+ public function morphOne($model, $morph = null, $type = '')
+ {
+ // 记录当前关联信息
+ $model = $this->parseModel($model);
+
+ if (is_null($morph)) {
+ $trace = debug_backtrace(false, 2);
+ $morph = Loader::parseName($trace[1]['function']);
+ }
+
+ if (is_array($morph)) {
+ list($morphType, $foreignKey) = $morph;
+ } else {
+ $morphType = $morph . '_type';
+ $foreignKey = $morph . '_id';
+ }
+
+ $type = $type ?: get_class($this);
+
+ return new MorphOne($this, $model, $foreignKey, $morphType, $type);
+ }
+
+ /**
+ * MORPH MANY 关联定义
+ * @access public
+ * @param string $model 模型名
+ * @param string|array $morph 多态字段信息
+ * @param string $type 多态类型
+ * @return MorphMany
+ */
+ public function morphMany($model, $morph = null, $type = '')
+ {
+ // 记录当前关联信息
+ $model = $this->parseModel($model);
+
+ if (is_null($morph)) {
+ $trace = debug_backtrace(false, 2);
+ $morph = Loader::parseName($trace[1]['function']);
+ }
+
+ $type = $type ?: get_class($this);
+
+ if (is_array($morph)) {
+ list($morphType, $foreignKey) = $morph;
+ } else {
+ $morphType = $morph . '_type';
+ $foreignKey = $morph . '_id';
+ }
+
+ return new MorphMany($this, $model, $foreignKey, $morphType, $type);
+ }
+
+ /**
+ * MORPH TO 关联定义
+ * @access public
+ * @param string|array $morph 多态字段信息
+ * @param array $alias 多态别名定义
+ * @return MorphTo
+ */
+ public function morphTo($morph = null, $alias = [])
+ {
+ $trace = debug_backtrace(false, 2);
+ $relation = Loader::parseName($trace[1]['function']);
+
+ if (is_null($morph)) {
+ $morph = $relation;
+ }
+
+ // 记录当前关联信息
+ if (is_array($morph)) {
+ list($morphType, $foreignKey) = $morph;
+ } else {
+ $morphType = $morph . '_type';
+ $foreignKey = $morph . '_id';
+ }
+
+ return new MorphTo($this, $morphType, $foreignKey, $alias, $relation);
+ }
+
+ /**
+ * 解析模型的完整命名空间
+ * @access protected
+ * @param string $model 模型名(或者完整类名)
+ * @return string
+ */
+ protected function parseModel($model)
+ {
+ if (false === strpos($model, '\\')) {
+ $path = explode('\\', static::class);
+ array_pop($path);
+ array_push($path, Loader::parseName($model, 1));
+ $model = implode('\\', $path);
+ }
+
+ return $model;
+ }
+
+ /**
+ * 获取模型的默认外键名
+ * @access protected
+ * @param string $name 模型名
+ * @return string
+ */
+ protected function getForeignKey($name)
+ {
+ if (strpos($name, '\\')) {
+ $name = basename(str_replace('\\', '/', $name));
+ }
+
+ return Loader::parseName($name) . '_id';
+ }
+
+ /**
+ * 检查属性是否为关联属性 如果是则返回关联方法名
+ * @access protected
+ * @param string $attr 关联属性名
+ * @return string|false
+ */
+ protected function isRelationAttr($attr)
+ {
+ $relation = Loader::parseName($attr, 1, false);
+
+ if (method_exists($this, $relation) && !method_exists('think\Model', $relation)) {
+ return $relation;
+ }
+
+ return false;
+ }
+
+ /**
+ * 智能获取关联模型数据
+ * @access protected
+ * @param Relation $modelRelation 模型关联对象
+ * @return mixed
+ */
+ protected function getRelationData(Relation $modelRelation)
+ {
+ if ($this->parent && !$modelRelation->isSelfRelation() && get_class($this->parent) == get_class($modelRelation->getModel())) {
+ $value = $this->parent;
+ } else {
+ // 获取关联数据
+ $value = $modelRelation->getRelation();
+ }
+
+ return $value;
+ }
+
+ /**
+ * 关联数据自动写入检查
+ * @access protected
+ * @return void
+ */
+ protected function checkAutoRelationWrite()
+ {
+ foreach ($this->together as $key => $name) {
+ if (is_array($name)) {
+ if (key($name) === 0) {
+ $this->relationWrite[$key] = [];
+ // 绑定关联属性
+ foreach ((array) $name as $val) {
+ if (isset($this->data[$val])) {
+ $this->relationWrite[$key][$val] = $this->data[$val];
+ }
+ }
+ } else {
+ // 直接传入关联数据
+ $this->relationWrite[$key] = $name;
+ }
+ } elseif (isset($this->relation[$name])) {
+ $this->relationWrite[$name] = $this->relation[$name];
+ } elseif (isset($this->data[$name])) {
+ $this->relationWrite[$name] = $this->data[$name];
+ unset($this->data[$name]);
+ }
+ }
+ }
+
+ /**
+ * 自动关联数据更新(针对一对一关联)
+ * @access protected
+ * @return void
+ */
+ protected function autoRelationUpdate()
+ {
+ foreach ($this->relationWrite as $name => $val) {
+ if ($val instanceof Model) {
+ $val->isUpdate()->save();
+ } else {
+ $model = $this->getRelation($name);
+ if ($model instanceof Model) {
+ $model->isUpdate()->save($val);
+ }
+ }
+ }
+ }
+
+ /**
+ * 自动关联数据写入(针对一对一关联)
+ * @access protected
+ * @return void
+ */
+ protected function autoRelationInsert()
+ {
+ foreach ($this->relationWrite as $name => $val) {
+ $method = Loader::parseName($name, 1, false);
+ $this->$method()->save($val);
+ }
+ }
+
+ /**
+ * 自动关联数据删除(支持一对一及一对多关联)
+ * @access protected
+ * @return void
+ */
+ protected function autoRelationDelete()
+ {
+ foreach ($this->relationWrite as $key => $name) {
+ $name = is_numeric($key) ? $name : $key;
+ $result = $this->getRelation($name);
+
+ if ($result instanceof Model) {
+ $result->delete();
+ } elseif ($result instanceof Collection) {
+ foreach ($result as $model) {
+ $model->delete();
+ }
+ }
+ }
+ }
+}
diff --git a/Server/thinkphp/library/think/model/concern/SoftDelete.php b/Server/thinkphp/library/think/model/concern/SoftDelete.php
new file mode 100644
index 00000000..ec866ac0
--- /dev/null
+++ b/Server/thinkphp/library/think/model/concern/SoftDelete.php
@@ -0,0 +1,246 @@
+getDeleteTimeField();
+
+ if ($field && !empty($this->getOrigin($field))) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 查询软删除数据
+ * @access public
+ * @return Query
+ */
+ public static function withTrashed()
+ {
+ $model = new static();
+
+ return $model->withTrashedData(true)->db(false);
+ }
+
+ /**
+ * 是否包含软删除数据
+ * @access protected
+ * @param bool $withTrashed 是否包含软删除数据
+ * @return $this
+ */
+ protected function withTrashedData($withTrashed)
+ {
+ $this->withTrashed = $withTrashed;
+ return $this;
+ }
+
+ /**
+ * 只查询软删除数据
+ * @access public
+ * @return Query
+ */
+ public static function onlyTrashed()
+ {
+ $model = new static();
+ $field = $model->getDeleteTimeField(true);
+
+ if ($field) {
+ return $model
+ ->db(false)
+ ->useSoftDelete($field, $model->getWithTrashedExp());
+ }
+
+ return $model->db(false);
+ }
+
+ /**
+ * 获取软删除数据的查询条件
+ * @access protected
+ * @return array
+ */
+ protected function getWithTrashedExp()
+ {
+ return is_null($this->defaultSoftDelete) ?
+ ['notnull', ''] : ['<>', $this->defaultSoftDelete];
+ }
+
+ /**
+ * 删除当前的记录
+ * @access public
+ * @return bool
+ */
+ public function delete($force = false)
+ {
+ if (!$this->isExists() || false === $this->trigger('before_delete', $this)) {
+ return false;
+ }
+
+ $force = $force ?: $this->isForce();
+ $name = $this->getDeleteTimeField();
+
+ if ($name && !$force) {
+ // 软删除
+ $this->data($name, $this->autoWriteTimestamp($name));
+
+ $result = $this->isUpdate()->withEvent(false)->save();
+
+ $this->withEvent(true);
+ } else {
+ // 读取更新条件
+ $where = $this->getWhere();
+
+ // 删除当前模型数据
+ $result = $this->db(false)
+ ->where($where)
+ ->removeOption('soft_delete')
+ ->delete();
+ }
+
+ // 关联删除
+ if (!empty($this->relationWrite)) {
+ $this->autoRelationDelete();
+ }
+
+ $this->trigger('after_delete', $this);
+
+ $this->exists(false);
+
+ return true;
+ }
+
+ /**
+ * 删除记录
+ * @access public
+ * @param mixed $data 主键列表 支持闭包查询条件
+ * @param bool $force 是否强制删除
+ * @return bool
+ */
+ public static function destroy($data, $force = false)
+ {
+ // 传入空不执行删除,但是0可以删除
+ if (empty($data) && 0 !== $data) {
+ return false;
+ }
+ // 包含软删除数据
+ $query = (new static())->db(false);
+
+ if (is_array($data) && key($data) !== 0) {
+ $query->where($data);
+ $data = null;
+ } elseif ($data instanceof \Closure) {
+ call_user_func_array($data, [ & $query]);
+ $data = null;
+ } elseif (is_null($data)) {
+ return false;
+ }
+
+ $resultSet = $query->select($data);
+
+ if ($resultSet) {
+ foreach ($resultSet as $data) {
+ $data->force($force)->delete();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 恢复被软删除的记录
+ * @access public
+ * @param array $where 更新条件
+ * @return bool
+ */
+ public function restore($where = [])
+ {
+ $name = $this->getDeleteTimeField();
+
+ if ($name) {
+ if (false === $this->trigger('before_restore')) {
+ return false;
+ }
+
+ if (empty($where)) {
+ $pk = $this->getPk();
+
+ $where[] = [$pk, '=', $this->getData($pk)];
+ }
+
+ // 恢复删除
+ $this->db(false)
+ ->where($where)
+ ->useSoftDelete($name, $this->getWithTrashedExp())
+ ->update([$name => $this->defaultSoftDelete]);
+
+ $this->trigger('after_restore');
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 获取软删除字段
+ * @access protected
+ * @param bool $read 是否查询操作 写操作的时候会自动去掉表别名
+ * @return string|false
+ */
+ protected function getDeleteTimeField($read = false)
+ {
+ $field = property_exists($this, 'deleteTime') && isset($this->deleteTime) ? $this->deleteTime : 'delete_time';
+
+ if (false === $field) {
+ return false;
+ }
+
+ if (false === strpos($field, '.')) {
+ $field = '__TABLE__.' . $field;
+ }
+
+ if (!$read && strpos($field, '.')) {
+ $array = explode('.', $field);
+ $field = array_pop($array);
+ }
+
+ return $field;
+ }
+
+ /**
+ * 查询的时候默认排除软删除数据
+ * @access protected
+ * @param Query $query
+ * @return void
+ */
+ protected function withNoTrashed($query)
+ {
+ $field = $this->getDeleteTimeField(true);
+
+ if ($field) {
+ $condition = is_null($this->defaultSoftDelete) ? ['null', ''] : ['=', $this->defaultSoftDelete];
+ $query->useSoftDelete($field, $condition);
+ }
+ }
+}
diff --git a/Server/thinkphp/library/think/model/concern/TimeStamp.php b/Server/thinkphp/library/think/model/concern/TimeStamp.php
new file mode 100644
index 00000000..99a31fa7
--- /dev/null
+++ b/Server/thinkphp/library/think/model/concern/TimeStamp.php
@@ -0,0 +1,92 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\model\concern;
+
+use DateTime;
+
+/**
+ * 自动时间戳
+ */
+trait TimeStamp
+{
+ /**
+ * 是否需要自动写入时间戳 如果设置为字符串 则表示时间字段的类型
+ * @var bool|string
+ */
+ protected $autoWriteTimestamp;
+
+ /**
+ * 创建时间字段 false表示关闭
+ * @var false|string
+ */
+ protected $createTime = 'create_time';
+
+ /**
+ * 更新时间字段 false表示关闭
+ * @var false|string
+ */
+ protected $updateTime = 'update_time';
+
+ /**
+ * 时间字段显示格式
+ * @var string
+ */
+ protected $dateFormat;
+
+ /**
+ * 时间日期字段格式化处理
+ * @access protected
+ * @param mixed $format 日期格式
+ * @param mixed $time 时间日期表达式
+ * @param bool $timestamp 是否进行时间戳转换
+ * @return mixed
+ */
+ protected function formatDateTime($format, $time = 'now', $timestamp = false)
+ {
+ if (empty($time)) {
+ return;
+ }
+
+ if (false === $format) {
+ return $time;
+ } elseif (false !== strpos($format, '\\')) {
+ return new $format($time);
+ }
+
+ if ($timestamp) {
+ $dateTime = new DateTime();
+ $dateTime->setTimestamp($time);
+ } else {
+ $dateTime = new DateTime($time);
+ }
+
+ return $dateTime->format($format);
+ }
+
+ /**
+ * 检查时间字段写入
+ * @access protected
+ * @return void
+ */
+ protected function checkTimeStampWrite()
+ {
+ // 自动写入创建时间和更新时间
+ if ($this->autoWriteTimestamp) {
+ if ($this->createTime && !isset($this->data[$this->createTime])) {
+ $this->data[$this->createTime] = $this->autoWriteTimestamp($this->createTime);
+ }
+ if ($this->updateTime && !isset($this->data[$this->updateTime])) {
+ $this->data[$this->updateTime] = $this->autoWriteTimestamp($this->updateTime);
+ }
+ }
+ }
+}
diff --git a/Server/thinkphp/library/think/process/exception/Faild.php b/Server/thinkphp/library/think/process/exception/Faild.php
new file mode 100644
index 00000000..38647bc1
--- /dev/null
+++ b/Server/thinkphp/library/think/process/exception/Faild.php
@@ -0,0 +1,42 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\process\exception;
+
+use think\Process;
+
+class Faild extends \RuntimeException
+{
+
+ private $process;
+
+ public function __construct(Process $process)
+ {
+ if ($process->isSuccessful()) {
+ throw new \InvalidArgumentException('Expected a failed process, but the given process was successful.');
+ }
+
+ $error = sprintf('The command "%s" failed.' . "\nExit Code: %s(%s)", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText());
+
+ if (!$process->isOutputDisabled()) {
+ $error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput());
+ }
+
+ parent::__construct($error);
+
+ $this->process = $process;
+ }
+
+ public function getProcess()
+ {
+ return $this->process;
+ }
+}
diff --git a/Server/thinkphp/library/think/response/Download.php b/Server/thinkphp/library/think/response/Download.php
new file mode 100644
index 00000000..5595f9ab
--- /dev/null
+++ b/Server/thinkphp/library/think/response/Download.php
@@ -0,0 +1,148 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\response;
+
+use think\Exception;
+use think\Response;
+
+class Download extends Response
+{
+ protected $expire = 360;
+ protected $name;
+ protected $mimeType;
+ protected $isContent = false;
+ protected $openinBrowser = false;
+ /**
+ * 处理数据
+ * @access protected
+ * @param mixed $data 要处理的数据
+ * @return mixed
+ * @throws \Exception
+ */
+ protected function output($data)
+ {
+ if (!$this->isContent && !is_file($data)) {
+ throw new Exception('file not exists:' . $data);
+ }
+
+ ob_end_clean();
+
+ if (!empty($this->name)) {
+ $name = $this->name;
+ } else {
+ $name = !$this->isContent ? pathinfo($data, PATHINFO_BASENAME) : '';
+ }
+
+ if ($this->isContent) {
+ $mimeType = $this->mimeType;
+ $size = strlen($data);
+ } else {
+ $mimeType = $this->getMimeType($data);
+ $size = filesize($data);
+ }
+
+ $this->header['Pragma'] = 'public';
+ $this->header['Content-Type'] = $mimeType ?: 'application/octet-stream';
+ $this->header['Cache-control'] = 'max-age=' . $this->expire;
+ $this->header['Content-Disposition'] = $this->openinBrowser ? 'inline' : 'attachment; filename="' . $name . '"';
+ $this->header['Content-Length'] = $size;
+ $this->header['Content-Transfer-Encoding'] = 'binary';
+ $this->header['Expires'] = gmdate("D, d M Y H:i:s", time() + $this->expire) . ' GMT';
+
+ $this->lastModified(gmdate('D, d M Y H:i:s', time()) . ' GMT');
+
+ $data = $this->isContent ? $data : file_get_contents($data);
+ return $data;
+ }
+
+ /**
+ * 设置是否为内容 必须配合mimeType方法使用
+ * @access public
+ * @param bool $content
+ * @return $this
+ */
+ public function isContent($content = true)
+ {
+ $this->isContent = $content;
+ return $this;
+ }
+
+ /**
+ * 设置有效期
+ * @access public
+ * @param integer $expire 有效期
+ * @return $this
+ */
+ public function expire($expire)
+ {
+ $this->expire = $expire;
+ return $this;
+ }
+
+ /**
+ * 设置文件类型
+ * @access public
+ * @param string $filename 文件名
+ * @return $this
+ */
+ public function mimeType($mimeType)
+ {
+ $this->mimeType = $mimeType;
+ return $this;
+ }
+
+ /**
+ * 获取文件类型信息
+ * @access public
+ * @param string $filename 文件名
+ * @return string
+ */
+ protected function getMimeType($filename)
+ {
+ if (!empty($this->mimeType)) {
+ return $this->mimeType;
+ }
+
+ $finfo = finfo_open(FILEINFO_MIME_TYPE);
+
+ return finfo_file($finfo, $filename);
+ }
+
+ /**
+ * 设置下载文件的显示名称
+ * @access public
+ * @param string $filename 文件名
+ * @param bool $extension 后缀自动识别
+ * @return $this
+ */
+ public function name($filename, $extension = true)
+ {
+ $this->name = $filename;
+
+ if ($extension && false === strpos($filename, '.')) {
+ $this->name .= '.' . pathinfo($this->data, PATHINFO_EXTENSION);
+ }
+
+ return $this;
+ }
+
+ /**
+ * 设置是否在浏览器中显示文件
+ * @access public
+ * @param bool $openinBrowser 是否在浏览器中显示文件
+ * @return $this
+ */
+ public function openinBrowser($openinBrowser) {
+ $this->openinBrowser = $openinBrowser;
+ return $this;
+ }
+}
diff --git a/Server/thinkphp/library/think/response/Jump.php b/Server/thinkphp/library/think/response/Jump.php
new file mode 100644
index 00000000..258448ca
--- /dev/null
+++ b/Server/thinkphp/library/think/response/Jump.php
@@ -0,0 +1,32 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\response;
+
+use think\Response;
+
+class Jump extends Response
+{
+ protected $contentType = 'text/html';
+
+ /**
+ * 处理数据
+ * @access protected
+ * @param mixed $data 要处理的数据
+ * @return mixed
+ * @throws \Exception
+ */
+ protected function output($data)
+ {
+ $data = $this->app['view']->fetch($this->options['jump_template'], $data);
+ return $data;
+ }
+}
diff --git a/Server/thinkphp/library/think/route/AliasRule.php b/Server/thinkphp/library/think/route/AliasRule.php
new file mode 100644
index 00000000..393cb310
--- /dev/null
+++ b/Server/thinkphp/library/think/route/AliasRule.php
@@ -0,0 +1,119 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+use think\Route;
+
+class AliasRule extends Domain
+{
+ /**
+ * 架构函数
+ * @access public
+ * @param Route $router 路由实例
+ * @param RuleGroup $parent 上级对象
+ * @param string $name 路由别名
+ * @param string $route 路由绑定
+ * @param array $option 路由参数
+ */
+ public function __construct(Route $router, RuleGroup $parent, $name, $route, $option = [])
+ {
+ $this->router = $router;
+ $this->parent = $parent;
+ $this->name = $name;
+ $this->route = $route;
+ $this->option = $option;
+ }
+
+ /**
+ * 检测路由别名
+ * @access public
+ * @param Request $request 请求对象
+ * @param string $url 访问地址
+ * @param bool $completeMatch 路由是否完全匹配
+ * @return Dispatch|false
+ */
+ public function check($request, $url, $completeMatch = false)
+ {
+ if ($dispatch = $this->checkCrossDomain($request)) {
+ // 允许跨域
+ return $dispatch;
+ }
+
+ // 检查参数有效性
+ if (!$this->checkOption($this->option, $request)) {
+ return false;
+ }
+
+ list($action, $bind) = array_pad(explode('|', $url, 2), 2, '');
+
+ if (isset($this->option['allow']) && !in_array($action, $this->option['allow'])) {
+ // 允许操作
+ return false;
+ } elseif (isset($this->option['except']) && in_array($action, $this->option['except'])) {
+ // 排除操作
+ return false;
+ }
+
+ if (isset($this->option['method'][$action])) {
+ $this->option['method'] = $this->option['method'][$action];
+ }
+
+ // 匹配后执行的行为
+ $this->afterMatchGroup($request);
+
+ if ($this->parent) {
+ // 合并分组参数
+ $this->mergeGroupOptions();
+ }
+
+ if (isset($this->option['ext'])) {
+ // 路由ext参数 优先于系统配置的URL伪静态后缀参数
+ $bind = preg_replace('/\.(' . $request->ext() . ')$/i', '', $bind);
+ }
+
+ $this->parseBindAppendParam($this->route);
+
+ if (0 === strpos($this->route, '\\')) {
+ // 路由到类
+ return $this->bindToClass($request, $bind, substr($this->route, 1));
+ } elseif (0 === strpos($this->route, '@')) {
+ // 路由到控制器类
+ return $this->bindToController($request, $bind, substr($this->route, 1));
+ } else {
+ // 路由到模块/控制器
+ return $this->bindToModule($request, $bind, $this->route);
+ }
+ }
+
+ /**
+ * 设置允许的操作方法
+ * @access public
+ * @param array $action 操作方法
+ * @return $this
+ */
+ public function allow($action = [])
+ {
+ return $this->option('allow', $action);
+ }
+
+ /**
+ * 设置排除的操作方法
+ * @access public
+ * @param array $action 操作方法
+ * @return $this
+ */
+ public function except($action = [])
+ {
+ return $this->option('except', $action);
+ }
+
+}
diff --git a/Server/thinkphp/library/think/route/Dispatch.php b/Server/thinkphp/library/think/route/Dispatch.php
new file mode 100644
index 00000000..7323c98d
--- /dev/null
+++ b/Server/thinkphp/library/think/route/Dispatch.php
@@ -0,0 +1,366 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+use think\App;
+use think\Container;
+use think\exception\ValidateException;
+use think\Request;
+use think\Response;
+
+abstract class Dispatch
+{
+ /**
+ * 应用对象
+ * @var App
+ */
+ protected $app;
+
+ /**
+ * 请求对象
+ * @var Request
+ */
+ protected $request;
+
+ /**
+ * 路由规则
+ * @var Rule
+ */
+ protected $rule;
+
+ /**
+ * 调度信息
+ * @var mixed
+ */
+ protected $dispatch;
+
+ /**
+ * 调度参数
+ * @var array
+ */
+ protected $param;
+
+ /**
+ * 状态码
+ * @var string
+ */
+ protected $code;
+
+ /**
+ * 是否进行大小写转换
+ * @var bool
+ */
+ protected $convert;
+
+ public function __construct(Request $request, Rule $rule, $dispatch, $param = [], $code = null)
+ {
+ $this->request = $request;
+ $this->rule = $rule;
+ $this->app = Container::get('app');
+ $this->dispatch = $dispatch;
+ $this->param = $param;
+ $this->code = $code;
+
+ if (isset($param['convert'])) {
+ $this->convert = $param['convert'];
+ }
+ }
+
+ public function init()
+ {
+ // 执行路由后置操作
+ if ($this->rule->doAfter()) {
+ // 设置请求的路由信息
+
+ // 设置当前请求的参数
+ $this->request->setRouteVars($this->rule->getVars());
+ $this->request->routeInfo([
+ 'rule' => $this->rule->getRule(),
+ 'route' => $this->rule->getRoute(),
+ 'option' => $this->rule->getOption(),
+ 'var' => $this->rule->getVars(),
+ ]);
+
+ $this->doRouteAfter();
+ }
+
+ return $this;
+ }
+
+ /**
+ * 检查路由后置操作
+ * @access protected
+ * @return void
+ */
+ protected function doRouteAfter()
+ {
+ // 记录匹配的路由信息
+ $option = $this->rule->getOption();
+ $matches = $this->rule->getVars();
+
+ // 添加中间件
+ if (!empty($option['middleware'])) {
+ $this->app['middleware']->import($option['middleware']);
+ }
+
+ // 绑定模型数据
+ if (!empty($option['model'])) {
+ $this->createBindModel($option['model'], $matches);
+ }
+
+ // 指定Header数据
+ if (!empty($option['header'])) {
+ $header = $option['header'];
+ $this->app['hook']->add('response_send', function ($response) use ($header) {
+ $response->header($header);
+ });
+ }
+
+ // 指定Response响应数据
+ if (!empty($option['response'])) {
+ foreach ($option['response'] as $response) {
+ $this->app['hook']->add('response_send', $response);
+ }
+ }
+
+ // 开启请求缓存
+ if (isset($option['cache']) && $this->request->isGet()) {
+ $this->parseRequestCache($option['cache']);
+ }
+
+ if (!empty($option['append'])) {
+ $this->request->setRouteVars($option['append']);
+ }
+ }
+
+ /**
+ * 执行路由调度
+ * @access public
+ * @return mixed
+ */
+ public function run()
+ {
+ $option = $this->rule->getOption();
+
+ // 检测路由after行为
+ if (!empty($option['after'])) {
+ $dispatch = $this->checkAfter($option['after']);
+
+ if ($dispatch instanceof Response) {
+ return $dispatch;
+ }
+ }
+
+ // 数据自动验证
+ if (isset($option['validate'])) {
+ $this->autoValidate($option['validate']);
+ }
+
+ $data = $this->exec();
+
+ return $this->autoResponse($data);
+ }
+
+ protected function autoResponse($data)
+ {
+ if ($data instanceof Response) {
+ $response = $data;
+ } elseif (!is_null($data)) {
+ // 默认自动识别响应输出类型
+ $isAjax = $this->request->isAjax();
+ $type = $isAjax ? $this->rule->getConfig('default_ajax_return') : $this->rule->getConfig('default_return_type');
+
+ $response = Response::create($data, $type);
+ } else {
+ $data = ob_get_clean();
+ $content = false === $data ? '' : $data;
+ $status = '' === $content && $this->request->isJson() ? 204 : 200;
+
+ $response = Response::create($content, '', $status);
+ }
+
+ return $response;
+ }
+
+ /**
+ * 检查路由后置行为
+ * @access protected
+ * @param mixed $after 后置行为
+ * @return mixed
+ */
+ protected function checkAfter($after)
+ {
+ $this->app['log']->notice('路由后置行为建议使用中间件替代!');
+
+ $hook = $this->app['hook'];
+
+ $result = null;
+
+ foreach ((array) $after as $behavior) {
+ $result = $hook->exec($behavior);
+
+ if (!is_null($result)) {
+ break;
+ }
+ }
+
+ // 路由规则重定向
+ if ($result instanceof Response) {
+ return $result;
+ }
+
+ return false;
+ }
+
+ /**
+ * 验证数据
+ * @access protected
+ * @param array $option
+ * @return void
+ * @throws ValidateException
+ */
+ protected function autoValidate($option)
+ {
+ list($validate, $scene, $message, $batch) = $option;
+
+ if (is_array($validate)) {
+ // 指定验证规则
+ $v = $this->app->validate();
+ $v->rule($validate);
+ } else {
+ // 调用验证器
+ $v = $this->app->validate($validate);
+ if (!empty($scene)) {
+ $v->scene($scene);
+ }
+ }
+
+ if (!empty($message)) {
+ $v->message($message);
+ }
+
+ // 批量验证
+ if ($batch) {
+ $v->batch(true);
+ }
+
+ if (!$v->check($this->request->param())) {
+ throw new ValidateException($v->getError());
+ }
+ }
+
+ /**
+ * 处理路由请求缓存
+ * @access protected
+ * @param Request $request 请求对象
+ * @param string|array $cache 路由缓存
+ * @return void
+ */
+ protected function parseRequestCache($cache)
+ {
+ if (is_array($cache)) {
+ list($key, $expire, $tag) = array_pad($cache, 3, null);
+ } else {
+ $key = str_replace('|', '/', $this->request->url());
+ $expire = $cache;
+ $tag = null;
+ }
+
+ $cache = $this->request->cache($key, $expire, $tag);
+ $this->app->setResponseCache($cache);
+ }
+
+ /**
+ * 路由绑定模型实例
+ * @access protected
+ * @param array|\Clousre $bindModel 绑定模型
+ * @param array $matches 路由变量
+ * @return void
+ */
+ protected function createBindModel($bindModel, $matches)
+ {
+ foreach ($bindModel as $key => $val) {
+ if ($val instanceof \Closure) {
+ $result = $this->app->invokeFunction($val, $matches);
+ } else {
+ $fields = explode('&', $key);
+
+ if (is_array($val)) {
+ list($model, $exception) = $val;
+ } else {
+ $model = $val;
+ $exception = true;
+ }
+
+ $where = [];
+ $match = true;
+
+ foreach ($fields as $field) {
+ if (!isset($matches[$field])) {
+ $match = false;
+ break;
+ } else {
+ $where[] = [$field, '=', $matches[$field]];
+ }
+ }
+
+ if ($match) {
+ $query = strpos($model, '\\') ? $model::where($where) : $this->app->model($model)->where($where);
+ $result = $query->failException($exception)->find();
+ }
+ }
+
+ if (!empty($result)) {
+ // 注入容器
+ $this->app->instance(get_class($result), $result);
+ }
+ }
+ }
+
+ public function convert($convert)
+ {
+ $this->convert = $convert;
+
+ return $this;
+ }
+
+ public function getDispatch()
+ {
+ return $this->dispatch;
+ }
+
+ public function getParam()
+ {
+ return $this->param;
+ }
+
+ 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'];
+ }
+
+ public function __debugInfo()
+ {
+ $data = get_object_vars($this);
+ unset($data['app'], $data['request'], $data['rule']);
+
+ return $data;
+ }
+}
diff --git a/Server/thinkphp/library/think/route/Domain.php b/Server/thinkphp/library/think/route/Domain.php
new file mode 100644
index 00000000..923d9b42
--- /dev/null
+++ b/Server/thinkphp/library/think/route/Domain.php
@@ -0,0 +1,237 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+use think\Container;
+use think\Loader;
+use think\Request;
+use think\Route;
+use think\route\dispatch\Callback as CallbackDispatch;
+use think\route\dispatch\Controller as ControllerDispatch;
+use think\route\dispatch\Module as ModuleDispatch;
+
+class Domain extends RuleGroup
+{
+ /**
+ * 架构函数
+ * @access public
+ * @param Route $router 路由对象
+ * @param string $name 路由域名
+ * @param mixed $rule 域名路由
+ * @param array $option 路由参数
+ * @param array $pattern 变量规则
+ */
+ public function __construct(Route $router, $name = '', $rule = null, $option = [], $pattern = [])
+ {
+ $this->router = $router;
+ $this->domain = $name;
+ $this->option = $option;
+ $this->rule = $rule;
+ $this->pattern = $pattern;
+ }
+
+ /**
+ * 检测域名路由
+ * @access public
+ * @param Request $request 请求对象
+ * @param string $url 访问地址
+ * @param bool $completeMatch 路由是否完全匹配
+ * @return Dispatch|false
+ */
+ public function check($request, $url, $completeMatch = false)
+ {
+ // 检测别名路由
+ $result = $this->checkRouteAlias($request, $url);
+
+ if (false !== $result) {
+ return $result;
+ }
+
+ // 检测URL绑定
+ $result = $this->checkUrlBind($request, $url);
+
+ if (!empty($this->option['append'])) {
+ $request->setRouteVars($this->option['append']);
+ unset($this->option['append']);
+ }
+
+ if (false !== $result) {
+ return $result;
+ }
+
+ // 添加域名中间件
+ if (!empty($this->option['middleware'])) {
+ Container::get('middleware')->import($this->option['middleware']);
+ unset($this->option['middleware']);
+ }
+
+ return parent::check($request, $url, $completeMatch);
+ }
+
+ /**
+ * 设置路由绑定
+ * @access public
+ * @param string $bind 绑定信息
+ * @return $this
+ */
+ public function bind($bind)
+ {
+ $this->router->bind($bind, $this->domain);
+ return $this;
+ }
+
+ /**
+ * 检测路由别名
+ * @access private
+ * @param Request $request
+ * @param string $url URL地址
+ * @return Dispatch|false
+ */
+ private function checkRouteAlias($request, $url)
+ {
+ $alias = strpos($url, '|') ? strstr($url, '|', true) : $url;
+
+ $item = $this->router->getAlias($alias);
+
+ return $item ? $item->check($request, $url) : false;
+ }
+
+ /**
+ * 检测URL绑定
+ * @access private
+ * @param Request $request
+ * @param string $url URL地址
+ * @return Dispatch|false
+ */
+ private function checkUrlBind($request, $url)
+ {
+ $bind = $this->router->getBind($this->domain);
+
+ if (!empty($bind)) {
+ $this->parseBindAppendParam($bind);
+
+ // 记录绑定信息
+ Container::get('app')->log('[ BIND ] ' . var_export($bind, true));
+
+ // 如果有URL绑定 则进行绑定检测
+ $type = substr($bind, 0, 1);
+ $bind = substr($bind, 1);
+
+ $bindTo = [
+ '\\' => 'bindToClass',
+ '@' => 'bindToController',
+ ':' => 'bindToNamespace',
+ ];
+
+ if (isset($bindTo[$type])) {
+ return $this->{$bindTo[$type]}($request, $url, $bind);
+ }
+ }
+
+ return false;
+ }
+
+ protected function parseBindAppendParam(&$bind)
+ {
+ if (false !== strpos($bind, '?')) {
+ list($bind, $query) = explode('?', $bind);
+ parse_str($query, $vars);
+ $this->append($vars);
+ }
+ }
+
+ /**
+ * 绑定到类
+ * @access protected
+ * @param Request $request
+ * @param string $url URL地址
+ * @param string $class 类名(带命名空间)
+ * @return CallbackDispatch
+ */
+ protected function bindToClass($request, $url, $class)
+ {
+ $array = explode('|', $url, 2);
+ $action = !empty($array[0]) ? $array[0] : $this->router->config('default_action');
+ $param = [];
+
+ if (!empty($array[1])) {
+ $this->parseUrlParams($request, $array[1], $param);
+ }
+
+ return new CallbackDispatch($request, $this, [$class, $action], $param);
+ }
+
+ /**
+ * 绑定到命名空间
+ * @access protected
+ * @param Request $request
+ * @param string $url URL地址
+ * @param string $namespace 命名空间
+ * @return CallbackDispatch
+ */
+ protected function bindToNamespace($request, $url, $namespace)
+ {
+ $array = explode('|', $url, 3);
+ $class = !empty($array[0]) ? $array[0] : $this->router->config('default_controller');
+ $method = !empty($array[1]) ? $array[1] : $this->router->config('default_action');
+ $param = [];
+
+ if (!empty($array[2])) {
+ $this->parseUrlParams($request, $array[2], $param);
+ }
+
+ return new CallbackDispatch($request, $this, [$namespace . '\\' . Loader::parseName($class, 1), $method], $param);
+ }
+
+ /**
+ * 绑定到控制器类
+ * @access protected
+ * @param Request $request
+ * @param string $url URL地址
+ * @param string $controller 控制器名 (支持带模块名 index/user )
+ * @return ControllerDispatch
+ */
+ protected function bindToController($request, $url, $controller)
+ {
+ $array = explode('|', $url, 2);
+ $action = !empty($array[0]) ? $array[0] : $this->router->config('default_action');
+ $param = [];
+
+ if (!empty($array[1])) {
+ $this->parseUrlParams($request, $array[1], $param);
+ }
+
+ return new ControllerDispatch($request, $this, $controller . '/' . $action, $param);
+ }
+
+ /**
+ * 绑定到模块/控制器
+ * @access protected
+ * @param Request $request
+ * @param string $url URL地址
+ * @param string $controller 控制器类名(带命名空间)
+ * @return ModuleDispatch
+ */
+ protected function bindToModule($request, $url, $controller)
+ {
+ $array = explode('|', $url, 2);
+ $action = !empty($array[0]) ? $array[0] : $this->router->config('default_action');
+ $param = [];
+
+ if (!empty($array[1])) {
+ $this->parseUrlParams($request, $array[1], $param);
+ }
+
+ return new ModuleDispatch($request, $this, $controller . '/' . $action, $param);
+ }
+
+}
diff --git a/Server/thinkphp/library/think/route/Resource.php b/Server/thinkphp/library/think/route/Resource.php
new file mode 100644
index 00000000..ff139282
--- /dev/null
+++ b/Server/thinkphp/library/think/route/Resource.php
@@ -0,0 +1,126 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+use think\Route;
+
+class Resource extends RuleGroup
+{
+ // 资源路由名称
+ protected $resource;
+
+ // REST路由方法定义
+ protected $rest = [];
+
+ /**
+ * 架构函数
+ * @access public
+ * @param Route $router 路由对象
+ * @param RuleGroup $parent 上级对象
+ * @param string $name 资源名称
+ * @param string $route 路由地址
+ * @param array $option 路由参数
+ * @param array $pattern 变量规则
+ * @param array $rest 资源定义
+ */
+ public function __construct(Route $router, RuleGroup $parent = null, $name = '', $route = '', $option = [], $pattern = [], $rest = [])
+ {
+ $this->router = $router;
+ $this->parent = $parent;
+ $this->resource = $name;
+ $this->route = $route;
+ $this->name = strpos($name, '.') ? strstr($name, '.', true) : $name;
+
+ $this->setFullName();
+
+ // 资源路由默认为完整匹配
+ $option['complete_match'] = true;
+
+ $this->pattern = $pattern;
+ $this->option = $option;
+ $this->rest = $rest;
+
+ if ($this->parent) {
+ $this->domain = $this->parent->getDomain();
+ $this->parent->addRuleItem($this);
+ }
+
+ if ($router->isTest()) {
+ $this->buildResourceRule();
+ }
+ }
+
+ /**
+ * 生成资源路由规则
+ * @access protected
+ * @return void
+ */
+ protected function buildResourceRule()
+ {
+ $origin = $this->router->getGroup();
+ $this->router->setGroup($this);
+
+ $rule = $this->resource;
+ $option = $this->option;
+
+ if (strpos($rule, '.')) {
+ // 注册嵌套资源路由
+ $array = explode('.', $rule);
+ $last = array_pop($array);
+ $item = [];
+
+ foreach ($array as $val) {
+ $item[] = $val . '/<' . (isset($option['var'][$val]) ? $option['var'][$val] : $val . '_id') . '>';
+ }
+
+ $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']))
+ || (isset($option['except']) && in_array($key, $option['except']))) {
+ continue;
+ }
+
+ if (isset($last) && strpos($val[1], '') && isset($option['var'][$last])) {
+ $val[1] = str_replace('', '<' . $option['var'][$last] . '>', $val[1]);
+ } elseif (strpos($val[1], '') && isset($option['var'][$rule])) {
+ $val[1] = str_replace('', '<' . $option['var'][$rule] . '>', $val[1]);
+ }
+
+ $this->addRule(trim($prefix . $val[1], '/'), $this->route . '/' . $val[2], $val[0]);
+ }
+
+ $this->router->setGroup($origin);
+ }
+
+ /**
+ * rest方法定义和修改
+ * @access public
+ * @param string $name 方法名称
+ * @param array|bool $resource 资源
+ * @return $this
+ */
+ public function rest($name, $resource = [])
+ {
+ if (is_array($name)) {
+ $this->rest = $resource ? $name : array_merge($this->rest, $name);
+ } else {
+ $this->rest[$name] = $resource;
+ }
+
+ return $this;
+ }
+}
diff --git a/Server/thinkphp/library/think/route/Rule.php b/Server/thinkphp/library/think/route/Rule.php
new file mode 100644
index 00000000..996305f7
--- /dev/null
+++ b/Server/thinkphp/library/think/route/Rule.php
@@ -0,0 +1,1130 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+use think\Container;
+use think\Request;
+use think\Response;
+use think\route\dispatch\Callback as CallbackDispatch;
+use think\route\dispatch\Controller as ControllerDispatch;
+use think\route\dispatch\Module as ModuleDispatch;
+use think\route\dispatch\Redirect as RedirectDispatch;
+use think\route\dispatch\Response as ResponseDispatch;
+use think\route\dispatch\View as ViewDispatch;
+
+abstract class Rule
+{
+ /**
+ * 路由标识
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * 路由对象
+ * @var Route
+ */
+ protected $router;
+
+ /**
+ * 路由所属分组
+ * @var RuleGroup
+ */
+ protected $parent;
+
+ /**
+ * 路由规则
+ * @var mixed
+ */
+ protected $rule;
+
+ /**
+ * 路由地址
+ * @var string|\Closure
+ */
+ protected $route;
+
+ /**
+ * 请求类型
+ * @var string
+ */
+ protected $method;
+
+ /**
+ * 路由变量
+ * @var array
+ */
+ protected $vars = [];
+
+ /**
+ * 路由参数
+ * @var array
+ */
+ protected $option = [];
+
+ /**
+ * 路由变量规则
+ * @var array
+ */
+ protected $pattern = [];
+
+ /**
+ * 需要和分组合并的路由参数
+ * @var array
+ */
+ protected $mergeOptions = ['after', 'model', 'header', 'response', 'append', 'middleware'];
+
+ /**
+ * 是否需要后置操作
+ * @var bool
+ */
+ protected $doAfter;
+
+ /**
+ * 是否锁定参数
+ * @var bool
+ */
+ protected $lockOption = false;
+
+ abstract public function check($request, $url, $completeMatch = false);
+
+ /**
+ * 获取Name
+ * @access public
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * 获取当前路由规则
+ * @access public
+ * @return string
+ */
+ public function getRule()
+ {
+ return $this->rule;
+ }
+
+ /**
+ * 获取当前路由地址
+ * @access public
+ * @return mixed
+ */
+ public function getRoute()
+ {
+ return $this->route;
+ }
+
+ /**
+ * 获取当前路由的请求类型
+ * @access public
+ * @return string
+ */
+ public function getMethod()
+ {
+ return strtolower($this->method);
+ }
+
+ /**
+ * 获取当前路由的变量
+ * @access public
+ * @return array
+ */
+ public function getVars()
+ {
+ return $this->vars;
+ }
+
+ /**
+ * 获取路由对象
+ * @access public
+ * @return Route
+ */
+ public function getRouter()
+ {
+ return $this->router;
+ }
+
+ /**
+ * 路由是否有后置操作
+ * @access public
+ * @return bool
+ */
+ public function doAfter()
+ {
+ return $this->doAfter;
+ }
+
+ /**
+ * 获取路由分组
+ * @access public
+ * @return RuleGroup|null
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * 获取路由所在域名
+ * @access public
+ * @return string
+ */
+ public function getDomain()
+ {
+ return $this->parent->getDomain();
+ }
+
+ /**
+ * 获取变量规则定义
+ * @access public
+ * @param string $name 变量名
+ * @return mixed
+ */
+ public function getPattern($name = '')
+ {
+ if ('' === $name) {
+ return $this->pattern;
+ }
+
+ return isset($this->pattern[$name]) ? $this->pattern[$name] : null;
+ }
+
+ /**
+ * 获取路由参数
+ * @access public
+ * @param string $name 变量名
+ * @return mixed
+ */
+ public function getConfig($name = '')
+ {
+ return $this->router->config($name);
+ }
+
+ /**
+ * 获取路由参数定义
+ * @access public
+ * @param string $name 参数名
+ * @return mixed
+ */
+ public function getOption($name = '')
+ {
+ if ('' === $name) {
+ return $this->option;
+ }
+
+ return isset($this->option[$name]) ? $this->option[$name] : null;
+ }
+
+ /**
+ * 注册路由参数
+ * @access public
+ * @param string|array $name 参数名
+ * @param mixed $value 值
+ * @return $this
+ */
+ public function option($name, $value = '')
+ {
+ if (is_array($name)) {
+ $this->option = array_merge($this->option, $name);
+ } else {
+ $this->option[$name] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 注册变量规则
+ * @access public
+ * @param string|array $name 变量名
+ * @param string $rule 变量规则
+ * @return $this
+ */
+ public function pattern($name, $rule = '')
+ {
+ if (is_array($name)) {
+ $this->pattern = array_merge($this->pattern, $name);
+ } else {
+ $this->pattern[$name] = $rule;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 设置标识
+ * @access public
+ * @param string $name 标识名
+ * @return $this
+ */
+ public function name($name)
+ {
+ $this->name = $name;
+
+ return $this;
+ }
+
+ /**
+ * 设置变量
+ * @access public
+ * @param array $vars 变量
+ * @return $this
+ */
+ public function vars($vars)
+ {
+ $this->vars = $vars;
+
+ return $this;
+ }
+
+ /**
+ * 设置路由请求类型
+ * @access public
+ * @param string $method
+ * @return $this
+ */
+ public function method($method)
+ {
+ return $this->option('method', strtolower($method));
+ }
+
+ /**
+ * 设置路由前置行为
+ * @access public
+ * @param array|\Closure $before
+ * @return $this
+ */
+ public function before($before)
+ {
+ return $this->option('before', $before);
+ }
+
+ /**
+ * 设置路由后置行为
+ * @access public
+ * @param array|\Closure $after
+ * @return $this
+ */
+ public function after($after)
+ {
+ return $this->option('after', $after);
+ }
+
+ /**
+ * 检查后缀
+ * @access public
+ * @param string $ext
+ * @return $this
+ */
+ public function ext($ext = '')
+ {
+ return $this->option('ext', $ext);
+ }
+
+ /**
+ * 检查禁止后缀
+ * @access public
+ * @param string $ext
+ * @return $this
+ */
+ public function denyExt($ext = '')
+ {
+ return $this->option('deny_ext', $ext);
+ }
+
+ /**
+ * 检查域名
+ * @access public
+ * @param string $domain
+ * @return $this
+ */
+ public function domain($domain)
+ {
+ return $this->option('domain', $domain);
+ }
+
+ /**
+ * 设置参数过滤检查
+ * @access public
+ * @param string|array $name
+ * @param mixed $value
+ * @return $this
+ */
+ public function filter($name, $value = null)
+ {
+ if (is_array($name)) {
+ $this->option['filter'] = $name;
+ } else {
+ $this->option['filter'][$name] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 绑定模型
+ * @access public
+ * @param array|string $var 路由变量名 多个使用 & 分割
+ * @param string|\Closure $model 绑定模型类
+ * @param bool $exception 是否抛出异常
+ * @return $this
+ */
+ public function model($var, $model = null, $exception = true)
+ {
+ if ($var instanceof \Closure) {
+ $this->option['model'][] = $var;
+ } elseif (is_array($var)) {
+ $this->option['model'] = $var;
+ } elseif (is_null($model)) {
+ $this->option['model']['id'] = [$var, true];
+ } else {
+ $this->option['model'][$var] = [$model, $exception];
+ }
+
+ return $this;
+ }
+
+ /**
+ * 附加路由隐式参数
+ * @access public
+ * @param array $append
+ * @return $this
+ */
+ public function append(array $append = [])
+ {
+ if (isset($this->option['append'])) {
+ $this->option['append'] = array_merge($this->option['append'], $append);
+ } else {
+ $this->option['append'] = $append;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 绑定验证
+ * @access public
+ * @param mixed $validate 验证器类
+ * @param string $scene 验证场景
+ * @param array $message 验证提示
+ * @param bool $batch 批量验证
+ * @return $this
+ */
+ public function validate($validate, $scene = null, $message = [], $batch = false)
+ {
+ $this->option['validate'] = [$validate, $scene, $message, $batch];
+
+ return $this;
+ }
+
+ /**
+ * 绑定Response对象
+ * @access public
+ * @param mixed $response
+ * @return $this
+ */
+ public function response($response)
+ {
+ $this->option['response'][] = $response;
+ return $this;
+ }
+
+ /**
+ * 设置Response Header信息
+ * @access public
+ * @param string|array $name 参数名
+ * @param string $value 参数值
+ * @return $this
+ */
+ public function header($header, $value = null)
+ {
+ if (is_array($header)) {
+ $this->option['header'] = $header;
+ } else {
+ $this->option['header'][$header] = $value;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 指定路由中间件
+ * @access public
+ * @param string|array|\Closure $middleware
+ * @param mixed $param
+ * @return $this
+ */
+ public function middleware($middleware, $param = null)
+ {
+ if (is_null($param) && is_array($middleware)) {
+ $this->option['middleware'] = $middleware;
+ } else {
+ foreach ((array) $middleware as $item) {
+ $this->option['middleware'][] = [$item, $param];
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * 设置路由缓存
+ * @access public
+ * @param array|string $cache
+ * @return $this
+ */
+ public function cache($cache)
+ {
+ return $this->option('cache', $cache);
+ }
+
+ /**
+ * 检查URL分隔符
+ * @access public
+ * @param bool $depr
+ * @return $this
+ */
+ public function depr($depr)
+ {
+ return $this->option('param_depr', $depr);
+ }
+
+ /**
+ * 是否合并额外参数
+ * @access public
+ * @param bool $merge
+ * @return $this
+ */
+ public function mergeExtraVars($merge = true)
+ {
+ return $this->option('merge_extra_vars', $merge);
+ }
+
+ /**
+ * 设置需要合并的路由参数
+ * @access public
+ * @param array $option
+ * @return $this
+ */
+ public function mergeOptions($option = [])
+ {
+ $this->mergeOptions = array_merge($this->mergeOptions, $option);
+ return $this;
+ }
+
+ /**
+ * 检查是否为HTTPS请求
+ * @access public
+ * @param bool $https
+ * @return $this
+ */
+ public function https($https = true)
+ {
+ return $this->option('https', $https);
+ }
+
+ /**
+ * 检查是否为AJAX请求
+ * @access public
+ * @param bool $ajax
+ * @return $this
+ */
+ public function ajax($ajax = true)
+ {
+ return $this->option('ajax', $ajax);
+ }
+
+ /**
+ * 检查是否为PJAX请求
+ * @access public
+ * @param bool $pjax
+ * @return $this
+ */
+ public function pjax($pjax = true)
+ {
+ return $this->option('pjax', $pjax);
+ }
+
+ /**
+ * 检查是否为手机访问
+ * @access public
+ * @param bool $mobile
+ * @return $this
+ */
+ public function mobile($mobile = true)
+ {
+ return $this->option('mobile', $mobile);
+ }
+
+ /**
+ * 当前路由到一个模板地址 当使用数组的时候可以传入模板变量
+ * @access public
+ * @param bool|array $view
+ * @return $this
+ */
+ public function view($view = true)
+ {
+ return $this->option('view', $view);
+ }
+
+ /**
+ * 当前路由为重定向
+ * @access public
+ * @param bool $redirect 是否为重定向
+ * @return $this
+ */
+ public function redirect($redirect = true)
+ {
+ return $this->option('redirect', $redirect);
+ }
+
+ /**
+ * 设置路由完整匹配
+ * @access public
+ * @param bool $match
+ * @return $this
+ */
+ public function completeMatch($match = true)
+ {
+ return $this->option('complete_match', $match);
+ }
+
+ /**
+ * 是否去除URL最后的斜线
+ * @access public
+ * @param bool $remove
+ * @return $this
+ */
+ public function removeSlash($remove = true)
+ {
+ return $this->option('remove_slash', $remove);
+ }
+
+ /**
+ * 设置是否允许跨域
+ * @access public
+ * @param bool $allow
+ * @param array $header
+ * @return $this
+ */
+ public function allowCrossDomain($allow = true, $header = [])
+ {
+ if (!empty($header)) {
+ $this->header($header);
+ }
+
+ if ($allow && $this->parent) {
+ $this->parent->addRuleItem($this, 'options');
+ }
+
+ return $this->option('cross_domain', $allow);
+ }
+
+ /**
+ * 检查OPTIONS请求
+ * @access public
+ * @param Request $request
+ * @return Dispatch|void
+ */
+ protected function checkCrossDomain($request)
+ {
+ if (!empty($this->option['cross_domain'])) {
+ $header = [
+ 'Access-Control-Allow-Credentials' => 'true',
+ 'Access-Control-Allow-Methods' => 'GET, POST, PATCH, PUT, DELETE',
+ 'Access-Control-Allow-Headers' => 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With',
+ ];
+
+ if (!empty($this->option['header'])) {
+ $header = array_merge($header, $this->option['header']);
+ }
+
+ if (!isset($header['Access-Control-Allow-Origin'])) {
+ $httpOrigin = $request->header('origin');
+
+ if ($httpOrigin && strpos(config('cookie.domain'), $httpOrigin)) {
+ $header['Access-Control-Allow-Origin'] = $httpOrigin;
+ } else {
+ $header['Access-Control-Allow-Origin'] = '*';
+ }
+ }
+
+ $this->option['header'] = $header;
+
+ if ($request->method(true) == 'OPTIONS') {
+ return new ResponseDispatch($request, $this, Response::create()->code(204)->header($header));
+ }
+ }
+ }
+
+ /**
+ * 设置路由规则全局有效
+ * @access public
+ * @return $this
+ */
+ public function crossDomainRule()
+ {
+ if ($this instanceof RuleGroup) {
+ $method = '*';
+ } else {
+ $method = $this->method;
+ }
+
+ $this->router->setCrossDomainRule($this, $method);
+
+ return $this;
+ }
+
+ /**
+ * 合并分组参数
+ * @access public
+ * @return array
+ */
+ public function mergeGroupOptions()
+ {
+ if (!$this->lockOption) {
+ $parentOption = $this->parent->getOption();
+ // 合并分组参数
+ foreach ($this->mergeOptions as $item) {
+ if (isset($parentOption[$item]) && isset($this->option[$item])) {
+ $this->option[$item] = array_merge($parentOption[$item], $this->option[$item]);
+ }
+ }
+
+ $this->option = array_merge($parentOption, $this->option);
+ $this->lockOption = true;
+ }
+
+ return $this->option;
+ }
+
+ /**
+ * 解析匹配到的规则路由
+ * @access public
+ * @param Request $request 请求对象
+ * @param string $rule 路由规则
+ * @param string $route 路由地址
+ * @param string $url URL地址
+ * @param array $option 路由参数
+ * @param array $matches 匹配的变量
+ * @return Dispatch
+ */
+ public function parseRule($request, $rule, $route, $url, $option = [], $matches = [])
+ {
+ if (is_string($route) && isset($option['prefix'])) {
+ // 路由地址前缀
+ $route = $option['prefix'] . $route;
+ }
+
+ // 替换路由地址中的变量
+ if (is_string($route) && !empty($matches)) {
+ $search = $replace = [];
+
+ foreach ($matches as $key => $value) {
+ $search[] = '<' . $key . '>';
+ $replace[] = $value;
+
+ $search[] = ':' . $key;
+ $replace[] = $value;
+ }
+
+ $route = str_replace($search, $replace, $route);
+ }
+
+ // 解析额外参数
+ $count = substr_count($rule, '/');
+ $url = array_slice(explode('|', $url), $count + 1);
+ $this->parseUrlParams($request, implode('|', $url), $matches);
+
+ $this->vars = $matches;
+ $this->option = $option;
+ $this->doAfter = true;
+
+ // 发起路由调度
+ return $this->dispatch($request, $route, $option);
+ }
+
+ /**
+ * 检查路由前置行为
+ * @access protected
+ * @param mixed $before 前置行为
+ * @return mixed
+ */
+ protected function checkBefore($before)
+ {
+ $hook = Container::get('hook');
+
+ foreach ((array) $before as $behavior) {
+ $result = $hook->exec($behavior);
+
+ if (false === $result) {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * 发起路由调度
+ * @access protected
+ * @param Request $request Request对象
+ * @param mixed $route 路由地址
+ * @param array $option 路由参数
+ * @return Dispatch
+ */
+ protected function dispatch($request, $route, $option)
+ {
+ if ($route instanceof \Closure) {
+ // 执行闭包
+ $result = new CallbackDispatch($request, $this, $route);
+ } elseif ($route instanceof Response) {
+ $result = new ResponseDispatch($request, $this, $route);
+ } elseif (isset($option['view']) && false !== $option['view']) {
+ $result = new ViewDispatch($request, $this, $route, is_array($option['view']) ? $option['view'] : []);
+ } elseif (!empty($option['redirect']) || 0 === strpos($route, '/') || strpos($route, '://')) {
+ // 路由到重定向地址
+ $result = new RedirectDispatch($request, $this, $route, [], isset($option['status']) ? $option['status'] : 301);
+ } elseif (false !== strpos($route, '\\')) {
+ // 路由到方法
+ $result = $this->dispatchMethod($request, $route);
+ } elseif (0 === strpos($route, '@')) {
+ // 路由到控制器
+ $result = $this->dispatchController($request, substr($route, 1));
+ } else {
+ // 路由到模块/控制器/操作
+ $result = $this->dispatchModule($request, $route);
+ }
+
+ return $result;
+ }
+
+ /**
+ * 解析URL地址为 模块/控制器/操作
+ * @access protected
+ * @param Request $request Request对象
+ * @param string $route 路由地址
+ * @return CallbackDispatch
+ */
+ protected function dispatchMethod($request, $route)
+ {
+ list($path, $var) = $this->parseUrlPath($route);
+
+ $route = str_replace('/', '@', implode('/', $path));
+ $method = strpos($route, '@') ? explode('@', $route) : $route;
+
+ return new CallbackDispatch($request, $this, $method, $var);
+ }
+
+ /**
+ * 解析URL地址为 模块/控制器/操作
+ * @access protected
+ * @param Request $request Request对象
+ * @param string $route 路由地址
+ * @return ControllerDispatch
+ */
+ protected function dispatchController($request, $route)
+ {
+ list($route, $var) = $this->parseUrlPath($route);
+
+ $result = new ControllerDispatch($request, $this, implode('/', $route), $var);
+
+ $request->setAction(array_pop($route));
+ $request->setController($route ? array_pop($route) : $this->getConfig('default_controller'));
+ $request->setModule($route ? array_pop($route) : $this->getConfig('default_module'));
+
+ return $result;
+ }
+
+ /**
+ * 解析URL地址为 模块/控制器/操作
+ * @access protected
+ * @param Request $request Request对象
+ * @param string $route 路由地址
+ * @return ModuleDispatch
+ */
+ protected function dispatchModule($request, $route)
+ {
+ list($path, $var) = $this->parseUrlPath($route);
+
+ $action = array_pop($path);
+ $controller = !empty($path) ? array_pop($path) : null;
+ $module = $this->getConfig('app_multi_module') && !empty($path) ? array_pop($path) : null;
+ $method = $request->method();
+
+ if ($this->getConfig('use_action_prefix') && $this->router->getMethodPrefix($method)) {
+ $prefix = $this->router->getMethodPrefix($method);
+ // 操作方法前缀支持
+ $action = 0 !== strpos($action, $prefix) ? $prefix . $action : $action;
+ }
+
+ // 设置当前请求的路由变量
+ $request->setRouteVars($var);
+
+ // 路由到模块/控制器/操作
+ return new ModuleDispatch($request, $this, [$module, $controller, $action], ['convert' => false]);
+ }
+
+ /**
+ * 路由检查
+ * @access protected
+ * @param array $option 路由参数
+ * @param Request $request Request对象
+ * @return bool
+ */
+ protected function checkOption($option, Request $request)
+ {
+ // 请求类型检测
+ if (!empty($option['method'])) {
+ if (is_string($option['method']) && false === stripos($option['method'], $request->method())) {
+ return false;
+ }
+ }
+
+ // AJAX PJAX 请求检查
+ foreach (['ajax', 'pjax', 'mobile'] as $item) {
+ if (isset($option[$item])) {
+ $call = 'is' . $item;
+ if ($option[$item] && !$request->$call() || !$option[$item] && $request->$call()) {
+ return false;
+ }
+ }
+ }
+
+ // 伪静态后缀检测
+ if ($request->url() != '/' && ((isset($option['ext']) && false === stripos('|' . $option['ext'] . '|', '|' . $request->ext() . '|'))
+ || (isset($option['deny_ext']) && false !== stripos('|' . $option['deny_ext'] . '|', '|' . $request->ext() . '|')))) {
+ return false;
+ }
+
+ // 域名检查
+ if ((isset($option['domain']) && !in_array($option['domain'], [$request->host(true), $request->subDomain()]))) {
+ return false;
+ }
+
+ // HTTPS检查
+ if ((isset($option['https']) && $option['https'] && !$request->isSsl())
+ || (isset($option['https']) && !$option['https'] && $request->isSsl())) {
+ return false;
+ }
+
+ // 请求参数检查
+ if (isset($option['filter'])) {
+ foreach ($option['filter'] as $name => $value) {
+ if ($request->param($name, '', null) != $value) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 解析URL地址中的参数Request对象
+ * @access protected
+ * @param Request $request
+ * @param string $rule 路由规则
+ * @param array $var 变量
+ * @return void
+ */
+ protected function parseUrlParams($request, $url, &$var = [])
+ {
+ if ($url) {
+ if ($this->getConfig('url_param_type')) {
+ $var += explode('|', $url);
+ } else {
+ preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) {
+ $var[$match[1]] = strip_tags($match[2]);
+ }, $url);
+ }
+ }
+ }
+
+ /**
+ * 解析URL的pathinfo参数和变量
+ * @access public
+ * @param string $url URL地址
+ * @return array
+ */
+ public function parseUrlPath($url)
+ {
+ // 分隔符替换 确保路由定义使用统一的分隔符
+ $url = str_replace('|', '/', $url);
+ $url = trim($url, '/');
+ $var = [];
+
+ if (false !== strpos($url, '?')) {
+ // [模块/控制器/操作?]参数1=值1&参数2=值2...
+ $info = parse_url($url);
+ $path = explode('/', $info['path']);
+ parse_str($info['query'], $var);
+ } elseif (strpos($url, '/')) {
+ // [模块/控制器/操作]
+ $path = explode('/', $url);
+ } elseif (false !== strpos($url, '=')) {
+ // 参数1=值1&参数2=值2...
+ $path = [];
+ parse_str($url, $var);
+ } else {
+ $path = [$url];
+ }
+
+ return [$path, $var];
+ }
+
+ /**
+ * 生成路由的正则规则
+ * @access protected
+ * @param string $rule 路由规则
+ * @param array $match 匹配的变量
+ * @param array $pattern 路由变量规则
+ * @param array $option 路由参数
+ * @param bool $completeMatch 路由是否完全匹配
+ * @param string $suffix 路由正则变量后缀
+ * @return string
+ */
+ protected function buildRuleRegex($rule, $match, $pattern = [], $option = [], $completeMatch = false, $suffix = '')
+ {
+ foreach ($match as $name) {
+ $replace[] = $this->buildNameRegex($name, $pattern, $suffix);
+ }
+
+ // 是否区分 / 地址访问
+ if ('/' != $rule) {
+ if (!empty($option['remove_slash'])) {
+ $rule = rtrim($rule, '/');
+ } elseif (substr($rule, -1) == '/') {
+ $rule = rtrim($rule, '/');
+ $hasSlash = true;
+ }
+ }
+
+ $regex = str_replace(array_unique($match), array_unique($replace), $rule);
+ $regex = str_replace([')?/', ')/', ')?-', ')-', '\\\\/'], [')\/', ')\/', ')\-', ')\-', '\/'], $regex);
+
+ if (isset($hasSlash)) {
+ $regex .= '\/';
+ }
+
+ return $regex . ($completeMatch ? '$' : '');
+ }
+
+ /**
+ * 生成路由变量的正则规则
+ * @access protected
+ * @param string $name 路由变量
+ * @param string $pattern 变量规则
+ * @param string $suffix 路由正则变量后缀
+ * @return string
+ */
+ protected function buildNameRegex($name, $pattern, $suffix)
+ {
+ $optional = '';
+ $slash = substr($name, 0, 1);
+
+ if (in_array($slash, ['/', '-'])) {
+ $prefix = '\\' . $slash;
+ $name = substr($name, 1);
+ $slash = substr($name, 0, 1);
+ } else {
+ $prefix = '';
+ }
+
+ if ('<' != $slash) {
+ return $prefix . preg_quote($name, '/');
+ }
+
+ if (strpos($name, '?')) {
+ $name = substr($name, 1, -2);
+ $optional = '?';
+ } elseif (strpos($name, '>')) {
+ $name = substr($name, 1, -1);
+ }
+
+ if (isset($pattern[$name])) {
+ $nameRule = $pattern[$name];
+ if (0 === strpos($nameRule, '/') && '/' == substr($nameRule, -1)) {
+ $nameRule = substr($nameRule, 1, -1);
+ }
+ } else {
+ $nameRule = $this->getConfig('default_route_pattern');
+ }
+
+ return '(' . $prefix . '(?<' . $name . $suffix . '>' . $nameRule . '))' . $optional;
+ }
+
+ /**
+ * 分析路由规则中的变量
+ * @access protected
+ * @param string $rule 路由规则
+ * @return array
+ */
+ protected function parseVar($rule)
+ {
+ // 提取路由规则中的变量
+ $var = [];
+
+ if (preg_match_all('/<\w+\??>/', $rule, $matches)) {
+ foreach ($matches[0] as $name) {
+ $optional = false;
+
+ if (strpos($name, '?')) {
+ $name = substr($name, 1, -2);
+ $optional = true;
+ } else {
+ $name = substr($name, 1, -1);
+ }
+
+ $var[$name] = $optional ? 2 : 1;
+ }
+ }
+
+ return $var;
+ }
+
+ /**
+ * 设置路由参数
+ * @access public
+ * @param string $method 方法名
+ * @param array $args 调用参数
+ * @return $this
+ */
+ public function __call($method, $args)
+ {
+ if (count($args) > 1) {
+ $args[0] = $args;
+ }
+ array_unshift($args, $method);
+
+ 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');
+ }
+
+ public function __debugInfo()
+ {
+ $data = get_object_vars($this);
+ unset($data['parent'], $data['router'], $data['route']);
+
+ return $data;
+ }
+}
diff --git a/Server/thinkphp/library/think/route/RuleGroup.php b/Server/thinkphp/library/think/route/RuleGroup.php
new file mode 100644
index 00000000..5781d8cf
--- /dev/null
+++ b/Server/thinkphp/library/think/route/RuleGroup.php
@@ -0,0 +1,601 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+use think\Container;
+use think\Exception;
+use think\Request;
+use think\Response;
+use think\Route;
+use think\route\dispatch\Response as ResponseDispatch;
+use think\route\dispatch\Url as UrlDispatch;
+
+class RuleGroup extends Rule
+{
+ // 分组路由(包括子分组)
+ protected $rules = [
+ '*' => [],
+ 'get' => [],
+ 'post' => [],
+ 'put' => [],
+ 'patch' => [],
+ 'delete' => [],
+ 'head' => [],
+ 'options' => [],
+ ];
+
+ // MISS路由
+ protected $miss;
+
+ // 自动路由
+ protected $auto;
+
+ // 完整名称
+ protected $fullName;
+
+ // 所在域名
+ protected $domain;
+
+ /**
+ * 架构函数
+ * @access public
+ * @param Route $router 路由对象
+ * @param RuleGroup $parent 上级对象
+ * @param string $name 分组名称
+ * @param mixed $rule 分组路由
+ * @param array $option 路由参数
+ * @param array $pattern 变量规则
+ */
+ public function __construct(Route $router, RuleGroup $parent = null, $name = '', $rule = [], $option = [], $pattern = [])
+ {
+ $this->router = $router;
+ $this->parent = $parent;
+ $this->rule = $rule;
+ $this->name = trim($name, '/');
+ $this->option = $option;
+ $this->pattern = $pattern;
+
+ $this->setFullName();
+
+ if ($this->parent) {
+ $this->domain = $this->parent->getDomain();
+ $this->parent->addRuleItem($this);
+ }
+
+ if (!empty($option['cross_domain'])) {
+ $this->router->setCrossDomainRule($this);
+ }
+
+ if ($router->isTest()) {
+ $this->lazy(false);
+ }
+ }
+
+ /**
+ * 设置分组的路由规则
+ * @access public
+ * @return void
+ */
+ protected function setFullName()
+ {
+ if (false !== strpos($this->name, ':')) {
+ $this->name = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $this->name);
+ }
+
+ if ($this->parent && $this->parent->getFullName()) {
+ $this->fullName = $this->parent->getFullName() . ($this->name ? '/' . $this->name : '');
+ } else {
+ $this->fullName = $this->name;
+ }
+ }
+
+ /**
+ * 获取所属域名
+ * @access public
+ * @return string
+ */
+ public function getDomain()
+ {
+ return $this->domain;
+ }
+
+ /**
+ * 检测分组路由
+ * @access public
+ * @param Request $request 请求对象
+ * @param string $url 访问地址
+ * @param bool $completeMatch 路由是否完全匹配
+ * @return Dispatch|false
+ */
+ public function check($request, $url, $completeMatch = false)
+ {
+ // 跨域OPTIONS请求
+ if ($dispatch = $this->checkCrossDomain($request)) {
+ return $dispatch;
+ }
+
+ // 检查分组有效性
+ if (!$this->checkOption($this->option, $request) || !$this->checkUrl($url)) {
+ return false;
+ }
+
+ // 检查前置行为
+ if (isset($this->option['before'])) {
+ if (false === $this->checkBefore($this->option['before'])) {
+ return false;
+ }
+ unset($this->option['before']);
+ }
+
+ // 解析分组路由
+ if ($this instanceof Resource) {
+ $this->buildResourceRule();
+ } elseif ($this->rule) {
+ if ($this->rule instanceof Response) {
+ return new ResponseDispatch($request, $this, $this->rule);
+ }
+
+ $this->parseGroupRule($this->rule);
+ }
+
+ // 获取当前路由规则
+ $method = strtolower($request->method());
+ $rules = $this->getMethodRules($method);
+
+ if ($this->parent) {
+ // 合并分组参数
+ $this->mergeGroupOptions();
+ // 合并分组变量规则
+ $this->pattern = array_merge($this->parent->getPattern(), $this->pattern);
+ }
+
+ if (isset($this->option['complete_match'])) {
+ $completeMatch = $this->option['complete_match'];
+ }
+
+ if (!empty($this->option['merge_rule_regex'])) {
+ // 合并路由正则规则进行路由匹配检查
+ $result = $this->checkMergeRuleRegex($request, $rules, $url, $completeMatch);
+
+ if (false !== $result) {
+ return $result;
+ }
+ }
+
+ // 检查分组路由
+ foreach ($rules as $key => $item) {
+ $result = $item->check($request, $url, $completeMatch);
+
+ if (false !== $result) {
+ return $result;
+ }
+ }
+
+ if ($this->auto) {
+ // 自动解析URL地址
+ $result = new UrlDispatch($request, $this, $this->auto . '/' . $url, ['auto_search' => false]);
+ } elseif ($this->miss && in_array($this->miss->getMethod(), ['*', $method])) {
+ // 未匹配所有路由的路由规则处理
+ $result = $this->miss->parseRule($request, '', $this->miss->getRoute(), $url, $this->miss->mergeGroupOptions());
+ } else {
+ $result = false;
+ }
+
+ return $result;
+ }
+
+ /**
+ * 获取当前请求的路由规则(包括子分组、资源路由)
+ * @access protected
+ * @param string $method
+ * @return array
+ */
+ protected function getMethodRules($method)
+ {
+ return array_merge($this->rules[$method], $this->rules['*']);
+ }
+
+ /**
+ * 分组URL匹配检查
+ * @access protected
+ * @param string $url
+ * @return bool
+ */
+ protected function checkUrl($url)
+ {
+ if ($this->fullName) {
+ $pos = strpos($this->fullName, '<');
+
+ if (false !== $pos) {
+ $str = substr($this->fullName, 0, $pos);
+ } else {
+ $str = $this->fullName;
+ }
+
+ if ($str && 0 !== stripos(str_replace('|', '/', $url), $str)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * 延迟解析分组的路由规则
+ * @access public
+ * @param bool $lazy 路由是否延迟解析
+ * @return $this
+ */
+ public function lazy($lazy = true)
+ {
+ if (!$lazy) {
+ $this->parseGroupRule($this->rule);
+ $this->rule = null;
+ }
+
+ return $this;
+ }
+
+ /**
+ * 解析分组和域名的路由规则及绑定
+ * @access public
+ * @param mixed $rule 路由规则
+ * @return void
+ */
+ public function parseGroupRule($rule)
+ {
+ $origin = $this->router->getGroup();
+ $this->router->setGroup($this);
+
+ if ($rule instanceof \Closure) {
+ Container::getInstance()->invokeFunction($rule);
+ } elseif (is_array($rule)) {
+ $this->addRules($rule);
+ } elseif (is_string($rule) && $rule) {
+ $this->router->bind($rule, $this->domain);
+ }
+
+ $this->router->setGroup($origin);
+ }
+
+ /**
+ * 检测分组路由
+ * @access public
+ * @param Request $request 请求对象
+ * @param array $rules 路由规则
+ * @param string $url 访问地址
+ * @param bool $completeMatch 路由是否完全匹配
+ * @return Dispatch|false
+ */
+ protected function checkMergeRuleRegex($request, &$rules, $url, $completeMatch)
+ {
+ $depr = $this->router->config('pathinfo_depr');
+ $url = $depr . str_replace('|', $depr, $url);
+
+ foreach ($rules as $key => $item) {
+ if ($item instanceof RuleItem) {
+ $rule = $depr . str_replace('/', $depr, $item->getRule());
+ if ($depr == $rule && $depr != $url) {
+ unset($rules[$key]);
+ continue;
+ }
+
+ $complete = null !== $item->getOption('complete_match') ? $item->getOption('complete_match') : $completeMatch;
+
+ if (false === strpos($rule, '<')) {
+ if (0 === strcasecmp($rule, $url) || (!$complete && 0 === strncasecmp($rule, $url, strlen($rule)))) {
+ return $item->checkRule($request, $url, []);
+ }
+
+ unset($rules[$key]);
+ continue;
+ }
+
+ $slash = preg_quote('/-' . $depr, '/');
+
+ if ($matchRule = preg_split('/[' . $slash . ']<\w+\??>/', $rule, 2)) {
+ if ($matchRule[0] && 0 !== strncasecmp($rule, $url, strlen($matchRule[0]))) {
+ unset($rules[$key]);
+ continue;
+ }
+ }
+
+ if (preg_match_all('/[' . $slash . ']?\w+\??>?/', $rule, $matches)) {
+ unset($rules[$key]);
+ $pattern = array_merge($this->getPattern(), $item->getPattern());
+ $option = array_merge($this->getOption(), $item->getOption());
+
+ $regex[$key] = $this->buildRuleRegex($rule, $matches[0], $pattern, $option, $complete, '_THINK_' . $key);
+ $items[$key] = $item;
+ }
+ }
+ }
+
+ if (empty($regex)) {
+ return false;
+ }
+
+ try {
+ $result = preg_match('/^(?:' . implode('|', $regex) . ')/u', $url, $match);
+ } catch (\Exception $e) {
+ throw new Exception('route pattern error');
+ }
+
+ if ($result) {
+ $var = [];
+ foreach ($match as $key => $val) {
+ if (is_string($key) && '' !== $val) {
+ list($name, $pos) = explode('_THINK_', $key);
+
+ $var[$name] = $val;
+ }
+ }
+
+ if (!isset($pos)) {
+ foreach ($regex as $key => $item) {
+ if (0 === strpos(str_replace(['\/', '\-', '\\' . $depr], ['/', '-', $depr], $item), $match[0])) {
+ $pos = $key;
+ break;
+ }
+ }
+ }
+
+ $rule = $items[$pos]->getRule();
+ $array = $this->router->getRule($rule);
+
+ foreach ($array as $item) {
+ if (in_array($item->getMethod(), ['*', strtolower($request->method())])) {
+ $result = $item->checkRule($request, $url, $var);
+
+ if (false !== $result) {
+ return $result;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * 获取分组的MISS路由
+ * @access public
+ * @return RuleItem|null
+ */
+ public function getMissRule()
+ {
+ return $this->miss;
+ }
+
+ /**
+ * 获取分组的自动路由
+ * @access public
+ * @return string
+ */
+ public function getAutoRule()
+ {
+ return $this->auto;
+ }
+
+ /**
+ * 注册自动路由
+ * @access public
+ * @param string $route 路由规则
+ * @return void
+ */
+ public function addAutoRule($route)
+ {
+ $this->auto = $route;
+ }
+
+ /**
+ * 注册MISS路由
+ * @access public
+ * @param string $route 路由地址
+ * @param string $method 请求类型
+ * @param array $option 路由参数
+ * @return RuleItem
+ */
+ public function addMissRule($route, $method = '*', $option = [])
+ {
+ // 创建路由规则实例
+ $ruleItem = new RuleItem($this->router, $this, null, '', $route, strtolower($method), $option);
+
+ $this->miss = $ruleItem;
+
+ return $ruleItem;
+ }
+
+ /**
+ * 添加分组下的路由规则或者子分组
+ * @access public
+ * @param string $rule 路由规则
+ * @param string $route 路由地址
+ * @param string $method 请求类型
+ * @param array $option 路由参数
+ * @param array $pattern 变量规则
+ * @return $this
+ */
+ public function addRule($rule, $route, $method = '*', $option = [], $pattern = [])
+ {
+ // 读取路由标识
+ if (is_array($rule)) {
+ $name = $rule[0];
+ $rule = $rule[1];
+ } elseif (is_string($route)) {
+ $name = $route;
+ } else {
+ $name = null;
+ }
+
+ $method = strtolower($method);
+
+ if ('/' === $rule || '' === $rule) {
+ // 首页自动完整匹配
+ $rule .= '$';
+ }
+
+ // 创建路由规则实例
+ $ruleItem = new RuleItem($this->router, $this, $name, $rule, $route, $method, $option, $pattern);
+
+ if (!empty($option['cross_domain'])) {
+ $this->router->setCrossDomainRule($ruleItem, $method);
+ }
+
+ $this->addRuleItem($ruleItem, $method);
+
+ return $ruleItem;
+ }
+
+ /**
+ * 批量注册路由规则
+ * @access public
+ * @param array $rules 路由规则
+ * @param string $method 请求类型
+ * @param array $option 路由参数
+ * @param array $pattern 变量规则
+ * @return void
+ */
+ public function addRules($rules, $method = '*', $option = [], $pattern = [])
+ {
+ foreach ($rules as $key => $val) {
+ if (is_numeric($key)) {
+ $key = array_shift($val);
+ }
+
+ if (is_array($val)) {
+ $route = array_shift($val);
+ $option = $val ? array_shift($val) : [];
+ $pattern = $val ? array_shift($val) : [];
+ } else {
+ $route = $val;
+ }
+
+ $this->addRule($key, $route, $method, $option, $pattern);
+ }
+ }
+
+ public function addRuleItem($rule, $method = '*')
+ {
+ if (strpos($method, '|')) {
+ $rule->method($method);
+ $method = '*';
+ }
+
+ $this->rules[$method][] = $rule;
+
+ return $this;
+ }
+
+ /**
+ * 设置分组的路由前缀
+ * @access public
+ * @param string $prefix
+ * @return $this
+ */
+ public function prefix($prefix)
+ {
+ if ($this->parent && $this->parent->getOption('prefix')) {
+ $prefix = $this->parent->getOption('prefix') . $prefix;
+ }
+
+ return $this->option('prefix', $prefix);
+ }
+
+ /**
+ * 设置资源允许
+ * @access public
+ * @param array $only
+ * @return $this
+ */
+ public function only($only)
+ {
+ return $this->option('only', $only);
+ }
+
+ /**
+ * 设置资源排除
+ * @access public
+ * @param array $except
+ * @return $this
+ */
+ public function except($except)
+ {
+ return $this->option('except', $except);
+ }
+
+ /**
+ * 设置资源路由的变量
+ * @access public
+ * @param array $vars
+ * @return $this
+ */
+ public function vars($vars)
+ {
+ return $this->option('var', $vars);
+ }
+
+ /**
+ * 合并分组的路由规则正则
+ * @access public
+ * @param bool $merge
+ * @return $this
+ */
+ public function mergeRuleRegex($merge = true)
+ {
+ return $this->option('merge_rule_regex', $merge);
+ }
+
+ /**
+ * 获取完整分组Name
+ * @access public
+ * @return string
+ */
+ public function getFullName()
+ {
+ return $this->fullName;
+ }
+
+ /**
+ * 获取分组的路由规则
+ * @access public
+ * @param string $method
+ * @return array
+ */
+ public function getRules($method = '')
+ {
+ if ('' === $method) {
+ return $this->rules;
+ }
+
+ return isset($this->rules[strtolower($method)]) ? $this->rules[strtolower($method)] : [];
+ }
+
+ /**
+ * 清空分组下的路由规则
+ * @access public
+ * @return void
+ */
+ public function clear()
+ {
+ $this->rules = [
+ '*' => [],
+ 'get' => [],
+ 'post' => [],
+ 'put' => [],
+ 'patch' => [],
+ 'delete' => [],
+ 'head' => [],
+ 'options' => [],
+ ];
+ }
+}
diff --git a/Server/thinkphp/library/think/route/RuleItem.php b/Server/thinkphp/library/think/route/RuleItem.php
new file mode 100644
index 00000000..a05d2deb
--- /dev/null
+++ b/Server/thinkphp/library/think/route/RuleItem.php
@@ -0,0 +1,292 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+use think\Container;
+use think\Exception;
+use think\Route;
+
+class RuleItem extends Rule
+{
+ protected $hasSetRule;
+
+ /**
+ * 架构函数
+ * @access public
+ * @param Route $router 路由实例
+ * @param RuleGroup $parent 上级对象
+ * @param string $name 路由标识
+ * @param string|array $rule 路由规则
+ * @param string|\Closure $route 路由地址
+ * @param string $method 请求类型
+ * @param array $option 路由参数
+ * @param array $pattern 变量规则
+ */
+ public function __construct(Route $router, RuleGroup $parent, $name, $rule, $route, $method = '*', $option = [], $pattern = [])
+ {
+ $this->router = $router;
+ $this->parent = $parent;
+ $this->name = $name;
+ $this->route = $route;
+ $this->method = $method;
+ $this->option = $option;
+ $this->pattern = $pattern;
+
+ $this->setRule($rule);
+
+ if (!empty($option['cross_domain'])) {
+ $this->router->setCrossDomainRule($this, $method);
+ }
+ }
+
+ /**
+ * 路由规则预处理
+ * @access public
+ * @param string $rule 路由规则
+ * @return void
+ */
+ public function setRule($rule)
+ {
+ if ('$' == substr($rule, -1, 1)) {
+ // 是否完整匹配
+ $rule = substr($rule, 0, -1);
+
+ $this->option['complete_match'] = true;
+ }
+
+ $rule = '/' != $rule ? ltrim($rule, '/') : '';
+
+ if ($this->parent && $prefix = $this->parent->getFullName()) {
+ $rule = $prefix . ($rule ? '/' . ltrim($rule, '/') : '');
+ }
+
+ if (false !== strpos($rule, ':')) {
+ $this->rule = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $rule);
+ } else {
+ $this->rule = $rule;
+ }
+
+ // 生成路由标识的快捷访问
+ $this->setRuleName();
+ }
+
+ /**
+ * 检查后缀
+ * @access public
+ * @param string $ext
+ * @return $this
+ */
+ public function ext($ext = '')
+ {
+ $this->option('ext', $ext);
+ $this->setRuleName(true);
+
+ return $this;
+ }
+
+ /**
+ * 设置别名
+ * @access public
+ * @param string $name
+ * @return $this
+ */
+ public function name($name)
+ {
+ $this->name = $name;
+ $this->setRuleName(true);
+
+ return $this;
+ }
+
+ /**
+ * 设置路由标识 用于URL反解生成
+ * @access protected
+ * @param bool $first 是否插入开头
+ * @return void
+ */
+ protected function setRuleName($first = false)
+ {
+ if ($this->name) {
+ $vars = $this->parseVar($this->rule);
+ $name = strtolower($this->name);
+
+ if (isset($this->option['ext'])) {
+ $suffix = $this->option['ext'];
+ } elseif ($this->parent->getOption('ext')) {
+ $suffix = $this->parent->getOption('ext');
+ } else {
+ $suffix = null;
+ }
+
+ $value = [$this->rule, $vars, $this->parent->getDomain(), $suffix, $this->method];
+
+ Container::get('rule_name')->set($name, $value, $first);
+ }
+
+ if (!$this->hasSetRule) {
+ Container::get('rule_name')->setRule($this->rule, $this);
+ $this->hasSetRule = true;
+ }
+ }
+
+ /**
+ * 检测路由
+ * @access public
+ * @param Request $request 请求对象
+ * @param string $url 访问地址
+ * @param array $match 匹配路由变量
+ * @param bool $completeMatch 路由是否完全匹配
+ * @return Dispatch|false
+ */
+ public function checkRule($request, $url, $match = null, $completeMatch = false)
+ {
+ // 检查参数有效性
+ if (!$this->checkOption($this->option, $request)) {
+ return false;
+ }
+
+ // 合并分组参数
+ $option = $this->mergeGroupOptions();
+
+ $url = $this->urlSuffixCheck($request, $url, $option);
+
+ if (is_null($match)) {
+ $match = $this->match($url, $option, $completeMatch);
+ }
+
+ if (false !== $match) {
+ if (!empty($option['cross_domain'])) {
+ if ($dispatch = $this->checkCrossDomain($request)) {
+ // 允许跨域
+ return $dispatch;
+ }
+
+ $option['header'] = $this->option['header'];
+ }
+
+ // 检查前置行为
+ if (isset($option['before']) && false === $this->checkBefore($option['before'])) {
+ return false;
+ }
+
+ return $this->parseRule($request, $this->rule, $this->route, $url, $option, $match);
+ }
+
+ return false;
+ }
+
+ /**
+ * 检测路由(含路由匹配)
+ * @access public
+ * @param Request $request 请求对象
+ * @param string $url 访问地址
+ * @param string $depr 路径分隔符
+ * @param bool $completeMatch 路由是否完全匹配
+ * @return Dispatch|false
+ */
+ public function check($request, $url, $completeMatch = false)
+ {
+ return $this->checkRule($request, $url, null, $completeMatch);
+ }
+
+ /**
+ * URL后缀及Slash检查
+ * @access protected
+ * @param Request $request 请求对象
+ * @param string $url 访问地址
+ * @param array $option 路由参数
+ * @return string
+ */
+ protected function urlSuffixCheck($request, $url, $option = [])
+ {
+ // 是否区分 / 地址访问
+ if (!empty($option['remove_slash']) && '/' != $this->rule) {
+ $this->rule = rtrim($this->rule, '/');
+ $url = rtrim($url, '|');
+ }
+
+ if (isset($option['ext'])) {
+ // 路由ext参数 优先于系统配置的URL伪静态后缀参数
+ $url = preg_replace('/\.(' . $request->ext() . ')$/i', '', $url);
+ }
+
+ return $url;
+ }
+
+ /**
+ * 检测URL和规则路由是否匹配
+ * @access private
+ * @param string $url URL地址
+ * @param array $option 路由参数
+ * @param bool $completeMatch 路由是否完全匹配
+ * @return array|false
+ */
+ private function match($url, $option, $completeMatch)
+ {
+ if (isset($option['complete_match'])) {
+ $completeMatch = $option['complete_match'];
+ }
+
+ $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))) {
+ return false;
+ }
+
+ $var = [];
+ $url = $depr . str_replace('|', $depr, $url);
+ $rule = $depr . str_replace('/', $depr, $this->rule);
+
+ if ($depr == $rule && $depr != $url) {
+ return false;
+ }
+
+ if (false === strpos($rule, '<')) {
+ if (0 === strcasecmp($rule, $url) || (!$completeMatch && 0 === strncasecmp($rule . $depr, $url . $depr, strlen($rule . $depr)))) {
+ return $var;
+ }
+ return false;
+ }
+
+ $slash = preg_quote('/-' . $depr, '/');
+
+ if ($matchRule = preg_split('/[' . $slash . ']?<\w+\??>/', $rule, 2)) {
+ if ($matchRule[0] && 0 !== strncasecmp($rule, $url, strlen($matchRule[0]))) {
+ return false;
+ }
+ }
+
+ if (preg_match_all('/[' . $slash . ']?\w+\??>?/', $rule, $matches)) {
+ $regex = $this->buildRuleRegex($rule, $matches[0], $pattern, $option, $completeMatch);
+
+ try {
+ if (!preg_match('/^' . $regex . ($completeMatch ? '$' : '') . '/u', $url, $match)) {
+ return false;
+ }
+ } catch (\Exception $e) {
+ throw new Exception('route pattern error');
+ }
+
+ foreach ($match as $key => $val) {
+ if (is_string($key)) {
+ $var[$key] = $val;
+ }
+ }
+ }
+
+ // 成功匹配后返回URL中的动态变量数组
+ return $var;
+ }
+
+}
diff --git a/Server/thinkphp/library/think/route/RuleName.php b/Server/thinkphp/library/think/route/RuleName.php
new file mode 100644
index 00000000..202fb0e2
--- /dev/null
+++ b/Server/thinkphp/library/think/route/RuleName.php
@@ -0,0 +1,147 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route;
+
+class RuleName
+{
+ protected $item = [];
+ protected $rule = [];
+
+ /**
+ * 注册路由标识
+ * @access public
+ * @param string $name 路由标识
+ * @param array $value 路由规则
+ * @param bool $first 是否置顶
+ * @return void
+ */
+ public function set($name, $value, $first = false)
+ {
+ if ($first && isset($this->item[$name])) {
+ array_unshift($this->item[$name], $value);
+ } else {
+ $this->item[$name][] = $value;
+ }
+ }
+
+ /**
+ * 注册路由规则
+ * @access public
+ * @param string $rule 路由规则
+ * @param RuleItem $route 路由
+ * @return void
+ */
+ public function setRule($rule, $route)
+ {
+ $this->rule[$route->getDomain()][$rule][$route->getMethod()] = $route;
+ }
+
+ /**
+ * 根据路由规则获取路由对象(列表)
+ * @access public
+ * @param string $name 路由标识
+ * @param string $domain 域名
+ * @return array
+ */
+ public function getRule($rule, $domain = null)
+ {
+ return isset($this->rule[$domain][$rule]) ? $this->rule[$domain][$rule] : [];
+ }
+
+ /**
+ * 获取全部路由列表
+ * @access public
+ * @param string $domain 域名
+ * @return array
+ */
+ public function getRuleList($domain = null)
+ {
+ $list = [];
+
+ foreach ($this->rule as $ruleDomain => $rules) {
+ foreach ($rules as $rule => $items) {
+ foreach ($items as $item) {
+ $val['domain'] = $ruleDomain;
+
+ foreach (['method', 'rule', 'name', 'route', 'pattern', 'option'] as $param) {
+ $call = 'get' . $param;
+ $val[$param] = $item->$call();
+ }
+
+ $list[$ruleDomain][] = $val;
+ }
+ }
+ }
+
+ if ($domain) {
+ return isset($list[$domain]) ? $list[$domain] : [];
+ }
+
+ return $list;
+ }
+
+ /**
+ * 导入路由标识
+ * @access public
+ * @param array $name 路由标识
+ * @return void
+ */
+ public function import($item)
+ {
+ $this->item = $item;
+ }
+
+ /**
+ * 根据路由标识获取路由信息(用于URL生成)
+ * @access public
+ * @param string $name 路由标识
+ * @param string $domain 域名
+ * @return array|null
+ */
+ public function get($name = null, $domain = null, $method = '*')
+ {
+ if (is_null($name)) {
+ return $this->item;
+ }
+
+ $name = strtolower($name);
+ $method = strtolower($method);
+
+ if (isset($this->item[$name])) {
+ if (is_null($domain)) {
+ $result = $this->item[$name];
+ } else {
+ $result = [];
+ foreach ($this->item[$name] as $item) {
+ if ($item[2] == $domain && ('*' == $item[4] || $method == $item[4])) {
+ $result[] = $item;
+ }
+ }
+ }
+ } else {
+ $result = null;
+ }
+
+ return $result;
+ }
+
+ /**
+ * 清空路由规则
+ * @access public
+ * @return void
+ */
+ public function clear()
+ {
+ $this->item = [];
+ $this->rule = [];
+ }
+}
diff --git a/Server/thinkphp/library/think/route/dispatch/Callback.php b/Server/thinkphp/library/think/route/dispatch/Callback.php
new file mode 100644
index 00000000..ca76fc99
--- /dev/null
+++ b/Server/thinkphp/library/think/route/dispatch/Callback.php
@@ -0,0 +1,26 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route\dispatch;
+
+use think\route\Dispatch;
+
+class Callback extends Dispatch
+{
+ public function exec()
+ {
+ // 执行回调方法
+ $vars = array_merge($this->request->param(), $this->param);
+
+ return $this->app->invoke($this->dispatch, $vars);
+ }
+
+}
diff --git a/Server/thinkphp/library/think/route/dispatch/Controller.php b/Server/thinkphp/library/think/route/dispatch/Controller.php
new file mode 100644
index 00000000..1de82992
--- /dev/null
+++ b/Server/thinkphp/library/think/route/dispatch/Controller.php
@@ -0,0 +1,30 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route\dispatch;
+
+use think\route\Dispatch;
+
+class Controller extends Dispatch
+{
+ public function exec()
+ {
+ // 执行控制器的操作方法
+ $vars = array_merge($this->request->param(), $this->param);
+
+ return $this->app->action(
+ $this->dispatch, $vars,
+ $this->rule->getConfig('url_controller_layer'),
+ $this->rule->getConfig('controller_suffix')
+ );
+ }
+
+}
diff --git a/Server/thinkphp/library/think/route/dispatch/Module.php b/Server/thinkphp/library/think/route/dispatch/Module.php
new file mode 100644
index 00000000..40bd7759
--- /dev/null
+++ b/Server/thinkphp/library/think/route/dispatch/Module.php
@@ -0,0 +1,138 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route\dispatch;
+
+use ReflectionMethod;
+use think\exception\ClassNotFoundException;
+use think\exception\HttpException;
+use think\Loader;
+use think\Request;
+use think\route\Dispatch;
+
+class Module extends Dispatch
+{
+ protected $controller;
+ protected $actionName;
+
+ public function init()
+ {
+ parent::init();
+
+ $result = $this->dispatch;
+
+ if (is_string($result)) {
+ $result = explode('/', $result);
+ }
+
+ if ($this->rule->getConfig('app_multi_module')) {
+ // 多模块部署
+ $module = strip_tags(strtolower($result[0] ?: $this->rule->getConfig('default_module')));
+ $bind = $this->rule->getRouter()->getBind();
+ $available = false;
+
+ if ($bind && preg_match('/^[a-z]/is', $bind)) {
+ // 绑定模块
+ list($bindModule) = explode('/', $bind);
+ if (empty($result[0])) {
+ $module = $bindModule;
+ }
+ $available = true;
+ } elseif (!in_array($module, $this->rule->getConfig('deny_module_list')) && is_dir($this->app->getAppPath() . $module)) {
+ $available = true;
+ } elseif ($this->rule->getConfig('empty_module')) {
+ $module = $this->rule->getConfig('empty_module');
+ $available = true;
+ }
+
+ // 模块初始化
+ if ($module && $available) {
+ // 初始化模块
+ $this->request->setModule($module);
+ $this->app->init($module);
+ } else {
+ throw new HttpException(404, 'module not exists:' . $module);
+ }
+ }
+
+ // 是否自动转换控制器和操作名
+ $convert = is_bool($this->convert) ? $this->convert : $this->rule->getConfig('url_convert');
+ // 获取控制器名
+ $controller = strip_tags($result[1] ?: $this->rule->getConfig('default_controller'));
+
+ $this->controller = $convert ? strtolower($controller) : $controller;
+
+ // 获取操作名
+ $this->actionName = strip_tags($result[2] ?: $this->rule->getConfig('default_action'));
+
+ // 设置当前请求的控制器、操作
+ $this->request
+ ->setController(Loader::parseName($this->controller, 1))
+ ->setAction($this->actionName);
+
+ return $this;
+ }
+
+ public function exec()
+ {
+ // 监听module_init
+ $this->app['hook']->listen('module_init');
+
+ try {
+ // 实例化控制器
+ $instance = $this->app->controller($this->controller,
+ $this->rule->getConfig('url_controller_layer'),
+ $this->rule->getConfig('controller_suffix'),
+ $this->rule->getConfig('empty_controller'));
+ } catch (ClassNotFoundException $e) {
+ throw new HttpException(404, 'controller not exists:' . $e->getClass());
+ }
+
+ $this->app['middleware']->controller(function (Request $request, $next) use ($instance) {
+ // 获取当前操作名
+ $action = $this->actionName . $this->rule->getConfig('action_suffix');
+
+ if (is_callable([$instance, $action])) {
+ // 执行操作方法
+ $call = [$instance, $action];
+
+ // 严格获取当前操作方法名
+ $reflect = new ReflectionMethod($instance, $action);
+ $methodName = $reflect->getName();
+ $suffix = $this->rule->getConfig('action_suffix');
+ $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName;
+ $this->request->setAction($actionName);
+
+ // 自动获取请求变量
+ $vars = $this->rule->getConfig('url_param_type')
+ ? $this->request->route()
+ : $this->request->param();
+ $vars = array_merge($vars, $this->param);
+ } elseif (is_callable([$instance, '_empty'])) {
+ // 空操作
+ $call = [$instance, '_empty'];
+ $vars = [$this->actionName];
+ $reflect = new ReflectionMethod($instance, '_empty');
+ } else {
+ // 操作不存在
+ throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()');
+ }
+
+ $this->app['hook']->listen('action_begin', $call);
+
+ $data = $this->app->invokeReflectMethod($instance, $reflect, $vars);
+
+ return $this->autoResponse($data);
+ });
+
+ return $this->app['middleware']->dispatch($this->request, 'controller');
+ }
+}
diff --git a/Server/thinkphp/library/think/route/dispatch/Redirect.php b/Server/thinkphp/library/think/route/dispatch/Redirect.php
new file mode 100644
index 00000000..fae2c9a6
--- /dev/null
+++ b/Server/thinkphp/library/think/route/dispatch/Redirect.php
@@ -0,0 +1,23 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route\dispatch;
+
+use think\Response;
+use think\route\Dispatch;
+
+class Redirect extends Dispatch
+{
+ public function exec()
+ {
+ return Response::create($this->dispatch, 'redirect')->code($this->code);
+ }
+}
diff --git a/Server/thinkphp/library/think/route/dispatch/Response.php b/Server/thinkphp/library/think/route/dispatch/Response.php
new file mode 100644
index 00000000..66f4e5ab
--- /dev/null
+++ b/Server/thinkphp/library/think/route/dispatch/Response.php
@@ -0,0 +1,23 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route\dispatch;
+
+use think\route\Dispatch;
+
+class Response extends Dispatch
+{
+ public function exec()
+ {
+ return $this->dispatch;
+ }
+
+}
diff --git a/Server/thinkphp/library/think/route/dispatch/Url.php b/Server/thinkphp/library/think/route/dispatch/Url.php
new file mode 100644
index 00000000..acc524e3
--- /dev/null
+++ b/Server/thinkphp/library/think/route/dispatch/Url.php
@@ -0,0 +1,169 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route\dispatch;
+
+use think\exception\HttpException;
+use think\Loader;
+use think\route\Dispatch;
+
+class Url extends Dispatch
+{
+ public function init()
+ {
+ // 解析默认的URL规则
+ $result = $this->parseUrl($this->dispatch);
+
+ return (new Module($this->request, $this->rule, $result))->init();
+ }
+
+ public function exec()
+ {}
+
+ /**
+ * 解析URL地址
+ * @access protected
+ * @param string $url URL
+ * @return array
+ */
+ protected function parseUrl($url)
+ {
+ $depr = $this->rule->getConfig('pathinfo_depr');
+ $bind = $this->rule->getRouter()->getBind();
+
+ if (!empty($bind) && preg_match('/^[a-z]/is', $bind)) {
+ $bind = str_replace('/', $depr, $bind);
+ // 如果有模块/控制器绑定
+ $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr);
+ }
+
+ list($path, $var) = $this->rule->parseUrlPath($url);
+ if (empty($path)) {
+ return [null, null, null];
+ }
+
+ // 解析模块
+ $module = $this->rule->getConfig('app_multi_module') ? array_shift($path) : null;
+
+ if ($this->param['auto_search']) {
+ $controller = $this->autoFindController($module, $path);
+ } else {
+ // 解析控制器
+ $controller = !empty($path) ? array_shift($path) : null;
+ }
+
+ if ($controller && !preg_match('/^[A-Za-z0-9][\w|\.]*$/', $controller)) {
+ throw new HttpException(404, 'controller not exists:' . $controller);
+ }
+
+ // 解析操作
+ $action = !empty($path) ? array_shift($path) : null;
+
+ // 解析额外参数
+ if ($path) {
+ if ($this->rule->getConfig('url_param_type')) {
+ $var += $path;
+ } else {
+ preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) {
+ $var[$match[1]] = strip_tags($match[2]);
+ }, implode('|', $path));
+ }
+ }
+
+ $panDomain = $this->request->panDomain();
+
+ if ($panDomain && $key = array_search('*', $var)) {
+ // 泛域名赋值
+ $var[$key] = $panDomain;
+ }
+
+ // 设置当前请求的参数
+ $this->request->setRouteVars($var);
+
+ // 封装路由
+ $route = [$module, $controller, $action];
+
+ if ($this->hasDefinedRoute($route, $bind)) {
+ throw new HttpException(404, 'invalid request:' . str_replace('|', $depr, $url));
+ }
+
+ return $route;
+ }
+
+ /**
+ * 检查URL是否已经定义过路由
+ * @access protected
+ * @param string $route 路由信息
+ * @param string $bind 绑定信息
+ * @return bool
+ */
+ protected function hasDefinedRoute($route, $bind)
+ {
+ list($module, $controller, $action) = $route;
+
+ // 检查地址是否被定义过路由
+ $name = strtolower($module . '/' . Loader::parseName($controller, 1) . '/' . $action);
+
+ $name2 = '';
+
+ if (empty($module) || $module == $bind) {
+ $name2 = strtolower(Loader::parseName($controller, 1) . '/' . $action);
+ }
+
+ $host = $this->request->host(true);
+
+ $method = $this->request->method();
+
+ if ($this->rule->getRouter()->getName($name, $host, $method) || $this->rule->getRouter()->getName($name2, $host, $method)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * 自动定位控制器类
+ * @access protected
+ * @param string $module 模块名
+ * @param array $path URL
+ * @return string
+ */
+ protected function autoFindController($module, &$path)
+ {
+ $dir = $this->app->getAppPath() . ($module ? $module . '/' : '') . $this->rule->getConfig('url_controller_layer');
+ $suffix = $this->app->getSuffix() || $this->rule->getConfig('controller_suffix') ? ucfirst($this->rule->getConfig('url_controller_layer')) : '';
+
+ $item = [];
+ $find = false;
+
+ foreach ($path as $val) {
+ $item[] = $val;
+ $file = $dir . '/' . str_replace('.', '/', $val) . $suffix . '.php';
+ $file = pathinfo($file, PATHINFO_DIRNAME) . '/' . Loader::parseName(pathinfo($file, PATHINFO_FILENAME), 1) . '.php';
+ if (is_file($file)) {
+ $find = true;
+ break;
+ } else {
+ $dir .= '/' . Loader::parseName($val);
+ }
+ }
+
+ if ($find) {
+ $controller = implode('.', $item);
+ $path = array_slice($path, count($item));
+ } else {
+ $controller = array_shift($path);
+ }
+
+ return $controller;
+ }
+
+}
diff --git a/Server/thinkphp/library/think/route/dispatch/View.php b/Server/thinkphp/library/think/route/dispatch/View.php
new file mode 100644
index 00000000..ea3ef11b
--- /dev/null
+++ b/Server/thinkphp/library/think/route/dispatch/View.php
@@ -0,0 +1,26 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\route\dispatch;
+
+use think\Response;
+use think\route\Dispatch;
+
+class View extends Dispatch
+{
+ public function exec()
+ {
+ // 渲染模板输出
+ $vars = array_merge($this->request->param(), $this->param);
+
+ return Response::create($this->dispatch, 'view')->assign($vars);
+ }
+}
diff --git a/Server/thinkphp/library/think/validate/ValidateRule.php b/Server/thinkphp/library/think/validate/ValidateRule.php
new file mode 100644
index 00000000..7cd70174
--- /dev/null
+++ b/Server/thinkphp/library/think/validate/ValidateRule.php
@@ -0,0 +1,171 @@
+
+// +----------------------------------------------------------------------
+
+namespace think\validate;
+
+/**
+ * Class ValidateRule
+ * @package think\validate
+ * @method ValidateRule confirm(mixed $rule, string $msg = '') static 验证是否和某个字段的值一致
+ * @method ValidateRule different(mixed $rule, string $msg = '') static 验证是否和某个字段的值是否不同
+ * @method ValidateRule egt(mixed $rule, string $msg = '') static 验证是否大于等于某个值
+ * @method ValidateRule gt(mixed $rule, string $msg = '') static 验证是否大于某个值
+ * @method ValidateRule elt(mixed $rule, string $msg = '') static 验证是否小于等于某个值
+ * @method ValidateRule lt(mixed $rule, string $msg = '') static 验证是否小于某个值
+ * @method ValidateRule eg(mixed $rule, string $msg = '') static 验证是否等于某个值
+ * @method ValidateRule in(mixed $rule, string $msg = '') static 验证是否在范围内
+ * @method ValidateRule notIn(mixed $rule, string $msg = '') static 验证是否不在某个范围
+ * @method ValidateRule between(mixed $rule, string $msg = '') static 验证是否在某个区间
+ * @method ValidateRule notBetween(mixed $rule, string $msg = '') static 验证是否不在某个区间
+ * @method ValidateRule length(mixed $rule, string $msg = '') static 验证数据长度
+ * @method ValidateRule max(mixed $rule, string $msg = '') static 验证数据最大长度
+ * @method ValidateRule min(mixed $rule, string $msg = '') static 验证数据最小长度
+ * @method ValidateRule after(mixed $rule, string $msg = '') static 验证日期
+ * @method ValidateRule before(mixed $rule, string $msg = '') static 验证日期
+ * @method ValidateRule expire(mixed $rule, string $msg = '') static 验证有效期
+ * @method ValidateRule allowIp(mixed $rule, string $msg = '') static 验证IP许可
+ * @method ValidateRule denyIp(mixed $rule, string $msg = '') static 验证IP禁用
+ * @method ValidateRule regex(mixed $rule, string $msg = '') static 使用正则验证数据
+ * @method ValidateRule token(mixed $rule='__token__', string $msg = '') static 验证表单令牌
+ * @method ValidateRule is(mixed $rule, string $msg = '') static 验证字段值是否为有效格式
+ * @method ValidateRule isRequire(mixed $rule = null, string $msg = '') static 验证字段必须
+ * @method ValidateRule isNumber(mixed $rule = null, string $msg = '') static 验证字段值是否为数字
+ * @method ValidateRule isArray(mixed $rule = null, string $msg = '') static 验证字段值是否为数组
+ * @method ValidateRule isInteger(mixed $rule = null, string $msg = '') static 验证字段值是否为整形
+ * @method ValidateRule isFloat(mixed $rule = null, string $msg = '') static 验证字段值是否为浮点数
+ * @method ValidateRule isMobile(mixed $rule = null, string $msg = '') static 验证字段值是否为手机
+ * @method ValidateRule isIdCard(mixed $rule = null, string $msg = '') static 验证字段值是否为身份证号码
+ * @method ValidateRule isChs(mixed $rule = null, string $msg = '') static 验证字段值是否为中文
+ * @method ValidateRule isChsDash(mixed $rule = null, string $msg = '') static 验证字段值是否为中文字母及下划线
+ * @method ValidateRule isChsAlpha(mixed $rule = null, string $msg = '') static 验证字段值是否为中文和字母
+ * @method ValidateRule isChsAlphaNum(mixed $rule = null, string $msg = '') static 验证字段值是否为中文字母和数字
+ * @method ValidateRule isDate(mixed $rule = null, string $msg = '') static 验证字段值是否为有效格式
+ * @method ValidateRule isBool(mixed $rule = null, string $msg = '') static 验证字段值是否为布尔值
+ * @method ValidateRule isAlpha(mixed $rule = null, string $msg = '') static 验证字段值是否为字母
+ * @method ValidateRule isAlphaDash(mixed $rule = null, string $msg = '') static 验证字段值是否为字母和下划线
+ * @method ValidateRule isAlphaNum(mixed $rule = null, string $msg = '') static 验证字段值是否为字母和数字
+ * @method ValidateRule isAccepted(mixed $rule = null, string $msg = '') static 验证字段值是否为yes, on, 或是 1
+ * @method ValidateRule isEmail(mixed $rule = null, string $msg = '') static 验证字段值是否为有效邮箱格式
+ * @method ValidateRule isUrl(mixed $rule = null, string $msg = '') static 验证字段值是否为有效URL地址
+ * @method ValidateRule activeUrl(mixed $rule, string $msg = '') static 验证是否为合格的域名或者IP
+ * @method ValidateRule ip(mixed $rule, string $msg = '') static 验证是否有效IP
+ * @method ValidateRule fileExt(mixed $rule, string $msg = '') static 验证文件后缀
+ * @method ValidateRule fileMime(mixed $rule, string $msg = '') static 验证文件类型
+ * @method ValidateRule fileSize(mixed $rule, string $msg = '') static 验证文件大小
+ * @method ValidateRule image(mixed $rule, string $msg = '') static 验证图像文件
+ * @method ValidateRule method(mixed $rule, string $msg = '') static 验证请求类型
+ * @method ValidateRule dateFormat(mixed $rule, string $msg = '') static 验证时间和日期是否符合指定格式
+ * @method ValidateRule unique(mixed $rule, string $msg = '') static 验证是否唯一
+ * @method ValidateRule behavior(mixed $rule, string $msg = '') static 使用行为类验证
+ * @method ValidateRule filter(mixed $rule, string $msg = '') static 使用filter_var方式验证
+ * @method ValidateRule requireIf(mixed $rule, string $msg = '') static 验证某个字段等于某个值的时候必须
+ * @method ValidateRule requireCallback(mixed $rule, string $msg = '') static 通过回调方法验证某个字段是否必须
+ * @method ValidateRule requireWith(mixed $rule, string $msg = '') static 验证某个字段有值的情况下必须
+ * @method ValidateRule must(mixed $rule = null, string $msg = '') static 必须验证
+ */
+class ValidateRule
+{
+ // 验证字段的名称
+ protected $title;
+
+ // 当前验证规则
+ protected $rule = [];
+
+ // 验证提示信息
+ protected $message = [];
+
+ /**
+ * 添加验证因子
+ * @access protected
+ * @param string $name 验证名称
+ * @param mixed $rule 验证规则
+ * @param string $msg 提示信息
+ * @return $this
+ */
+ protected function addItem($name, $rule = null, $msg = '')
+ {
+ if ($rule || 0 === $rule) {
+ $this->rule[$name] = $rule;
+ } else {
+ $this->rule[] = $name;
+ }
+
+ $this->message[] = $msg;
+
+ return $this;
+ }
+
+ /**
+ * 获取验证规则
+ * @access public
+ * @return array
+ */
+ public function getRule()
+ {
+ return $this->rule;
+ }
+
+ /**
+ * 获取验证字段名称
+ * @access public
+ * @return string
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+ /**
+ * 获取验证提示
+ * @access public
+ * @return array
+ */
+ public function getMsg()
+ {
+ return $this->message;
+ }
+
+ /**
+ * 设置验证字段名称
+ * @access public
+ * @return $this
+ */
+ public function title($title)
+ {
+ $this->title = $title;
+
+ return $this;
+ }
+
+ public function __call($method, $args)
+ {
+ if ('is' == strtolower(substr($method, 0, 2))) {
+ $method = substr($method, 2);
+ }
+
+ array_unshift($args, lcfirst($method));
+
+ return call_user_func_array([$this, 'addItem'], $args);
+ }
+
+ public static function __callStatic($method, $args)
+ {
+ $rule = new static();
+
+ if ('is' == strtolower(substr($method, 0, 2))) {
+ $method = substr($method, 2);
+ }
+
+ array_unshift($args, lcfirst($method));
+
+ return call_user_func_array([$rule, 'addItem'], $args);
+ }
+}
diff --git a/Server/thinkphp/phpunit.xml.dist b/Server/thinkphp/phpunit.xml.dist
new file mode 100644
index 00000000..37c3d2b5
--- /dev/null
+++ b/Server/thinkphp/phpunit.xml.dist
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ./library/think/*/tests/
+
+
+
+
+
+ ./library/
+
+ ./library/think/*/tests
+ ./library/think/*/assets
+ ./library/think/*/resources
+ ./library/think/*/vendor
+
+
+
+
\ No newline at end of file
diff --git a/Serverruntime/log/202507/07.log b/Serverruntime/log/202507/07.log
index 9496ef4b..ce887b9a 100644
--- a/Serverruntime/log/202507/07.log
+++ b/Serverruntime/log/202507/07.log
@@ -23,3 +23,28 @@
[运行时间:0.008414s] [吞吐率:118.85req/s] [内存消耗:441.96kb] [文件加载:17]
[ error ] [0]Fatal error: Class 'think\Container' not found[E:\WorkSpace\Maokaka\Server\public\index.php:33]
[ info ] [ LOG ] INIT File
+---------------------------------------------------------------
+[ 2025-07-07T12:25:29+08:00 ] 127.0.0.1 GET www.yishi.com/
+[运行时间:0.013366s] [吞吐率:74.82req/s] [内存消耗:23.02kb] [文件加载:17]
+[ error ] [0]Fatal error: Class 'think\Container' not found[E:\WorkSpace\Maokaka\Server\public\index.php:33]
+[ info ] [ LOG ] INIT File
+---------------------------------------------------------------
+[ 2025-07-07T12:26:30+08:00 ] 127.0.0.1 GET www.yishi.com/
+[运行时间:0.014007s] [吞吐率:71.39req/s] [内存消耗:23.02kb] [文件加载:17]
+[ error ] [0]Fatal error: Class 'think\Container' not found[E:\WorkSpace\Maokaka\Server\public\index.php:33]
+[ info ] [ LOG ] INIT File
+---------------------------------------------------------------
+[ 2025-07-07T12:27:25+08:00 ] 127.0.0.1 GET www.yishi.com/
+[运行时间:0.013642s] [吞吐率:73.30req/s] [内存消耗:23.02kb] [文件加载:17]
+[ error ] [0]Fatal error: Class 'think\Container' not found[E:\WorkSpace\Maokaka\Server\public\index.php:33]
+[ info ] [ LOG ] INIT File
+---------------------------------------------------------------
+[ 2025-07-07T12:27:26+08:00 ] 127.0.0.1 GET www.yishi.com/
+[运行时间:0.004214s] [吞吐率:237.30req/s] [内存消耗:20.68kb] [文件加载:18]
+[ error ] [0]Fatal error: Class 'think\Container' not found[E:\WorkSpace\Maokaka\Server\public\index.php:33]
+[ info ] [ LOG ] INIT File
+---------------------------------------------------------------
+[ 2025-07-07T12:31:39+08:00 ] 127.0.0.1 GET www.yishi.com/
+[运行时间:0.014264s] [吞吐率:70.11req/s] [内存消耗:23.02kb] [文件加载:17]
+[ error ] [0]Fatal error: Class 'think\Container' not found[E:\WorkSpace\Maokaka\Server\public\index.php:33]
+[ info ] [ LOG ] INIT File