2024 日本 PHP 研討會

$_SERVER

(PHP 4 >= 4.1.0, PHP 5, PHP 7, PHP 8)

$_SERVER伺服器和執行環境資訊

說明

$_SERVER 是一個 陣列,包含標頭、路徑和腳本位置等資訊。此陣列中的項目是由網路伺服器建立的,因此無法保證每個網路伺服器都會提供所有這些項目;伺服器可能會省略一些項目,或提供這裡未列出的其他項目。然而,大多數這些變數都記載於 » CGI/1.1 規範 中,並且很可能會被定義。

注意命令列 上執行 PHP 時,大多數這些項目將不可用或沒有任何意義。

除了下面列出的元素之外,PHP 還會根據請求標頭的值建立額外的元素。這些項目的名稱為 HTTP_,後接標頭名稱,標頭名稱會大寫,並使用底線代替連字號。例如,Accept-Language 標頭將以 $_SERVER['HTTP_ACCEPT_LANGUAGE'] 的形式提供。

索引

'PHP_SELF'
目前正在執行的腳本的文件名,相對於文件根目錄。例如,位於網址 http://example.com/foo/bar.php 的腳本中的 $_SERVER['PHP_SELF'] 將會是 /foo/bar.php__FILE__ 常數包含目前(即包含的)檔案的完整路徑和檔名。 如果 PHP 作為命令列處理器運行,則此變數包含腳本名稱。
'argv'
傳遞給腳本的參數陣列。當腳本在命令列上運行時,這提供了 C 語言風格的命令列參數訪問方式。當通過 GET 方法調用時,這將包含查詢字串。
'argc'
包含傳遞給腳本的命令列參數的數量(如果在命令列上運行)。
'GATEWAY_INTERFACE'
伺服器正在使用的 CGI 規範版本;例如 'CGI/1.1'
'SERVER_ADDR'
執行目前腳本的伺服器的 IP 位址。
'SERVER_NAME'
執行目前腳本的伺服器主機名稱。如果腳本在虛擬主機上運行,則這將是為該虛擬主機定義的值。

注意 在 Apache 2 下,必須設定 UseCanonicalName = OnServerName。否則,此值會反映用戶端提供的可被偽造的主機名稱。在安全性相關的環境中,依賴此值並不安全。

'SERVER_SOFTWARE'
伺服器識別字串,在回應請求時在標頭中提供。
'SERVER_PROTOCOL'
用於請求頁面的資訊協定名稱和版本;例如 'HTTP/1.0'
'REQUEST_METHOD'
用於訪問頁面的請求方法;例如 'GET''HEAD''POST''PUT'

注意:

如果請求方法是 HEAD,PHP 腳本會在發送標頭後(也就是在產生任何輸出而沒有輸出緩衝之後)終止。

'REQUEST_TIME'
請求開始的時間戳記。
'REQUEST_TIME_FLOAT'
請求開始的時間戳記,具有微秒精度。
'QUERY_STRING'
用於訪問頁面的查詢字串(如果有的話)。
'DOCUMENT_ROOT'
目前腳本正在執行的文件根目錄,在伺服器的設定檔中定義。
'HTTPS'
如果腳本是透過 HTTPS 協定查詢的,則設定為非空值。
'REMOTE_ADDR'
使用者瀏覽目前頁面的 IP 位址。
'REMOTE_HOST'
使用者瀏覽目前頁面的主機名稱。反向 DNS 查詢是基於使用者的 REMOTE_ADDR

注意網頁伺服器必須設定為建立此變數。例如,在 Apache 中,必須在 httpd.conf 內設定 HostnameLookups On 才能使其存在。另請參閱 gethostbyaddr()

'REMOTE_PORT'
使用者機器上用於與網頁伺服器通訊的連接埠。
'REMOTE_USER'
已驗證的使用者。
'REDIRECT_REMOTE_USER'
如果請求是內部重新導向,則為已驗證的使用者。
'SCRIPT_FILENAME'

目前正在執行之腳本的絕對路徑名稱。

注意:

如果使用 CLI 以相對路徑(例如 file.php../file.php)執行腳本,$_SERVER['SCRIPT_FILENAME'] 將包含使用者指定的相對路徑。

'SERVER_ADMIN'
在網頁伺服器設定檔中指定給 SERVER_ADMIN (針對 Apache) 指令的值。如果腳本在虛擬主機上執行,則這將是為該虛擬主機定義的值。
'SERVER_PORT'
網頁伺服器在伺服器機器上用於通訊的連接埠。對於預設設定,這將是 '80';例如,使用 SSL 將會將其更改為您定義的安全 HTTP 連接埠。

注意在 Apache 2 下,必須在 httpd.conf 中設定 UseCanonicalName = On 以及 UseCanonicalPhysicalPort = On 才能取得實際的連接埠,否則,這個值可能會被偽造,而且可能傳回或不傳回實際的連接埠值。在安全性相關的環境中,不應依賴此值。

