在程序开发过程中,统计用户访问的IP是再正常不过的功能了,今天特意来分享一下PHP获取客户端IP真实地址方法。
一、PHP获取客户端IP 代码
此示例代码既可以完美实现php获取客户端ipv4与ipv6;
前提是只要你的服务器支持ipv6网络访问;
<?php
if ($_SERVER["HTTP_CLIENT_IP"] && strcasecmp($_SERVER["HTTP_CLIENT_IP"], "unknown")) {
$ip = $_SERVER["HTTP_CLIENT_IP"];
}elseif ($_SERVER["HTTP_X_FORWARDED_FOR"] && strcasecmp($_SERVER["HTTP_X_FORWARDED_FOR"], "unknown")) {
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}elseif ($_SERVER["REMOTE_ADDR"] && strcasecmp($_SERVER["REMOTE_ADDR"], "unknown")) {
$ip = $_SERVER["REMOTE_ADDR"];
}else{
$ip = "unknown";
}
注意:
1、文章最后面有说明PHP获取客户端IP地址的代码为什么都要依次获取 HTTP_CLIENT_IP 、 HTTP_X_FORWARDED_FOR 与 REMOTE_ADDR?
2、如果你要分清楚是IPV4还是IPV6?还需要用正则表达式匹配。例如,匹配IPV4:
$res = preg_match ( '/[\d\.]{7,15}/', $ip, $matches ) ? $matches [0] : '';
echo $res;
二、PHP获取客户端IP 原理
PHP获取客户端IP地址有四种方法:
- HTTP_CLIENT_IP
- HTTP_X_FORWARDED_FOR
- REMOTE_ADDR
- HTTP_VIA
$_SERVER['HTTP_CLIENT_IP'] 代理端的(有可能存在,可伪造)
HTTP_CLIENT_IP 是代理服务器发送的HTTP头。如果是“超级匿名代理”,则返回none值。同样,REMOTE_ADDR也会被替换为这个代理服务器的IP。
$_SERVER['HTTP_VIA'] 代理端的
HTTP_VIA是代理服务器地址,和HTTP_CLIENT_IP同理;绝大多数情况下,我们是用HTTP_VIA来判断用户是否通过代理访问的?是就会直接退出,不会再继续执行下去,这是保证安全的一项措施。
因此,这里获取IP一般是直接使用 $_SERVER['HTTP_CLIENT_IP'] ,没必要再使用 $_SERVER['HTTP_VIA'] 了。
$_SERVER['HTTP_X_FORWARDED_FOR'] 用户是在哪个IP使用的代理(有可能存在,也可以伪造)
$_SERVER['REMOTE_ADDR'] 访问端(有可能是用户,有可能是代理的)IP
REMOTE_ADDR是你的客户端跟你的服务器“握手”时候的IP。如果使用了“匿名代理”,REMOTE_ADDR将显示代理服务器的IP。
1、没有使用代理服务器的情况:
REMOTE_ADDR = 您的 IP
HTTP_VIA = 没数值或不显示
HTTP_X_FORWARDED_FOR = 没数值或不显示
2、使用透明代理服务器的情况:Transparent Proxies
REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 您的真实 IP ;经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
这类代理服务器还是将您的信息转发给您的访问对象,无法达到隐藏真实身份的目的。
3、使用普通匿名代理服务器的情况:Anonymous Proxies
REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 代理服务器 IP ;经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
隐藏了您的真实IP,但是向访问对象透露了您是使用代理服务器访问他们的。
4、使用欺骗性代理服务器的情况:Distorting Proxies
REMOTE_ADDR = 代理服务器 IP
HTTP_VIA = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 随机的 IP ;经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
告诉了访问对象您使用了代理服务器,但编造了一个虚假的随机IP代替您的真实IP欺骗它。
5、使用高匿名代理服务器的情况:High Anonymity Proxies (Elite proxies)
REMOTE_ADDR = 代理服务器 IP
HTTP_VIA = 没数值或不显示
HTTP_X_FORWARDED_FOR = 没数值或不显示 ;经过多个代理服务器时,这个值类似如下:203.98.182.163, 203.98.182.163, 203.129.72.215。
完全用代理服务器的信息替代了您的所有信息,就象您就是完全使用那台代理服务器直接访问对象。
三、PHP获取客户端IP 其它问题
1、关于 REMOTE_ADDR
这个变量获取到的是《直接来源》的 IP 地址,所谓《直接来源》指的是直接请求该地址的客户端 IP 。这个 IP 在单服务器的情况下,很准确的是客户端 IP ,无法伪造。当然并不是所有的程序都一定是单服务器,比如在采用负载均衡的情况(比如采用 haproxy 或者 nginx 进行负载均衡),这个 IP 就是转发机器的 IP ,因为过程是客户端->负载均衡->服务端。是由负载均衡直接访问的服务端而不是客户端。
2、关于 HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP
基于《一》,在负载均衡的情况下直接使用 REMOTE_ADDR 是无法获取客户端 IP 的,这就是一个问题,必须解决。于是就衍生出了负载均衡端将客户端 IP 加入到 HEAD 中发送给服务端,让服务端可以获取到客户端的真实 IP 。当然也就产生了各位所说的伪造,毕竟 HEAD 除了协议里固定的那几个数据,其他数据都是可自定义的。
3、为何网上找到获取客户端 IP 的代码都要依次获取 HTTP_CLIENT_IP 、 HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR?
基于《一》和《二》以及对程序通用性的考虑,所以才这样做。 假设你在程序里直接写死了 REMOTE_ADDR ,有一天你们的程序需要做负载均衡了,那么,你有得改了。当然如果你想这么做也行,看个人爱好和应用场景。也可以封装一个只有 REMOTE_ADDR 的方法,等到需要的时候改这一个方法就行了。
总结:
php获取客户端ip地址到此就算全部结束了,php获取客户端真实ip地址其实就是这么的简单。
大家只需要知道两点:
1、REMOTE_ADDR 得到的是客户端真实IP地址,并且IP不可伪造(虽然有时候得到的IP也是代理的)
2、HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP 得到的是代理端的IP地址,是可以伪造的