PHP 如何获取客户端 IP
在做网站开发或功能调试时,经常会遇到需要获取访问用户IP的场景——比如统计访问量、限制恶意刷屏、给不同地区用户展示对应内容,这些场景都离不开“客户端IP”这个关键信息。对于用PHP开发的网站来说,获取客户端IP的操作其实不难,但很多新手容易踩坑,比如拿到的不是真实用户IP,而是代理服务器的IP。
先搞懂:为什么直接拿 $_SERVER['REMOTE_ADDR'] 不行?
刚接触PHP的新手,第一反应可能是翻PHP自带的超全局变量 $_SERVER,找到里面的 REMOTE_ADDR 项,就觉得“这就是客户端IP了”。但举个生活化的例子:你用公司的WiFi刷网页,公司的网络是通过一个对外的代理服务器上网的,这时候 $_SERVER['REMOTE_ADDR'] 拿到的会是公司代理服务器的IP,而不是你手机或电脑的真实IP——相当于快递到了小区驿站,驿站的地址只是中转点,不是你家的实际地址。

所以,REMOTE_ADDR 只能拿到直接连接到网站服务器的设备IP,如果用户经过了代理、CDN(比如阿里云、腾讯云的加速服务)、Nginx反向代理这些中转设备,这个值就不是真实客户端IP了,这就是很多人拿到“假IP”的核心原因。
如何获取真实客户端IP?分场景来写就不会错
既然直接用 REMOTE_ADDR 有局限,那就要根据网站的部署场景,读取正确的代理头信息,再做适配处理。下面按最常见的3种场景,用生活化的方法解释,新手也能直接用代码。
场景1:网站用了CDN或反向代理(最常见)
现在几乎所有网站都会用CDN加速,比如淘宝、抖音的静态资源都是通过CDN分发的,这时候用户的请求会先到CDN节点,再转到你的服务器,这时候CDN会把真实客户端IP放到特定的HTTP头里,常见的头有两个:X-Forwarded-For 和 X-Real-IP。
还是用快递的例子:CDN就像小区的代收点,在包裹上写了“寄件人真实地址是XX,代收点地址是YY”,X-Forwarded-For 就是这个“寄件人真实地址”的记录,格式是“客户端真实IP, 代理1IP, 代理2IP...”,所以只需要取这个头里的第一个值,就是用户的真实IP。
这部分的PHP代码可以这么写,还要加个判断:如果这个头不存在,就 fallback 到 REMOTE_ADDR:
`php
function getClientIp() {
// 先看X-Forwarded-For头,拆分后取第一个真实IP
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
$realIp = trim($ipList[0]);
// 再看X-Real-IP头,有些代理会用这个
} elseif (isset($_SERVER['HTTP_X_REAL_IP'])) {
$realIp = $_SERVER['HTTP_X_REAL_IP'];
// 最后才用直接连接的REMOTE_ADDR
} else {
$realIp = $_SERVER['REMOTE_ADDR'];
}
return $realIp;
}
`
场景2:自己配置了Nginx反向代理
如果是公司内部部署,用Nginx当反向代理转发请求到PHP-FPM,这时候需要在Nginx里主动把真实IP透传给PHP,否则PHP还是只能拿到Nginx的IP。这就像你要让驿站把寄件人的真实地址告诉收件人,得跟驿站说“一定要附上真实寄件地址”。
Nginx的配置里,在转发请求的 location 块里加一行:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
或者更简单的:proxy_set_header X-Forwarded-For $remote_addr;
这样PHP就能读到正确的头信息了,再配合上面的函数就能拿到真实IP。
场景3:本地开发调试
如果是在自己电脑上做本地开发,比如用XAMPP、WAMP跑PHP,这时候没有代理,直接访问的话,$_SERVER['REMOTE_ADDR'] 拿到的是 127.0.0.1(本地回环地址),这个是对的,不需要加额外的头,直接用就好,不用纠结其他参数。
最后要注意:别踩IP格式的小坑
拿到IP后,还要注意过滤掉无效内容,比如有些代理会在 X-Forwarded-For 里加空格,或者带端口号,比如 192.168.1.1:1234,这时候用 trim() 去掉前后空格,再用 filter_var() 验证IP格式,避免拿到奇怪的内容:
`php
// 加个IP有效性验证,防止非法内容
if (!filter_var($realIp, FILTER_VALIDATE_IP)) {
$realIp = '未知IP';
}
`
总结一下,PHP获取客户端IP的核心是:先判断有没有代理/CDN,再读取对应透传的头信息,最后做简单过滤,就不会再拿到“假IP”了。