2011-08-09 145 views
9

我需要檢查一個文件是否「本地」打開(同一臺機器或網絡)。我正在使用:PHP:如何檢查客戶端是否是本地的?

<?php 
if ((substr($_SERVER['REMOTE_ADDR'],0,8) == "192.168.") || ($_SERVER['REMOTE_ADDR'] == "127.0.0.1")) { 
    // client is local 
} else { 
    // client is not local 
} 

但我不確定這是最好的方法。

什麼是這樣做的更簡單的方法?

+2

在這裏,你限制自己的IPv4。現在,這還不夠。你應該 a)對IPv6也很熟悉,並且 b)定義什麼是「本地」的定義列表:真的只有192.168。*?如果你在一個擁有自己IP的網絡中呢?或在一個10. *網絡? – glglgl

+0

可能重複的[如何知道IP是否是外部的?](http://stackoverflow.com/questions/14125735/how-to-know-if-an-ip-is-external-or-not) – user956584

回答

9

一如既往地「萬無一失」,可能會非常棘手。

如果我們限制自己使用IPv4,那麼檢查「127.0.0.1」會照顧localhost情況,但會檢查「192.168」。很明顯是錯誤的 - 只有腳本運行在恰好位於192.168網絡上的服務器上,並使用16位子網掩碼才能運行。

檢查$ _SERVER ['REMOTE_ADDR']對$ _SERVER ['SERVER_ADDR']是一個更好的選擇。儘管如此,這仍然沒有考慮到多宿主主機(即除127.0.0.1之外還有幾個IP地址的主機)的情況。

爲了捕獲所有相同的網絡情況,您需要檢查SERVER_ADDR和子網掩碼的組合對REMOTE_ADDR,但是子網掩碼在$ _SERVER中不可用。

但是,我發現一個功能,它幾乎做你想要的here。這是幾個屏幕,它被稱爲clientInSameSubnet。不是我的代碼,但看起來是正確的。

+0

檢查$ _SERVER ['SERVER_ADDR']是一個好主意。在rfc1918空間中擁有虛擬主機並不一定意味着客戶端也來自該空間。例如,有負載平衡結構,其中一個節點位於私有子網中,而負載均衡器具有「公共」IP(請參閱http://www.linuxvirtualserver.org/VS-NAT.html)。 – Friek

+1

您當然有那裏有一點,正如我所說,萬無一失並不容易。但它比問題中引用的代碼更好,它涵蓋了常見的情況。 – Uffe

+0

@Uffe,那麼我們如何從PHP獲取與子網掩碼相關的信息? – Pacerier

42

Friek說的是真的,但前提是你知道如何獲得真正的客戶端的IP,就可以知道它是用PHP filters本地地址:

if (! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) 
{ 
    // is a local ip address 
} 
+0

如果真正的客戶端IP是IPv6,那麼這不起作用。 –

+0

它應該根據2010年的這個問題工作: https://bugs.php.net/bug.php?id=47435 –

+0

爲127.0.0.1它不會工作 – Nikita

3

如果有人已經很難找到上述代碼,由@Uffe建議,我已將它列入如下:

<?php 
/** 
* Check if a client IP is in our Server subnet 
* 
* @param string $client_ip 
* @param string $server_ip 
* @return boolean 
*/ 
function clientInSameSubnet($client_ip=false,$server_ip=false) { 
    if (!$client_ip) 
     $client_ip = $_SERVER['REMOTE_ADDR']; 
    if (!$server_ip) 
     $server_ip = $_SERVER['SERVER_ADDR']; 

    // Extract broadcast and netmask from ifconfig 
    if (!($p = popen("ifconfig","r"))) return false; 
    $out = ""; 
    while(!feof($p)) 
     $out .= fread($p,1024); 
    fclose($p); 

    // This is to avoid wrapping. 
    $match = "/^.*".$server_ip; 
    $match .= ".*Bcast:(\d{1,3}\.\d{1,3}i\.\d{1,3}\.\d{1,3}).*"; 
    $match .= "Mask:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/im"; 
    if (!preg_match($match,$out,$regs)) 
     return false; 

    $bcast = ip2long($regs[1]); 
    $smask = ip2long($regs[2]); 
    $ipadr = ip2long($client_ip); 
    $nmask = $bcast & $smask; 

    return (($ipadr & $smask) == ($nmask & $smask)); 
} 
相關問題