msgbartop
PHP源码分析,Zend引擎分析,Web相关技术研究,Web技术分享–左手代码 右手诗
msgbarbottom

13 Nov 09 Nginx(PHP/fastcgi)的PATH_INFO问题

PATH_INFO是一个CGI 1.1的标准,经常用来做为传参载体.

比如, 我们可以使用PATH_INFO来代替Rewrite来实现伪静态页面, 另外不少PHP框架也使用PATH_INFO来作为路由载体.

在Apache中, 当不加配置的时候, 对于PHP脚本, AcceptPathInfo是默认接受的, 也就是说:

如果在服务器在存在一个/laruence/index.php

那么, 对于如下请求,

/laruence/index.php/dummy
/laruence/dummy

Apache都接受, 都会认为是对info.php的访问, 并会设置PATH_INFO为dummy

而对于Nginx下, 是不支持PATH INFO的, 也就是它不会默认设置PATH_INFO.

而因为默认的配置文件对PHP的支持只是很基础的, 所以对于默认配置来说对于上面的访问也会是404, 提示找不到文件出错.

这对于一些使用PATH_INFO来传递关键信息的PHP框架来说(比如Kohana, Thinkphp), 简直是致命的.

对于这个问题, 一般来说有俩种解决方法, 第一种就是使用rewrite, 但是这个方法的缺点也是很明显的, 需要把PATH_INFO转换成Query String. 此处就不说明这种方法了~

而, 第二种方法就是我今天要提的, 模拟PATH_INFO:

首先 , 我们知道在Nginx中, 是通过对文件名的扩展名匹配, 来决定是否要交给php cgi服务器去解释的. 在nginx.conf中一般都有如下的默认配置段:

location ~ .php$ {
	fastcgi_index  index.php;
	fastcgi_pass   127.0.0.1:9000;
	include        fastcgi_params;
}

所以,对于形如/laruence/info.php/pathinfo这样的文件路径, Nginx是不会正确的交给php cgi服务器的. 所以我们需要改写这段配置为:

	location ~ .php {//片段匹配
	fastcgi_index  index.php;
	fastcgi_pass   127.0.0.1:9000;
	include        fastcgi_params;
}

现在, 脚本路径已经交由PHP自己处理了. 那怎么增加PATH_INFO呢?

首先, 我们需要打开PHP中cgi.fix_pathinfo配置项, 打开这个配置项以后, PHP会去根据CGI规范来检查SCRIPT_FILENAME中那部分是访问脚本和PATH_INFO(ini配置解释), 并根据SCRIPT_NAME来修改PATH_INFO(和PATH_TRANSLATED)为正确的值(其实也就是说明, PHP最初对CGI 1.1的支持并不到位)

然后, 就只要添加一个FASTCGI_PARAM项就好了:

location ~ .php {
	fastcgi_index  index.php;
	fastcgi_pass   127.0.0.1:9000;
	include        fastcgi_params;
	fastcgi_param  PATH_INFO $fastcgi_script_name;
}

现在试试吧…

btw: 当然, 上面的解决方法, 把对路径的分析交给了PHP去处理, 网上也有朋友给出了另外一种配置方法, 这个方法是由Nginx来分析路径(也就不需要fix_pathinfo):

location ~ \.php
{
	fastcgi_index index.php;
	fastcgi_pass 127.0.0.1:9000;
	include      fastcgi_params;
	set $path_info "";
	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 /var/html/$real_script_name;
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
}

Related Posts:

Tags: , ,

Reader's Comments

  1. |

    按上文修改conf后
    访问/p.php/
    得到的结果是
    /p.php/index.php

  2. |

    得到的结果
    /p.php/index.php

    是正常的.相当于一个文件夹.

    文章转载请求.:)

  3. |

    纠正下, 我访问/p.php/
    PATH_INFO是/index.php
    访问/p.php/aa
    PATH_INFO是/aa
    不明白了

  4. |

    @esayr
    大概理解你的意思了, 可是问题是apache下访问/p.php/返回的是/
    难道只能通过程序去”智能”判断么?
    能否通过调整nginx的配置来解决呢?

  5. |

    @zwws 我已补充自己判断的配置, ;)

  6. |

    反复折腾了三次到现在, 结果依旧如下:

    访问http://localhost/p.php/

    PATH_INFO 为 /index.php
    PHP_SELF 为 /p.php/index.php

    配置文件和http://localhost/p.php/的phpinfo()截图放在这了:

    http://www.zvv.cn/nginx_conf.rar

  7. |

    有空的话帮忙瞅瞅, thanks. :)

  8. |

    解决了.

    http://www.zvv.cn/blog/show-110-1.html

  9. |

    @zwws con~~ ;)

  10. |

    好文章,转载到 deving.cn 了,希望可以和更多的人分享

  11. |

    [...] 通过在nginx.conf中模拟PATH_INFO的方法会有一个bug. 那就是PATH_INFO不会被urldecode. [...]

Leave a Comment

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word