Nginx + phpFPM:PATH_INFO始终为空

ki1q1bka  于 2023-04-19  发布在  PHP
关注(0)|答案(9)|浏览(224)

我在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',
  .....
)

我想不出问题出在哪里,有什么想法吗?

dsekswqp

dsekswqp1#

我偶然发现了一个解决方案。$fastcgi_path_info var与$fastcgi_split_path_info一起工作,需要在location块中设置。下面是在我们的环境中工作的情况:

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行,以避免破坏值。)

x4shl7ld

x4shl7ld2#

PHP调试

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

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

在任何情况下,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;
}

逐行解释

fastcgi_split_path_infoSCRIPT_NAMEPATH_INFO之间分割您的位置。

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

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

正则表达式回顾

  • 第一个正则表达式组,(.+?\.php),期望任何字符(点.),至少一次或多次(加号+)。尾部为.php.php中的点被转义为\.php,因此它实际上不是“任何字符”。

问号?使加号延迟(+?),因此计算在第一个.php后缀处停止。

*例如-/some.php/next.php/path-info被评估为/some.phpSCRIPT_NAME,其中PATH_INFO/next.php/path-info;注意,不要把SCRIPT_NAME/some.php/next.phpPATH_INFO/path-info

  • 第二个regexp组(/.*)基本上将以斜杠开头的所有内容作为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;

其他FCGI参数则在fastcgi.conf的include中设置。这个文件,有时也被命名为fastcgi_params,应该由您的发行版提供。

include fastcgi.conf;

最后将请求传递给当前的PHP示例套接字(这里是PHP 7.4):

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

总结

现在请记住,所有这些都只发生在周围的位置块被命中的情况下。上面的例子是一个前缀位置,意味着每个位置都匹配,以前缀/main.php开始。这是一个典型的配置,用于只有一个名为main.php的中心文件的路由PHP应用程序。要捕获所有.php文件,必须使用正则表达式。它可以像^.+?\.php(/|$)一样简单。.php后面的(/|$)意味着(和更多字符)或在位置的.php部分之后没有。也允许子目录,因此表达式基本上匹配包含字符串.php的每个位置,只要是在结尾或者后面有斜线

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

由于该位置只是允许进入以下块的保护区,因此最终的PHP文件名和路径信息仍然如上所述进行分割。如果结果文件名不存在,则返回404。
这只是一个简单的配置。当然,有无数的可能性来配置位置regex,以满足您的特定应用程序的需要。要详细介绍所有这些细节将是一本小书。

evrscar2

evrscar23#

我的工作配置如下:

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;
}
h79rfbju

h79rfbju4#

试试这个:

set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;

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

xv8emn3q

xv8emn3q5#

对于来这里的人,阅读的东西..
问题似乎是正则表达式(regex)在

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

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

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

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

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

zyfwsgd66#

答案很晚,但可能对某人有用。
我使用变量REQUEST_URI而不是PATH_INFO。看起来它包含的值与PATH_INFO应该具有的值相同。

zzoitvuj

zzoitvuj7#

这是我得到的,而且效果很好。

  • 简体中文
  • php 5.6.24

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

9o685dep

9o685dep8#

参考:https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_split_path_info

location ~ .+\.php {
    fastcgi_pass    {your_php_fpm_sock_or_server};

    # Some old (custom) frameworks use "PATH_INFO" for routing, requiring the following 2 settings. (e.g. index.php/Home/index)
    fastcgi_split_path_info             ^(.+\.php)(.*)$;
    fastcgi_param   PATH_INFO           $fastcgi_path_info;

    fastcgi_param   SCRIPT_FILENAME     $realpath_root$fastcgi_script_name;

    include         fastcgi_params;
}
aij0ehis

aij0ehis9#

我遇到过这个问题,但我的情况略有不同,因为我在我的指令中使用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;

这里有两个特别注意事项:

  • 我通过brew安装了nginx,它没有包含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

相关问题