¶«Éƽ̨ADLab£ºThinkPHP5Ô¶³Ì´úÂëÖ´ÐЩ¶´·ÖÎö
Ðû²¼Ê±¼ä 2018-12-112018Äê12ÔÂ9ÈÕ£¬ThinkPHPÍŶÓÐû²¼ÁËÒ»¸ö²¹¶¡¸üУ¬ÐÞ¸´ÁËÒ»´¦ÓÉÓÚ·ÓɽâÎöȱÏݵ¼ÖµĴúÂëÖ´ÐЩ¶´¡£¸Ã©¶´Î£º¦Ë®Æ½·Ç³£¸ß£¬Ä¬ÈÏ»·¾³ÅäÖü´¿Éµ¼ÖÂÔ¶³Ì´úÂëÖ´ÐС£¾¹ý¶«Éƽ̨ADLabÄþ¾²Ñо¿Ô±¶ÔThinkPHPµÄ56¸öС°æ±¾µÄÔ´Âë·ÖÎöºÍÑéÖ¤£¬È·¶¨¾ßÌåÊÜÓ°ÏìµÄ°æ±¾Îª:
ThinkPHP 5.0.5-5.0.22
ThinkPHP 5.1.0-5.1.30©¶´¸´ÏÖ

©¶´·ÖÎö
library/think/Request.php:678
public function pathinfo()
{
if (is_null($this->pathinfo)) {
if (isset($_GET[$this->config['var_pathinfo']])) {
// ÅжÏURLÀïÃæÊÇ·ñÓмæÈÝģʽ²ÎÊý
$pathinfo = $_GET[$this->config['var_pathinfo']];
unset($_GET[$this->config['var_pathinfo']]);
} elseif ($this->isCli()) {
// CLIģʽÏ index.php module/controller/action/params/...
$pathinfo = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
} elseif ('cli-server' == PHP_SAPI) {
$pathinfo = strpos($this->server('REQUEST_URI'), '?') ? strstr($this->server('REQUEST_URI'), '?', true) : $this->server('REQUEST_URI');
} elseif ($this->server('PATH_INFO')) {
$pathinfo = $this->server('PATH_INFO');
}
// ·ÖÎöPATHINFOÐÅÏ¢
if (!isset($pathinfo)) {
foreach ($this->config['pathinfo_fetch'] as $type) {
if ($this->server($type)) {
$pathinfo = (0 === strpos($this->server($type), $this->server('SCRIPT_NAME'))) ?
substr($this->server($type), strlen($this->server('SCRIPT_NAME'))) : $this->server($type);
break;
}
}
}
$this->pathinfo = empty($pathinfo) || '/' == $pathinfo ? '' : ltrim($pathinfo, '/');
}
return $this->pathinfo;
}
¸Ã·Óɺ¯ÊýÖÐ$this->config['var_pathinfo']ÊÇÅäÖÃÎļþµÄĬÈÏÖµ£¬Æä³õʼ»¯´úÂëÈçÏ£¬ÖµÎª¡¯s¡¯:
·ÖÎö·¢ÏÖpathinfoº¯Êý±»library/think/Request.php:716ÖеÄpathº¯Êýµ÷Óãº
public function path()
{
if (is_null($this->path)) {
$suffix = $this->config['url_html_suffix'];
$pathinfo = $this->pathinfo();
if (false === $suffix) {
// ½ûֹα¾²Ì¬·ÃÎÊ
$this->path = $pathinfo;
} elseif ($suffix) {
// È¥³ýÕý³£µÄURLºó׺
$this->path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
} else {
// ÔÊÐíÈκκó׺·ÃÎÊ
$this->path = preg_replace('/\.' . $this->ext() . '$/i', '', $pathinfo);
}
}
return $this->path;
}
ÏÔÈ»£¬ÕâÀï$this->pathÔ´×Ôpathinfo£¬Òò´Ë¿ÉÒÔ±»¹¥»÷Õß¿ØÖÆ¡£¼ÌÐø·ÖÎö¸Ã±äÁ¿µÄͨ±¨£¬ÔÚlibrary/think/App.php:597Öб»ÒýÓãº
//public function routecheck()
$path = $this->request->path();
// ÊÇ·ñÇ¿ÖÆ·ÓÉģʽ
$must = !is_null($this->routeMust) ? $this->routeMust : $this->route->config('url_route_must');
// ·Óɼì²â ·µ»ØÒ»¸öDispatch¹¤¾ß
$dispatch = $this->route->check($path, $must);
if (!empty($routeKey)) {
try {
if ($option) {
$this->cache->connect($option)->tag('route_cache')->set($routeKey, $dispatch);
} else {
$this->cache->tag('route_cache')->set($routeKey, $dispatch);
}
} catch (\Exception $e) {
// ´æÔÚ±Õ°üµÄʱºò»º´æÎÞЧ
}
}
return $dispatch;
public function check($url, $must = false)
{
// ×Ô¶¯¼ì²âÓòÃû·ÓÉ
$domain = $this->checkDomain();
$url = str_replace($this->config['pathinfo_depr'], '|', $url);
$completeMatch = $this->config['route_complete_match'];
$result = $domain->check($this->request, $url, $completeMatch);
if (false === $result && !empty($this->cross)) {
// ¼ì²â¿çÓò·ÓÉ
$result = $this->cross->check($this->request, $url, $completeMatch);
}
if (false !== $result) {
// ·ÓÉÆ¥Åä
return $result;
} elseif ($must) {
// Ç¿ÖÆ·Óɲ»Æ¥ÅäÔòÅ׳öÒì³£
throw new RouteNotFoundException();
}
// ĬÈÏ·ÓɽâÎö
return new UrlDispatch($this->request, $this->group, $url, [
'auto_search' => $this->autoSearchController,
]);
}
·ÖÎö´úÂë¿ÉÖª£¬Èç¹û¿ªÆôÁËÇ¿ÖÆ·ÓÉÔò»áÅ׳öÒì³££¬Ò²¾ÍÊǹٷ½Ëù˵µÄ¸Ã©¶´ÔÚ¿ªÆôÇ¿ÖÆ·ÓɵÄÇé¿öϲ»ÊÜÓ°Ï죨ĬÈϲ»¿ªÆô£©¡£
Checkº¯Êý×îºóʵÀý»¯Ò»¸öUrlDispatch¹¤¾ß£¬½«$urlͨ±¨¸øÁ˽ṹº¯Êý¡£¼ÌÐø·ÖÎöUrlDispatchµÄ¸¸ÀàÒ²¾ÍÊÇDispatchÀàµÄ½á¹¹º¯Êý:
library/think/route/Dispatch.php:64
{
$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'];
}
}
$dispatch±äÁ¿¿É¿Ø²¢¸³Öµ¸øÁË$this->dispatch£¬¾¹ý¶à´Îº¯Êýµ÷Ó÷µ»Ø£¬×îºóÈçϵÄUrlÀàµÄinit º¯Êý½«»á±»µ÷ÓÃÀ´´¦ÖÃ$this->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()
{}
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)) {
ÕâÀïµ÷ÓÃparseUrlPathº¯Êý¶Ô$url½øÐнâÎö£¬¼ÌÐø·ÖÎö¸Ãº¯Êý£º
public function parseUrlPath($url)
{....
....
} 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];
}
ÏÔÈ»£¬$urlµÄ¸ñʽΪ¡°Ä£¿é/¿ØÖÆÆ÷/²Ù×÷¡±£¬$urlÖ§½âÐγÉÒ»¸öÊý×é´æµ½$path±äÁ¿Öв¢·µ»Øµ½µ÷ÓÃÕß¡£
¼ÌÐø·ÖÎö·âװ·ÓɵĴúÂë:
library/think/route/dispatch/Url.php:48
list($path, $var) = $this->rule->parseUrlPath($url);...
...
// ½âÎöÄ£¿é
$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;
}
// ½âÎö²Ù×÷
$action = !empty($path) ? array_shift($path) : null;
...
...
// ÉèÖõ±Ç°ÇëÇóµÄ²ÎÊý
$this->request->setRouteVars($var);
// ·âװ·ÓÉ
$route = [$module, $controller, $action];
return $route;
·ÓÉ·â×°·µ»Øµ½library/think/route/dispatch/Url.php:20
class Url extends Dispatch
{public function init()
{
// ½âÎöĬÈϵÄURL¹æÔò
$result = $this->parseUrl($this->dispatch);
return (new Module($this->request, $this->rule, $result))->init();
}
$result¾ÍÊÇ·â×°ºÃµÄ·ÓÉÊý×飬ͨ±¨¸øÁËModuleµÄ½á¹¹º¯Êý¡£
ÓÉÓÚModuleÒ²ÊǼ̳Ð×ÔDispatchÀֱ࣬½Ó¿´DispatchµÄ½á¹¹º¯Êý:
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'];
}
}
$result¸³Öµ¸øÁË$this->dispatch¡£È»ºóµ÷ÓÃModuleÀàµÄinitº¯Êý£º
public function init()
{
parent::init();
$result = $this->dispatch;
if ($this->rule->getConfig('app_multi_module')) {
// ¶àÄ£¿é²¿Êð
$module = strip_tags(strtolower($result[0] ?: $this->rule->getConfig('default_module')));
...
...
} elseif (!in_array($module, $this->rule->getConfig('deny_module_list')) && is_dir($this->app->getAppPath() . $module)) {
$available = true;
}
...
...
// Ä£¿é³õʼ»¯
if ($module && $available) {
// ³õʼ»¯Ä£¿é
$this->request->setModule($module);
$this->app->init($module);
} else {
throw new HttpException(404, 'module not exists:' . $module);
}
}
// »ñÈ¡¿ØÖÆÆ÷Ãû
$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;
}
ÕâÀï´æÔÚµÚÒ»¸ö¶Ô$moduleµÄÅжϣ¬ÐèÒªÈÃ$available¼´ÊÇtrue£¬Õâ¾ÍÐèÒªis_dir($this->app->getAppPath() . $module)½¨Á¢¡£¹Ù·½demo¸ø³öµÄÄ£¿éÊÇindex£¬¶øʵ¼Ê¿ª·¢·¨Ê½·×Æ綨´æÔÚ¸ÃÄ£¿éÃû£¬ËùÒԽṹpayloadʱÕâÀïÊÇÒ»¸ö×¢Òâµã¡£
Âú×ãÕâ¸öÅжÏÌõ¼þºó£¬¼ÌÐø·ÖÎöºóÐøµÄ¿ØÖÆÁ÷»á½øÈëÈçÏÂmoduleµÄexecº¯Êý£ºlibrary/think/route/dispatch/Module.php:80
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'));
if ($instance instanceof Controller) {
$instance->registerMiddleware();
}
} catch (ClassNotFoundException $e) {
throw new HttpException(404, 'controller not exists:' . $e->getClass());
}
·ÖÎö·¢ÏÖ£¬$this->controllerÊǹ¥»÷Õ߿ɿصģ¬²¢Í¨±¨¸øÁËÈçϵÄcontrollerº¯Êý£¬¼ÌÐø·ÖÎö¸Ãº¯Êý£º
{
list($module, $class) = $this->parseModuleAndClass($name, $layer, $appendSuffix);
if (class_exists($class)) {
return $this->__get($class);
} elseif ($empty && class_exists($emptyClass = $this->parseClass($module, $layer, $empty, $appendSuffix))) {
return $this->__get($emptyClass);
}
throw new ClassNotFoundException('class not exists:' . $class, $class);
}
ÔÚÕâÀnameÊǹ¥»÷Õ߿ɿصģ¬²¢Í¨±¨¸øÁËÈçϵÄparseModuleAndClassº¯Êý£º
protected function parseModuleAndClass($name, $layer, $appendSuffix)
{if (false !== strpos($name, '\\')) {
$class = $name;
$module = $this->request->module();
} else {
if (strpos($name, '/')) {
list($module, $name) = explode('/', $name, 2);
} else {
$module = $this->request->module();
}
$class = $this->parseClass($module, $layer, $name, $appendSuffix);
}
return [$module, $class];
}
·ÖÎö·¢ÏÖ£¬µ±$name´æÔÚ·´Ð±¸Üʱ¾ÍÖ±½Ó½«$name¸³Öµ¸ø$class²¢·µ»Ø¡£ÏÔÈ»£¬¹¥»÷Õßͨ¹ý¿ØÖÆÊäÈë¾Í¿ÉÒÔ²Ù¿ØÀàµÄʵÀý»¯¹ý³Ì£¬´Ó¶øÔì³É´úÂëÖ´ÐЩ¶´¡£
²¹¶¡·ÖÎö
ÔÚThinkPHP5.0.23ÒÔ¼°5.1.31°æ±¾ÖУ¬Ôö¼ÓÁ˶Ô$controllerµÄÕýÔò¹ýÂË£º
µ¼ÖÂÎÞ·¨ÔÙ´«Èë\think\appÕâÖÖÐÎʽµÄ¿ØÖÆÆ÷¡£
½á ÂÛ
´Ë©¶´ÊÇÒòΪ¿ò¼Ü¶Ô´«ÈëµÄ·ÓɲÎÊý¹ýÂ˲»Ñϸñ£¬µ¼Ö¹¥»÷Õß¿ÉÒÔ²Ù×÷·ÇÔ¤ÆڵĿØÖÆÆ÷ÀàÀ´Ô¶³ÌÖ´ÐдúÂë¡£½øÒ»²½·ÖÎö·¢ÏÖ£¬Ä³Ð©ThinkPHP°æ±¾²»ÊÜÒѹûÈ»µÄPOCµÄÓ°Ï죬ÕâÊÇÓÉÓÚ¸ÃPOCȱ·¦Í걸ÐÔ¿¼ÂÇ¡£Òò´Ë£¬Ç¿ÁÒ½¨ÒéÓû§¼°Ê±½«5.0.x°æ±¾Éý¼¶µ½5.0.23£¬½«5.1.x°æ±¾Éý¼¶µ½5.1.31£¬ÒÔÃâÔâÊܹ¥»÷¡£