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

发布于 2024-08-14 02:54:31 字数 208 浏览 5 评论 0原文

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

读了一段时间后,发现 PATH_INFO 源自 CGI/1.1,并且我并不总是出现在所有配置中。

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

I'm seeking a portable way to receive the (handy) $_SERVER['PATH_INFO'] variable.

After reading a while, it turns out PATH_INFO is originated from CGI/1.1, and my not always be present in all configuration.

What is the best (mostly security-wise) way to get that variable - apart from extracting it manually (security concern).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

欢你一世 2024-08-21 02:54:31

好吧,我(几乎)确信,如果不使用 $_SERVER 超级全局键,提供另一种方法来找出 PATH_INFO 是不可能的,也就是说< a href="http://pt.php.net/manual/en/reserved.variables.server.php" rel="nofollow noreferrer">让我们首先列出我们可能<的所有 $_SERVER 键 使用:

  • PHP_SELF''QUERY_STRING''SCRIPT_FILENAME''PATH_TRANSLATED''SCRIPT_NAME''REQUEST_URI''PATH_INFO''ORIG_PATH_INFO
  • '
  • >可能
  • 忽略
  • 我们显然需要
  • '

最后两个 现在我们应该(我实际上不知道这一点,我只是假设因为你这么说)过滤你提供的链接中存在的所有键(哪个BTW是离线ATM) ,这给我们留下了以下键:

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

关于您对 安东尼的回答

你现在只是在玩弄变量。
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”,

我不想在这里变得严厉(而且我仍然相信还有更多的解决方案)但是如果< code>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'

您还应该阅读本文了解为什么不使用PHP_SELF

如果这对你不起作用,我很抱歉,但我可以想到其他办法。

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

Well, I'm (almost) sure that without making use of the $_SERVER superglobal keys, providing a alternative way to figure out PATH_INFO is just impossible, that being said lets first list all of the $_SERVER keys that we may possibly use:

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

We obviously need to ignore the last two. Now we should (I don't know this for a fact, I'm just assuming because you said so) filter all the keys that exist in the link you provided (which BTW is offline ATM), that leaves us with the following keys:

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

Regarding your comment to Anthonys answer:

You are just juggling variables now.
SCRIPT_FILENAME is a part of the CGI
spec. It will not be available if
PATH_INFO is unavailable. As for
REQUEST_URI, it's apache's mod_rewrite
specific. – LiraNuna

I'm running LightTPD/1.4.20-1 (Win32) with PHP 5.3.0 as CGI, cgi.fix_pathinfo = 1 and $_SERVER['REQUEST_URI'] is very available to me, I also remember using that same variable back in the days when no one used mod_rewrite so my honest humble guess is that you're plain wrong in this point. Regarding the SCRIPT_FILENAME key I'm unable to test that one out ATM. Still, if we close our eyes really hard and believe that you're right that leaves us with only one variable:

  • 'PHP_SELF'

I'm not trying in being harsh here (and I still believe that there are more solutions) but if PHP_SELF is the only key you want us to work with (assuming there are no impositions on PHP_SELF itself) there is only one solution left:

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

This function should work, however there may be some problems using the __FILE__ constant since it returns the path to the file where the __FILE__ constant is declared and not the path to the requested PHP script, so that's why the $whatToUse is there for: sou you can replace it with 'SCRIPT_FILENAME' or if you really believe in what you are saying, just use '.php'.

You should also read this regarding why not to use PHP_SELF.

If this doesn't work for you, I'm sorry but I can think of anything else.

EDIT - Some more reading for you:

清风无影 2024-08-21 02:54:31

我认为这里有一个以其他方式获取“path_info”的技巧:

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

例如,访问如下 URL: http://somehost.com/index.php/some/path/here$path_info 的值为:"/some/path/here 它在 Windows 和 Linux 上运行的各种 apache 服务器中对我有用,但我不能 100% 确定它是否“安全”和“可移植”,显然

我不会在“所有”服务器配置中测试它,但似乎有效...

