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

Wiem, że istnieje mnóstwo nagłówków zmiennych $_SERVER dostępnych do pobierania adresów IP. Zastanawiałem się, czy istnieje ogólna zgoda co do tego, jak najdokładniej odzyskać prawdziwy adres IP użytkownika (dobrze wiedząc, że żadna metoda nie jest idealna) za pomocą 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. Bardzo bym chciał, gdyby ktoś mógł wbić dziury w odpowiedzi lub rzućcie trochę światła na coś bardziej dokładnego.

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 (update)

REMOTE_ADDR nadal reprezentuje najbardziej wiarygodne źródło adresu IP. Inne zmienne $_SERVER wymienione tutaj mogą być sfałszowane przez zdalnego klienta bardzo łatwo. Celem tego rozwiązania jest próba określenia adresu IP klienta siedzącego za proxy. Dla celów ogólnych, możesz rozważ użycie tego w połączeniu z adresem IP zwracanym bezpośrednio z $_SERVER['REMOTE_ADDR'] i przechowywanie obu.

Dla 99,9% użytkowników rozwiązanie to idealnie dopasuje się do Twoich potrzeb. nie ochroni cię przed 0,1% złośliwych użytkowników, którzy chcą nadużywać Twojego systemu poprzez wstrzykiwanie własnych nagłówków żądań. Jeśli polegasz na adresach IP w czymś krytycznym, uciekaj się do REMOTE_ADDR i nie trudź się obsługą osób stojących za proxy.

Author: Peter Mortensen, 2009-10-28

18 answers

Oto krótszy, czystszy sposób na uzyskanie adresu IP:

function get_ip_address(){
    foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
        if (array_key_exists($key, $_SERVER) === true){
            foreach (explode(',', $_SERVER[$key]) as $ip){
                $ip = trim($ip); // just to be safe

                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
                    return $ip;
                }
            }
        }
    }
}

Twój kod wydaje się już całkiem kompletny, nie widzę w nim żadnych możliwych błędów (poza zwykłymi zastrzeżeniami IP), zmieniłbym funkcję validate_ip(), aby polegać na rozszerzeniu filtra:

public function validate_ip($ip)
{
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false)
    {
        return false;
    }

    self::$ip = sprintf('%u', ip2long($ip)); // you seem to want this

    return true;
}

Również Twój HTTP_X_FORWARDED_FOR fragment można uprościć z tego:

// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    // check if multiple ips exist in var
    if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false)
    {
        $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        
        foreach ($iplist as $ip)
        {
            if ($this->validate_ip($ip))
                return $ip;
        }
    }
    
    else
    {
        if ($this->validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
            return $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
}

Do tego:

// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
    $iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        
    foreach ($iplist as $ip)
    {
        if ($this->validate_ip($ip))
            return $ip;
    }
}

Możesz również chcieć zweryfikować adresy IPv6.

 290
Author: Alix Axel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-03 21:27:23

Nawet wtedy uzyskanie prawdziwego adresu IP użytkownika będzie zawodne. Wszystko, co muszą zrobić, to użyć anonimowego serwera proxy (takiego, który nie honoruje nagłówków dla http_x_forwarded_for, http_forwarded, itp.), a wszystko, co masz, to adres IP ich serwera proxy.

Możesz wtedy sprawdzić, czy istnieje lista adresów IP serwera proxy, które są anonimowe, ale nie ma sposobu, aby upewnić się, że jest to 100% dokładne, jak również i najbardziej to zrobić, to dać Ci znać, że jest to serwer proxy. A jeśli ktoś jest sprytny, może sfałszować nagłówki dla HTTP forwards.

Powiedzmy, że nie lubię lokalnej uczelni. Dowiaduję się, jakie adresy IP zarejestrowali, i dostaję ich adres IP zbanowany na twojej stronie, robiąc złe rzeczy, ponieważ domyślam się, że szanujesz HTTP do przodu. Lista jest nieskończona.

Potem są, jak się domyślacie, wewnętrzne adresy IP, takie jak sieć uczelni, którą wcześniej wymieniłem. Dużo używa 10.format x.X.X. / Align = "left" / został przekazany do wspólnej sieci.

W takim razie nie będę się tym przejmował, ale dynamiczne adresy IP są już drogą szerokopasmową. Więc. Nawet jeśli otrzymasz adres IP użytkownika, spodziewaj się, że zmieni się on w ciągu 2-3 miesięcy, najdłużej.

 13
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 07:58:09

