PHP获取APP客户端的IP地址的方法

分析php获取客户端ip

 

用php能获取客户端ip,这个大家都知道,代码如下:

 

  1. /** 
  2.  * 获取客户端ip 
  3.  * @param number $type 
  4.  * @return string 
  5.  */  
  6. function getClientIp($type = 0) {  
  7.     $type       =  $type ? 1 : 0;  
  8.     static $ip  =   NULL;  
  9.     if ($ip !== NULL) return $ip[$type];  
  10.     if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {  
  11.         $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);  
  12.         $pos    =   array_search('unknown',$arr);  
  13.         if(false !== $pos) unset($arr[$pos]);  
  14.         $ip     =   trim($arr[0]);  
  15.     }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {  
  16.         $ip     =   $_SERVER['HTTP_CLIENT_IP'];  
  17.     }elseif (isset($_SERVER['REMOTE_ADDR'])) {  
  18.         $ip     =   $_SERVER['REMOTE_ADDR'];  
  19.     }  
  20.     // IP地址合法验证  
  21.     $long = sprintf("%u",ip2long($ip));  
  22.     $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);  
  23.     return $ip[$type];  
  24. }  


虽然这个非常非常的简单,但是php本就是服务器端语言,为什么它能够获取客户端ip.这其实是一件神奇的事,至少我和我的小伙伴们惊呆了.

 

无论什么语言,服务器端按照理论来说,都应该获取不到客户端ip,无论是c++,erlang,或者其他.

有人可能认为c++不是可以获取客户端ip吗?

是的,的确可以,但是那个是c++写的客户端程序才可以,如果c++写的服务器端程序,还可以吗?

 

群里有人说:这个ip的获取是由于包发送的时候,同时带有ip,mac地址,所以自然就知道了.

我不这样认为,因为理论上来说,包发送的时候的确带上了ip地址,也带上了mac地址,但是从数据包的角度来解释的话,一般都是在局域网内部传输时才会包上MAC头,经过路由不断转发,实际上每经过一级设备都被剥去一层,到最后就只剩下TCP/IP的数据头和数据了。MAC只可能是在网络底层的物理层中传输。(也就是说client的mac地址信息是不可能在公网上传输的,公网上的MAC信息是最后一跳设备的接口MAC

http是应用层协议,因此,到应用层的时候都是数据,根本就不可能还包含ip地址,mac地址...

之后分析$_SERVER变量,这个变量里包含了很多客户端和服务器的一些信息.并且包括使用的web服务器,之后查询资料得出:

php能获取客户端ip地址的原因是,$_SERVER变量是从服务器那边获取的,也就是说:

真正获取客户端ip的是web服务器,比如:apache,nginx.

然后在由web服务器把$_SERVER变量传递给php.

本着分析到底的心态,我进行一次实验,抓包软件进行捕捉

捕捉如下:

PHP获取APP客户端的IP地址的方法

很容易看得出,这里是底层的包,抓出来的ip地址也不在应用层,因此,这部分的ip,mac到应用层就已经没了

但是下一个包如下:

PHP获取APP客户端的IP地址的方法

这个包是数据包,到了应用层仍然是在的,这里可以看出数据包中带有host然后传递给了web服务器,之后在由web服务器传递给php

其他小伙伴是否还有真相?欢迎拍砖

 

-------------------------------------------------------------------------------------------------------------------------------------

php获取客户端真实IP 防止代理和作弊

 

内容提要:这种情况下同样透露了客户端是使用了代理服务器,但编造了一个虚假的随机IP(220.4.251.159)代替客户端的真实IP来欺骗它……

  获取客户端ip其实不是个简单的活儿,因为存在Ip欺骗,和代理问题,所以获取客户端的IP的真实性会打折扣的,不能百分百准确.但是我们还是尽量找一个比较完善的获取客户端真正ip方法.使用php获取IP的方法能找到很多.

getIp

  1. function getIp() { 
  2.     if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) $ip = getenv("HTTP_CLIENT_IP"); 
  3.     else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) $ip = getenv("HTTP_X_FORWARDED_FOR"); 
  4.     else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) $ip = getenv("REMOTE_ADDR"); 
  5.     else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) $ip = $_SERVER['REMOTE_ADDR']; 
  6.     else $ip = "unknown"; 
  7.     return ($ip); 

  现在需要对这段代码进行解释,这里用到了两个函数,getenv()和strcasecmp(),前一个函数获取得系统的环境变量,如果能取到值,则返回该值,不能则返回false.

  $_SERVER是服务器超级全局变量数组,用$_SERVER['REMOTE_ADDR']同样可以获取到客户端的IP地址.二者的区别在于,getenv不支持IIS的isapi方式运行的php.

  strcasecmp(string1,string2)字符串函数的用法是把string1和string2进行比较,如果相等返回0,如果string1大于string2,返回大于0的数,小于则返回小于0的数.

  函数先使用客户IP,如果不成立尝试用代理的方法,如果不行,再使用REMOTE_ADDR.还看到过一个检测IP更详细的方法,考虑了IP的欺骗,和多重代理代码.方法相类似.

  1. function getip() { 
  2.     $unknown = 'unknown'; 
  3.     if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], $unknown)) { 
  4.         $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; 
  5.     } 
  6.     elseif(isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], $unknown)) { 
  7.         $ip = $_SERVER['REMOTE_ADDR']; 
  8.     } 
  9.     /*  
  10. 处理多层代理的情况  
  11. 或者使用正则方式:$ip = preg_match("/[\d\.]{7,15}/", $ip, $matches) ? $matches[0] : $unknown;  
  12. */ 
  13.     if (false !== strpos($ip, ',')) $ip = reset(explode(',', $ip)); 
  14.     return $ip; 

