PHP_SELF变量解析和重复路径解决
最近升級PHP到PHP7版本,并重新部署了新的Nginx,啟動的時候發(fā)現(xiàn)了一個問題,全局變量$_SERVER['PHP_SELF']的值發(fā)生了改變,從而影響到代碼的功能。因此我們來了解下$_SERVER全局變量中的PHP_SELF/PATH_INFO/SCRIPT_NAME等參數(shù)以及其關(guān)系。
CGI 1.1規(guī)范
之前的文章 [ php-fpm進(jìn)程數(shù)管理 ] 已經(jīng)簡單說過CGI的內(nèi)容,這里我們再詳細(xì)講一下。
CGI是Common Gateway Interface(通用網(wǎng)管協(xié)議),用于讓交互程序和Web服務(wù)器通信的協(xié)議。它負(fù)責(zé)處理URL的請求,啟動一個進(jìn)程,將客戶端發(fā)送的數(shù)據(jù)作為輸入,由Web服務(wù)器收集程序的輸出并加上合適的頭部,再發(fā)送回客戶端。
FastCGI是基于CGI的增強(qiáng)版本的協(xié)議,不同于創(chuàng)建新的進(jìn)程來服務(wù)請求,使用持續(xù)的進(jìn)程和創(chuàng)建的子進(jìn)程來處理一連串的進(jìn)程,這些進(jìn)程由FastCGI服務(wù)器管理,開銷更小,效率更高。
CGI誕生于1993年美國國家計算機(jī)中心,目的是為不同的動態(tài)頁面處理語言(php/python/java)在不同的服務(wù)器下(apache/nginx)提供一致的接口規(guī)范,提供會話環(huán)境變量、會話客戶端等信息。
在RFC-CGI1.1文檔中包含了協(xié)議的全部內(nèi)容,我們現(xiàn)在只關(guān)注它的 4.1節(jié):Request Meta-Variables 。
標(biāo)準(zhǔn)中定義了處理請求應(yīng)該實現(xiàn)的17個屬性和如何自定義新屬性,比如:
- SERVER_PROTOCOL :信息協(xié)議的名字和修訂版。格式為protocol/reVision 。
- SERVER_PORT :發(fā)送請求的端口號。
- REQUEST_METHOD :請求的方法。對于HTTP,有"GET"、 "HEAD"、 "POST"等等。
- PATH_INFO :額外的路徑信息,由客戶端給出的。換句話說,腳本可以由他們的虛擬路徑名來訪問,在這個路徑的末尾附帶額外的信息。這個額外信息被作為PATH_INFO發(fā)送。這個信息如果在傳遞給CGI腳本之前來自URL就可以由服務(wù)器來解碼。
- PATH_TRANSLATED :服務(wù)器提供了一個PATH_INFO的轉(zhuǎn)換版本,它需要路徑并且為它做虛擬到物理的映射。
- SCRIPT_NAME :將要執(zhí)行的腳本的一個虛擬路徑。
- QUERY_STRING :在引用腳本的URL中緊跟在?之后的信息。這是一個查詢信息。它不能以任何方式來解碼。這個變量總是可以在有查詢信息的時候被設(shè)置,而不管命令行解碼。
- REMOTE_HOST :產(chǎn)生請求的主機(jī)名。如果服務(wù)器沒有這個信息,它應(yīng)該設(shè)置REMOTE_ADDR 并且讓這個為未設(shè)置狀態(tài)。
- REMOTE_ADDR :產(chǎn)生請求的遠(yuǎn)程主機(jī)的IP地址。
- AUTH_TYPE :如果服務(wù)器支持用戶驗證,腳本就受保護(hù)。這是一個協(xié)議規(guī)范授權(quán)方法,用于驗證用戶。
- REMOTE_USER :如果服務(wù)器支持用戶驗證,腳本就受保護(hù)。這是他們授權(quán)的用戶名。
- REMOTE_IDENT :如果HTTP服務(wù)器支持RFC931認(rèn)證,這個變量將被設(shè)置為從服務(wù)器取出的遠(yuǎn)程用戶名。這個變量的用法應(yīng)該只限制在登陸的時候。
- CONTENT_TYPE :對于哪些已經(jīng)附上信息的請求,比如 HTTP POST和PUT,這是數(shù)據(jù)的內(nèi)容類型。
- CONTENT_LENGTH :客戶端給的數(shù)據(jù)內(nèi)容的長度。
這些變量需要各個語言和服務(wù)器進(jìn)行自己的實現(xiàn),同時他們也會有自己定義的一些變量。如我們今天要說的PHP語言中的$_SERVER['PHP_SELF']變量。
PHP的超全局變量$_SERVER
$_SERVER 是一個包含了諸如頭信息(header)、路徑(path)、以及腳本位置(script locations)等等信息的數(shù)組。這個數(shù)組中的項目由 Web 服務(wù)器創(chuàng)建。不能保證每個服務(wù)器都提供全部項目;服務(wù)器可能會忽略一些,或者提供一些沒有在這里列舉出來的項目。這也就意味著大量的此類變量都會在? CGI 1.1 規(guī)范中說明,所以應(yīng)該仔細(xì)研究一下。__FILE__ 常量包含當(dāng)前(例如包含)文件的完整路徑和文件名。
與此相關(guān)的,我們這里主要關(guān)注的幾個變量是:
- PHP_SELF: 當(dāng)前執(zhí)行腳本的文件名,與 document root 有關(guān)。例如,在地址為 http://example.com/foo/bar.php 的腳本中值為 /foo/bar.php。
- SCRIPT_NAME: 包含當(dāng)前腳本的路徑。這在頁面需要指向自己時非常有用。
- PATH_INFO: 包含由客戶端提供的、跟在真實腳本名稱之后并且在查詢語句(query string)之前的路徑信息,如果存在的話。例如,如果當(dāng)前腳本是通過 URL http://www.example.com/php/path_info.php/some/stuff?foo=bar 被訪問,那么值為 /some/stuff。
文檔里表述的Web服務(wù)器,在我的環(huán)境里指代的是Nginx。在Apache中,當(dāng)不加配置的時候?qū)τ赑HP腳本, AcceptPathInfo是默認(rèn)接受的。而對于Nginx下, 是不支持PATH INFO的, 也就是它不會默認(rèn)設(shè)置PATH_INFO.
因此,對于一個Nginx架構(gòu)的常規(guī)請求來說,這幾個字段的值分別是:
# 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中出現(xiàn)重復(fù)路徑
在我部署完成新的Nginx服務(wù)后,得到的上面三個字段的值為:
# 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字段存在重復(fù)的路徑,而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;那么我們?yōu)槭裁磁渲昧薖ATH_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后,此時的結(jié)果是:
# http://www.baidu.com:8080/odp/index.php?r=update PHP_SELF: SCRIPT_NAMEPATH_INFO SCRIPT_NAME: SCRIPT_NAME PATH_INFO: PATH_INFO而其他變量均正常,因此我們可以進(jìn)一步理解:
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才能拿到完整的當(dāng)前執(zhí)行腳本的文件或路徑。
總結(jié)
為了不同服務(wù)器、不同語言之間的請求通信,于是有了CGI協(xié)議規(guī)范,這個規(guī)范在不同的服務(wù)器和語言中有自己的實現(xiàn),在Web Server: Nginx的配置文件中,可以設(shè)置不同變量的值,解析后傳遞給PHP-FPM(PHP-FastCGI Process Manager),再進(jìn)一步傳遞給負(fù)責(zé)響應(yīng)請求的PHP子進(jìn)程,而PHP中也定義了關(guān)于請求通信的全局變量$_SERVER,用于解析請求和處理邏輯。這就是整個關(guān)于解析請求信息的流程。
由于PHP中$_SERVER中的這幾個變量的定義有一定混淆,也依賴于不同的實現(xiàn)和Server環(huán)境,如PATH_INFO在Nginx/Apache中的不同默認(rèn)狀態(tài),因此,如果需要頁面指向自己時,除非如上面示例中的那種url,建議使用SCRIPT_NAME變量即可。
參考資料
總結(jié)
以上是生活随笔為你收集整理的PHP_SELF变量解析和重复路径解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑功耗监测_应急监测便携式VOC检测仪
- 下一篇: 电路板上的插头怎么拔下来_空调维修排查电