PHP 获取客户端真实 IP 地址的几种方法与注意事项

橘子海
橘子海
发布时间:2026-10-16| 6人浏览过
原创

在 Web 开发中,准确识别用户 IP 是风控、日志记录和需求的关键环节。由于现代网络环境普遍存在 CDN、负载均衡和反向代理,直接使用服务器变量往往无法获得最终用户的真实 IP。本文将分析 PHP 中常见的 IP 获取方式,探讨其背后的原理、潜在的安全风险以及如何正确配置以应对代理场景。

基础:直接访问场景下的 IP 获取

在没有中间代理(如 Nginx 反向代理或 CDN)的直接请求场景中,最标准的做法是读取 $_SERVER['REMOTE_ADDR']。该变量记录了与当前 Web 服务器建立 TCP 连接的最后一个 IP 地址。

// 示例代码
$ip = $_SERVER["REMOTE_ADDR"];
echo $ip;

这种方式简单可靠,但一旦经过代理,它获取到的将是代理服务器的 IP,而非最终客户端。

进阶:处理反向代理与 CDN 场景

当流量经过 Nginx 代理、CDN 或负载均衡器时,原始客户端 IP 通常会通过 HTTP Header 传递给后端 PHP。常用的头部包括 X-Forwarded-For 和 X-Real-IP。

第1步:检查常用头部变量

不同代理软件传递的头部名称不同,通常优先级顺序如下:

  • HTTP_CLIENT_IP:一些代理设置的字段,较少见且容易被伪造。
  • HTTP_X_FORWARDED_FOR:最常见的代理 IP 传递头部,通常是一个逗号分隔的列表 client, proxy1, proxy2。
  • HTTP_X_FORWARDED:早期标准,逐渐被取代。
  • HTTP_FORWARDED_FOR / HTTP_FORWARDED:RFC 7239 定义的新一代头部,部分现代网关支持。

以下是一个综合判断逻辑,优先使用代理头,最后回退到 REMOTE_ADDR:

function getClientIp() {
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        // X-Forwarded-For 可能包含多个 IP,取第一个
        $ips = explode(", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
        $ip = $ips[0];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED'];
    } elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_FORWARDED_FOR'];
    } elseif (!empty($_SERVER['HTTP_FORWARDED'])) {
        $ip = $_SERVER['HTTP_FORWARDED'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}

第2步:安全过滤与验证(关键步骤)

上述代码在功能上满足了“获取”的需求,但存在极大的安全隐患。HTTP 头信息是可以被任意客户端伪造的。如果直接将获取到的 IP 用于数据库写入或安全策略匹配,攻击者可以轻易通过发送伪造 Header 注入假 IP。

因此,必须进行双重验证:

  1. 信任链控制:只在确认请求来源是受信任的代理服务器(如阿里云 SLB、腾讯云 CLB 或本地 Nginx)时才去读取 Header。PHP 可以通过限制允许的 IP 范围或使用框架提供的 Trusted Proxy 机制来实现。
  2. 格式校验:获取到 IP 后,务必使用内置函数验证其合法性,防止非法字符注入。

合法 IP 校验示例

$raw_ip = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
// 使用 filter_var 确保它是合法的 IP 字符串
$real_ip = filter_var($raw_ip, FILTER_VALIDATE_IP);
if ($real_ip === false) {
    $real_ip = $_SERVER['REMOTE_ADDR'];
}

第3步:区分内网与公网 IP(特殊业务需求)

某些业务需要识别用户是否位于公司内网。此时可以使用正则表达式筛选掉私有地址段(如 10.x.x.x, 172.16.x.x, 192.168.x.x)。注意:此方法依赖 Header 内容的真实性,仅适用于受控环境。

function isPrivateIp($ip) {
    return preg_match("/^(127\.0\.0\.1|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[0-1])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})$/", $ip);
}

Nginx 配合优化方案

相比于在 PHP 中进行复杂的逻辑判断,最佳实践是在 Nginx 层统一处理。在 Nginx 配置中将真实 IP 写入一个特定的 Header(如 X-Real-IP),然后在 PHP 中只读取这一个受信任的头,并配合 allow/deny 指令确保只有 Nginx 能访问该 Header。这能有效规避 Header 伪造攻击。

总结

PHP 获取客户端 IP 并非简单的几行代码,而是一个涉及网络架构认知与安全防御的系统工程。对于普通应用,使用 filter_var 结合 X-Forwarded-For 即可满足大部分需求;对于高安全性要求的系统,必须结合 Nginx 等前置设备的信任链配置,严禁直接信任前端传来的 IP 信息。以上就是 PHP 获取客户端真实 IP 地址多种方法的详细内容,更多关于 PHP 服务器开发的文章请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。