Używamy:

/**
 * Get the customer's IP address.
 *
 * @return string
 */
public function getIpAddress() {
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    } else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        return trim($ips[count($ips) - 1]);
    } else {
        return $_SERVER['REMOTE_ADDR'];
    }
}

Wybuch na HTTP_X_FORWARDED_FOR jest spowodowany dziwnymi problemami z wykrywaniem adresów IP, gdy Squid był używany.

 8
Author: gabrielk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 07:59:15

Moja odpowiedź jest w zasadzie tylko dopracowaną, w pełni zweryfikowaną i w pełni spakowaną wersją odpowiedzi @AlixAxel:

<?php

/* Get the 'best known' client IP. */

if (!function_exists('getClientIP'))
    {
        function getClientIP()
            {
                if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) 
                    {
                        $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
                    };

                foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key)
                    {
                        if (array_key_exists($key, $_SERVER)) 
                            {
                                foreach (explode(',', $_SERVER[$key]) as $ip)
                                    {
                                        $ip = trim($ip);

                                        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false)
                                            {
                                                return $ip;
                                            };
                                    };
                            };
                    };

                return false;
            };
    };

$best_known_ip = getClientIP();

if(!empty($best_known_ip))
    {
        $ip = $clients_ip = $client_ip = $client_IP = $best_known_ip;
    }
else
    {
        $ip = $clients_ip = $client_ip = $client_IP = $best_known_ip = '';
    };

?>

Zmiany:

  • Upraszcza nazwę funkcji (ze stylem formatowania 'camelCase').

  • Zawiera on sprawdzenie, czy funkcja nie jest już zadeklarowana w innej części kodu.

  • Uwzględnia zgodność "CloudFlare".

  • Inicjalizuje wiele nazw zmiennych "związanych z IP" do zwracanej wartości funkcji' getClientIP'.

  • Zapewnia, że jeśli funkcja nie zwróci poprawnego adresu IP, wszystkie zmienne zostaną ustawione na pusty łańcuch zamiast null.

  • To tylko (45) linijek kodu.

 4
Author: James Anderson Jr.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-07 14:31:27

Największe pytanie brzmi w jakim celu?

Twój kod jest prawie tak wszechstronny, jak to może być - ale widzę, że jeśli zauważysz to, co wygląda jak nagłówek dodany przez proxy, używasz tego zamiast CLIENT_IP, jednak jeśli chcesz te informacje do celów audytu, to ostrzegam - jest bardzo łatwy do sfałszowania.

Z pewnością nigdy nie powinieneś używać adresów IP do jakiegokolwiek uwierzytelniania - nawet te mogą być sfałszowane.

Możesz uzyskać lepszy pomiar adresu IP klienta wypychając aplet flash lub java, który łączy się z serwerem przez port inny niż http (co ujawniłoby przezroczyste proxy lub przypadki, w których nagłówki wstrzyknięte przez proxy są fałszywe - ale pamiętaj, że jeśli klient może połączyć się tylko przez web proxy lub port wychodzący jest zablokowany, nie będzie połączenia z apletu.

 3
Author: symcbean,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-03 21:27:52

Zdaję sobie sprawę, że powyżej są dużo lepsze i bardziej zwięzłe odpowiedzi, a to nie jest funkcja ani najbardziej wdzięczny skrypt wokół. W naszym przypadku musieliśmy wypisać zarówno fałszywy x_forwarded_for, jak i bardziej niezawodny remote_addr w prostym przełączniku per-say. Wymagało to umożliwienia wprowadzania spacji do innych funkcji if-none lub if-singular (zamiast zwracać tylko preformatowaną funkcję). Wymagało var "on lub off" z etykietą dostosowaną do ustawień platformy za pomocą przełącznika. Informatyka wymagało to również, aby $ip było dynamiczne w zależności od żądania, tak aby przybrało formę forwarded_for.

Również nie widziałem nikogo adres isset () vs !empty() -- its possible to enter nothing for x_forwarded_for yet still trigger isset() truth resulting in blank var, a way to get around is to use & & and combine both as conditions. Pamiętaj, że możesz fałszować słowa takie jak "PWNED" jako x_forwarded_for więc upewnij się, że sterylizujesz do prawdziwej składni ip, jeśli twoje wyjście gdzieś chronione lub w DB.

Również, można przetestować za pomocą google translate, jeśli potrzebujesz multi-proxy, aby zobaczyć tablicę w x_forwarder_for. Jeśli chcesz przetestować fałszywe nagłówki, sprawdź to rozszerzenie Chrome Client Header Spoof . Domyślnie będzie to tylko standardowe remote_addr podczas gdy za Anon proxy.

Nie wiem, gdzie remote_addr może być pusty, ale jest tam jako awaryjne na wszelki wypadek.

// proxybuster - attempts to un-hide originating IP if [reverse]proxy provides methods to do so
  $enableProxyBust = true;

if (($enableProxyBust == true) && (isset($_SERVER['REMOTE_ADDR'])) && (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) && (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))) {
    $ip = end(array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']))));
    $ipProxy = $_SERVER['REMOTE_ADDR'];
    $ipProxy_label = ' behind proxy ';
} elseif (($enableProxyBust == true) && (isset($_SERVER['REMOTE_ADDR']))) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $ipProxy = '';
    $ipProxy_label = ' no proxy ';
} elseif (($enableProxyBust == false) && (isset($_SERVER['REMOTE_ADDR']))) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $ipProxy = '';
    $ipProxy_label = '';
} else {
    $ip = '';
    $ipProxy = '';
    $ipProxy_label = '';
}