'SERVER_SIGNATURE'
包含伺服器版本和虛擬主機名稱的字串,如果啟用,則會新增到伺服器產生的頁面中。
'PATH_TRANSLATED'
在伺服器完成任何虛擬到實體的映射後,目前腳本的檔案系統路徑(而非文件根目錄路徑)。

注意Apache 2 使用者可以在 httpd.conf 中使用 AcceptPathInfo = On 來定義 PATH_INFO

'SCRIPT_NAME'
包含目前腳本的路徑。這對於需要指向自身的頁面很有用。__FILE__ 常數包含目前(即包含的)檔案的完整路徑和檔名。
'REQUEST_URI'
用於存取此頁面的 URI;例如 '/index.html'。
'PHP_AUTH_DIGEST'
執行 Digest HTTP 驗證時,此變數會設定為用戶端傳送的「授權」標頭(您應該使用它進行適當的驗證)。
'PHP_AUTH_USER'
執行 HTTP 驗證時,此變數會設定為使用者提供的使用者名稱。
'PHP_AUTH_PW'
執行 HTTP 驗證時,此變數會設定為使用者提供的密碼。
'AUTH_TYPE'
執行 HTTP 驗證時,此變數會設定為驗證類型。
'PATH_INFO'
如果可用,包含任何客戶端提供的路徑名稱資訊,這些資訊位於實際腳本檔名之後,但在查詢字串之前。例如,如果目前腳本是透過 URI http://www.example.com/php/path_info.php/some/stuff?foo=bar 存取的,則 $_SERVER['PATH_INFO'] 將包含 /some/stuff
'ORIG_PATH_INFO'
PHP 處理前的原始 'PATH_INFO' 版本。

範例

範例 #1 $_SERVER 範例

<?php
echo $_SERVER['SERVER_NAME'];
?>

上述範例將輸出類似以下內容

www.example.com

注意事項

注意:

這是一個「超全域變數」或自動全域變數。這僅表示它在整個腳本的所有作用域中都可用。在函式或方法內存取它不需要使用 global $variable;

另請參閱

新增註釋

使用者貢獻的註釋 38 則註釋

Vladimir Kornea
15 年前
1. 所有鍵值以 'HTTP_' 開頭的 $_SERVER 陣列元素都來自 HTTP 請求標頭,不可信任。

2. 所有傳送到腳本的 HTTP 標頭都可透過 $_SERVER 陣列取得,名稱以 'HTTP_' 為前綴。

3. 如果誤用,$_SERVER['PHP_SELF'] 很危險。如果請求 login.php/nearly_arbitrary_string,$_SERVER['PHP_SELF'] 將不僅包含 login.php,還包含整個 login.php/nearly_arbitrary_string。如果您在未執行 HTML 編碼的情況下將 $_SERVER['PHP_SELF'] 列印為表單標籤的 action 屬性值,攻擊者可以透過提供使用者指向您網站的連結(例如以下連結)來執行 XSS 攻擊

<a href='http://www.example.com/login.php/"><script type="text/javascript">...</script><span a="'>Example.com</a>

javascript 區塊將定義一個事件處理函式,並將其綁定到表單的提交事件。此事件處理程式將透過 <img> 標籤載入一個外部檔案,並以提交的使用者名稱和密碼作為參數。

請使用 $_SERVER['SCRIPT_NAME'] 而不是 $_SERVER['PHP_SELF']。將每個傳送到瀏覽器且不應解譯為 HTML 的字串進行 HTML 編碼,除非您完全確定它不包含瀏覽器可以解譯為 HTML 的任何內容。
vcoletti at tiscali dot it
4 年前
要列出所有 $_SERVER 參數,只需執行

foreach ($_SERVER as $parm => $value) echo "$parm = '$value'\n";

無需列出陣列的所有可能鍵值。
MarkAgius at markagius dot co dot uk
13 年前
您遺漏了 'REDIRECT_STATUS'

如果您將所有錯誤頁面指向同一個檔案,這非常有用。

檔案:.htaccess
# .htaccess 檔案。

ErrorDocument 404 /error-msg.php
ErrorDocument 500 /error-msg.php
ErrorDocument 400 /error-msg.php
ErrorDocument 401 /error-msg.php
ErrorDocument 403 /error-msg.php
# 檔案結束。

檔案:error-msg.php
<?php
$HttpStatus
= $_SERVER["REDIRECT_STATUS"] ;
if(
$HttpStatus==200) {print "文件已處理並傳送給您。";}
if(
$HttpStatus==400) {print "錯誤的 HTTP 請求";}
if(
$HttpStatus==401) {print "未經授權 - 無效的密碼";}
if(
$HttpStatus==403) {print "禁止訪問";}
if(
$HttpStatus==500) {print "內部伺服器錯誤";}
if(
$HttpStatus==418) {print "我是茶壺! - 這是 1998 年定義的真實值";}

?>
Lord Mac
15 年前
一個更加改良的版本...

<?php
phpinfo
(32);
?>
jonbarnett at gmail dot com
16 年前
值得注意的是,$_SERVER 變數會為任何 HTTP 請求標頭建立,包括您可能自行發明的標頭

