要想讓nginx支持PATH_INFO,首先需要知道什么是pathinfo,為什么要用pathinfo?
pathinfo不是nginx的功能,pathinfo是php的功能。
php中有兩個pathinfo,一個是環境變量$_SERVER['PATH_INFO'];另一個是pathinfo函數,pathinfo() 函數以數組的形式返回文件路徑的信息;。
nginx能做的只是對$_SERVER['PATH_INFO]值的設置。
下面我們舉例說明比較直觀。先說php中兩種pathinfo的作用,再說如何讓nginx支持pathinfo。
php中的兩個pathinfo
php中的pathinfo()
pathinfo()函數可以對輸入的路徑進行判斷,以數組的形式返回文件路徑的信息,數組包含以下元素。
- [dirname] 路徑的目錄
- [basename] 帶后綴 文件名
- [extension] 文件后綴
- [filename] 不帶后綴文件名(需php5.2以上版本)
例如
print_r(pathinfo("/nginx/test.txt"));
輸出:
Array
(
[dirname] => /nginx
[basename] => test.txt
[extension] => txt
[filename] => test
)
php中的$_SERVER['PATH_INFO']
PHP中的全局變量$_SERVER['PATH_INFO'],PATH_INFO是一個CGI 1.1的標准,經常用來做為傳參載體。
被很多系統用來優化url路徑格式,最著名的如THINKPHP框架。
對於下面這個網址:
http://www.test.cn/index.php/test/my.html?c=index&m=search
我們可以得到 $_SERVER['PATH_INFO'] = ‘/test/my.html’,而此時 $_SERVER['QUERY_STRING'] = 'c=index&m=search';
如果不借助高級方法,php中http://www.test.com/index.php?type=search 這樣的URL很常見,大多數人可能會覺得不太美觀而且對於搜索引擎也是非常不友好的(實際上有沒有影響未知),因為現在的搜索引擎已經很智能了,可以收入帶參數的后綴網頁,不過大家出於整潔的考慮還是想希望能夠重寫URL,
下面是一段解析利用PATH_INFO的進行重寫的非常簡單的代碼:
if(!isset($_SERVER['PATH_INFO']))
{
$pathinfo = 'default';
}
else{
$pathinfo = explode('/', $_SERVER['PATH_INFO']);
}
if(is_array($pathinfo) && !empty($pathinfo))
{
$page = $pathinfo[1];
}
else
{
$page = 'default.php';
}
有了以上認識我們就可以介入nginx對$_SERVER['PATH_INFO']支持的問題了。在這之前還要介紹一個php.ini中的配置參數cgi.fix_pathinfo,它是用來對設置cgi模式下為php是否提供絕對路徑信息或PATH_INFO信息。沒有這個參數之前PHP設置絕對路徑PATH_TRANSLATED的值為SCRIPT_FILENAME,沒有PATH_INFO值。設置這個參數為cgi.fix_pathinfo=1后,cgi設置完整的路徑信息PATH_TRANSLATED的值為SCRIPT_FILENAME,並且設置PATH_INFO信息;如果設為cgi.fix_pathinfo=0則只設置絕對路徑PATH_TRANSLATED的值為SCRIPT_FILENAME。cgi.fix_pathinfo的默認值是1。
nginx默認是不會設置PATH_INFO環境變量的的值,需要php使用cgi.fix_pathinfo=1來完成路徑信息的獲取,但同時會帶來安全隱患,需要把cgi.fix_pathinfo=0設置為0,這樣php就獲取不到PATH_INFO信息,那些依賴PATH_INFO進行URL美化的程序就失效了。
1.可以通過rewrite方式代替php中的PATH_INFO
實例:thinkphp的pathinfo解決方案
設置URL_MODEL=2
location / {
if (!-e $request_filename){
rewrite ^/(.*)$ /index.php?s=/$1 last;
}
}
2.nginx配置文件中設置PATH_INFO值
請求的網址是/abc/index.php/abc
PATH_INFO的值是/abc
SCRIPT_FILENAME的值是$doucment_root/abc/index.php
SCRIPT_NAME /abc/index.php
舊版本的nginx使用如下方式配置
location ~ \.php
{
#fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
}
整理之后 nginx.conf 的代碼:
location / {
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
break;
}
}
location ~ \.php
{
#fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
}
最后總結: 【注意:location ~ \.php { 是沒有 $ 的 ,原來是 location ~ \.php$ {,所以記住這個也要改到】
只要修改nginx里面配置文件就行:
location ~ \.php {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_FILENAME $document_root$real_script_name;
# fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
}

