Url.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace think\route\dispatch;
  13. use think\exception\HttpException;
  14. use think\helper\Str;
  15. use think\Request;
  16. use think\route\Rule;
  17. /**
  18. * Url Dispatcher
  19. */
  20. class Url extends Controller
  21. {
  22. public function __construct(Request $request, Rule $rule, $dispatch)
  23. {
  24. $this->request = $request;
  25. $this->rule = $rule;
  26. // 解析默认的URL规则
  27. $dispatch = $this->parseUrl($dispatch);
  28. parent::__construct($request, $rule, $dispatch, $this->param);
  29. }
  30. /**
  31. * 解析URL地址
  32. * @access protected
  33. * @param string $url URL
  34. * @return array
  35. */
  36. protected function parseUrl(string $url): array
  37. {
  38. $depr = $this->rule->config('pathinfo_depr');
  39. $bind = $this->rule->getRouter()->getDomainBind();
  40. if ($bind && preg_match('/^[a-z]/is', $bind)) {
  41. $bind = str_replace('/', $depr, $bind);
  42. // 如果有域名绑定
  43. $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr);
  44. }
  45. $path = $this->rule->parseUrlPath($url);
  46. if (empty($path)) {
  47. return [null, null];
  48. }
  49. $appName = !empty($path) ? array_shift($path) : null;
  50. // 解析控制器
  51. $controller = !empty($path) ? array_shift($path) : $this->rule->config('default_controller');
  52. if ($controller && !preg_match('/^[A-Za-z0-9][\w|\.]*$/', $controller)) {
  53. throw new HttpException(404, 'controller not exists:' . $controller);
  54. }
  55. // 解析操作
  56. $action = !empty($path) ? array_shift($path) : $this->rule->config('default_action');
  57. $var = [];
  58. // 解析额外参数
  59. if ($path) {
  60. preg_replace_callback('/(\w+)\|([^\|]+)/', function ($match) use (&$var) {
  61. $var[$match[1]] = strip_tags($match[2]);
  62. }, implode('|', $path));
  63. }
  64. $panDomain = $this->request->panDomain();
  65. if ($panDomain && $key = array_search('*', $var)) {
  66. // 泛域名赋值
  67. $var[$key] = $panDomain;
  68. }
  69. // 设置当前请求的参数
  70. $this->param = $var;
  71. // 封装路由
  72. $route = [$appName, $controller, $action];
  73. if ($this->hasDefinedRoute($route)) {
  74. throw new HttpException(404, 'invalid request:' . str_replace('|', $depr, $url));
  75. }
  76. return $route;
  77. }
  78. /**
  79. * 检查URL是否已经定义过路由
  80. * @access protected
  81. * @param array $route 路由信息
  82. * @return bool
  83. */
  84. protected function hasDefinedRoute(array $route): bool
  85. {
  86. [$appName, $controller, $action] = $route;
  87. // 检查地址是否被定义过路由
  88. $name = strtolower($appName . '/' . Str::studly($controller) . '/' . $action);
  89. $host = $this->request->host(true);
  90. $method = $this->request->method();
  91. if ($this->rule->getRouter()->getName($name, $host, $method)) {
  92. return true;
  93. }
  94. return false;
  95. }
  96. }