取得真實 IP get_client_ip()
<?php
function get_client_ip(): ?string {
$headers = [
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR'
];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
// X-Forwarded-For 可能包含多個 IP,取第一個 (客戶端原始 IP)
$ips = explode(',', $_SERVER[$header]);
$ip = trim($ips[0]);
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
return $_SERVER['REMOTE_ADDR'] ?? null;
}
?>
驗證 IPv4 格式 is_ip()
<?php
function is_ip(string $ip): bool {
// 使用內建過濾器,同時支援 IPv4/IPv6
return filter_var($ip, FILTER_VALIDATE_IP) !== false;
}
// 僅允許 IPv4
function is_ipv4(string $ip): bool {
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false;
}
// 原文手動檢查邏輯 (教學用)
function is_ip_manual(string $ip): bool {
$parts = explode('.', $ip);
if (count($parts) !== 4) return false;
foreach ($parts as $part) {
if (!ctype_digit($part)) return false;
$num = (int)$part;
if ($num < 0 || $num > 255) return false;
// 禁止前導零 (如 01, 001) - 視需求而定
if (strlen($part) > 1 && $part[0] === '0') return false;
}
return true;
}
?>
安全應用場景
- 記錄登入日誌:儲存
get_client_ip() 供稽核。
- API 速率限制:以 IP 為鍵計數。
- 地理定位/語言切換:搭配 GeoIP 資料庫。
- 防刷單/風控:檢查代理 IP、資料中心 IP (需第三方 IP 信譽庫)。
注意事項
X-Forwarded-For 易偽造,**僅信任已知反向代理 (如 Nginx, Cloudflare) 轉發的標頭**。
- 內網部署時,確保反向代理正確設定
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;。
- IPv6 格式 (如
::1, 2001:db8::1) 請用 FILTER_VALIDATE_IP 完整支援。