获取PATH_INFO的便携且安全的方法

时间:2009-12-10 21:08:32

标签: php pathinfo

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

在阅读一段时间后,事实证明PATH_INFO来自CGI / 1.1,并且我并不总是出现在所有配置中。

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

6 个答案:

答案 0 :(得分:11)

好吧,我(几乎)确定不使用$_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   具体。 - LiraNuna

我正在运行 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是你希望我们合作的唯一关键(假设没有强加于PHP_SELF本身)只剩下一个解决方案:

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

如果这对您不起作用,我很抱歉,但我还能想到其他任何事情。

编辑 - 为您提供更多内容:

答案 1 :(得分:2)

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

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

例如,访问以下网址:http://somehost.com/index.php/some/path/here$path_info的值为:"/some/path/here"

它适用于在Windows和Linux上运行的各种apache服务器,但我不是100%确定它是否“安全”和“可移植”,但是我不会在“所有”服务器配置中测试它,但是似乎工作......

答案 2 :(得分:1)

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区分开来。

答案 3 :(得分:1)

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

让我看看我是否理解:

1)您对CLI不感兴趣:

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

2)您希望在所有OS + HTTP服务器+ PHP组合中使用PATH_INFO:

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

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

简而言之:“ $ _ SERVER取决于服务器”...所以便携式解决方案无法在$ _SERVER上转发......(仅举几个例子:我们有一个教程在NginX HTTP服务器上设置PHP / CGI $ _SERVER变量,请访问kbeezie.com/view/php-self-path-nginx /)

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

所以,只要我们有 URL字符串 ...然后是,我们就有了一种便携且安全的方法来确定它的PATH_INFO。


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

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

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

    如何获取URL?

    1)凭借您对每个HTTP服务器+ OS + 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脚本返回一个发送“document.URL”信息的javascript代码。 (可移植性问题转移到客户端。)

    如何从URL获取PATH_INFO?

    This code linked here does this.

    这是我对这个问题的拙见和态度。

    您怎么看?

答案 4 :(得分:0)

发布前我没有看到评论或链接。根据上面引用的页面提供的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;
}

答案 5 :(得分:-1)

你可以尝试

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