如果瀏覽器發送以下 HTTP 請求標頭:
X-Debug-Custom: some string

那麼

<?php
$_SERVER
['HTTP_X_DEBUG_CUSTOM']; // "some string"
?>

有更好的方法來識別瀏覽器發送的 HTTP 請求標頭,但如果您知道預期會收到什麼,例如具有自訂標頭的 AJAX 腳本,那麼這種方法很方便。

適用於使用 mod_php 的 Apache 上的 PHP5。不知道這是否適用於其他環境。
pierstoval at example dot com
7 年前
由於 PHP 的 $_SERVER 變數包含許多變數,我想必須說明它也包含環境變數。

例如,使用 PHP 腳本,我們可以這樣做

MY_ENV_VAR=Hello php -r 'echo $_SERVER["MY_ENV_VAR"];'

將顯示「Hello」。

但是,在內部,PHP 會確保 $_SERVER 中的「內部」鍵不會被覆蓋,因此您無法執行以下操作

REQUEST_TIME=Hello php -r 'var_dump($_SERVER["REQUEST_TIME"]);'

將顯示類似 1492897785 的內容

但是,許多變數仍然容易受到環境注入的影響。

我在這裡建立了一個 gist ( https://gist.github.com/Pierstoval/f287d3e61252e791a943dd73874ab5ee ),其中包含我在 Windows 上使用 WSL bash 的 PHP7.0.15 的 PHP 設定,結果是唯一「安全」的變數如下:

PHP_SELF
SCRIPT_NAME
SCRIPT_FILENAME
PATH_TRANSLATED
DOCUMENT_ROOT
REQUEST_TIME_FLOAT
REQUEST_TIME
argv
argc

所有其他變數都可以被環境變數覆蓋,這實際上不太好,因為它有時會破壞 PHP 應用程式...

(我只在 CLI 上測試過,我沒有耐心用 Apache mod_php 或 Nginx + PHP-FPM 測試,但我可以想像很多 $_SERVER 屬性並非「那麼」安全……)
chris at ocproducts dot com
7 年前
絕對路徑指南...

資料:__FILE__
資料類型:字串
用途:執行中 PHP 檔案的絕對路徑名稱,包含檔名。
注意事項:這不是 PHP 處理器呼叫的檔案,而是正在執行的檔案。因此,如果您在 include 檔案內,它就是 include 檔案。
注意事項:符號連結會預先解析,因此不要相信路徑比較是準確的。
注意事項:不要假設所有作業系統都使用「/」作為目錄分隔符號。
在網頁模式下運作:是
在 CLI 模式下運作:是

資料:__DIR__
資料類型:字串
用途:執行中 PHP 檔案的絕對路徑名稱,不包含檔名。
注意事項:這不是 PHP 處理器呼叫的檔案,而是正在執行的檔案。因此,如果您在 include 檔案內,它就是 include 檔案。
注意事項:符號連結會預先解析,因此不要相信路徑比較是準確的。
注意事項:不要假設所有作業系統都使用「/」作為目錄分隔符號。
在網頁模式下運作:是
在 CLI 模式下運作:是

資料:$_SERVER['SCRIPT_FILENAME']
資料類型:字串
用途:原始 PHP 檔案的絕對路徑名稱,包含檔名。
注意事項:並非在所有 PHP 環境中都設定,可能需要在 include 其他檔案之前從 __FILE__ 複製設定。
注意事項:符號連結不會預先解析,如果需要解析,請使用 PHP 的「realpath」函式。
注意事項:不要假設所有作業系統都使用「/」作為目錄分隔符號。
注意事項:「檔名」讓您認為它只是一個檔名,但它實際上是完整的絕對路徑名稱。將識別符號讀作「腳本的檔案系統(路徑)名稱」。
在網頁模式下運作:是
在 CLI 模式下運作:是

資料:$_SERVER['PATH_TRANSLATED']
資料類型:字串
用途:原始 PHP 檔案的絕對路徑名稱,包含檔名。
注意事項:它可能未設定,最好不要使用它。只需使用 realpath($_SERVER['SCRIPT_FILENAME'])(並注意它本身可能需要被模擬)。
注意事項:符號連結會預先解析,因此不要相信路徑比較是準確的。
注意事項:不要假設所有作業系統都使用「/」作為目錄分隔符號。
在網頁模式下運作:是
在 CLI 模式下運作:否

資料:$_SERVER['DOCUMENT_ROOT']
資料類型:字串
用途:取得網頁伺服器文件根目錄的絕對路徑。沒有尾端斜線。
注意事項:除非您控制伺服器環境,否則不要相信它已設定或設定正確。
注意事項:符號連結可能會或可能不會預先解析,如果需要解析,請使用 PHP 的「realpath」函式。
注意事項:不要假設所有作業系統都使用「/」作為目錄分隔符號。
在網頁模式下運作:是
在 CLI 模式下運作:否

請注意,如果未設定某些內容,它可能會遺失在 $_SERVER 中,或者它可能是空白的,因此請使用 PHP 的「empty」函式進行測試。

請注意,如果您在命令列上呼叫「php --info」,則由於未涉及任何 PHP 檔案,因此這些設定中的一些自然會是空白的。
Richard York
15 年前
這裡沒有記載的是,透過 shell 存取 PHP 時,$_SERVER 會填入一些非常有用的資訊。

["_SERVER"]=>
array(24) {
["MANPATH"]=>
string(48) "/usr/share/man:/usr/local/share/man:/usr/X11/man"
["TERM"]=>
string(11) "xterm-color"
["SHELL"]=>
string(9) "/bin/bash"
["SSH_CLIENT"]=>
string(20) "127.0.0.1 41242 22"
["OLDPWD"]=>
string(60) "/Library/WebServer/Domains/www.example.com/private"
["SSH_TTY"]=>
string(12) "/dev/ttys000"
["USER"]=>
string(5) "username"
["MAIL"]=>
string(15) "/var/mail/username"
["PATH"]=>
string(57) "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin"
["PWD"]=>
string(56) "/Library/WebServer/Domains/www.example.com/www"
["SHLVL"]=>
string(1) "1"
["HOME"]=>
string(12) "/Users/username"
["LOGNAME"]=>
string(5) "username"
["SSH_CONNECTION"]=>
string(31) "127.0.0.1 41242 10.0.0.1 22"
["_"]=>
string(12) "/usr/bin/php"
["__CF_USER_TEXT_ENCODING"]=>
string(9) "0x1F5:0:0"
["PHP_SELF"]=>
string(10) "Shell.php"
["SCRIPT_NAME"]=>
string(10) "Shell.php"
["SCRIPT_FILENAME"]=>
string(10) "Shell.php"
["PATH_TRANSLATED"]=>
string(10) "Shell.php"
["DOCUMENT_ROOT"]=>
string(0) ""
["REQUEST_TIME"]=>
int(1247162183)
["argv"]=>
array(1) {
[0]=>
string(10) "Shell.php"
}
["argc"]=>
int(1)
}
ywarnier at beeznest dot org
7 年前
請注意,$_SERVER['REQUEST_URI'] 在某些情況下可能包含通訊協定和網域。

例如,當透過呼叫 stream_context_create() 並將 HTTP 標頭 'request_fulluri' 設定為 1 來呼叫頁面時,就會發生這種情況。

例如

$http = ['request_fulluri' => 1, /* 其他參數 */];
$context = stream_context_create(array( 'http' => $http ));
$fp = fopen($some_url, 'rb', false, $context);

當在 $some_url 伺服器上輸出 $_SERVER['REQUEST_URI'] 時,您會得到
https://some_url/some_script.php

移除 request_fulluri => 1 選項,$_SERVER['REQUEST_URI'] 就會回到它的「正常」狀態
/some_script.php

顯然,request_fulluri 在使用某些代理伺服器時很有用。

在這種情況下,沒有適當的方法可以「偵測」是否設定了這個選項,您可能應該使用其他 $_SERVER[] 元素的組合(例如 REQUEST_SCHEME、SERVER_NAME 和 SERVER_PORT)來判斷是否為這種情況。

一種快速(且可改進的)偵測方法是將 REQUEST_URI 的開頭與 REQUEST_SCHEME 進行比較

$scheme = $_SERVER['REQUEST_SCHEME'] . '://';
if (strcmp(substr($_SERVER['REQUEST_URI'], 0, strlen($scheme)), $scheme) === 0) {
// 已設定 request_fulluri
}
chris at ocproducts dot com
7 年前
URL 路徑指南...

資料:$_SERVER['PHP_SELF']
資料類型:字串
用途:目前 PHP 檔案的 URL 路徑名稱,包含路徑資訊 (請參閱 $_SERVER['PATH_INFO']),但不包含 URL 查詢字串。包含開頭的斜線。
注意事項:這是經過 URL 重寫後的結果(也就是 PHP 所看到的,不一定與原始呼叫的 URL 相同)。
在網頁模式下運作:是
在 CLI 模式下運作:不穩定(模擬僅包含 CLI 腳本的確切呼叫路徑,以及您可能使用的任何特殊相對路徑名稱,未設為絕對路徑,也未正規化或預先解析)

資料:$_SERVER['SCRIPT_NAME']
資料類型:字串
用途:目前 PHP 檔案的 URL 路徑名稱,不包含路徑資訊和 URL 查詢字串。包含開頭的斜線。
注意事項:這是經過 URL 重寫後的結果(也就是 PHP 所看到的,不一定與原始呼叫的 URL 相同)。
注意事項:並非所有 PHP 環境都已設定,可能需要透過 preg_replace('#\.php/.*#', '.php', $_SERVER['PHP_SELF']) 設定。
在網頁模式下運作:是
在 CLI 模式下運作:不穩定(模擬僅包含 CLI 腳本的確切呼叫路徑,以及您可能使用的任何特殊相對路徑名稱,未設為絕對路徑,也未正規化或預先解析)

資料:$_SERVER['REDIRECT_URL']
資料類型:字串
用途:目前 PHP 檔案的 URL 路徑名稱,不適用路徑資訊,也不包含 URL 查詢字串。包含開頭的斜線。
注意事項:這是 URL 重寫前的結果(也就是原始呼叫的 URL)。
注意事項:並非所有 PHP 環境都已設定,而且肯定只有具有 URL 重寫功能的環境才會有。
在網頁模式下運作:是
在 CLI 模式下運作:否

資料:$_SERVER['REQUEST_URI']
資料類型:字串
用途:目前 PHP 檔案的 URL 路徑名稱,包含路徑資訊和 URL 查詢字串。包含開頭的斜線。
注意事項:這是 URL 重寫前的結果(也就是原始呼叫的 URL)。*
*: 我至少看過一種情況並非如此(URL 重寫器提供了另一個 $_SERVER 變數來代替),但 URL 重寫器的作者後來修復了它,所以大概可以忽略這個特定注意事項。
注意事項:並非所有 PHP 環境都已設定,可能需要透過 $_SERVER['REDIRECT_URL'] . '?' . http_build_query($_GET) 設定 [如果已設定 $_SERVER['REDIRECT_URL'],且不完美,因為我們不知道哪些 GET 參數是原始傳遞的,哪些是在 URL 重寫中注入的] --否則-- $_SERVER['PHP_SELF'] . '?' . http_build_query($_GET)。
在網頁模式下運作:是
在 CLI 模式下運作:否

資料:$_SERVER['PATH_INFO']
資料類型:字串
用途:尋找路徑資訊,這是 URL 呼叫中 .php 檔名後面的資料。這是一個奇怪的概念。
注意事項:某些環境可能不支援,除非您完全控制伺服器,否則最好避免使用。
在網頁模式下運作:是
在 CLI 模式下運作:否

請注意,如果未設定某些內容,它可能會遺失在 $_SERVER 中,或者它可能是空白的,因此請使用 PHP 的「empty」函式進行測試。
krinklemail at gmail dot com
12 年前
如果發送到 PHP 腳本的請求包含 "Content-Type" 或/和 "Content-Length" 標頭,與一般的 HTTP 標頭不同,它們不會以 $_SERVER['HTTP_CONTENT_TYPE'] 的形式出現在 $_SERVER 中。PHP 會根據 CGI/1.1 規範[1] 將這些標頭從 HTTP_ 比對群組中移除。

這些標頭仍然可以存取,但前提是請求是 POST 請求。如果是 POST 請求,它們將以以下形式提供:
$_SERVER['CONTENT_LENGTH']
$_SERVER['CONTENT_TYPE']

[1] https://www.ietf.org/rfc/rfc3875
lemonostif at gmail dot com
5 年前
PHP_SELF 的設計簡直是程式設計師的恥辱。這是自 PHP 4 版以來最廣泛存在的漏洞之一,但手冊卻絲毫未提及它的危險性。至少應該用大寫字母明確說明「它的值可以由使用者提供」,如果您想讓網路更安全的話……
Tonin
16 年前
在使用 ServerAlias 指令設定 Apache 虛擬主機時,使用 $_SERVER['SERVER_NAME'] 變數時,請務必檢查 UseCanonicalName Apache 指令。如果設定為 On,這個變數將永遠使用 Apache 的 ServerName 值。如果設定為 Off,它將使用瀏覽器發送的標頭中提供的值。

根據您想要如何使用這個變數的內容,將其設定為 On 或 Off。
info at mtprod dot com
15 年前
在 Windows IIS 7 上,您必須使用 $_SERVER['LOCAL_ADDR'] 而不是 $_SERVER['SERVER_ADDR'] 來取得伺服器的 IP 位址。
jarrod at squarecrow dot com
15 年前
$_SERVER['DOCUMENT_ROOT'] 非常有用,尤其是在開發環境中工作時。如果您正在開發大型專案,您可能會在頁面中包含大量檔案。例如:

<?php
//定義用於「include」URL 的常數 - 有助於保持路徑清晰

define("REGISTRY_CLASSES", $_SERVER['DOCUMENT_ROOT']."/SOAP/classes/");
define("REGISTRY_CONTROLS", $_SERVER['DOCUMENT_ROOT']."/SOAP/controls/");

define("STRING_BUILDER", REGISTRY_CLASSES. "stringbuilder.php");
define("SESSION_MANAGER", REGISTRY_CLASSES. "sessionmanager.php");
define("STANDARD_CONTROLS", REGISTRY_CONTROLS."standardcontrols.php");
?>

在開發環境中,您很少會直接在根目錄下工作,尤其是在本機執行 PHP 時,使用 DOCUMENT_ROOT 是維持 URL 一致性的一個好方法。這將為您節省數小時的工作時間,讓您不必費心將應用程式從開發環境部署到正式伺服器(更不用說避免 include 路徑失敗的頭痛問題了)。
Stefano (info at sarchittu dot org)
14 年前
一種取得頁面絕對路徑的方法,不受網站位置(因此在本地機器和伺服器上都能正常運作,無需任何設定)和伺服器作業系統(在 Unix 系統和 Windows 系統上都能正常運作)的影響。

它唯一需要的參數是放置此腳本的資料夾
例如,我會將它放在我的 SCRIPT 資料夾中,並將 SCRIPT 的字元長度寫入 $conflen 變數中

<?php
$conflen
=strlen('SCRIPT');
$B=substr(__FILE__,0,strrpos(__FILE__,'/'));
$A=substr($_SERVER['DOCUMENT_ROOT'], strrpos($_SERVER['DOCUMENT_ROOT'], $_SERVER['PHP_SELF']));
$C=substr($B,strlen($A));
$posconf=strlen($C)-$conflen-1;
$D=substr($C,1,$posconf);
$host='http://'.$_SERVER['SERVER_NAME'].'/'.$D;
?>

最終 `$host` 會包含絕對路徑。
Mark Simon
5 年前
這麼近,卻又那麼遠……

`$_SERVER` 幾乎包含了所有關於目前網頁環境的資訊。但方便存取通訊協定和實際網站根目錄的功能會很有幫助。

對於通訊協定,您可能有也可能沒有 `$_SERVER['HTTPS']`,而且它可能有也可能是空的。對於網站根目錄,`$_SERVER['DOCUMENT_ROOT']` 取決於伺服器設定,並且不適用於虛擬主機。

實際應用上,我通常會在我的程式碼中包含以下內容:

<?php
// 網站根目錄
// 用法:include("$root/includes/something.inc.php");
$root = $_SERVER['WEB_ROOT'] = str_replace($_SERVER['SCRIPT_NAME'],'',$_SERVER['SCRIPT_FILENAME']);

// 主機和通訊協定
// 用法:$url = "$protocol://$host/images/something.jpg";
$host = $_SERVER['HTTP_HOST'];
$protocol=$_SERVER['PROTOCOL'] = isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ? 'https' : 'http';
?>
steve at sc-fa dot com
15 年前
如果您是透過代理伺服器提供服務,那麼查看這些 `$_SERVER` 變數在您代理伺服器後面的機器上的作用幾乎可以肯定會節省時間。

使用 `$_SERVER['HTTP_X_FORWARDED_FOR']` 取代 `$_SERVER['REMOTE_ADDR']`

使用 $_SERVER['HTTP_X_FORWARDED_HOST'] 以及
$_SERVER['HTTP_X_FORWARDED_SERVER'] 來取代 (至少在我們的案例中) $_SERVER['SERVER_NAME']
kamil00110
1 年前
這段程式碼可以用來協助找出試圖挖掘伺服器檔案以尋找某些東西的人。

.htaccess

ErrorDocument 404 /your.php
ErrorDocument 403 /your.php

<?php
//取得時間
$time = date("H:i:s d.m.y");
//取得使用者位址
$usr = $_SERVER['REMOTE_ADDR'];
//取得「訪客」輸入的網址
$url = $_SERVER['REQUEST_URI'];
//取得您的伺服器位址
$ip = $_SERVER['SERVER_ADDR'];
//整合資訊
$sus = "[".$time."] ".$usr." ".$ip.$url.PHP_EOL;
//寫入記錄檔
file_put_contents("susip.txt", $sus, FILE_APPEND);
?>
Daniels118
2 年前
如果您需要知道客戶端使用的協定 (http 或 https),那麼如果您的伺服器位於代理伺服器或負載平衡器之後,$_SERVER['HTTPS'] 變數實際上可能不會回報真實情況(實際上,客戶端可以使用 https 連接到負載平衡器,然後負載平衡器使用 http 將請求轉發到伺服器)。
如果代理伺服器/負載平衡器設定正確,它可以在標頭中傳送原始請求協定,您可以在 $_SERVER[HTTP_X_FORWARDED_PROTO] 變數中找到它。
pomat at live dot it
11 年前
在 Windows 系統中,$_SERVER['DOCUMENT_ROOT'] 可能包含反斜線,當然它也可能包含或不包含結尾的斜線(反斜線)。
我看到以下是如何正確處理此問題的範例

<?php
include(dirname($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR . 'file.php');
?>

好的,後者可以用於存取文件根目錄的父目錄中的檔案,但實際上並未正確解決此問題。
最後,不用擔心。在所有情況下,使用正斜線並附加結尾斜線應該是安全的。
假設我們有這個

<?php
$path
= 'subdir/file.php';
$result = $_SERVER['DOCUMENT_ROOT'] . '/' . $path;
?>

在 Linux 系統上,$result 可能類似以下:
1) "/var/www/subdir/file.php"
2) "/var/www//subdir/file.php"
字串 2 與字串 1 的解析方式相同(使用 'cd' 指令試試看)。