一、没有使用代理服务器的PHP获取客户端IP情况:

    REMOTE_ADDR = 客户端IP
    HTTP_X_FORWARDED_FOR = 没数值或不显示

二、使用透明代理服务器的情况:Transparent Proxies

    REMOTE_ADDR = 最后一个代理服务器 IP
    HTTP_X_FORWARDED_FOR = 客户端真实 IP (经过多个代理服务器时,这个值类似:221.5.252.160, 203.98.182.163, 203.129.72.215)
    这类代理服务器还是将客户端真实的IP发送给了访问对象,无法达到隐藏真实身份的目的.

三、使用普通匿名代理服务器的PHP获取客户端IP情况:Anonymous Proxies

    REMOTE_ADDR = 最后一个代理服务器 IP
    HTTP_X_FORWARDED_FOR = 代理服务器 IP (经过多个代理服务器时,这个值类似:203.98.182.163, 203.98.182.163, 203.129.72.215)
    这种情况下隐藏了客户端的真实IP,但是向访问对象透露了客户端是使用代理服务器访问它们的.

四、使用欺骗性代理服务器的情况:Distorting Proxies

    REMOTE_ADDR = 代理服务器 IP
    HTTP_X_FORWARDED_FOR = 随机的 IP(经过多个代理服务器时,这个值类似:220.4.251.159, 203.98.182.163, 203.129.72.215)
    这种情况下同样透露了客户端是使用了代理服务器,但编造了一个虚假的随机IP(220.4.251.159)代替客户端的真实IP来欺骗它.

五、使用高匿名代理服务器的PHP获取客户端IP情况:High Anonymity Proxies (Elite proxies)

    REMOTE_ADDR = 代理服务器 IP
    HTTP_X_FORWARDED_FOR = 没数值或不显示

    无论是REMOTE_ADDR还是HTTP_FORWARDED_FOR,这些头消息未必能够取得到,因为不同的浏览器不同的网络设备可能发送不同的IP头消息.因此PHP使用$_SERVER["REMOTE_ADDR"] 、$_SERVER["HTTP_X_FORWARDED_FOR"] 获取的值可能是空值也可能是“unknown”值.

 
---------------------------------------------------------------------------------------------------------------
深入分析几种PHP获取客户端IP的情况
 
 

在这篇文章中,我们将会为大家详细介绍

在PHP获取客户端IP中常使用 $_SERVER["REMOTE_ADDR"] 。但如果客户端是使用代理服务器来访问,那取到的是代理服务器的 IP 地址,而不是真正的客户端 IP 地址。要想透过代理服务器取得客户端的真实 IP 地址,就要使用 $_SERVER["HTTP_X_FORWARDED_FOR"] 来读取。

但只有客户端使用“透明代理”的情况下,$_SERVER["HTTP_X_FORWARDED_FOR"] 的值才是客户端真正的IP(如果是多层代理,该值可能是由客户端真正IP和多个代理服务器的IP组成,由逗号“,”分隔),而在“匿名代理”、“欺骗性代理”的情况下是代理服务器的IP值(如果是多层代理,该值可能由多个代理服务器的IP组成,由逗号“,”分隔),在“高匿名代理”的情况下是空值。

关于HTTP头信息中的REMOTE_ADDR、HTTP_FORWARDED_FOR值,我们在下文中有详细的介绍,假设客户端真实IP是221.5.252.160:

 

一、没有使用代理服务器的PHP获取客户端IP情况:

REMOTE_ADDR = 客户端IP
HTTP_X_FORWARDED_FOR = 没数值或不显示

二、使用透明代理服务器的情况:Transparent Proxies

REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_X_FORWARDED_FOR = 客户端真实 IP (经过多个代理服务器时,这个值类似:221.5.252.160, 203.98.182.163, 203.129.72.215)
这类代理服务器还是将客户端真实的IP发送给了访问对象,无法达到隐藏真实身份的目的。

