Nginx + phpFPM:PATH_INFO总是空的

use*_*714 8 php fastcgi nginx

我在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;
     }
Run Code Online (Sandbox Code Playgroud)

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

fastcgi_param   PATH_INFO       $fastcgi_path_info;
Run Code Online (Sandbox Code Playgroud)

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

cgi.fix_pathinfo = 0
Run Code Online (Sandbox Code Playgroud)

我认为这应该有效,但是当我打印出所有服务器变量时,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',
  .....
)
Run Code Online (Sandbox Code Playgroud)

我无法确定问题所在.有任何想法吗?

小智 6

我偶然发现了一个解决方案。该$fastcgi_path_info变种与一起工作$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;
}
Run Code Online (Sandbox Code Playgroud)

下的Nginx 文档中也有一个示例fastcgi_split_path_info

(...我现在看到匹配上面的不止一篇文章。可能需要在 include 语句之后设置 PATH_INFO 行,以避免破坏值。)


Hol*_*nke 6

使用 PHP 进行调试

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

echo "called SCRIPT_NAME: {$_SERVER['SCRIPT_NAME']} with PATH_INFO: {$_SERVER['PATH_INFO']}";
Run Code Online (Sandbox Code Playgroud)

无论如何,phpinfo()可以帮助找到很多内部 php 信息,比如变量和配置。

Nginx 配置

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

location /main.php {
  # regex to split $uri to $fastcgi_script_name and $fastcgi_path_info
  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;
}
Run Code Online (Sandbox Code Playgroud)

逐行解释

fastcgi_split_path_info您的位置分割为SCRIPT_NAMEPATH_INFO

fastcgi_split_path_info ^(.+?\.php)(/.*)$;
Run Code Online (Sandbox Code Playgroud)

正则表达式第一个括号中的表达式提取SCRIPT_NAME,而第二个括号中的表达式提取PATH_INFO


回顾一下正则表达式

  • 第一个正则表达式组(.+?\.php)需要任何字符(点.),至少一次或多次(加号+)。带有尾随.php. 中的点.php被转义为\.php,因此它实际上不被视为“任何字符”。
    问号?使加号变得惰性 ( +?),因此计算在第一个.php后缀处停止。

    • 例如-用 a of/some.php/next.php/path-info计算为a of ; 请注意,不要将 a of与 a of 搭配使用。SCRIPT_NAME/some.phpPATH_INFO/next.php/path-infoSCRIPT_NAME/some.php/next.phpPATH_INFO/path-info
  • 第二个正则表达式组(/.*)基本上将以斜杠开头的所有内容都视为PATH_INFO

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


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

try_files $fastcgi_script_name =404;
Run Code Online (Sandbox Code Playgroud)

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

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

include fastcgi.conf;
Run Code Online (Sandbox Code Playgroud)

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

fastcgi_pass unix:/run/php/php7.4-fpm.sock;
Run Code Online (Sandbox Code Playgroud)

结论

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

location ~ ^.+?\.php(/|$) {
  #...
}
Run Code Online (Sandbox Code Playgroud)

由于该位置只是允许进入以下块的守卫,因此最终的 PHP 文件名和路径信息仍然按照上述方式进行分割。如果生成的文件名不存在,则返回 404。

这只是一个简单的配置。当然,配置位置正则表达式有多种可能性,以满足您特定应用程序的需求。要详细讨论所有这些细节将是一本小书。


sal*_*nap 5

我的工作配置如下:

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;
}
Run Code Online (Sandbox Code Playgroud)


Mic*_*eim 1

尝试这个:

set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
Run Code Online (Sandbox Code Playgroud)

http://wiki.nginx.org/PHPFcgiExample

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