【问题标题】:Portable and safe way to get PATH_INFO获取 PATH_INFO 的便携且安全的方法
【发布时间】:2010-12-25 10:30:17
【问题描述】:

我正在寻找一种便携式方式来接收(方便的)$_SERVER['PATH_INFO'] 变量。

读了一会儿,原来PATH_INFO 源自 CGI/1.1,我并不总是出现在所有配置中。

获取该变量的最佳(主要是安全方面)方法是什么 - 除了手动提取它(安全问题)。

【问题讨论】:

  • 你能澄清一下“便携式”吗? PATH_INFO 由所有现代网络服务器提供。一些较旧的服务器(IIS 是一个很好的坏例子)有问题,但现在在更现代的 PHP 版本下你不应该有问题,可以纠正这些问题。
  • 一些服务器配置禁用了 CGI 接口给出的变量。我见过没有PATH_INFO 的现代(apache2.2)Web 服务器。
  • 您是否只需要客户端前端的脚本PATH_INFO?我的意思是,如果您有一个在脚本中调用的脚本来执行一些后端工作,您是否也想要该脚本的 path_info?
  • 这里唯一明智的做法是要求您的脚本在符合 CGI 1.1 的服务器上运行,并假设 PATH_INFO 设置正确。获取该变量的最佳方法是$_SERVER['PATH_INFO']
  • @Ben - 从理论上讲,您能否将尾随路径重写为脚本可以将其视为 $_['GET'] 的 GET 变量?

标签: php pathinfo


【解决方案1】:

好吧,我(几乎)确定,如果不使用 $_SERVER 超全局键,提供另一种方法来找出 PATH_INFO 是不可能的,也就是说 lets first list all of the $_SERVER keys 我们可能 可能使用:

  • 'PHP_SELF'
  • 'QUERY_STRING'
  • 'SCRIPT_FILENAME'
  • 'PATH_TRANSLATED'
  • 'SCRIPT_NAME'
  • 'REQUEST_URI'
  • 'PATH_INFO'
  • 'ORIG_PATH_INFO'

我们显然需要忽略最后两个。现在我们应该(我不知道这个事实,我只是假设因为你这么说)过滤你提供的链接中存在的所有键 (which BTW is offline ATM),留下我们使用以下键:

  • 'PHP_SELF'
  • 'SCRIPT_FILENAME'
  • 'REQUEST_URI'

关于您对Anthonys answer的评论:

你现在只是在玩弄变量。 SCRIPT_FILENAME 是 CGI 的一部分 规格。它将不可用,如果 PATH_INFO 不可用。至于 REQUEST_URI,是apache的mod_rewrite 具体的。 – 里拉努纳

我正在运行 LightTPD/1.4.20-1 (Win32) 和 PHP 5.3.0 作为 CGI,cgi.fix_pathinfo = 1$_SERVER['REQUEST_URI'] 对我来说非常可用,我还记得使用它在没有人使用 mod_rewrite 的日子里,同样的变量,所以 我诚实的谦虚猜测是,你在这一点上完全错了。关于SCRIPT_FILENAME 键,我无法测试那个ATM。尽管如此,如果我们真的闭上眼睛并相信你是对的,那么我们就只有一个变量:

  • 'PHP_SELF'

我并不想在这里变得苛刻(我仍然相信还有更多的解决方案),但如果 PHP_SELF 是您希望我们使用的唯一关键(假设没有对 @987654337 施加任何限制) @ 本身)只剩下一个解决方案了:

function PATH_INFO()
{
 if (array_key_exists('PATH_INFO', $_SERVER) === true)
 {
  return $_SERVER['PATH_INFO'];
 }

 $whatToUse = basename(__FILE__); // see below

 return substr($_SERVER['PHP_SELF'], strpos($_SERVER['PHP_SELF'], $whatToUse) + strlen($whatToUse));
}

这个函数应该可以工作,但是使用 __FILE__ 常量可能会出现一些问题,因为它返回声明__FILE__ 常量的文件的路径,而不是请求的 PHP 脚本的路径,这就是 $whatToUse 存在的原因:您可以将其替换为 'SCRIPT_FILENAME',或者如果您真的相信您所说的话,只需使用 '.php'强>。

你也应该read this regarding why not to use PHP_SELF

如果这对你不起作用,我很抱歉,但我可以想到别的。

编辑 - 为您阅读更多内容:

