添加网站文件
This commit is contained in:
119
thinkphp/library/think/route/AliasRule.php
Normal file
119
thinkphp/library/think/route/AliasRule.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
366
thinkphp/library/think/route/Dispatch.php
Normal file
366
thinkphp/library/think/route/Dispatch.php
Normal file
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
236
thinkphp/library/think/route/Domain.php
Normal file
236
thinkphp/library/think/route/Domain.php
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\route;
|
||||
|
||||
use think\Container;
|
||||
use think\Loader;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
126
thinkphp/library/think/route/Resource.php
Normal file
126
thinkphp/library/think/route/Resource.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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], '<id>') && isset($option['var'][$last])) {
|
||||
$val[1] = str_replace('<id>', '<' . $option['var'][$last] . '>', $val[1]);
|
||||
} elseif (strpos($val[1], '<id>') && isset($option['var'][$rule])) {
|
||||
$val[1] = str_replace('<id>', '<' . $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;
|
||||
}
|
||||
}
|
||||
1130
thinkphp/library/think/route/Rule.php
Normal file
1130
thinkphp/library/think/route/Rule.php
Normal file
File diff suppressed because it is too large
Load Diff
601
thinkphp/library/think/route/RuleGroup.php
Normal file
601
thinkphp/library/think/route/RuleGroup.php
Normal file
@@ -0,0 +1,601 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
292
thinkphp/library/think/route/RuleItem.php
Normal file
292
thinkphp/library/think/route/RuleItem.php
Normal file
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
147
thinkphp/library/think/route/RuleName.php
Normal file
147
thinkphp/library/think/route/RuleName.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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 = [];
|
||||
}
|
||||
}
|
||||
26
thinkphp/library/think/route/dispatch/Callback.php
Normal file
26
thinkphp/library/think/route/dispatch/Callback.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
30
thinkphp/library/think/route/dispatch/Controller.php
Normal file
30
thinkphp/library/think/route/dispatch/Controller.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
138
thinkphp/library/think/route/dispatch/Module.php
Normal file
138
thinkphp/library/think/route/dispatch/Module.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
23
thinkphp/library/think/route/dispatch/Redirect.php
Normal file
23
thinkphp/library/think/route/dispatch/Redirect.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
23
thinkphp/library/think/route/dispatch/Response.php
Normal file
23
thinkphp/library/think/route/dispatch/Response.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace think\route\dispatch;
|
||||
|
||||
use think\route\Dispatch;
|
||||
|
||||
class Response extends Dispatch
|
||||
{
|
||||
public function exec()
|
||||
{
|
||||
return $this->dispatch;
|
||||
}
|
||||
|
||||
}
|
||||
169
thinkphp/library/think/route/dispatch/Url.php
Normal file
169
thinkphp/library/think/route/dispatch/Url.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
26
thinkphp/library/think/route/dispatch/View.php
Normal file
26
thinkphp/library/think/route/dispatch/View.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user