zoukankan      html  css  js  c++  java
  • 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.

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

    捕捉如下:

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

    但是下一个包如下:

    这个包是数据包,到了应用层仍然是在的,这里可以看出数据包中带有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);  
    }
  • 相关阅读:
    mysql之SQL入门与提升(三)
    DROOLS通过URL访问changset
    drools规则管理Guvnor的安装
    kafka offset manage
    kafka comsumer
    kafka与zookeeper
    kafka数据祸福和failover
    kafka一些问题点的分析
    近期开发storm遇到一些问题的解决点
    关于大数据平台ETL可行性方案
  • 原文地址:https://www.cnblogs.com/kenshinobiy/p/4577843.html
Copyright © 2011-2022 走看看