PHP_SELF变量解析和重复路径解决
最近升级PHP
到PHP7
版本,并重新部署了新的Nginx
,启动的时候发现了一个问题,全局变量$_SERVER['PHP_SELF']
的值发生了改变,从而影响到代码的功能。因此我们来了解下$_SERVER
全局变量中的PHP_SELF/PATH_INFO/SCRIPT_NAME
等参数以及其关系。
CGI 1.1
规范
之前的文章 [ php-fpm进程数管理 ] 已经简单说过CGI的内容,这里我们再详细讲一下。
CGI
是Common 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 POST
和PUT
,这是数据的内容类型。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_INFO
在Nginx/Apache
中的不同默认状态,因此,如果需要页面指向自己时,除非如上面示例中的那种url
,建议使用SCRIPT_NAME
变量即可。
参考资料
- segmentfault-php-fpm进程数管理: https://segmentfault.com/a/11...
- RFC-CGI1.1: https://tools.ietf.org/html/r...
- CGI规范及其历史:http://www.voidcn.com/article...
- php关于$_SERVER中一些和环境有关的参数详解: https://www.jianshu.com/p/fea...
- PHP文档-$_SERVER:http://php.net/manual/zh/rese...
PHP_SELF变量解析和重复路径解决相关推荐
- PHP几种常见魔术方法与魔术变量解析
PHP几种常见魔术方法与魔术变量解析 先不多说,直接上代码,如下: 1 class Demo 2 { 3 private $str = 'str'; 4 5 //实例化时自动加载function 6 ...
- java环境变量修改不了_win10系统安装了jdk,修改环境变量配置不生效的解决方法...
Win10系统安装了jdk,修改环境变量配置不生效怎么办?今天系统天地给大家分享win10系统安装了jdk,修改环境变量配置不生效的解决方法. 访问: win10系统安装了jdk,修改环境变量配置不生 ...
- PHP字符串中的变量解析(+教你如何在PHP字符串中加入变量)
定义字符串的时候,用单引号或者双引号都是可以的.我个人习惯是用双引号. 在输出字符串的时候,若字符串中含有字符串变量,使用单引号和双引号则是有区别的.如下面程序: 1 2 3 4 5 6 7 8 &l ...
- linux shell变量的,linux shell变量解析
摘要 腾兴网为您分享:linux shell变量解析,智影,智联招聘,智慧消防,音恋等软件知识,以及考拉fm电台,快快游戏,京东企业购app,pdf加密工具,高德导航3d版,电脑驱动,兰溪新闻,我爱网 ...
- 人人都能看懂的Spring源码解析,Spring如何解决循环依赖
人人都能看懂的Spring源码解析,Spring如何解决循环依赖 原理解析 什么是循环依赖 循环依赖会有什么问题? 如何解决循环依赖 问题的根本原因 如何解决 为什么需要三级缓存? Spring的三级 ...
- 报错未能找到程序集“platform.winmd”: 请使用 /AI 或通过设置 LIBPATH 环境变量指定程序集搜索路径,问题解决办法
报错C1107 未能找到程序集"platform.winmd"和"Windows.winmd" 说在前面的话 文章供自己回顾学习使用(学生党踩坑总结) 做计算机 ...
- Crash工具实战-变量解析【转】
转自:http://blog.chinaunix.net/uid-14528823-id-4358785.html Crash工具实战-变量解析 Crash工具用于解析Vmcore文件,Vmcore文 ...
- C语言求网格的最大不重复路径数的算法(附完整源码)
C语言求网格的最大不重复路径数的算法 C语言求网格的最大不重复路径数的算法完整源码(定义,实现,main函数测试) C语言求网格的最大不重复路径数的算法完整源码(定义,实现,main函数测试) #in ...
- InstallSheild 获取系统环境变量,如Desktop路径等
使用FOLDER_DESKTOP变量获取的桌面路径可能为:C:\Users\Public\Desktop 而不是C:\Users\用户\Desktop Copy and paste the follo ...
最新文章
- php操作MySQL
- Spring Boot学习笔记-进阶(3)
- python读excel两列为字典_用python读取Excel并保存字典?一两行代码完成骚操作
- 信息检索IR评价中常见的评价指标-MAP\NDCG\ERR\P@10等
- 【计算机网络复习 数据链路层】3.6.1 局域网
- @程序员,一文掌握 Web 应用中的图片优化技巧!
- Linux网络子系统中协议栈的入口处理
- TextWatcher接口
- 软件产品需求分析思维导图
- 两个excel表格取交集_(怎么用excel把两个表格数据做交集)如何把不同excel表格数据取交集...
- 计算机打字考试的技巧,快速打字有什么技巧
- Python文件操作-替换srt文件行文本
- 织梦dedeCMS留言薄
- 选址|如何开一家咖啡店?店铺租金多少合适?
- 联想电脑如何改w ndows更新,电脑是否能升级到Windows 8.1 及支持Windows 8.1系统的机型汇总...
- Codeforces 814D An overnight dance in discotheque 贪心
- CPU大小端模式对C语言底层开发的影响
- 网络通讯学习(3)-----UDP通讯(仅了解)
- 知乎神回复:计算机专业学成什么样,才算“大学没白读“?
- 【OS Pintos】Project1 项目要求说明 | 进程中止信息 | 参数传递 | 用户内存访问 | 有关项目实现的建议
热门文章
- sql 日期类型空值等于 1900-01-01
- 本地存储cookie和localStorage区别特点
- git clone时出现 error:inflate:data stream error(incorrect data check)
- ExtJS4.2学习(10)分组表格控件--GroupingGrid(转)
- Python安装scikit-learn包
- Discretized Streams: An Efficient and Fault-Tolerant Model for Stream Processing on Large Clusters
- flex中dispatchEvent的用法(自定义事件) .
- java类的结构:构造器 —(13)
- 项目管理的测试版发布
- HTML5概要与新增标签