PHP_SELF变量解析和重复路径解决

栏目: PHP · 发布时间: 5年前

内容简介:最近升级之前的文章

最近升级 PHPPHP7 版本,并重新部署了新的 Nginx ,启动的时候发现了一个问题,全局变量 $_SERVER['PHP_SELF'] 的值发生了改变,从而影响到代码的功能。因此我们来了解下 $_SERVER 全局变量中的 PHP_SELF/PATH_INFO/SCRIPT_NAME 等参数以及其关系。

CGI 1.1 规范

之前的文章 [ php-fpm进程数管理 ] 已经简单说过CGI的内容,这里我们再详细讲一下。

CGICommon Gateway Interface(通用网管协议) ,用于让交互程序和Web服务器通信的协议。它负责处理URL的请求,启动一个进程,将客户端发送的数据作为输入,由Web服务器收集程序的输出并加上合适的头部,再发送回客户端。

FastCGI 是基于 CGI 的增强版本的协议,不同于创建新的进程来服务请求,使用持续的进程和创建的子进程来处理一连串的进程,这些进程由FastCGI服务器管理,开销更小,效率更高。

CGI 诞生于 1993 年美国国家计算机中心,目的是为不同的动态页面处理语言 (php/python/java) 在不同的服务器下 (apache/nginx) 提供一致的接口规范,提供会话环境变量、会话客户端等信息。

RFC-CGI1.1 文档中包含了协议的全部内容,我们现在只关注它的 4.1节:Request Meta-Variables

标准中定义了处理请求应该实现的 17 个属性和如何自定义新属性,比如:

  • SERVER_PROTOCOL :信息协议的名字和修订版。格式为 protocol/reVision
  • SERVER_PORT :发送请求的端口号。
  • REQUEST_METHOD :请求的方法。对于 HTTP ,有 "GET"、 "HEAD"、 "POST" 等等。
  • PATH_INFO :额外的路径信息,由客户端给出的。换句话说,脚本可以由他们的虚拟路径名来访问,在这个路径的末尾附带额外的信息。这个额外信息被作为 PATH_INFO 发送。这个信息如果在传递给 CGI 脚本之前来自 URL 就可以由服务器来解码。
  • PATH_TRANSLATED :服务器提供了一个 PATH_INFO 的转换版本,它需要路径并且为它做虚拟到物理的映射。
  • SCRIPT_NAME :将要执行的脚本的一个虚拟路径。
  • QUERY_STRING :在引用脚本的 URL 中紧跟在 之后的信息。这是一个查询信息。它不能以任何方式来解码。这个变量总是可以在有查询信息的时候被设置,而不管命令行解码。
  • REMOTE_HOST :产生请求的主机名。如果服务器没有这个信息,它应该设置 REMOTE_ADDR 并且让这个为未设置状态。
  • REMOTE_ADDR :产生请求的远程主机的 IP 地址。
  • AUTH_TYPE :如果服务器支持用户验证,脚本就受保护。这是一个协议规范授权方法,用于验证用户。
  • REMOTE_USER :如果服务器支持用户验证,脚本就受保护。这是他们授权的用户名。
  • REMOTE_IDENT :如果 HTTP 服务器支持 RFC931 认证,这个变量将被设置为从服务器取出的远程用户名。这个变量的用法应该只限制在登陆的时候。
  • CONTENT_TYPE :对于哪些已经附上信息的请求,比如 HTTP POSTPUT ,这是数据的内容类型。
  • CONTENT_LENGTH :客户端给的数据内容的长度。

这些变量需要各个语言和服务器进行自己的实现,同时他们也会有自己定义的一些变量。如我们今天要说的 PHP 语言中的 $_SERVER['PHP_SELF'] 变量。

PHP 的超全局变量 $_SERVER

$_SERVER 是一个包含了诸如 头信息(header)、路径(path)、以及脚本位置(script locations) 等等信息的数组。这个数组中的项目由 Web 服务器创建。不能保证每个服务器都提供全部项目;服务器可能会忽略一些,或者提供一些没有在这里列举出来的项目。这也就意味着大量的此类变量都会在 » CGI 1.1 规范中说明,所以应该仔细研究一下。

__FILE__ 常量包含当前(例如包含)文件的完整路径和文件名。

与此相关的,我们这里主要关注的几个变量是:

  • PHP_SELF : 当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/foo/bar.php 的脚本中值为 /foo/bar.php
  • SCRIPT_NAME : 包含当前脚本的路径。这在页面需要指向自己时非常有用。
  • PATH_INFO : 包含由客户端提供的、跟在真实脚本名称之后并且在查询语句 (query string) 之前的路径信息,如果存在的话。例如,如果当前脚本是通过 URL http://www.example.com/php/path_info.php/some/stuff?foo=bar 被访问,那么值为 /some/stuff

