PHP获取客户端IP
PHP获取客户端IP
引言
记录访问日志、做地域统计或IP限定时要拿真实访客IP。经过Nginx反代或CDN后,REMOTE_ADDR是代理地址,真实IP藏在转发头里,直接取单一字段容易拿到代理IP,需要按可信链兜底并校验。
直连场景
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
没有反代时,这就是直连客户端IP。
反代后取真实IP
$headers = [
'HTTP_X_FORWARDED_FOR',
'HTTP_X_REAL_IP',
'HTTP_CLIENT_IP',
];
foreach ($headers as $h) {
if (!empty($_SERVER[$h])) {
$ip = explode(',', $_SERVER[$h])[0];
break;
}
}
X-Forwarded-For可能是逗号分隔的IP链,取第一个才是原始客户端。
封装函数
function getClientIp(): string {
foreach (['HTTP_X_FORWARDED_FOR','HTTP_X_REAL_IP'] as $h) {
if (!empty($_SERVER[$h])) {
$ip = trim(explode(',', $_SERVER[$h])[0]);
if (filter_var($ip, FILTER_VALIDATE_IP)) return $ip;
}
}
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}
filter_var校验格式,非法就回退到REMOTE_ADDR。
代理头必须由服务端写入
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
头要由可信Nginx设置,不能完全信任客户端自带。
注意事项
- XFF是逗号链,取最左原始IP;
- 客户端可伪造XFF,只信任自己配置的代理;
- filter_var校验IPv4/IPv6格式;
- 不要用伪造IP做安全鉴权,登录风控仍需服务端;
- CDN场景真实IP在CDN回源头,需查厂商文档;
- 内网代理REMOTE_ADDR是网关IP,别当访客IP。
总结
直连取REMOTE_ADDR,反代后从X-ForwardedFor、X-Real-IP按序兜底,XFF逗号链取第一个,filter_var校验后回退,代理头由可信Nginx写入。关键是客户端可伪造转发头,只信任自己配置的代理链,IP适合统计不适合单独做安全判定,CDN需用厂商回源头。