Aby te dynamiczne do użycia w funkcjach lub zapytaniach/echo/views poniżej, powiedzmy w przypadku log gen lub raportowania błędów użyj globals lub po prostu echo em w dowolnym miejscu, bez tworzenia mnóstwa innych warunków lub statycznych funkcji wyjściowych.

function fooNow() {
    global $ip, $ipProxy, $ipProxy_label;
    // begin this actions such as log, error, query, or report
}

Dziękuję za wszystkie twoje wspaniałe myśli. Proszę daj mi znać, czy to może być lepsze, nadal trochę nowe w tych nagłówkach:)

 1
Author: dhaupin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-06 20:55:30

Wymyśliłem tę funkcję, która nie zwraca po prostu adresu IP, ale tablicę z informacjami o IP.

// Example usage:
$info = ip_info();
if ( $info->proxy ) {
    echo 'Your IP is ' . $info->ip;
} else {
    echo 'Your IP is ' . $info->ip . ' and your proxy is ' . $info->proxy_ip;
}

Oto Funkcja:

/**
 * 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.
 *
 * @since 1.1.3
 *
 * @return object {
 *         IP Address details
 *
 *         string $ip The users IP address (might be spoofed, if $proxy is true)
 *         bool $proxy True, if a proxy was detected
 *         string $proxy_id The proxy-server IP address
 * }
 */
function ip_info() {
    $result = (object) array(
        'ip' => $_SERVER['REMOTE_ADDR'],
        'proxy' => false,
        'proxy_ip' => '',
    );

    /*
     * This code tries to bypass a proxy and get the actual IP address of
     * the visitor behind the proxy.
     * Warning: These values might be spoofed!
     */
    $ip_fields = array(
        'HTTP_CLIENT_IP',
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED',
        'HTTP_X_CLUSTER_CLIENT_IP',
        'HTTP_FORWARDED_FOR',
        'HTTP_FORWARDED',
        'REMOTE_ADDR',
    );
    foreach ( $ip_fields as $key ) {
        if ( array_key_exists( $key, $_SERVER ) === true ) {
            foreach ( explode( ',', $_SERVER[$key] ) as $ip ) {
                $ip = trim( $ip );

                if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false ) {
                    $forwarded = $ip;
                    break 2;
                }
            }
        }
    }

    // If we found a different IP address then REMOTE_ADDR then it's a proxy!
    if ( $forwarded != $result->ip ) {
        $result->proxy = true;
        $result->proxy_ip = $result->ip;
        $result->ip = $forwarded;
    }

    return $result;
}
 1
Author: Philipp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-04 17:57:21

Jak ktoś powiedział wcześniej, kluczem jest to, z jakiego powodu chcesz przechowywać adresy IP użytkownika.

Podam przykład z systemu rejestracji, nad którym pracuję i oczywiście rozwiązanie, aby przyczynić się do tej starej dyskusji, która często pojawia się w moich poszukiwaniach.

