在開發中經常需要獲取用戶訪問的完整 URL(含協議、域名、端口、查詢參數),用於分享鏈接生成、回調地址構建、日誌記錄等。本文提供一個健壯的通用函數,正確處理 HTTPS、非 80/443 端口、反向代理等場景。
<?php
/**
* 獲取當前請求的完絡 URL
* @return string 完整 URL,如 https://example.com:8443/path?query=1
*/
function get_current_url(): string {
$protocol = 'http';
// 判斷 HTTPS:直接訪問或反向代理(X-Forwarded-Proto)
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
$protocol = 'https';
} elseif (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$protocol = 'https';
}
$host = $_SERVER['HTTP_HOST'] ?? ($_SERVER['SERVER_NAME'] ?? 'localhost');
$port = $_SERVER['SERVER_PORT'] ?? 80;
$uri = $_SERVER['REQUEST_URI'] ?? '/';
// 標準端口不顯示
$portPart = (($protocol === 'http' && $port == 80) || ($protocol === 'https' && $port == 443)) ? '' : ":$port";
return "{$protocol}://{$host}{$portPart}{$uri}";
}
// 使用示例
echo get_current_url();
// 輸出示例: https://www.example.com:8443/article/123?from=share
?>
| 場景 | 處理邏輯 |
|---|---|
| HTTPS 識別 | 優先檢查 $_SERVER['HTTPS'],兼容 Nginx/Apache 反向代理的 X-Forwarded-Proto 頭 |
| Host 獲取 | 優先 HTTP_HOST(含端口),回退 SERVER_NAME |
| 端口判斷 | HTTP 默認 80,HTTPS 默認 443,非標準端口追加顯示 |
| URI 獲取 | REQUEST_URI 包含查詢字符串,比 PHP_SELF 更完整 |
// 獲取真實客戶端 IP(若在反向代理後)
function get_client_ip(): string {
$headers = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP'];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
$ips = explode(',', $_SERVER[$header]);
return trim($ips[0]);
}
}
return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
}
request()->fullUrl() / url()->full()$request->getUri()Request::instance()->url(true)Url::current(),統一入口管理。$_SERVER['HTTPS'] 在某些 Apache 配置下可能為 off 字符串而非未設置,嚴格判斷 === 'on'。HTTP_HOST,需確認實際傳遞的頭信息。REQUEST_URI 為重寫前路徑,通常符合預期。$_SERVER['PHP_SELF'],存在 XSS 風險且不含查詢參數。