在 Windows 系統上,$result 可能類似以下:
1) "C:/apache/htdocs/subdir/file.php"
2) "C:/apache/htdocs//subdir/file.php"
3) "C:\apache\htdocs/subdir/file.php"
4) "C:\apache\htdocs\/subdir/file.php"
所有這些字串都會被解析為 "C:\apache\htdocs\subdir\file.php"(使用 'cd' 指令試試看)。
lilJoshu
6 年前
請記住:

雖然 $_SERVER["REQUEST_METHOD"] 最初是基於 GET、POST、PUT、HEAD 方法設計的,但伺服器可以允許更多方法。

如果您正在建構也將使用 PATCH 和 DELETE 等方法的 RESTful 介面,這一點可能很重要。

同樣重要的是,它也可能成為安全風險和注入的攻擊點。在根據 REQUEST_METHOD 建構某些動作的情況下,建議將其放入 switch 陳述式中。

<?php
switch ($_SERVER["REQUEST_METHOD"]){
case
"PUT":
foo_replace_data();
break;
case
"POST":
foo_add_data();
break;
case
"HEAD";
foo_set_that_cookie();
break;
case
"GET":
default:
foo_fetch_stuff()
break;
}

?>
Tom
12 年前
請注意,伺服器陣列(即使是 $_SERVER['SERVER_NAME'])的大部分內容都是由客戶端提供的,並且可以被操縱。它們也可能被用於注入攻擊,因此必須像任何其他使用者輸入一樣進行檢查和處理。
chris
15 年前
您可以在 phpinfo() 輸出的底部附近找到 $_SERVER 陣列中所有內容的表格。
pudding06 at gmail dot com
15 年前
以下是一種簡單、快速但有效的方法來阻止不必要的外部訪客訪問您的本地伺服器:

