PHP獲取APP客戶端的IP地址的方法


分析php獲取客戶端ip

 

用php能獲取客戶端ip,這個大家都知道,代碼如下:

 

[php]  view plain copy print ?
 
  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);  
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM