$_SERVER 變數分類速查表
| 鍵名 | 說明 | 範例值 |
PHP_SELF | 當前執行腳本路徑(相對 Document Root) | /index.php |
argv | 命令列模式下傳遞給腳本的參數陣列 | ['arg1', 'arg2'] |
argc | 命令列參數個數 | 2 |
GATEWAY_INTERFACE | CGI 規範版本 | CGI/1.1 |
SERVER_NAME | 伺服器主機名稱(虛擬主機設定值) | example.com |
SERVER_SOFTWARE | 伺服器識別字串 | Apache/2.4.41 (Ubuntu) |
SERVER_PROTOCOL | 請求協議名稱與版本 | HTTP/1.1 |
REQUEST_METHOD | 請求方法 | GET、POST、PUT、DELETE |
QUERY_STRING | 查詢字串(? 之後部分) | id=123&name=test |
DOCUMENT_ROOT | 腳本所在文檔根目錄(配置值) | /var/www/html |
HTTP_ACCEPT | 請求 Accept 標頭 | text/html,application/xhtml+xml |
HTTP_ACCEPT_CHARSET | 請求 Accept-Charset 標頭 | utf-8, iso-8859-1 |
HTTP_ACCEPT_ENCODING | 請求 Accept-Encoding 標頭 | gzip, deflate, br |
HTTP_ACCEPT_LANGUAGE | 請求 Accept-Language 標頭 | zh-TW,zh;q=0.9,en;q=0.8 |
HTTP_CONNECTION | 請求 Connection 標頭 | keep-alive |
HTTP_HOST | 請求 Host 標頭(含埠號) | example.com:8080 |
HTTP_REFERER | 來源頁面 URL(可偽造、不可靠) | https://google.com/search?q=php |
HTTP_USER_AGENT | 使用者瀏覽器識別字串 | Mozilla/5.0 ... Chrome/119.0 |
HTTPS | 是否 HTTPS 請求 | on / off |
REMOTE_ADDR | 客戶端 IP 位址 | 203.0.113.45 |
REMOTE_HOST | 客戶端主機名(需 DNS 反解,通常為空) | host.example.com |
REMOTE_PORT | 客戶端連接埠 | 54321 |
SCRIPT_FILENAME | 當前執行腳本絕對路徑 | /var/www/html/index.php |
SERVER_ADMIN | 伺服器管理員郵箱(配置值) | admin@example.com |
SERVER_PORT | 伺服器監聽埠 | 80 / 443 |
SERVER_SIGNATURE | 伺服器版本與虛擬主機名組合字串 | Apache/2.4.41 Server at example.com Port 80 |
PATH_TRANSLATED | 腳本檔案系統路徑(非 Document Root) | /var/www/html/index.php |
SCRIPT_NAME | 當前腳本路徑(含檔名) | /index.php |
REQUEST_URI | 完整請求 URI(含查詢字串) | /index.php?id=123 |
PHP_AUTH_USER | HTTP Basic Auth 使用者名稱 | admin |
PHP_AUTH_PW | HTTP Basic Auth 密碼 | secret |
AUTH_TYPE | HTTP 認證類型 | Basic |
實戰應用場景
1. 取得客戶端真實 IP(含代理/負載均衡器)
<?php
function getClientIP() {
$headers = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP'];
foreach ($headers as $h) {
if (!empty($_SERVER[$h])) {
$ips = explode(',', $_SERVER[$h]);
return trim($ips[0]); // 取第一個
}
}
return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
}
?>
2. 判斷請求類型
<?php
$isAjax = (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest');
$isPost = ($_SERVER['REQUEST_METHOD'] ?? '') === 'POST';
$isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || ($_SERVER['SERVER_PORT'] ?? 80) == 443;
?>
3. 構建當前完整 URL
<?php
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'];
$uri = $_SERVER['REQUEST_URI'] ?? '';
$currentUrl = $protocol . '://' . $host . $uri;
?>
4. 防盜鏈 / 來源檢查
<?php
$referer = $_SERVER['HTTP_REFERER'] ?? '';
$allowedDomains = ['example.com', 'api.example.com'];
$refererHost = parse_url($referer, PHP_URL_HOST) ?? '';
if (!in_array($refererHost, $allowedDomains, true)) {
http_response_code(403);
exit('Forbidden');
}
?>
5. CLI 模式參數處理
<?php
if (php_sapi_name() === 'cli') {
global $argv, $argc;
// $argv[0] 是腳本名稱
for ($i = 1; $i < $argc; $i++) {
echo "Arg $i: {$argv[$i]}\n";
}
}
?>
安全性注意事項
- 不可信任:
HTTP_* 開頭變數來自客戶端請求標頭,**可任意偽造**,嚴禁直接用於權限判斷、SQL 拼接、檔案路徑構建。
REMOTE_ADDR 在反向代理後為代理 IP,需配合 X-Forwarded-For 並**驗證代理可信來源**。
REQUEST_URI、PHP_SELF 包含用戶輸入,輸出到 HTML 時必須 htmlspecialchars() 防 XSS。
argv/argc 僅 CLI 可用,Web 模式下不存在或為空。
常見陷阱
| 現象 | 原因 | 解決 |
| SERVER_NAME 非預期值 | 虛擬主機配置 UseCanonicalName Off | 改用 HTTP_HOST 或在 Apache 設定 UseCanonicalName On |
| HTTPS 為 off 但實際是 HTTPS | Nginx 反代未傳遞 HTTPS 標頭 | Nginx 加 proxy_set_header X-Forwarded-Proto https;,PHP 判斷 $_SERVER['HTTP_X_FORWARDED_PROTO'] |
| PATH_INFO 為空 | PHP 配置 cgi.fix_pathinfo=0 或 Nginx 未正確 fastcgi_split_path_info | 調整 Nginx/Apache 配置啟用 PATH_INFO |
總結
$_SERVER 是 PHP 與 Web 伺服器溝通的核心橋樑,掌握各鍵名含義、來源可信度與典型應用模式,能編寫更健壯、安全的應用。記住:**所有 HTTP_* 變數皆來自客戶端,必須驗證後使用**。