在 PHP 中獲取「當前頁面的完整 URL」看似簡單,實則涉及協議(HTTP/HTTPS)、主機、埠號、路徑、查詢字串等多個組件。本文梳理 $_SERVER 超全域變數的關鍵鍵值,提供可直接生產環境使用的封裝函數,並說明常見陷阱。
| 變數 | 含義 | 範例 |
|---|---|---|
| HTTP_HOST | 請求標頭 Host,含埠號(非標準埠) | example.com:8080 |
| SERVER_NAME | 伺服器設定的主機名 | example.com |
| REQUEST_URI | 完整請求路徑含查詢字串 | /path/to/page?foo=bar |
| PHP_SELF | 當前腳本路徑(相對 DocumentRoot) | /index.php |
| QUERY_STRING | 查詢字串(不含 ?) | foo=bar&baz=1 |
| HTTPS | HTTPS 請求時為 'on' | on / 未設定 |
| SERVER_PORT | 伺服器埠號 | 80 / 443 / 8080 |
<?php
// 簡易版(忽略 HTTPS 與非標準埠)
$url = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// 兼容 HTTPS
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$url = $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// 顯式包含埠號(非 80/443 時)
$port = $_SERVER['SERVER_PORT'];
$host = $_SERVER['HTTP_HOST'];
if (($scheme === 'http' && $port !== '80') || ($scheme === 'https' && $port !== '443')) {
$host = $_SERVER['SERVER_NAME'] . ':' . $port;
}
$url = $scheme . '://' . $host . $_SERVER['REQUEST_URI'];
<?php
/**
* 獲取當前頁面完整 URL
* @return string
*/
function getCurrentUrl(): string
{
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? ($_SERVER['SERVER_NAME'] ?? 'localhost');
$uri = $_SERVER['REQUEST_URI'] ?? '/';
// 若 HTTP_HOST 不含埠號且為非標準埠,補充 SERVER_PORT
if (strpos($host, ':') === false) {
$port = (int)($_SERVER['SERVER_PORT'] ?? 80);
if (($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443)) {
$host .= ':' . $port;
}
}
return $scheme . '://' . $host . $uri;
}
parse_url(getCurrentUrl(), PHP_URL_PATH) 或 $_SERVER['PHP_SELF']strtok(getCurrentUrl(), '?')HTTP_X_FORWARDED_PROTO、HTTP_X_FORWARDED_HOST、HTTP_X_FORWARDED_FOR,並信任代理層設定。$_SERVER['PHP_SELF'] 易受 XSS 攻擊(如 /script.php/<script>alert(1)</script>),輸出到 HTML 時務必使用 htmlspecialchars()。REQUEST_URI 同理。