Nginx + phpFPM:PATH_INFO总是空的

时间:2013-12-30 22:52:02

标签: nginx fastcgi php

我在Debian上配置了nginx stable(1.4.4)+ PHP(使用FastCGI,php-fpm)。这很好用:

     location ~* ^/~(.+?)(/.*\.php)$ {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        alias /home/$1/public_html$2;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_index index.php;
        autoindex on;
     }

我使用PATH_INFO变量,因此我将以下行添加到fastcgi_params:

fastcgi_param   PATH_INFO       $fastcgi_path_info;

在/etc/php5/fpm/php.ini中:

cgi.fix_pathinfo = 0

我认为应该可行,但是当我打印出所有服务器变量时,PATH_INFO始终为空:

    array (
  'USER' => 'www-data',
  'HOME' => '/var/www',
  'FCGI_ROLE' => 'RESPONDER',
  'QUERY_STRING' => '',
  'REQUEST_METHOD' => 'GET',
  'CONTENT_TYPE' => '',
  'CONTENT_LENGTH' => '',
  'SCRIPT_FILENAME' => '/usr/share/nginx/html/srv_var.php',
  'SCRIPT_NAME' => '/srv_var.php',
  'PATH_INFO' => '',
  'REQUEST_URI' => '/srv_var.php',
  'DOCUMENT_URI' => '/srv_var.php',
  'DOCUMENT_ROOT' => '/usr/share/nginx/html',
  'SERVER_PROTOCOL' => 'HTTP/1.1',
  'GATEWAY_INTERFACE' => 'CGI/1.1',
  'SERVER_SOFTWARE' => 'nginx/1.4.4',
  .....
)

我无法确定问题所在。有什么想法吗?

8 个答案:

答案 0 :(得分:3)

我偶然发现了一个解决方案。 $fastcgi_path_info var与$fastcgi_split_path_info一起使用,需要在位置块中设置。这是在我们的环境中起作用的:

location ~ [^/]\.php(/|$) {
    root /var/www/jurism-php;
    if (!-f $document_root$fastcgi_script_name) {
        return 404;
    }
    # Mitigate https://httpoxy.org/ vulnerabilities
    fastcgi_param HTTP_PROXY "";
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    include fastcgi_params;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
}

fastcgi_split_path_info下的Nginx documentation还有一个示例。

(...我现在看到匹配上面的多个帖子。可能需要在include语句之后设置PATH_INFO行,以避免破坏该值。)

答案 1 :(得分:1)

试试这个:

set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

http://wiki.nginx.org/PHPFcgiExample

http://trac.nginx.org/nginx/ticket/321

答案 2 :(得分:1)

我的工作配置如下:

location ~ [^/]\.php(/|$) {
    fastcgi_split_path_info ^(.+\.php)($|/.*);
    try_files $fastcgi_script_name =404;

    set $path_info $fastcgi_path_info;
    fastcgi_param PATH_INFO $path_info;

    fastcgi_pass 127.0.0.1:9000;
    fastcgi_index  index.php;  
    include fastcgi_params;    
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_ignore_client_abort off;
}

答案 3 :(得分:1)

对于到这里来的人,阅读东西。

问题似乎是其中的正则表达式(regex)

