目前网上流行的所谓“取真实IP地址”的方法,都有bug,没有考虑到多层透明代理的情况。

多数代码类似:
$user_IP = ($_SERVER["HTTP_VIA"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"];
$user_IP = ($user_IP) ? $user_IP : $_SERVER["REMOTE_ADDR"];


事实上,上面的代码只试用与用户只使用了1层代理,如果用户有2层,3层HTTP_X_FORWARDED_FOR 的值是:“本机真实IP,1层代理IP,2层代理IP,.....” ,如果这个时候你的数据中保存IP字段的长度很小(15个字节),数据库就报错了。
实际应用中,因为使用多层透明代理的情况比较少,所以这种用户并不多。

其他应用情况,现在越来越多的网站使用了代理加速方式,比如 新浪、SOHU的新闻 都使用Squid做代理方式,利用多台服务器分流。Squid本身类似透明代理,会发送“HTTP_X_FORWARDED_FOR” ,HTTP_X_FORWARDED_FOR 中包括客户的IP地址,如果此时客户已经使用了一层透明代理,那么程序取的 “HTTP_X_FORWARDED_FOR” 就包括两个IP地址。(我遇到过3个IP地址的情况,4个的未遇到过)

所以取“真正”IP地址的方式,还应该判断  “HTTP_X_FORWARDED_FOR”  中是否有“,”逗号,或者长度是否超长(超过15字节 xxx.xxx.xxx.xxx)。

所以代码应该如下:
[php版本]
<?
function get_real_ip(){
$ip=false;
if(!empty($_SERVER["HTTP_CLIENT_IP"])){
 $ip = $_SERVER["HTTP_CLIENT_IP"];
}
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
 $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
 if ($ip) { array_unshift($ips, $ip); $ip = FALSE; }
 for ($i = 0; $i < count($ips); $i++) {
  if (!eregi ("^(10|172\.16|192\.168)\.", $ips[$i])) { // 判断是否内网的IP
   $ip = $ips[$i];
   break;
  }
 }
}
return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
}

echo get_real_ip();
?>

内文分页: [1] [2] [3]
文章来源: 本站原创 引用(0) 阅读(1468)
 
对《获取客户端IP地址的几种方法》有 0 条评论
发表评论
昵称

网址

电邮
打开HTML 打开UBB 表情 打开表情 隐藏 记住我 [注册]