Wiem, że istnieje mnóstwo $ _SERVER nagłówków zmiennych dostępnych do wyszukiwania adresów IP. Zastanawiałem się, czy istnieje ogólna zgoda co do tego, jak najdokładniej uzyskać prawdziwy adres IP użytkownika (dobrze wiedząc, że żadna metoda nie jest idealna) przy użyciu tych zmiennych?
Spędziłem trochę czasu próbując znaleźć dogłębne rozwiązanie i opracowałem następujący kod oparty na wielu źródłach. Bardzo bym chciała, gdyby ktoś mógł wywiercić dziurę w odpowiedzi lub rzucić nieco światła na coś być może bardziej dokładnego.
edycja obejmuje optymalizacje z @Alix
/**
* Retrieves the best guess of the client's actual IP address.
* Takes into account numerous HTTP proxy headers due to variations
* in how different ISPs handle IP addresses in headers between hops.
*/
public function get_ip_address() {
// Check for shared internet/ISP IP
if (!empty($_SERVER['HTTP_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_CLIENT_IP']))
return $_SERVER['HTTP_CLIENT_IP'];
// Check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
// Check if multiple IP addresses exist in var
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip) {
if ($this->validate_ip($ip))
return $ip;
}
}
}
if (!empty($_SERVER['HTTP_X_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_X_FORWARDED']))
return $_SERVER['HTTP_X_FORWARDED'];
if (!empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->validate_ip($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']))
return $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
if (!empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->validate_ip($_SERVER['HTTP_FORWARDED_FOR']))
return $_SERVER['HTTP_FORWARDED_FOR'];
if (!empty($_SERVER['HTTP_FORWARDED']) && $this->validate_ip($_SERVER['HTTP_FORWARDED']))
return $_SERVER['HTTP_FORWARDED'];
// Return unreliable IP address since all else failed
return $_SERVER['REMOTE_ADDR'];
}
/**
* Ensures an IP address is both a valid IP address and does not fall within
* a private network range.
*
* @access public
* @param string $ip
*/
public function validate_ip($ip) {
if (filter_var($ip, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 |
FILTER_FLAG_IPV6 |
FILTER_FLAG_NO_PRIV_RANGE |
FILTER_FLAG_NO_RES_RANGE) === false)
return false;
self::$ip = $ip;
return true;
}
Words of Warning (aktualizacja)
REMOTE_ADDR
nadal stanowi najbardziej niezawodne źródło adresu IP. Inne $_SERVER
wymienione tutaj zmienne mogą być bardzo łatwo sfałszowane przez zdalnego klienta. Celem tego rozwiązania jest próba ustalenia adresu IP klienta siedzącego za serwerem proxy. Do celów ogólnych możesz rozważyć użycie tego w połączeniu z adresem IP zwróconym bezpośrednio z $_SERVER['REMOTE_ADDR']
i zapisaniem obu.
Dla 99,9% użytkowników to rozwiązanie idealnie spełni Twoje potrzeby. Nie ochroni cię przed 0,1% złośliwych użytkowników, którzy chcą nadużyć twojego systemu poprzez wstrzyknięcie własnych nagłówków żądań. Jeśli polegasz na adresach IP w celach krytycznych dla misji, REMOTE_ADDR
uciekaj się do osób stojących za serwerem proxy i nie zawracaj sobie tym głowy.