文档里表述的 Web 服务器,在我的环境里指代的是 Nginx 。在 Apache 中,当不加配置的时候对于 PHP 脚本, AcceptPathInfo 是默认接受的。而对于 Nginx 下, 是不支持 PATH INFO 的, 也就是它不会默认设置 PATH_INFO .

因此,对于一个 Nginx 架构的常规请求来说,这几个字段的值分别是:

# http://www.baidu.com:8080/odp/index.php?r=update
PHP_SELF: /odp/index.php
SCRIPT_NAME: /odp/index.php
PATH_INFO: null

问题: PHP_SELF 中出现重复路径

在我部署完成新的 Nginx 服务后,得到的上面三个字段的值为:

# http://www.baidu.com:8080/odp/index.php?r=update
PHP_SELF: /odp/index.php/odp/index.php
SCRIPT_NAME: /odp/index.php
PATH_INFO: /odp/index.php

注意这里的 PHP_SELF 字段存在重复的路径,而 PATH_INFO 也存在了值,此时的 nginx.conf 配置为:

fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

# 注意这一行,我们配置了PATH_INFO字段
fastcgi_param  PATH_INFO          $fastcgi_script_name;
fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

那么我们为什么配置了 PATH_INFO 就会影响 PHP_SELF 的值了呢?这一点,我们首先会想到 PHP_SELF 这个自定义属性的来源是什么,然而,我并没有找到任何的文档说明。但我们可以通过重命名的方式,来探究一下它的定义:

fastcgi_param  PATH_INFO          PATH_INFO;
# fastcgi_param  PATH_INFO          $fastcgi_script_name;

fastcgi_param  SCRIPT_NAME        SCRIPT_NAME;
# fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;

变更这两行,我们将其重命名为指定字符串,而不是请求传入的变量, nginx reload 后,此时的结果是:

# http://www.baidu.com:8080/odp/index.php?r=update
PHP_SELF: SCRIPT_NAMEPATH_INFO
SCRIPT_NAME: SCRIPT_NAME
PATH_INFO: PATH_INFO

而其他变量均正常,因此我们可以进一步理解:

PHP_SELF = SCRIPT_NAME + PATH_INFO

自定义变量: PHP_SELF

那么 PHP 为什么要自定义这个属性呢?在官方文档里有这么一个 url 请求,此时:

# http://www.example.com/php/path_info.php/some/stuff?foo=bar 
PHP_SELF: /php/path_info.php/some/stuff
SCRIPT_NAME: /php/path_info.php
PATH_INFO: /some/stuff

所以,在这种场景下,只有 PHP_SELF 才能拿到完整的当前执行脚本的文件或路径。

总结

为了不同服务器、不同语言之间的请求通信,于是有了 CGI 协议规范,这个规范在不同的服务器和语言中有自己的实现,在 Web Server: Nginx 的配置文件中,可以设置不同变量的值,解析后传递给 PHP-FPM(PHP-FastCGI Process Manager) ,再进一步传递给负责响应请求的 PHP 子进程,而 PHP 中也定义了关于请求通信的全局变量 $_SERVER ,用于解析请求和处理逻辑。这就是整个关于解析请求信息的流程。

由于 PHP$_SERVER 中的这几个变量的定义有一定混淆,也依赖于不同的实现和 Server 环境,如 PATH_INFONginx/Apache 中的不同默认状态,因此,如果需要页面指向自己时,除非如上面示例中的那种 url ,建议使用 SCRIPT_NAME 变量即可。

参考资料

  1. segmentfault-php-fpm进程数管理: https://segmentfault.com/a/11...
  2. RFC-CGI1.1: https://tools.ietf.org/html/r...
  3. CGI规范及其历史: http://www.voidcn.com/article...
  4. php关于$_SERVER中一些和环境有关的参数详解: https://www.jianshu.com/p/fea...

以上所述就是小编给大家介绍的《PHP_SELF变量解析和重复路径解决》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

动手玩转Scratch2.0编程

动手玩转Scratch2.0编程

马吉德·马吉 (Majed Marji) / 电子工业出版社 / 2015-10-1 / CNY 69.00

Scratch 是可视化的编程语言,其丰富的学习环境适合所有年龄阶段的人。利用它可以制作交互式程序、富媒体项目,包括动画故事、读书报告、科学实验、游戏和模拟程序等。《动手玩转Scratch2.0编程—STEAM创新教育指南》的目标是将Scratch 作为工具,教会读者最基本的编程概念,同时揭示Scratch 在教学上的强大能力。 《动手玩转Scratch2.0编程—STEAM创新教育指南》共......一起来看看 《动手玩转Scratch2.0编程》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具