<?php
// 僅限本地請求
if ($_SERVER['REMOTE_ADDR'] !== '127.0.0.1') die(header("Location: /"));
?>

這會將所有外部流量導向您的首頁。當然,您可以發送 404 或其他自訂錯誤。最佳做法是不要停留在帶有自訂錯誤訊息的頁面上,因為您承認該頁面確實存在。這就是為什麼我將不需要的呼叫重新導向到(例如)phpmyadmin 的原因。
picov at e-link dot it
13 年前
一個用於檢測目前頁面網址是否已被 mod_rewrite 重寫的簡單函式

<?php
public function urlWasRewritten() {
$realScriptName=$_SERVER['SCRIPT_NAME'];
$virtualScriptName=reset(explode("?", $_SERVER['REQUEST_URI']));
return !(
$realScriptName==$virtualScriptName);
}
?>
silverquick at gmail dot com
16 年前
我認為 HTTPS 元素只會出現在 Apache 2.x 版中。它不在這裡的「特殊」變數列表中
https://apache-httpd.dev.org.tw/docs/1.3/mod/mod_rewrite.html#RewriteCond
但它在這裡
https://apache-httpd.dev.org.tw/docs/2.0/mod/mod_rewrite.html#rewritecond
centurianii at yahoo dot co dot uk
7 年前
如果您在 Apache 虛擬主機檔案中使用指令,將重新導向應用於所有請求,例如
RewriteEngine On
RewriteCond "%{REQUEST_URI}" "!=/index.php"
RewriteRule "^/(.*)$" "index.php?$1" [NC,NE,L,QSA]
您應該預期您的 $_SERVER 全域變數會有一些偏差。

