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

CDN 環境下獲取用戶真實 IP 的 PHP 與 ASP 實現方案

     編輯:PHP 綜合知識

問題背景

使用 CDN 或反向代理後,$_SERVER['REMOTE_ADDR'] 獲取到的是代理服務器 IP,需從 HTTP_CLIENT_IP、HTTP_X_FORWARDED_FOR 等頭部提取真實客戶端 IP。

ASP 實現(經典參考)

function checkip(checkstring)
    dim re1
    set re1 = new RegExp
    re1.pattern = "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"
    re1.global = false
    re1.IgnoreCase = false
    checkip = re1.test(checkstring)
    set re1 = nothing
end function

function get_cli_ip()
    dim client_ip
    if checkip(Request.ServerVariables("HTTP_CLIENT_IP")) = true then
        get_cli_ip = Request.ServerVariables("HTTP_CLIENT_IP")
    else
        MyArray = split(Request.ServerVariables("HTTP_X_FORWARDED_FOR"), ",")
        if ubound(MyArray) >= 0 then
            client_ip = trim(MyArray(0))
            if checkip(client_ip) = true then
                get_cli_ip = client_ip
                exit function
            end if
        end if
        get_cli_ip = Request.ServerVariables("REMOTE_ADDR")
    end if
end function

PHP 實現(Discuz 風格,生產可用)

<?php
function getRealIp() {
    $unknown = 'unknown';
    $ip = $unknown;

    // 1. HTTP_CLIENT_IP
    if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), $unknown)) {
        $ip = getenv('HTTP_CLIENT_IP');
    }
    // 2. HTTP_X_FORWARDED_FOR (可能包含多個 IP,取第一個非內網)
    elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), $unknown)) {
        $forwarded = explode(',', getenv('HTTP_X_FORWARDED_FOR'));
        $firstIp = trim($forwarded[0]);
        $parts = explode('.', $firstIp);
        // 過濾私有網段
        if (!($parts[0] == '10' || ($parts[0] == '192' && $parts[1] == '168') || ($parts[0] == '172' && $parts[1] >= 16 && $parts[1] <= 31))) {
            $ip = $firstIp;
        } else {
            $ip = getenv('REMOTE_ADDR');
        }
    }
    // 3. REMOTE_ADDR
    elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), $unknown)) {
        $ip = getenv('REMOTE_ADDR');
    }
    // 4. $_SERVER 兜底
    elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], $unknown)) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

// 使用
$realIp = getRealIp();
echo "客戶端真實 IP: $realIp";
?>

關鍵點總結

  1. 優先級:HTTP_CLIENT_IP > HTTP_X_FORWARDED_FOR(首個非私有 IP) > REMOTE_ADDR
  2. 私有網段過濾:10.x.x.x、192.168.x.x、172.16-31.x.x、127.x.x.x
  3. 可信代理:生產環境建議在 Nginx/Apache 層通過 set_real_ip_from/real_ip_header 固化可信代理 IP,避免頭部偽造
  4. IPv6:現代項目需同時支持 IPv6 格式解析與存儲

安全提示

HTTP 頭部可被客戶端偽造,關鍵業務(登錄、支付、風控)應結合設備指紋、行為分析、短信驗證等多因子驗證,不可單純依賴 IP 判斷身份。

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