本文已收录于PHP全栈系列专栏:PHP快速入门与实战
在Web应用程序中,IP地址是常见的数据项。例如,它可以用于用户认证、访问控制、日志记录和其他安全功能。然而,在某些情况下,获取客户端的真实IP地址可能会变得非常困难。
由于HTTP协议的本质,当您从Web服务器接收请求时,它只包含HTTP头中的客户端的最后一个代理服务器的IP地址。这称为X-Forwarded-For头。
因此,如果您希望了解客户端的真实IP地址,则需要深入探究HTTP请求如何跨多个代理服务器传递。
本文将向您展示如何使用PHP和Nginx来获取客户端的真实IP地址。
在深入探讨代码之前,我们需要先了解一些基础知识。如什么是HTTP,HTTP请求包含了哪些信息。请求到服务器这个过程是怎么一回事等。
HTTP请求由请求行、请求头和请求体组成。
请求行指定请求方法(GET、POST等)、URI和HTTP协议的版本号。
请求头包含HTTP版本、Host头、User-Agent头、Cookie头和其他自定义头部。
请求体包含客户端提交的数据,通常是表单数据或JSON数据。
HTTP代理服务器是介于客户端和Web服务器之间的一种服务器。代理服务器可以用于缓存、负载均衡、安全性和其他目的。当客户端向代理服务器发出HTTP请求时,代理服务器将该请求转发到下一个目标服务器。
X-Forwarded-For头是一种HTTP头部,用于指示客户端的真实IP地址。当Web服务器从代理服务器接收请求时,它会检查X-Forwarded-For头,并提取最后一个IP地址。如果此头不存在,则Web服务器将使用代理服务器的IP地址。
如果请求通过多个代理服务器传递,则每个代理服务器都可以在X-Forwarded-For头中添加一个IP地址。在这种情况下,最后一个IP地址是客户端的真实IP地址。
PHP代码正常工作,我们需要在Nginx服务器上启用X-Forwarded-For头部。这是通过将以下行添加到Nginx配置文件中完成的:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
此行告诉Nginx将客户端的IP地址添加到X-Forwarded-For头中。当请求被转发时,代理服务器将检查此头以提取客户端的真实IP地址。
以下是完整的Nginx配置文件示例:
server {
listen 80;
server_name example.com;
access_log /var/log/nginx/example.access.log main;
error_log /var/log/nginx/example.error.log;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
此配置将所有请求转发到本地主机上运行的HTTP服务器。每个传入请求都会添加一个X-Forwarded-For头并转发到9000端口。
以下是获取客户端真实IP地址的PHP代码:
function get_ip_address() {
// Check for shared Internet/ISP IP
if (!empty($_SERVER['HTTP_CLIENT_IP']) && validate_ip($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
}
// Check for IP passed in via HTTP_X_FORWARDED_FOR header
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Check if multiple IP addresses exist in this header
$ip_addresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($ip_addresses as $ip) {
if (validate_ip($ip)) {
return $ip;
}
}
}
// Check for IP passed in via REMOTE_ADDR header
if (validate_ip($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR'];
}
// Return unreliable IP address since all else failed
return $_SERVER['REMOTE_ADDR'];
}
function validate_ip($ip) {
if (strtolower($ip) === 'unknown') {
return false;
}
// Generate IPv4 network address
$ipv4_network = ip2long('0.0.0.0/24');
// Generate IPv6 network address
$ipv6_network = inet_pton('::ffff:0.0.0.0') . '/96';
// Check if IP address is IPv4
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
// Convert IP to IPv4 network address
$ip_network = ip2long($ip) & ~((1 << (32 - 24)) - 1);
return $ip_network === $ipv4_network;
}
// Check if IP address is IPv6
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false) {
// Convert IP to IPv6 network address
$ip_network = inet_pton($ip) & ~((1 << (128 - 96)) - 1);
return $ip_network === $ipv6_network;
}
return false;
}
此代码使用3种方法来检测客户端的真实IP地址:
如果HTTP_CLIENT_IP头部存在且有效,则返回该IP地址。
如果HTTP_X_FORWARDED_FOR头部存在,则迭代其值,并返回第一个有效IP地址。
如果REMOTE_ADDR头部存在且有效,则返回该IP地址。
如果所有检查都失败,则返回REMOTE_ADDR头中的IP地址。
validate_ip()函数用于检查传递的IP地址是否有效。以下是它的工作原理:
检查地址是否为“unknown”。
生成IPv4和IPv6的网络地址。
检测IP地址是否为IPv4,并将其转换为网络地址。如果地址匹配IPv4网络地址,则返回true。
检测IP地址是否为IPv6,并将其转换为网络地址。如果地址匹配IPv6网络地址,则返回true。
以上内容介绍了如何通过PHP结合Nginx实现获取用户真实IP地址。我们从了解了HTTP请求和代理服务器的工作原理出发,并讨论了X-Forwarded-For头的作用。最后演示了如何编写有效的PHP代码来获取客户端真实IP地址。
相信通过本文,你对获取用户真实IP地址有了更深入的理解,如果你有什么疑问或者建议,欢迎在下方评论区留言。后续更多内容将收录在专栏PHP快速入门与实战中,感谢大家支持。喜欢记得三联哟。