假設您發送一個網址:[主機名稱]/a/b?x=1&y=2
這會使 Apache 修改為:/index.php?/a/b?x=1&y=2

現在您的 $_SERVER 全域變數包含以下內容
'REQUEST_URI' => '/a/b?x=1&y=2',它保留主機名稱後面的初始網址
'QUERY_STRING' => 'a/b&x=1&y=2',請注意 PHP 如何將 '?' 替換為 '&'
'SCRIPT_NAME' => '/index.php',正如預期的那樣。

要測試您的 $_SERVER 全域變數
function serverArray(){
$arr = array();
foreach($_SERVER as $key=>$value)
$arr[] = '&nbsp;&nbsp;&nbsp;\'' . $key . '\' => \'' . (isset($value)? $value : '-') . '\'';
return @\sort($arr)? '$_SERVER = array(<br />' . implode($arr, ',<br />') . '<br />);' : false;
}
echo serverArray();
mirko dot steiner at slashdevslashnull dot de
15 年前
<?php

// 符合 RFC 2616 的 Accept Language 解析器
// http://www.ietf.org/rfc/rfc2616.txt, 14.4 Accept-Language, 第 104 頁
// 超文字傳輸協定 -- HTTP/1.1

foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lang) {
$pattern = '/^(?P<primarytag>[a-zA-Z]{2,8})'.
'(?:-(?P<subtag>[a-zA-Z]{2,8}))?(?:(?:;q=)'.
'(?P<quantifier>\d\.\d))?$/';

$splits = array();

printf("Lang:,,%s''\n", $lang);
if (
preg_match($pattern, $lang, $splits)) {
print_r($splits);
} else {
echo
"\n沒有符合的結果\n";
}
}

