Jaki jest najdokładniejszy sposób pobierania poprawnego adresu IP użytkownika w PHP?

Wiem, że jest ich mnóstwo$ _SERVER dostępne nagłówki zmiennych do pobierania adresów IP. Zastanawiałem się, czy istnieje ogólna zgoda co do tego, jak najdokładniej uzyskać rzeczywisty adres IP użytkownika (dobrze wiedząc, że żadna metoda nie jest idealna) przy użyciu wspomnianych zmiennych?

Spędziłem trochę czasu próbując znaleźć dogłębne rozwiązanie i wymyśliłem następujący kod oparty na wielu źródłach. Uwielbiałbym to, gdyby ktoś mógł włożyć dziurę w odpowiedzi lub rzucić trochę światła na coś, co może być bardziej dokładne.

edycja zawiera 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 reprezentujenajbardziej wiarygodne źródło adresu IP. Inny$_SERVER Zmienne wymienione tutaj mogą być łatwo sfałszowane przez klienta zdalnego. Celem tego rozwiązania jest próba określenia adresu IP klienta siedzącego za serwerem proxy. Dla 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 przechowywanie obu.

Dla 99,9% użytkowników rozwiązanie to idealnie pasuje do Twoich potrzeb. Nie ochroni Cię przed 0,1% złośliwych użytkowników, którzy chcą nadużyć twojego systemu, wprowadzając własne nagłówki żądań. Jeśli polegasz na adresach IP dla czegoś krytycznego, skorzystaj zREMOTE_ADDR i nie zawracaj sobie głowy cateringiem dla tych, którzy są za pełnomocnikiem.

questionAnswers(10)

yourAnswerToTheQuestion