首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 精準獲取客戶端 IP 地址:兼容代理與負載均衡

     編輯:PHP 相關知識

在 Web 開發中獲取用戶真實 IP 看似簡單,實則暗藏陷阱:反向代理、CDN、負載均衡器都會在請求鏈路中插入多層轉發標頭。單純讀取 $_SERVER['REMOTE_ADDR'] 往往只能拿到代理伺服器的 IP。以下函式按優先級依次檢查常見標頭,最大程度還原真實客戶端 IP。

核心函式

<?php
/**
 * 獲取客戶端真實 IP 地址
 * 優先級:HTTP_CLIENT_IP > HTTP_X_FORWARDED_FOR > REMOTE_ADDR
 *
 * @return string IP 字串或「無法獲取!」
 */
function getClientIp(): string
{
    $ipKeys = [
        'HTTP_CLIENT_IP',       // 標準代理標頭
        'HTTP_X_FORWARDED_FOR', // 常見代理/CDN 標頭(可能包含多個 IP,逗號分隔)
        'REMOTE_ADDR',          // 直連或最後一級代理 IP
    ];

    foreach ($ipKeys as $key) {
        if (!empty($_SERVER[$key])) {
            // X-Forwarded-For 可能包含 "client, proxy1, proxy2",取第一個
            $ipList = explode(',', $_SERVER[$key]);
            $clientIp = trim($ipList[0]);

            // 簡單合法性過濾(可選:加入 filter_var 驗證)
            if (filter_var($clientIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                return $clientIp;
            }
            // 若為私有/保留地址,繼續嘗試下一個標頭
        }
    }

    return '無法獲取!';
}

// 使用範例
echo 'Client IP: ' . getClientIp();
?>

關鍵細節解析

  1. 標頭優先級:HTTP_CLIENT_IP 較少見但更直接;HTTP_X_FORWARDED_FOR 是事實標準,格式為 client, proxy1, proxy2,取首段即為原始客戶端。
  2. 防偽造:標頭可被客戶端偽造。生產環境必須配合受信任代理清單(如 Nginx set_real_ip_from、Apache RemoteIPTrustedProxy)在 Web 伺服器層面重寫 REMOTE_ADDR,PHP 僅作為最後防線。
  3. IPv6 支援:filter_var 同時驗證 IPv4/IPv6,FILTER_FLAG_NO_PRIV_RANGE 排除私有網段(10.x、172.16-31.x、192.168.x),FILTER_FLAG_NO_RES_RANGE 排除保留網段。
  4. 多層代理場景:若經過 CDN → WAF → Nginx → PHP,建議在 Nginx 層用 real_ip_header + set_real_ip_from 固化真實 IP 到 REMOTE_ADDR,PHP 直接讀取即可,無需複雜邏輯。

進階:結合受信任代理清單的生產級寫法

<?php
function getRealIp(array $trustedProxies = []): string
{
    // 1. 若已在 Web Server 層正確設定 real_ip,直接信任 REMOTE_ADDR
    $remote = $_SERVER['REMOTE_ADDR'] ?? '';
    if ($remote && filter_var($remote, FILTER_VALIDATE_IP)) {
        // 若 REMOTE_ADDR 在信任清單內,說明已被上游正確重寫
        if (empty($trustedProxies) || in_array($remote, $trustedProxies, true)) {
            return $remote;
        }
    }

    // 2. 回退:解析 X-Forwarded-For(需確保上游不可偽造)
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = array_map('trim', explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
        // 從右向左找第一個不在信任清單的 IP
        for ($i = count($ips) - 1; $i >= 0; $i--) {
            if (!in_array($ips[$i], $trustedProxies, true) && filter_var($ips[$i], FILTER_VALIDATE_IP)) {
                return $ips[$i];
            }
        }
    }

    return $remote ?: '未知';
}

// 範例:Nginx 信任 10.0.0.0/8 內部網段
$trusted = ['10.0.0.1', '10.0.0.2']; // 實際應用可用 CIDR 判斷庫
echo getRealIp($trusted);
?>

總結

  • 簡單項目:使用基礎版 getClientIp() 即可滿足 90% 場景。
  • 生產環境:務必在 Web 伺服器層(Nginx/Apache)配置 Real IP 模組,PHP 僅做兜底。
  • 安全審計:記錄 IP 時同時存儲 HTTP_X_FORWARDED_FOR 原始值,便於事後追蹤。

掌握 IP 獲取的層層邏輯,讓你的訪問日誌、風控系統、地理定位功能建立在可信的數據基礎之上。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved