0

情况

您好,我对 PHP 关于无扩展 PHP 文件的预期/默认行为和/或“过去”处理请求的实际文件(即 PHP 之前的默认“回退”操作)的 URL 请求感到困惑它完全采用404-ing)。这是我的情况:

我在本地服务器上的目录结构(运行带有非常基本的 PHP 5.5.1 设置的 nginx 1.5.3)如下所示:

/index
/index.php
/other
/other.php
/rootdir/index
/rootdir/index.php
/rootdir/other
/rootdir/other.php

八个文件的内容都是一样的:

<?php
echo $_SERVER['PHP_SELF'] . ', ' . $_SERVER['REQUEST_URI'];
?>

但是,到达各自的端点会产生一些奇怪的(对我来说)结果。

研究

GET /index.php
'/index.php, /index.php' # Makes sense...

GET /index.php/something_else
'/index.php, /index.php/something_else' # Also makes sense...

GET /index/something_else
'/index.php, /index/something_else' # Let's call this ANOMALY 1... (see below)

GET /something_else
'/index.php, /something_else' # ANOMALY 2

GET /other.php
'/other.php, /other.php' # Expected...

GET /other.php/something_else
'/index.php, /other.php/something_else' # ANOMALY 3

GET /rootdir/index.php
'/rootdir/index.php, /rootdir/index.php' # Expected...

GET /rootdir/index.php/something_else
'/index.php, /rootdir/index.php/something_else' # ANOMALY 4

GET /rootdir/other.php
'/rootdir/other.php, /rootdir/other.php' # Expected...

GET /rootdir/other.php/something_else
'/index.php, /rootdir/other.php/something_else' # ANOMALY 5

我的理解是,当服务器/index.php在请求 URI 中找不到用户正在寻找的内容时,它会重定向到;这很有意义......我不明白的是:

  1. 为什么尽管我没有设置专用的 404 页面,但它会执行此操作(我没有告诉它/index.php在 404 之前尝试;我希望它显示一个合法的、非自定义的 404 页面,如果没有找到和/或无法处理。我认为它应该在找不到某些东西时显示默认服务器 404 页面......显然情况并非总是如此......?)
  2. 为什么在子目录中/rootdir/index.php找不到东西时它不尝试。/rootdir/

问题

  1. 关于未找到的地址,是否有人能够阐明 PHP 的逻辑是什么(或者它可能是 nginx 所做的;我还没有弄清楚)?为什么我看到我所看到的?(特别是关于异常 #4 和 #5。我希望它/rootdir/index.php用于处理它的“404”,或者我希望是一个真正的 404 页面;回退/index.php是出乎意料的。)

  2. 作为一个直接的推论(推论?)问题,我怎样才能模拟无扩展的 PHP 文件来处理发生在它们“下方”的命中(例如在 Anomaly #1 的情况下;这实际上正是我想要的,尽管它不是完全符合我的预期)而不依赖于.htaccess、mod_rewriting 或重定向?或者这是一个愚蠢的问题?:-)

参考

我正在尝试推出一个自定义实现来处理像/some_dir/index.php/fake_subdir/some_other_dir/index.php/fake_subdir(即不同的“回退处理程序”)这样的请求,而不依赖于 Apache,但是 PHP(或 Nginx 的?)默认回退行为背后的逻辑让我无法理解。这些页面主要是这个问题的来源:

4

2 回答 2

1
 GET /other.php/something_else

PATH_INFO这在 Apache 中被调用。当 Apache 扫描 URL 的“目录”时,它会返回第一个文件(或执行第一个脚本),它实际上是一个文件/脚本,例如

GET /foo/bar/baz/index.php/a/b/c/
     ^--dir
         ^--dir
             ^---dir
                 ^---script
                         ^^^^^^^--- path_info

实际上,真正的要求是

GET /foo/bar/baz/index.php

然后 Apache 将获取 URL 目录结构中未使用的尾随部分并将其转换为路径信息。在 PHP 中,您将拥有

$_SERVER['REQUEST_URI'] = '/foo/bar/baz/index.php';
$_SERVER['PATH_INFO'] = 'a/b/c';
于 2013-09-20T16:09:46.217 回答
0

好吧,我弄清楚发生了什么:我的 nginx 服务器配置错误。

Marc B 的回答虽然与 Apache 相关,但促使我检查了我的 PATH_INFO 值——你瞧,PATH_INFO 是不存在的,即使对于像GET /other.php/something_else.

更多的搜索找到了答案。使用 nginxfastcgi_split_path_info将 URI 拆分为 a) 脚本的路径和 b)如果使用该指令后完成,则出现在脚本名称后面的路径将失败,因为它会将URI 重写为指向磁盘上的文件. 这消除了获得 PATH_INFO 字符串的任何可能性。try_files

作为解决方案,我做了三件事(其中一些可能是多余的,但我都做了,以防万一):

  1. 在服务器的位置块中,在设置 PATH_INFOfastcgi_split_path_info 之前使用

    fastcgi_param PATH_INFO $fastcgi_path_info;
    

    ...并 使用.try_files

  2. 存储$fastcgi_path_info为局部变量,以防以后发生变化(例如使用set $path_info $fastcgi_path_info;

  3. 使用时try_files不要使用$uri……使用$fastcgi_script_name。(很确定这是我最大的错误。)

示例配置

server {

    # ... *snip* ...

    location ~ \.php {
        # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
        fastcgi_split_path_info ^(.+\.php)(/.*)$;

        include fastcgi_params;

        fastcgi_index index.php;
        fastcgi_intercept_errors on;
        fastcgi_pass 127.0.0.1:9000;

        try_files $fastcgi_script_name =404;
    }

    # ... *snip* ...

}

其中fastcgi_params包含:

set            $path_info         $fastcgi_path_info;
fastcgi_param  PATH_INFO          $path_info;
fastcgi_param  PATH_TRANSLATED    $document_root$path_info;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;

# ... *snip* ...

参考

以下链接很好地解释了该问题并提供了替代 nginx 配置:

于 2013-09-20T21:59:03.310 回答