location ~* ^/~(.+?)(/.*\.php)$ {

将永远不会匹配不以.php结尾的uri,因此另一个正则表达式将永远不会“捕获”最后一个捕获组中的任何内容。

    fastcgi_split_path_info ^(.+?\.php)(/.*)$;

因此,将第一个正则表达式更改为以下内容将“修复”该问题。

location ~ [^/]\.php(/|$) {

答案 4 :(得分:0)

迟到的答案但对某人可能有用。

我使用变量REQUEST_URI而不是PATH_INFO。看起来它包含与PATH_INFO应具有的相同的值。

答案 5 :(得分:0)

这是我得到的。它就像一个魅力。

  • nginx 1.10.1
  • php 5.6.24

https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/

答案 6 :(得分:0)

我遇到过这个问题,但我的情况略有不同,因为我在指令中使用了 try_files。这是我的配置以及技术说明:

这就是我的 location 块的样子

location / {
    include         php-fpm.conf;
    try_files       $uri $uri/ /index.php =404;
}

php-fpm.conf

fastcgi_pass                127.0.0.1:9000;
fastcgi_index               index.php;
fastcgi_split_path_info     ^(.+?\.php)(/.+)$;
fastcgi_param               PATH_INFO       $fastcgi_path_info;
set $path_info              $fastcgi_path_info;
include                     fastcgi.conf;
fastcgi_param               PATH_INFO $path_info;

这里有两个特别通知:

  • 我通过 nginx 安装了 brew 并且它包含 PATH_INFO 参数,所以我不得不手动添加它(取自 here
fastcgi_param   PATH_INFO               $fastcgi_path_info;
  • 使用 try_files 是一种特殊情况 (source)
The ​try_files directive changes URI of a request to the one matched on the file system, and subsequent attempt to split the URI into $fastcgi_script_name and $fastcgi_path_info results in empty path info - as there is no path info in the URI after try_files.
  • 所以我们要做的是将 INFO_PATH 保存到一个临时变量,然后使用该临时变量设置 INFO_PATH

答案 7 :(得分:0)

首先,在现代 PHP 中,PATH_INFO 存储在 $_SERVER 数组中。试试:

echo "called SCRIPT_NAME: {$_SERVER['SCRIPT_NAME']} with PATH_INFO: {$_SERVER['PATH_INFO']}";

在任何情况下,phpinfo() 都会帮助查找许多内部 php 信息,例如变量和配置。

至于 NginX 配置,大部分已经在其他帖子中进行了解释。所以这是一个总结,并仔细研究了以下示例位置块的详细信息和原因:

location /main.php {
  # regex to split $uri to $fastcgi_script_name and $fastcgi_path
  fastcgi_split_path_info ^(.+?\.php)(/.*)$;

  # Check that the PHP script exists before passing it
  try_files $fastcgi_script_name =404;

  # Bypass the fact that try_files resets $fastcgi_path_info
  # see: http://trac.nginx.org/nginx/ticket/321
  set $path_info $fastcgi_path_info;
  fastcgi_param PATH_INFO $path_info;

  # set the standard fcgi paramters
  include fastcgi.conf;

  # pass the request to the socket
  fastcgi_pass unix:/run/php/php7.4-fpm.sock;
}

fastcgi_split_path_info 将您的位置在 SCRIPT_NAMEPATH_INFO 之间分开。

fastcgi_split_path_info ^(.+?\.php)(/.*)$;

第一个括号中的表达式提取 SCRIPT_NAME 第二个 PATH_INFO。所以 (.+?\.php) 需要任何字符(点 .),至少一次或多次(加号 +)。带有尾随 .php.php 中的点被转义为 \.php,因此从字面上看不是“任何字符”。

问号 ? 使加号懒惰 (+?),因此计算在第一个 .php 后缀处停止。所以 /some.php/next.php/path-info 被评估为 SCRIPT_NAME/some.phpPATH_INFO/next.php/path-info 而不是 SCRIPT_NAME/some.php/next.phpPATH_INFO/path-info

第二个表达式基本上将所有以斜杠开头的内容作为 PATH_INFO

前导 ^ 和尾随 $ 将表达式绑定到行的开头和结尾。

下一行检查提取的脚本是否确实作为文件存在:

try_files $fastcgi_script_name =404;

否则返回 404 错误。这可以防止将不存在的文件提供给 PHP 处理器,但是有重置 $fastcgi_path_info 变量的坏习惯(请参阅:http://trac.nginx.org/nginx/ticket/321)。一种解决方法是将 $fastcgi_path_info 存储在 $path_info 中,并将 FCGI 参数设置为存储的 $path_info。这是由接下来的两行完成的:

# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

然后在 fastcgi.conf 的包含中设置其他 FCGI 参数。此文件有时也称为 fastcgi_params,应由您的发行版提供。

include fastcgi.conf;

然后最后将请求传递给您当前的 PHP 实例套接字(此处为 PHP 7.4):

fastcgi_pass unix:/run/php/php7.4-fpm.sock;

现在请记住,所有这一切只会发生,如果周围的位置块被击中。上面的例子是一个前缀位置,意味着每个位置都匹配,以前缀 /main.php 开头。这将是路由 PHP 应用程序的典型配置,该应用程序只有一个名为 main.php 的中央文件。要捕获所有 .php 文件,必须使用正则表达式,这可能与 ^.+?\.php(/|$) 一样简单。 (/|$) 后面的 .php 表示位置的 .php 部分后面有一个反斜杠(和更多字符)或什么都没有。也允许使用子目录,因此表达式基本上匹配包含字符串 .php 的每个位置,只要它位于末尾或后跟斜杠即可。

location ~ ^.+?\.php(/|$) {
  #...
}

由于位置只是允许进入以下块的守卫,最终的PHP文件名和路径信息仍然如上所述分开。如果生成的文件名不存在,则返回 404。这只是一个简单的配置。当然,配置位置正则表达式有无数种可能性,以满足您特定应用程序的需求。要深入了解所有这些细节将是一本小书。

相关问题