?>

範例輸出

Google Chrome 3.0.195.27 Windows xp

Lang:,,de-DE''
陣列
(
[0] => de-DE
[primarytag] => de
[1] => de
[subtag] => DE
[2] => DE
)
Lang:,,de;q=0.8''
陣列
(
[0] => de;q=0.8
[primarytag] => de
[1] => de
[subtag] =>
[2] =>
[quantifier] => 0.8
[3] => 0.8
)
Lang:,,en-US;q=0.6''
陣列
(
[0] => en-US;q=0.6
[primarytag] => en
[1] => en
[subtag] => US
[2] => US
[quantifier] => 0.6
[3] => 0.6
)
Lang:,,en;q=0.4''
陣列
(
[0] => en;q=0.4
[primarytag] => en
[1] => en
[subtag] =>
[2] =>
[quantifier] => 0.4
[3] => 0.4
)
php at isnoop dot net
14 年前
使用 Apache 的 SetEnv 指令在您的虛擬主機或 Apache 設定檔中設定任意 $_SERVER 變數。

SetEnv 變數名稱 "變數值"
sammyhacker at gmail dot com
3 年前
簡而言之,$_SERVER 包含所有環境變數。

CGI 的運作方式是 HTTP 應用程式伺服器填入所有必要的環境變數,然後叫用 PHP 程序。而這些環境變數儲存在 $_SERVER 中。
plugwash at p10link dot net
9 年前
請注意,透過此陣列存取 x-forwarded-for 和類似的標頭是一個不好的做法。在填入陣列時,標頭名稱會被修改,而這種修改可能會引入欺騙漏洞。

