2011-08-09 17 views
9

Muszę sprawdzić, czy plik jest otwarty "lokalnie" (ten sam komputer lub sieć). Używam:PHP: jak sprawdzić, czy klient jest lokalny?

<?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 
} 

Ale nie jestem pewien, czy to jest najlepszy sposób.

Co jest bardziej niezawodnym sposobem robienia tego?

+2

Tutaj ograniczasz się do IPv4. W dzisiejszych czasach to nie wystarczy. Powinieneś: a) wygodnie z IPv6 oraz b) zdefiniować listę definicji, co jest "lokalne": tak naprawdę tylko 192.168. *? Co jeśli jesteś w sieci z własnym adresem IP? Lub w ramach sieci 10. *? – glglgl

+0

możliwy duplikat [Jak sprawdzić, czy adres IP jest zewnętrzny czy nie?] (Http://stackoverflow.com/questions/14125735/how-to-know-if-an-ip-is-external- lub-not) – user956584

Odpowiedz

9

"Niezawodny", jak zawsze, może być trudny.

Jeśli ograniczymy się do IPv4, sprawdzenie adresu "127.0.0.1" zajmie się sprawą localhost, ale sprawdzenie "192.168". jest błędne - działa tylko wtedy, gdy skrypt jest uruchamiany na serwerze, który znajduje się w sieci 192.168, używając 16-bitowej maski podsieci.

Sprawdzanie $ _SERVER ['REMOTE_ADDR'] przeciwko $ _SERVER ['SERVER_ADDR'] byłoby lepszym rozwiązaniem. Nadal nie zajmuje się jednak przypadkiem hosta wieloadresowego (tj. Takiego, który ma kilka adresów IP oprócz 127.0.0.1).

Aby przechwycić wszystkie sprawy należące do tej samej sieci, należy sprawdzić kombinację SERVER_ADDR i maski podsieci przed REMOTE_ADDR, ale maska ​​podsieci nie jest dostępna w $ _SERVER.

BUT Znalazłem funkcję, która ma praktycznie wszystko, co chcesz here. To kilka ekranów w dół i nazywa się clientInSameSubnet. Nie mój kod, ale wygląda dobrze.

+0

Sprawdzanie przeciwko $ _SERVER ['SERVER_ADDR'] jest złym pomysłem. Posiadanie vhosta w przestrzeni rfc1918 niekoniecznie oznacza, że ​​klient również pochodzi z tej przestrzeni. Na przykład istnieją konstrukcje równoważenia obciążenia, w których węzeł znajduje się w prywatnej podsieci, podczas gdy moduł równoważący obciążenie ma "publiczny" adres IP (patrz http://www.linuxvirtualserver.org/VS-NAT.html). – Friek

+1

Na pewno masz to punkt, a jak już powiedziałem, niezawodny nie będzie łatwy. Ale jest lepszy niż kod cytowany w pytaniu i obejmuje typowe przypadki. – Uffe

+0

@Uffe, Jak więc uzyskać informacje związane z maską podsieci z PHP? – Pacerier

42

Co powiedział Friek to prawda, ale pod warunkiem, że wiesz, jak zdobyć IP realnego klienta, można powiedzieć, czy jest to lokalny adres używając 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

Co nie zadziała, jeśli rzeczywisty adres IP klienta to IPv6. –

+0

Powinien działać zgodnie z tym wydaniem od 2010: https://bugs.php.net/bug.php?id=47435 –

+0

dla 127.0.0.1 to nie zadziała – Nikita

3

W przypadku gdy ktoś ma problem ze znalezieniem powyższy kod , zasugerowane przez @Uffe, zawarłem to poniżej:

<?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)); 
} 
Powiązane problemy