最近比较流行的框架比如laravel,yii国内的thinkphp都提供了以重定url的方式来实现pathinfo的url风格。
以thinkphp为例,提供了名为 "s"的get参数,只需要将路径重定向到这个参数上即可,比如nginx下:
location / {
if (!-e $request_filename){
rewrite ^/(.*) /index.php?s=$1 last;
}
}
现在laravel和yii2的重写规则更加简单,仅仅需要:
location / {
try_files $uri $uri/ /index.php?$args;
}
RewriteEngine on
# If a directory or a file exists, use the request directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Otherwise forward the request to index.php
RewriteRule . index.php
当你访问一个无法访问的路径时,比如 localhost/Index/index 实际上在你的webroot目录是没有Index/index目录或Index/index.html文件的,这时候我们就需要让框架来处理请求,将/Index/index 这个路径交给框架,而框架唯一的入口就是localhost/index.php,所以我们只需要将该请求重写到这个url上就可以了。
当访问
localhost/index/index?a=1
时,会重定向到:
localhost/index.php?a=1
那么/index/index这个字符串哪去了?答案应该在一个环境变量$_SERVER['REQUEST_URI']或者类似的变量,让我们通过Yii2里面的一个函数来研究一下具体流程:
protected function resolveRequestUri()
{
if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // IIS
$requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
} elseif (isset($_SERVER['REQUEST_URI'])) {
$requestUri = $_SERVER['REQUEST_URI'];
if ($requestUri !== '' && $requestUri[0] !== '/') {
$requestUri = preg_replace('/^(http|https):\/\/[^\/]+/i', '', $requestUri);
}
} elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0 CGI
$requestUri = $_SERVER['ORIG_PATH_INFO'];
if (!empty($_SERVER['QUERY_STRING'])) {
$requestUri .= '?' . $_SERVER['QUERY_STRING'];
}
} else {
throw new InvalidConfigException('Unable to determine the request URI.');
}
return $requestUri;
}
这个方法应该是用获得重定向之前的url,也就是你浏览器地址栏中所显示的 /index/index?a=1 这个原始字符串。在nginx和apache中,默认的是$_SERVER['REQUEST_URI']而在iis中略有不同,比如$_SERVER['HTTP_X_REWRITE_URL']和$_SERVER['ORIG_PATH_INFO']。
好了,不管它处理过程,我们只要知道通过这个方法得到了原始url,然后我们可以根据这个url来解析pathinfo吧::
if (!empty($_SERVER['REQUEST_URI']))
{
$path = preg_replace('/\?.*$/sD', '', $_SERVER['REQUEST_URI']);
}
以上只是我个人的猜测,并未深入yii2框架追根溯源,如有错误请指出,不胜感激。