当前位置: 当前位置:首页 > 热点 > php获取客户端真实ip正文

php获取客户端真实ip

作者:休闲 来源:焦点 浏览: 【大 中 小】 发布时间:2026-10-17 06:22:43 评论数:

做Web开发,获户端总会踩到获取客户端IP这个坑。取客你以为$_SERVER['REMOTE_ADDR']就是真实用户IP?那就错了。那只是获户端跟你服务器建立TCP连接的机器地址。用户经过CDN、取客反向代理、真实负载均衡,获户端甚至自己挂了代理,取客REMOTE_ADDR就变成了中间那台服务器的真实IP。我见过不少新手写的获户端日志系统,记下来全是取客内网地址,排查问题根本对不上号。真实

要拿真实IP,获户端得从HTTP头里找。取客常用的真实有X-Forwarded-For(XFF)和X-Real-IP。XFF是个逗号分隔的列表,每经过一层代理,就把上一层的IP追加到末尾。比如请求经过CDN、再经过Nginx,最后到你的PHP-FPM,XFF可能长这样:203.0.113.5, 10.0.0.1。最左边那个,理论上才是用户的原始IP。X-Real-IP则是Nginx这类代理直接设置的,通常只包含一个IP。

但直接信任这些头很危险。客户端可以自己伪造XFF头,比如用curl发个请求,随便写个X-Forwarded-For: 1.2.3.4,你后端要是直接取第一个值,那用户就能伪造IP,绕过基于IP的频率限制、黑名单,或者污染你的统计。我见过有人做投票系统,就因为这个被刷了几万票。正确做法是,先判断REMOTE_ADDR是否是你的可信代理IP,是,才去解析XFF;不是,那就直接用REMOTE_ADDR。

写个简单的函数,大致逻辑是这样:

function getClientIp() {  $ip = $_SERVER['REMOTE_ADDR'] ?? ''; $trustedProxies = ['127.0.0.1', '10.0.0.0/8']; // 你的代理IP列表 if (in_array($ip, $trustedProxies) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {  $xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); // 从右往左找,跳过可信代理IP for ($i = count($xff) - 1; $i >= 0; $i--) {  $candidate = trim($xff[$i]); if (!isTrustedProxy($candidate, $trustedProxies)) {  $ip = $candidate; break; } } } return $ip; }

这代码不算完美,但思路对——不盲信头信息,只信任来自已知代理的转发数据。生产环境建议用现成库,比如symfony/http-foundation的Request::getClientIp(),人家处理了各种边缘情况,包括IPv6、私有地址过滤。

还有个坑是CDN。用了Cloudflare、阿里云CDN,它们会覆盖或追加自己的头。Cloudflare用CF-Connecting-IP,阿里云用X-Forwarded-For但会重置。这时候你得在Nginx层就把真实IP设好,用set_real_ip_from和fastcgi_param,PHP那边反而省事。我习惯在Nginx配置里写:

set_real_ip_from 103.21.244.0/22; # Cloudflare IP段 real_ip_header CF-Connecting-IP;

这样PHP拿到的REMOTE_ADDR已经是真实IP,代码里不用再折腾。但前提是你得定期更新Cloudflare的IP段,人家会变。

说到底,没有哪个函数能一劳永逸。你得清楚自己的架构——有没有代理?代理是否可信?头信息会不会被篡改?把这些搞明白,IP获取就是几行代码的事。搞不明白,写再多防御代码也是白搭。最后提醒一句,获取IP只是第一步,你要用它做安全限制的话,最好结合User-Agent、Cookie等做综合判断,单靠IP太容易被绕了。