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

最近升级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...
  5. PHP文档-$_SERVER:http://php.net/manual/zh/rese...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/252297.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中的类加多线程代码修炼之二

背景:在上一篇文章中 写到了我第一次使用C使用多个类多个线程进行编程,由于是第一接手“这么大一个工程”,所以还是要有个参照物的,由于我呢之前好几年一直在看的一个C代码工程就是ORB-SLAM了,这个工程使用C语言&#…

3-4 第三天 Generator生成器

Generator是ES6里面的新增规范,ES6其实就是ES2015。ES5、ES6、ES7这些术语大家上网一查就都明白了。JavaScript是一个范程,就是我们说的JS。ES就是ECMA Script,是JavaScript标准的书面说法。ES4、5、6、7其实是JS这门语言发展中的不同的版本。…

神奇的事情--长见识了

背景:我的这个工程里有多个命名空间,之所以是这样是因为,有一个跟踪算法他本身有几个namespace,然后我在他的基础上进行整合代码,将其作为一个功能接口,供其他函数调用,我在整合代码时,将我新加…

箭头函数的使用用法(一)

1 //箭头函数的一个好处是简化回调函数2 //箭头函数没有参数,就使用圆刮号代表参数部分;3 var f () >5;4 console.log(f());5 //两个参数的情况,代码块只有一条语句,可以省略{}6 var f (a,b)> console.log(ab);7 f(1,3);8…

LinkedList中查询(contains)和删除(remove)源码分析

一、contains源码分析 本文分析双向链表LinkedList的查询操作源码实现。jdk中源程序中,LinkedList的查询操作,通过contains(Object o)函数实现。具体见下面两部分程序:① public boolean contains(Object o) {return indexOf(o) ! -1; } ② p…

分块入门

我貌似和所有的数据结构都有些误会。。。。。。 在处理一些修改查询问题的时候,我们可以利用分治的思想,比如说把一个线性的数据不断分成一棵二叉树,也就是我们所说的线段树,这样我们就可以在logn的时限里做到修改和查询。同理我们…

开始使用gitlab

不得不说,我真不是一个合格的程序猿,工作马上两年了,github和gitlab用的一点也不熟练,每次兴致来了就搞几下,可是每次都浅尝辄止,不求甚解,时间一长,上一次练习的步骤就都记不起来了…

淘宝top平台调用接口响应时间优化

我的专栏地址:我的segmentfault,欢迎浏览 一、背景 调用top接口的响应时间长(160ms左右),超时和连接异常频繁发生。导致消息组件消费工程的tps遇到瓶颈(单实例单消息队列250tps),只能通过增加实…

win10上编译libharu库

背景: 最近的项目需要自动的生成pdf文件,我在网上查看相关的资料,发现目前比较流行的生成pdf文件的库有两个,一个是libpdf,另一个是libharu。libpdf个人使用时免费的但是商业使用就需要收费了,否则得到的p…

爬虫——正则表达式re模块

为什么要学习正则表达式 实际上爬虫一共就四个主要步骤: 明确目标:需清楚目标网站爬:将所有的目标网站的内容全部爬下来取:在爬下来的网站内容中去掉对我们没有用处的数据,只留取我们需要的数据处理数据:按…

深入Spring Boot:快速集成Dubbo + Hystrix

2019独角兽企业重金招聘Python工程师标准>>> 背景 Hystrix 旨在通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。Hystrix具备拥有回退机制和断路器功能的线程和信号隔离,请求缓存和请求打包&#xff…

opencv图像仿射变换和普通旋转

背景:今天需要对程序生成的图像进行旋转90度和下采样操作,当然还有改变图像类型的操作,就是把原来.png的图像转换为.jpg的图像,主要是我目前使用libharu库,无法成功从本地加载png图像到pdf中去,不得不使用j…

try{}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会 不会被执行,什么时候被执行,在 return 前还是后?...

这是一道面试题,首先finally{}里面的code肯定是会执行的,至于在return前还是后, 看答案说的是在return后执行,我觉得不对,百度了一下,有说return前的,有说return后的,还有return中间…

相机和镜头选型需要注意哪些问题

背景: 最近需要优于项目需求需要对工业相机和镜头进行选型,于是我就开启的学习相机之旅,虽然我一直在做机器视觉方向,但是我对相机的了解还是很少,我想正好趁这次机会好好学习一下。如果有错误的观点请指正。 一、相…

正則表達式,终极使用!3个工具,搞定一切

文章前提,本人。不会正则的不论什么语法,仅仅懂一点正则的概念。本人从未自己写过正则,都是网上收罗进行改动的。相同。没有时间去研究正则。 可是为了方便,入手了几个工具。 如今就为大家一一展示。 第一个,regexBuil…

VS2017 C++工程 执行python脚本

我解决了哪怕很小的一个问题,我也想记录下来来见证我的经历。 背景: 一、使用libhuru库生成pdf报告 最近参与一些测试工作,希望测试结束后能够根据测试得到的数据和图像自动生成测试报告,最开始调研到了生成报告的库有libharu和…

运行imgui例程

背景:目前在做一个视觉测试系统,需要做一个界面,将相机获取的图像,以及测试过程中的数据呈现在界面上,在我印象里,做界面就用qt吧,直到这个月真要开始做界面了,我的领导给我建议用im…

性能测试总结(三)--工具选型篇

性能测试总结(三)--工具选型篇 本篇文章主要简单总结下性能测试工具的原理以及如何选型。性能测试和功能测试不同,性能测试的执行是基本功能的重复和并发,需要模拟多用户,在性能测试执行时需要监控指标参数,同时性能测试的结果不是…

创建一个最简单的imgui测试用例

在上一篇文章中,我们初步认识了一下imgui,并且成功运行了他提供的demo。这只是开始学习imgui的第一步,在实际使用时,我们需要将imgui应用到自己的工程中去,所以你需要具备将imgui加到你工程中去的能力,简单起见&#x…

idea中maven的setting.xml的配置

2019独角兽企业重金招聘Python工程师标准>>> <?xml version"1.0" encoding"UTF-8"?> <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance&qu…