【讨论】:

  • REQUEST_URI 来自 mod_rewrite,这就是它特定于 apache 的原因。
  • 那你怎么解释我在 LigHTTPD 上有 REQUEST_URI 变量?
  • lighttpd 有 mod_rewrite 等价物吗?两者都是开源的,你知道 - 我敢打赌他们共享代码。
  • “您还应该阅读这篇文章,了解为什么不使用PHP_SELF。” - 这表示不要使用PHP_SELF 在页面上写东西。我移动信息并验证它。
  • 我在 lighttpd 上的唯一模块是:mod_access、mod_cgi、mod_dirlisting、mod_indexfile、mod_mimetype 和 mod_staticfile。不管怎样,它不是特定于 Apache 的。
【解决方案2】:

我认为这是以其他方式获取“path_info”的技巧:

$path_info = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['PHP_SELF']);

例如,访问像:http://somehost.com/index.php/some/path/here 这样的 URL,$path_info 的值将是:"/some/path/here"

它在 Windows 和 linux 上运行的各种 apache 服务器中对我有用,但我不能 100% 确定它是否“安全”和“便携”,显然我没有在“所有”服务器配置中测试它,但是似乎工作......

【讨论】:

    【解决方案3】:
    function getPathInfo() {
        if (isset($_SERVER['PATH_INFO'])) {
            return $_SERVER['PATH_INFO'];
        }  
        $scriptname = preg_quote($_SERVER["SCRIPT_NAME"], '/');
        $pathinfo = preg_replace("/^$scriptname/", "", $_SERVER["PHP_SELF"]);
        return $pathinfo;
    }
    

    编辑:没有 SCRIPT_NAME,并假设您有 DOCUMENT_ROOT(或者可以自己定义/发现它)并假设您有 SCRIPT_FILENAME,那么:

    function getPathInfo() {
        if (isset($_SERVER['PATH_INFO'])) {
            return $_SERVER['PATH_INFO'];
        }  
        $docroot = preg_quote($_SERVER["DOCUMENT_ROOT"], "/");
        $scriptname = preg_replace("/^$docroot/", "", $_SERVER["SCRIPT_FILENAME"]);
        $scriptname = preg_quote($scriptname, "/");
        $pathinfo = preg_replace("/^$scriptname/", "", $_SERVER["PHP_SELF"]);
        return $pathinfo;
    }
    

    还有@Anthony(没有足够的代表发表评论,抱歉):使用 str_replace() 将匹配字符串中的任何位置。它不能保证有效,您只想在开始时匹配它。此外,您仅使用 1 个斜线(通过 strrpos)来确定 SCRIPT_NAME 的方法,仅在脚本位于根目录下时才有效,这就是为什么您最好将 script_filename 与 docroot 进行比较。

    【讨论】:

    • 正则表达式的构造中出现了一个小而致命的错误。
    • 是的,我确实检查过了。我在粘贴到 SO 时省略了分隔符参数,因为我认为它默认为 /,显然不是。它还有哪些其他方面的问题?
    • 如果你用'index.php/path/to/somewhere.ext?var=data'调用它,你会得到一个很好的错误。此外,SCRIPT_NAME 也遇到了与PATH_INFO 相同的问题。
    • 我知道你们俩都想帮忙,但我真的需要一种便携的方式。
    • 好吧,我不能代表 IIS,但在 nginx 中,我个人通过 fastcgi_param 公开了 script_name、script_filename、request_uri 等。 lighttpd 也是如此。无论如何,回到主题:PATH_INFO 是处理请求的脚本名称与请求的完整 http 路径之间的区别。您需要发现或定义这些东西来计算它。
    【解决方案4】:

    这取决于“便携”和“安全”的定义。

    让我看看我是否理解:

    1) 你对 CLI 不感兴趣:

    • 你提到了 PHP/CGI
    • PATH_INFO 是 URL 的一部分;因此,只有在从 URL 访问脚本(即从 HTTP 连接,通常由浏览器请求)时讨论 PATH_INFO 才有意义

    2) 您希望在所有操作系统 + HTTP 服务器 + PHP 组合中都有 PATH_INFO:

    • 操作系统可能是 Windows、Linux 等
    • HTTP 服务器可能是 Apache 1、Apache 2、NginX、Lighttpd 等。
    • PHP 可能是版本 4、5、6 或任何版本

    嗯... PHP_INFO,在 $_SERVER 数组中,由 PHP 提供给仅在特定条件下执行的脚本,具体取决于上述软件。它并不总是可用的。整个 $_SERVER 数组也是如此!

    简而言之:“$_SERVER 依赖于服务器”...因此可移植解决方案无法在 $_SERVER 上中继...(仅举一个例子:我们有一个教程在 kbeezie.com/view/php-self-path-nginx/ 的 NginX HTTP 服务器上设置 PHP/CGI $_SERVER 变量)

    3) 尽管上面提到了,但值得一提的是,如果我们以某种方式将请求的完整 URL 用作字符串,则可以通过应用正则表达式从中获取 PATH_INFO和其他 PHP 字符串函数,安全(也将输入字符串验证为有效 URI)。

    所以,只要我们有 URL 字符串...那么是的,我们有一种可移植且安全的方法来从中确定 PATH_INFO。


    现在,我们有两个明确且重点突出的实施问题:

    1. 如何获取网址?
    2. 如何从 URL 中获取 PATH_INFO?

    在几种可能性中,这是一种可能的方法:

    如何获取网址?

    1) 凭借您对每个 HTTP 服务器 + 操作系统 + PHP 版本组合的深入而全面的了解,检查并尝试从 $_SERVER 数组中获取 URL 的每种可能性(验证 'PHP_SELF'、'QUERY_STRING'、'SCRIPT_FILENAME'、 'PATH_TRANSLATED'、'SCRIPT_NAME'、'REQUEST_URI'、'PATH_INFO'、'ORIG_PATH_INFO'、'HTTP_HOST'、'DOCUMENT_ROOT' 或其他)

    2) 如果上一步失败,使 PHP 脚本返回一个 javascript 代码,该代码将“document.URL”信息发回。 (转移到客户端的可移植性问题。)

    如何从 URL 中获取 PATH_INFO?

    This code linked here does this.

    这是我的拙见和解决问题的方法。

    你怎么看?

    【讨论】:

    【解决方案5】:

    在发布之前我没有看到 cmets 或链接。根据上面引用的页面作为 CGI 派生变量给出的内容,这可能会起作用:

    function getPathInfo() {
        if (isset($_SERVER['PATH_INFO'])) {
            return $_SERVER['PATH_INFO'];
        }  
    
        $script_filename = $_SERVER["SCRIPT_FILENAME"];
        $script_name_start = strrpos($script_filename, "/");
        $script_name = substr($script_filename, $script_name_start);
    
        //With the above you should have the plain file name of script without path        
    
        $script_uri = $_SERVER["REQUEST_URI"];
        $script_name_length = strlen($script_name);
        $path_start = $script_name_length + strpos($script_name, $script_uri);
    
        //You now have the position of where the script name ends in REQUEST_URI
    
        $pathinfo = substr($script_uri, $path_start);
        return $pathinfo;
    }
    

    【讨论】:

    • 同样,如果未定义 PATH_INFOSCRIPT_NAMEREQUEST_URI 将不可用。
    • 您能否提供一份所提供的全局变量列表?它们中的任何一个是否已经包含路径信息,只是不容易提取形式?
    • 好的。我认为哎呀,我都在努力为您的情况提供真正的帮助和良好的运动,但是继续指向同一页面,好像它是最终来源一样,然后表现得好像我们提供的东西很愚蠢,这真的很不礼貌不使用该页面上列出的全局变量的解决方案。如果您可以从麻烦的脚本所在的同一目录中执行以下操作,那将非常有帮助:
    • 你现在只是在处理变量。 SCRIPT_FILENAME 是 CGI 规范的一部分。如果 PATH_INFO 不可用,它将不可用。至于REQUEST_URI,是apache的mod_rewrite特有的。
    • 创建一个名为“globaltest.php”的页面,放入“phpinfo();”在那个脚本中。打开“yourserver.org/globaltest.php/stuff”。提供包含“globaltest.php”或“globaltest.php/stuff”的任何变量的列表。如果没有变量对“/stuff”进行任何引用,那么我看不出您希望如何从脚本中以任何安全或不安全的方式提取它。
    【解决方案6】:

    你可以试试

    $_ENV['PATH_INFO']; or
    getenv('PATH_INFO']; 
    

    【讨论】:

    • PATH_INFO 是通过服务器端定义的。它可能并不总是存在,不管它是由_ENV 还是_SERVER 访问的。
    • 不用说_ENV 甚至不包含该属性。
    猜你喜欢
    • 2023-04-09
    • 2013-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    相关资源
    最近更新 更多