詳情請參閱 http://en.wikipedia.org/wiki/User:Brion_VIBBER/Cool_Cat_incident_report 中關於此漏洞的真實案例說明。
jit_chavan at yahoo dot com
10 年前
搜尋 $_SERVER["REDIRECT_URL"] 一陣子後,注意到 PHP 文件頁面本身並沒有提到它。看起來這似乎只有 Apache 伺服器(而非其他伺服器)才會產生,在我的情況下,使用 $_SERVER["REQUEST_URI"] 會比較有用。
chris at ocproducts dot com
7 年前
腳本參數指南...

資料:$_GET
資料類型:陣列(映射)
用途:包含所有 GET 參數(即已解析的 URL 查詢字串)。
注意事項:GET 參數名稱必須符合 PHP 變數命名規則,例如不允許使用點號,且點號會被替換。
在網頁模式下運作:是
在 CLI 模式下運作:否

資料:$_SERVER['QUERY_STRING']
資料類型:字串
用途:取得未解析的 URL 查詢字串。
注意事項:並非所有 PHP 環境都已設定,可能需要透過 http_build_query($_GET) 設定。
在網頁模式下運作:是
在 CLI 模式下運作:否

資料:$_SERVER['argv']
資料類型:陣列(列表)
用途:取得 CLI 呼叫參數。
網頁模式的運作:薄弱(只包含單個參數,即查詢字串)
在 CLI 模式下運作:是
wbeaumo1 at gmail dot com
14 年前
別忘了 $_SERVER['HTTP_COOKIE']。它包含使用者代理發送的 'Cookie' 標頭的原始值。
2962051004 at qq dot com
6 年前
<?php
/*
有時候你會發現你的網站加了 CDN 之後就無法取得正確的使用者 IP,這個函式可以幫你
*/
function real_ip()
{
$ip = $_SERVER['REMOTE_ADDR'];
if (isset(
$_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach (
$matches[0] AS $xip) {
if (!
preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
} elseif (isset(
$_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset(
$_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (isset(
$_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
}
return
$ip;

}
echo
real_ip();

?>
Johan Winge
4 年前
應該要注意的是,$_SERVER['SERVER_PROTOCOL'] 的值永遠不會包含子字串 "HTTPS"。假設這是一個常見的錯誤和混淆來源。請改用 $_SERVER['HTTPS']。
cupy at email dot cz
15 年前
技術說明
$_SERVER['argc'] 和 $_SERVER['argv'][] 有一些奇怪的行為,
從 Linux (bash) 命令列使用時,如果像這樣呼叫
"php ./script_name.php 0x020B"
一切正常,但是
"./script_name.php 0x020B"
就不正確了 - $_SERVER['argv'][1] 會傳遞 "0" 而不是 "0x020B" - 請參考下面的程式碼。
看起來參數從 bash 傳遞到 PHP 時出了問題。
(但是在 bash 層級檢查,0x020B 作為 $1 可以被正確理解)

試試這個例子

------------->8------------------
cat ./script_name.php
#! /usr/bin/php

if( $_SERVER['argc'] == 2)
{
// 很奇怪... 我們必須使用這個技巧才能從參數傳遞例如 0x020B
// 忽略這個: "PHP 提醒:在 ... 中未定義的偏移量:2"
$EID = $_SERVER['argv'][1] + $_SERVER['argv'][2] + $_SERVER['argv'][3];
}
否則
{ // 預設值
$EID = 0x0210; // PPS 失敗
}
To Top