Wiele bibliotek rejestracyjnych php używa ip do ograniczania/blokowania nieudanych prób na podstawie adresu IP użytkownika. Rozważmy tę tabelę:

-- mysql
DROP TABLE IF EXISTS `attempts`;
CREATE TABLE `attempts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` varchar(39) NOT NULL, /*<<=====*/
  `expiredate` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 -- sqlite
...

Wtedy, gdy użytkownik próbuje zrobić login lub cokolwiek związanego z Obsługa jak resetowanie hasła, funkcja jest wywoływana na początku:

public function isBlocked() {
      /*
       * used one of the above methods to capture user's ip!!!
       */
      $ip = $this->ip;
      // delete attempts from this ip with 'expiredate' in the past
      $this->deleteAttempts($ip, false);
      $query = $this->dbh->prepare("SELECT count(*) FROM {$this->token->get('table_attempts')} WHERE ip = ?");
      $query->execute(array($ip));
      $attempts = $query->fetchColumn();
      if ($attempts < intval($this->token->get('attempts_before_verify'))) {
         return "allow";
      }
      if ($attempts < intval($this->token->get('attempts_before_ban'))) {
         return "captcha";
      }
      return "block";
   }

Powiedzmy, na przykład, $this->token->get('attempts_before_ban') === 10 i 2 użytkowników przychodzi dla tych samych adresów IP, jak w przypadku poprzednich kodów gdzie nagłówki mogą być sfałszowane , następnie po 5 próbach każda oba są zbanowane! Nawet najgorsze, jeśli wszystkie pochodzą z tego samego proxy, to tylko pierwszych 10 użytkowników będzie zalogowanych, a cała reszta zostanie zbanowana!