I think here is a trick to get "path_info" in other way:

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

For example, access to a URL like: http://somehost.com/index.php/some/path/here, the value of $path_info would be: "/some/path/here"

It worked for me in various apache servers running on windows and linux, but I'm not 100% sure if it's "safe" and "portable", ovbiously I don't test it in "ALL" servers configs, but appears to work...

亚希 2024-08-21 02:54:31
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 进行比较。

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

Edit: without SCRIPT_NAME, and assuming you have DOCUMENT_ROOT (or can define/discover it yourself) and assuming you have SCRIPT_FILENAME, then:

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

Also @ Anthony (not enough rep to comment, sorry): Using str_replace() will match anywhere in the string. It's not guaranteed to work, you want to only match it at the start. Also, your method of only going 1 slash back (via strrpos) to determine SCRIPT_NAME, will only work if the script is under the root, which is why you're better off diffing script_filename against docroot.

无人问我粥可暖 2024-08-21 02:54:31

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

让我看看我是否理解:

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 或任何版本

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

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

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

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


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

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

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

如何获取URL?

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 脚本返回发送“document.URL”信息的 javascript 代码后退。 (可移植性问题转移到客户端。)

如何从URL中获取PATH_INFO?

此处链接的代码可以执行此操作。

这是我对这个问题的拙见和方法。

你怎么认为?

It depends on the definitions for "portable" and "safe".

Let me see if I understood:

1) You are not interested on CLI:

  • you mentioned PHP/CGI
  • PATH_INFO is a piece of an URL; so, it only makes sense to discuss PATH_INFO when the script is accessed from a URL (i.e. from an HTTP connection, usually requested by a browser)

2) You want to have PATH_INFO in all OS + HTTP server + PHP combination:

  • OS may be Windows, Linux, etc
  • HTTP server may be Apache 1, Apache 2, NginX, Lighttpd, etc.
  • PHP may be version 4, 5, 6 or any version

Hmmm... PHP_INFO, in the $_SERVER array, is provided by PHP to a script in execution only under certain conditions, depending on the softwares mentioned above. It is not always available. The same is true for the entire $_SERVER array!

In short: "$_SERVER depends on the server"... so a portable solution can't relay on $_SERVER... (just to give one example: we have a tutorial to set up PHP/CGI $_SERVER variables on NginX HTTP server at kbeezie.com/view/php-self-path-nginx/)

3) Despite what was mentioned above, it worths mentioning that if we somehow have the full URL that was requested available as a string, it is possible to obtain the PATH_INFO from it by applying regular expressions and other PHP string functions, safely (also validating the input string as a valid URI).

So, provided that we have the URL string... then YES, WE HAVE a portable and safe way to determine PATH_INFO from it.


Now, we have two clear and focused implementation issues:

  1. How to obtain the URL?
  2. How to obtain the PATH_INFO from the URL?

Among several possibilities, here is a possible approach:

How to obtain the URL?

1) With your deep and comprehensive knowledge about each HTTP server + OS + PHP version combination, check and try each possibility to obtain the URL from the $_SERVER array (verify 'PHP_SELF', 'QUERY_STRING', 'SCRIPT_FILENAME', 'PATH_TRANSLATED', 'SCRIPT_NAME', 'REQUEST_URI', 'PATH_INFO', 'ORIG_PATH_INFO', 'HTTP_HOST', 'DOCUMENT_ROOT' or whatever)

2) If previous step failed, make the PHP script return a javascript code that sends "document.URL" information back. (The portability issue transfered to client-side.)

How to obtain the PATH_INFO from the URL?

This code linked here does this.

This is my humble opinion and approach to the problem.

What do you think?

清晨说晚安 2024-08-21 02:54:31

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

I didn't see the comments or the link before posting. Here is something that might work, based on what the page referenced above gives as CGI-derived variables:

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;
}
并安 2024-08-21 02:54:31

你可以尝试

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

you could try

$_ENV['PATH_INFO']; or
getenv('PATH_INFO']; 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文