三、使用普通匿名代理服务器的PHP获取客户端IP情况:Anonymous Proxies

REMOTE_ADDR = 最后一个代理服务器 IP
HTTP_X_FORWARDED_FOR = 代理服务器 IP (经过多个代理服务器时,这个值类似:203.98.182.163, 203.98.182.163, 203.129.72.215)
这种情况下隐藏了客户端的真实IP,但是向访问对象透露了客户端是使用代理服务器访问它们的。

四、使用欺骗性代理服务器的情况:Distorting Proxies

REMOTE_ADDR = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 随机的 IP(经过多个代理服务器时,这个值类似:220.4.251.159, 203.98.182.163, 203.129.72.215)
这种情况下同样透露了客户端是使用了代理服务器,但编造了一个虚假的随机IP(220.4.251.159)代替客户端的真实IP来欺骗它。

五、使用高匿名代理服务器的PHP获取客户端IP情况:High Anonymity Proxies (Elite proxies)

REMOTE_ADDR = 代理服务器 IP
HTTP_X_FORWARDED_FOR = 没数值或不显示

无论是REMOTE_ADDR还是HTTP_FORWARDED_FOR,这些头消息未必能够取得到,因为不同的浏览器不同的网络设备可能发送不同的IP头消息。因此PHP使用$_SERVER["REMOTE_ADDR"] 、$_SERVER["HTTP_X_FORWARDED_FOR"] 获取的值可能是空值也可能是“unknown”值。

因此,使用PHP获取客户端IP的代码可以如下:

  1. function getip() {  
  2. $unknown = 'unknown';  
  3. if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) 
    && $_SERVER['HTTP_X_FORWARDED_FOR'] 
    && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], 
    $unknown) ) {  
  4. $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];  
  5. } elseif ( isset($_SERVER['REMOTE_ADDR']) 
    && $_SERVER['REMOTE_ADDR'] && 
    strcasecmp($_SERVER['REMOTE_ADDR'], $unknown) ) {  
  6. $ip = $_SERVER['REMOTE_ADDR'];  
  7. }  
  8. /*  
  9. 处理多层代理的情况  
  10. 或者使用正则方式:$ip = preg_match("/[d.]
    {7,15}/", $ip, $matches) ? $matches[0] : $unknown;  
  11. */  
  12. if (false !== strpos($ip, ','))  
  13. $ip = reset(explode(',', $ip));  
  14.  return $ip;  


PHP获取客户端IP时另外一点需注意,使用函数getenv(’HTTP_X_FORWARDED_FOR’)或getenv(’REMOTE_ADDR’) 也可以如上代码一样取得同样的效果。但getenv()不支持在IIS的isapi方式下运行的PHP。

------------------------------------------------------------------------------------------------------------------

php获取客户端真实ip地址的三种方法

第一种方法,还算靠谱,本人以前一直用的是这个方法:

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=$ips[$i];
                break;
            }
        }
    }
    return ($ip ? $ip : $_SERVER['REMOTE_ADDR']); 
}

第二种方法:

function get_real_ip(){
    static $realip;
    if(isset($_SERVER)){
        if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
            $realip=$_SERVER['HTTP_X_FORWARDED_FOR'];
        }else if(isset($_SERVER['HTTP_CLIENT_IP'])){
            $realip=$_SERVER['HTTP_CLIENT_IP'];
        }else{
            $realip=$_SERVER['REMOTE_ADDR'];
        }
    }else{
        if(getenv('HTTP_X_FORWARDED_FOR')){
            $realip=getenv('HTTP_X_FORWARDED_FOR');
        }else if(getenv('HTTP_CLIENT_IP')){
            $realip=getenv('HTTP_CLIENT_IP');
        }else{
            $realip=getenv('REMOTE_ADDR');
        }
    }
    return $realip;
}

第三种方法,摘自DISCUZ,应该还不错吧!

// 获取IP地址(摘自discuz)
function getIp(){
    $ip='未知IP';
    if(!empty($_SERVER['HTTP_CLIENT_IP'])){
        return is_ip($_SERVER['HTTP_CLIENT_IP'])?$_SERVER['HTTP_CLIENT_IP']:$ip;
    }elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
        return is_ip($_SERVER['HTTP_X_FORWARDED_FOR'])?$_SERVER['HTTP_X_FORWARDED_FOR']:$ip;
    }else{
        return is_ip($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:$ip;
    }
}
function is_ip($str){
    $ip=explode('.',$str);
    for($i=0;$i<count($ip);$i++){  
        if($ip[$i]>255){  
            return false;  
        }  
    }  
    return preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$str);  
}

 

 

如何联系我:【万里虎】www.bravetiger.cn 【QQ】3396726884 (咨询问题100元起,帮助解决问题500元起) 【博客】http://www.cnblogs.com/kenshinobiy/