Krytyczne jest to, że potrzebujemy unikalnego indeksu w tabeli attempts i możemy go uzyskać z kombinacja Jak:

 `ip` varchar(39) NOT NULL,
 `jwt_load varchar(100) NOT NULL

Gdzie jwt_load pochodzi z pliku cookie http, który podąża za technologią JSON Web token , w której przechowujemy tylko zaszyfrowany ładunek, który powinien zawierać dowolną/unikalną wartość dla każdego użytkownika. Oczywiście żądanie powinno zostać zmienione na: "SELECT count(*) FROM {$this->token->get('table_attempts')} WHERE ip = ? AND jwt_load = ?", A klasa powinna również zainicjować private $jwt.

 1
Author: centurian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-27 11:22:13

Zastanawiam się, czy nie powinieneś iterować nad eksplodującym HTTP_X_FORWARDED_FOR w odwrotnej kolejności, ponieważ z mojego doświadczenia wynika, że adres IP użytkownika kończy się na końcu listy rozdzielonej przecinkami, więc zaczynając od początku nagłówka, jesteś bardziej prawdopodobny, aby uzyskać adres ip jednego z proxy zwrócony, który potencjalnie może nadal zezwalać na przechwytywanie sesji, ponieważ wielu użytkowników może przejść przez ten proxy.

 0
Author: Chris Withers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-15 08:05:14

Dzięki za to, bardzo przydatne.

Pomogłoby jednak, gdyby kod był poprawny składniowo. Jak to jest jest { zbyt wiele wokół linii 20. Obawiam się, że nikt tego nie wypróbował.

Może i jestem szalony, ale po wypróbowaniu go na kilku ważnych i nieprawidłowych adresach, jedyną wersją validate_ip (), która zadziałała, było to:

    public function validate_ip($ip)
    {
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) === false)
            return false;
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) === false)
            return false;
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false)
            return false;

        return true;
    }
 0
Author: Mark Boon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-24 22:28:33

Oto zmodyfikowana wersja, jeśli używasz CloudFlare usługi warstwy buforowania

function getIP()
{
    $fields = array('HTTP_X_FORWARDED_FOR',
                    'REMOTE_ADDR',
                    'HTTP_CF_CONNECTING_IP',
                    'HTTP_X_CLUSTER_CLIENT_IP');

    foreach($fields as $f)
    {
        $tries = $_SERVER[$f];
        if (empty($tries))
            continue;
        $tries = explode(',',$tries);
        foreach($tries as $try)
        {
            $r = filter_var($try,
                            FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 |
                            FILTER_FLAG_NO_PRIV_RANGE |
                            FILTER_FLAG_NO_RES_RANGE);

            if ($r !== false)
            {
                return $try;
            }
        }
    }
    return false;
}
 0
Author: jmserra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 08:02:34

Just a VB.NET Wersja odpowiedzi:

Private Function GetRequestIpAddress() As IPAddress
    Dim serverVariables = HttpContext.Current.Request.ServerVariables
    Dim headersKeysToCheck = {"HTTP_CLIENT_IP", _
                              "HTTP_X_FORWARDED_FOR", _
                              "HTTP_X_FORWARDED", _
                              "HTTP_X_CLUSTER_CLIENT_IP", _
                              "HTTP_FORWARDED_FOR", _
                              "HTTP_FORWARDED", _
                              "REMOTE_ADDR"}
    For Each thisHeaderKey In headersKeysToCheck
        Dim thisValue = serverVariables.Item(thisHeaderKey)
        If thisValue IsNot Nothing Then
            Dim validAddress As IPAddress = Nothing
            If IPAddress.TryParse(thisValue, validAddress) Then
                Return validAddress
            End If
        End If
    Next
    Return Nothing
End Function
 0
Author: Abacus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 08:03:12

Just another clean way:

  function validateIp($var_ip){
    $ip = trim($var_ip);

    return (!empty($ip) &&
            $ip != '::1' &&
            $ip != '127.0.0.1' &&
            filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false)
            ? $ip : false;
  }

  function getClientIp() {
    $ip = @$this->validateIp($_SERVER['HTTP_CLIENT_IP']) ?:
          @$this->validateIp($_SERVER['HTTP_X_FORWARDED_FOR']) ?:
          @$this->validateIp($_SERVER['HTTP_X_FORWARDED']) ?:
          @$this->validateIp($_SERVER['HTTP_FORWARDED_FOR']) ?:
          @$this->validateIp($_SERVER['HTTP_FORWARDED']) ?:
          @$this->validateIp($_SERVER['REMOTE_ADDR']) ?:
          'LOCAL OR UNKNOWN ACCESS';

    return $ip;
  }
 0
Author: Liko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-16 20:45:54

Z klasy Request Symfony https://github.com/symfony/symfony/blob/1bd125ec4a01220878b3dbc3ec3156b073996af9/src/Symfony/Component/HttpFoundation/Request.php

const HEADER_FORWARDED = 'forwarded';
const HEADER_CLIENT_IP = 'client_ip';
const HEADER_CLIENT_HOST = 'client_host';
const HEADER_CLIENT_PROTO = 'client_proto';
const HEADER_CLIENT_PORT = 'client_port';

/**
 * Names for headers that can be trusted when
 * using trusted proxies.
 *
 * The FORWARDED header is the standard as of rfc7239.
 *
 * The other headers are non-standard, but widely used
 * by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
 */
protected static $trustedHeaders = array(
    self::HEADER_FORWARDED => 'FORWARDED',
    self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
    self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
    self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
    self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
);

/**
 * Returns the client IP addresses.
 *
 * In the returned array the most trusted IP address is first, and the
 * least trusted one last. The "real" client IP address is the last one,
 * but this is also the least trusted one. Trusted proxies are stripped.
 *
 * Use this method carefully; you should use getClientIp() instead.
 *
 * @return array The client IP addresses
 *
 * @see getClientIp()
 */
public function getClientIps()
{
    $clientIps = array();
    $ip = $this->server->get('REMOTE_ADDR');
    if (!$this->isFromTrustedProxy()) {
        return array($ip);
    }
    if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
        $forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
        preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
        $clientIps = $matches[3];
    } elseif (self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
        $clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
    }
    $clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
    $firstTrustedIp = null;
    foreach ($clientIps as $key => $clientIp) {
        // Remove port (unfortunately, it does happen)
        if (preg_match('{((?:\d+\.){3}\d+)\:\d+}', $clientIp, $match)) {
            $clientIps[$key] = $clientIp = $match[1];
        }
        if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
            unset($clientIps[$key]);
        }
        if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
            unset($clientIps[$key]);
            // Fallback to this when the client IP falls into the range of trusted proxies
            if (null ===  $firstTrustedIp) {
                $firstTrustedIp = $clientIp;
            }
        }
    }
    // Now the IP chain contains only untrusted proxies and the client IP
    return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
}
 0
Author: luchaninov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-16 16:33:55

Dziwię się, że nikt nie wspomniał o filtrze_input, więc oto odpowiedź Alixa Axela skondensowana do jednej linii:

function get_ip_address(&$keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'])
{
    return empty($keys) || ($ip = filter_input(INPUT_SERVER, array_pop($keys), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))? $ip : get_ip_address($keys);
}
 0
Author: mattavatar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-04 17:54:12

Wiem, że jest za późno na odpowiedź. Ale możesz spróbować tych opcji:

Opcja 1: (za pomocą curl)

$ch = curl_init();

// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "https://ifconfig.me/");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

// grab URL and pass it to the browser
$ip = curl_exec($ch);

// close cURL resource, and free up system resources
curl_close($ch);

return $ip;

Opcja 2: (działa dobrze na Macu)

return trim(shell_exec("dig +short myip.opendns.com @resolver1.opendns.com"));

Option 3: (Just used a trick)

return str_replace('Current IP CheckCurrent IP Address: ', '', strip_tags(file_get_contents('http://checkip.dyndns.com')));

Może być odniesieniem: https://www.tecmint.com/find-linux-server-public-ip-address/

 0
Author: Jonjie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-08-28 03:37:37

Odpowiedziałeś na swoje pytanie! :)

function getRealIpAddr() {
    if(!empty($_SERVER['HTTP_CLIENT_IP']))   //Check IP address from shared Internet
    {
        $IPaddress = $_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //To check IP address is passed from the proxy
    {
        $IPaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else
    {
        $IPaddress = $_SERVER['REMOTE_ADDR'];
    }
    return $IPaddress;
}

Źródło

 -1
Author: Alex Weber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 07:54:51
/**
 * Sanitizes IPv4 address according to Ilia Alshanetsky's book
 * "php|architect?s Guide to PHP Security", chapter 2, page 67.
 *
 * @param string $ip An IPv4 address
 */
public static function sanitizeIpAddress($ip = '')
{
if ($ip == '')
    {
    $rtnStr = '0.0.0.0';
    }
else
    {
    $rtnStr = long2ip(ip2long($ip));
    }

return $rtnStr;
}

//---------------------------------------------------

/**
 * Returns the sanitized HTTP_X_FORWARDED_FOR server variable.
 *
 */
public static function getXForwardedFor()
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
    $rtnStr = $_SERVER['HTTP_X_FORWARDED_FOR'];
    }
elseif (isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR']))
    {
    $rtnStr = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
    }
elseif (getenv('HTTP_X_FORWARDED_FOR'))
    {
    $rtnStr = getenv('HTTP_X_FORWARDED_FOR');
    }
else
    {
    $rtnStr = '';
    }

// Sanitize IPv4 address (Ilia Alshanetsky):
if ($rtnStr != '')
    {
    $rtnStr = explode(', ', $rtnStr);
    $rtnStr = self::sanitizeIpAddress($rtnStr[0]);
    }

return $rtnStr;
}

//---------------------------------------------------

/**
 * Returns the sanitized REMOTE_ADDR server variable.
 *
 */
public static function getRemoteAddr()
{
if (isset($_SERVER['REMOTE_ADDR']))
    {
    $rtnStr = $_SERVER['REMOTE_ADDR'];
    }
elseif (isset($HTTP_SERVER_VARS['REMOTE_ADDR']))
    {
    $rtnStr = $HTTP_SERVER_VARS['REMOTE_ADDR'];
    }
elseif (getenv('REMOTE_ADDR'))
    {
    $rtnStr = getenv('REMOTE_ADDR');
    }
else
    {
    $rtnStr = '';
    }

// Sanitize IPv4 address (Ilia Alshanetsky):
if ($rtnStr != '')
    {
    $rtnStr = explode(', ', $rtnStr);
    $rtnStr = self::sanitizeIpAddress($rtnStr[0]);
    }

return $rtnStr;
}

//---------------------------------------------------

/**
 * Returns the sanitized remote user and proxy IP addresses.
 *
 */
public static function getIpAndProxy()
{
$xForwarded = self::getXForwardedFor();
$remoteAddr = self::getRemoteAddr();

if ($xForwarded != '')
    {
    $ip    = $xForwarded;
    $proxy = $remoteAddr;
    }
else
    {
    $ip    = $remoteAddr;
    $proxy = '';
    }

return array($ip, $proxy);
}
 -6
Author: Meketrefe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-13 16:31:14