Jak uzyskać adres IP klienta w Laravel 5+

147

Próbuję uzyskać adres IP klienta w Laravel.

Uzyskanie adresu IP klienta w PHP jest łatwe przy użyciu $_SERVER["REMOTE_ADDR"]. Działa dobrze w rdzeniu PHP, ale kiedy używam tego samego w Laravel, zwraca IP serwera zamiast IP odwiedzającego.

Amrinder Singh
źródło

Odpowiedzi:

206

Patrząc na Laravel API :

Request::ip();

Wewnętrznie używa getClientIpsmetody z obiektu żądania Symfony :

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
    $ip = $clientIps[0]; // Fallback to this when the client IP falls into the range of trusted proxies
    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 (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
            unset($clientIps[$key]);
        }
    }
    // Now the IP chain contains only untrusted proxies and the client IP
    return $clientIps ? array_reverse($clientIps) : array($ip);
} 
samlev
źródło
4
Użycie obiektu Request nie działa dla mnie, zwraca adres mojego serwera Homestead. 192.168.10.10, który oczywiście nie jest moim adresem IP.
Vince Kronlein
@VinceKronlein dla twojego przypadku sprawdź tę odpowiedź stackoverflow.com/a/41769505/3437790
Sebastien Horin
4
@VinceKronlein w twoim przypadku było bardzo poprawne. Ponieważ łączyłeś się z Homestead, w swojej sieci LOKALNEJ, miałeś 192. IP. Gdybyś miał dostęp do cudzego serwera domowego, przez Internet, twój adres IP wyszedłby przez twojego dostawcę usług internetowych i zostałby użyty twój publiczny.
ied3vil
92

Jeśli korzystasz z modułu równoważenia obciążenia, Laravel \Request::ip() zawsze zwraca adres IP modułu równoważenia:

            echo $request->ip();
            // server ip

            echo \Request::ip();
            // server ip

            echo \request()->ip();
            // server ip

            echo $this->getIp(); //see the method below
            // clent ip

Ta niestandardowa metoda zwraca rzeczywisty adres IP klienta:

public function getIp(){
    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;
                }
            }
        }
    }
}

Oprócz tego sugeruję, abyś był bardzo ostrożny podczas korzystania z oprogramowania pośredniego przepustnicy Laravel : używa Request::ip()również oprogramowania Laravel , więc wszyscy odwiedzający zostaną zidentyfikowani jako ten sam użytkownik i bardzo szybko osiągniesz limit przepustnicy. Doświadczyłem tego na żywo i spowodowało to duże problemy.

Aby to naprawić:

Illuminate \ Http \ Request.php

    public function ip()
    {
        //return $this->getClientIp(); //original method
        return $this->getIp(); // the above method
    }

Możesz teraz również użyć Request::ip(), co powinno zwrócić prawdziwy adres IP w produkcji.

Sebastien Horin
źródło
1
jest poprawne czy (zmienna_filtra ...) wewnątrz drugiego foreach? ten kod nigdy nie zostanie wykonany.
Mistre83
@ Mistre83 Tak, masz rację, myślę, że to przeoczenie testowe. Aktualizuję to!
Sebastien Horin
6
to faktycznie działa z laravel 5.4. Rozważ tworzenie PR na githubie. Myślę, że powinno to być zachowanie domyślne
Crystal
1
To zadziałało w Laravel 5.3, kiedy metoda ip () obiektu żądania Laravel zwracała 127.0.0.1
w5m
3
Czy nie możesz tego naprawić za pomocą zaufanych serwerów proxy? - laravel.com/docs/master/requests#configuring-trusted-proxies
user2722667
77

Użyj request()->ip().

Z tego, co rozumiem, od Laravel 5 zaleca się / dobrą praktyką korzystanie z funkcji globalnych, takich jak:

response()->json($v);
view('path.to.blade');
redirect();
route();
cookie();

I jeśli już, kiedy używam funkcji zamiast statycznej notacji, moje IDE nie świeci jak choinka.

Stan Smulders
źródło
3
Masz rację, że requestjest to funkcja „globalna” - jest to jedna z globalnych funkcji pomocniczych udostępnianych przez laravel. Jednak fasada Zapytanie nie jest statyczna (ani nie jest metoda IP) - request()->fooi Reqest::fooi $request->foosą identyczne. Spójrz na tę istotę na przykład: gist.github.com/cjke/026e3036c6a10c672dc5
Chris,
1
W porządku - oba są równie poprawne. Pomyślałem tylko o tym, co powiedziałeś: „to nie Request::ipmoże być mylące
Chris
3
Problem polega na tym, że te funkcje globalne nie są łatwe do przetestowania - nie można z nich kpić. Fasady mogą być. Staram się unikać funkcji globalnych, ponieważ oznacza to przekopywanie się do źródła funkcji globalnych, aby kpić z jej wywołań, co jest dodatkową pracą, irytujące i nie powinno być moim obowiązkiem.
hackel
1
Chociaż request()->ip()jest poprawna, otaczający tekst jest bardzo mylące - zwłaszcza powiedzieć „to nie jest Request::ip.
Chris
1
@Chris Dzięki, masz całkowitą rację. Zmieniono dla jasności!
Stan Smulders
30

Dodaj przestrzeń nazw

use Request;

Następnie wywołaj funkcję

Request::ip();
shalini
źródło
1
Jeśli używasz przestrzeni nazw: -> użyj Illuminate \ Http \ Request; pogrubienie Zmień nazwę przestrzeni nazw dla żądania, ponieważ oba będą ze sobą kolidować
shalini
Oryginalna odpowiedź jest prawidłowa. Musisz importować, use Requestponieważ próbujesz użyć elewacji. Podana przestrzeń nazw jest przeznaczona dla klasy bazowej. Jeśli zaimportujesz, otrzymasz błąd, ponieważ ip()nie można go nazwać statycznie, do tego służy fasada.
jfadich
Jeśli masz zamiar niepokoić importowanie klasy, należy użyć rzeczywistą elewację, a nie alias: use Illuminate\Support\Facades\Request. Jeśli nie, po prostu użyj \Request::.
hackel
19

W przypadku Laravel 5 możesz użyć obiektu Request. Po prostu wywołaj jego ip()metodę, na przykład:

$request->ip();
Todor Todorov
źródło
16

W Laravel 5

public function index(Request $request) {
  $request->ip();
}
Govind Samrow
źródło
15

Należy zadbać o dwie rzeczy:

  1. Pobierz funkcję pomocniczą, która zwraca a Illuminate\Http\Requesti wywołaj ->ip()metodę:

    request()->ip();
    
  2. Pomyśl o konfiguracji serwera, może on korzystać z serwera proxy lub load-balancer, zwłaszcza w konfiguracji AWS ELB.

Jeśli tak jest w Twoim przypadku, musisz postępować zgodnie z sekcją „ Konfigurowanie zaufanych serwerów proxy ” lub nawet ustawić opcję „Zaufanie wszystkim proxy”.

Czemu? Ponieważ bycie twoim serwerem spowoduje load-balancerzamiast tego twój proxy / IP.

Jeśli jesteś na wyważarce AWS, przejdź do App\Http\Middleware\TrustProxiesi spraw, aby $proxiesdeklaracja wyglądała następująco:

protected $proxies = '*';

Teraz przetestuj to i świętuj, ponieważ właśnie uratowałeś się przed problemami z oprogramowaniem pośredniczącym przepustnicy. Opiera się również na request()->ip()i bez ustawiania "TrustProxies", możesz zablokować wszystkim swoim użytkownikom logowanie zamiast blokowania tylko adresu IP winowajcy.

A ponieważ oprogramowanie pośredniczące przepustnicy nie jest prawidłowo wyjaśnione w dokumentacji, polecam obejrzenie „ samouczka laravel 5.2 dla początkujących, ograniczanie szybkości interfejsu API

Przetestowano w Laravel 5.7

Yevgeniy Afanasyev
źródło
7

W Laravel 5.4 nie możemy wywołać ip static. Oto poprawny sposób na uzyskanie adresu IP użytkownika:

 use Illuminate\Http\Request;

public function contactUS(Request $request)
    {
        echo $request->ip();
        return view('page.contactUS');
    }
Vahid Alvandi
źródło
7

Jeśli wywołasz tę funkcję, łatwo uzyskasz adres IP klienta. Użyłem już tego w moim istniejącym projekcie:

public function getUserIpAddr(){
       $ipaddress = '';
       if (isset($_SERVER['HTTP_CLIENT_IP']))
           $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
       else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
           $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
       else if(isset($_SERVER['HTTP_X_FORWARDED']))
           $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
       else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
           $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
       else if(isset($_SERVER['HTTP_FORWARDED']))
           $ipaddress = $_SERVER['HTTP_FORWARDED'];
       else if(isset($_SERVER['REMOTE_ADDR']))
           $ipaddress = $_SERVER['REMOTE_ADDR'];
       else
           $ipaddress = 'UNKNOWN';    
       return $ipaddress;
    }
Soura Sankar Ghosh
źródło
6

Jeśli nadal otrzymujesz adres IP 127.0.0.1, musisz dodać swoje „proxy”, ale pamiętaj, że musisz je zmienić przed rozpoczęciem produkcji!

Przeczytaj „ Konfigurowanie zaufanych serwerów proxy ”.

I dodaj to:

class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var array
     */
    protected $proxies = '*';

Teraz request()->ip()podaje poprawny adres IP.

Philipp Mochine
źródło
@ Huzaifa99 dziwne to działało przez jakiś czas, a nie, nie działa! Jakie dziwne (znalazłeś inne rozwiązanie?)
Philipp Mochine
4

Jeśli chcesz IP klienta, a twój serwer jest za aws elb, użyj następującego kodu. Przetestowano na laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Aung Bo
źródło
1
Już nie działa, teraz „trustHeaderSet” jest już potrzebny
Philipp Mochine
„najnowsze” wersje laravel można znaleźć w dokumentacji laravel.com/docs/5.5/requests#configuring-trusted-proxies
Sandra
2

Rozwiązanie 1: Funkcji tego typu można użyć do uzyskania adresu IP klienta

public function getClientIPaddress(Request $request) {
    $clientIp = $request->ip();
    return $clientIp;
}

Rozwiązanie 2: jeśli rozwiązanie 1 nie zapewnia dokładnego adresu IP , możesz użyć tej funkcji do uzyskania prawdziwego adresu IP gościa.

 public function getClientIPaddress(Request $request) {

    if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
        $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
        $_SERVER['HTTP_CLIENT_IP'] = $_SERVER["HTTP_CF_CONNECTING_IP"];
    }
    $client  = @$_SERVER['HTTP_CLIENT_IP'];
    $forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
    $remote  = $_SERVER['REMOTE_ADDR'];

    if(filter_var($client, FILTER_VALIDATE_IP)){
        $clientIp = $client;
    }
    elseif(filter_var($forward, FILTER_VALIDATE_IP)){
        $clientIp = $forward;
    }
    else{
        $clientIp = $remote;
    }

    return $clientIp;
 }

NB: Jeśli użyłeś modułu równoważenia obciążenia / serwera proxy na swoim serwerze rzeczywistym, musisz użyć rozwiązania 2, aby uzyskać prawdziwy adres IP dla gości.

Majbah Habib
źródło
1

Możesz uzyskać adres IP na kilka sposobów, wykorzystując żądanie IP, żądanie getClientIp i współpracę z partnerem w zakresie pozyskiwania. W tym modelu powiem Ci najlepszy sposób na uzyskanie aktualnego adresu IP klienta w laravel 5.8.

$clientIP = request()->ip();

dd($clientIP);

Możesz śledzić to stąd

hammad khan
źródło
0

Jeśli masz wiele serwerów proxy, tak jak CDN + Load Balancer.
Użycie funkcji Laravel Request :: ip () spowoduje uzyskanie prawego adresu IP proxy, ale nie adresu IP klienta.
Możesz spróbować następującego rozwiązania.

app / Http / Middleware / TrustProxies.php

protected $proxies = ['0.0.0.0/0'];

Źródła: https://github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215

Bing
źródło
0

Użyłem funkcji Sebastiena Horina getIp i request () -> ip () (na żądanie globalne), ponieważ do localhost funkcja getIp zwraca null:

$this->getIp() ?? request()->ip();

Funkcja getIp:

public function getIp(){
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;
            }
        }
    }
}

}

pedro.caicedo.dev
źródło
0

Jeśli martwisz się o uzyskanie adresu IP, ale nie potrzebujesz lub nie chcesz korzystać z żadnej funkcjonalności Laravel, możesz użyć tylko php:

PHP <5.3.0
$ localIP = getHostByName (php_uname ('n'));

PHP> = 5.3.0
$ localIP = getHostByName (getHostName ());

jak odpowiedział w tym wątku: PHP jak uzyskać lokalny adres IP systemu

jarno punt
źródło
-2

Kiedy chcemy, aby użytkownik ip_address:

$_SERVER['REMOTE_ADDR']

i chcę adres serwera:

$_SERVER['SERVER_ADDR']
shashikant parmar
źródło
-2
  $ip = $_SERVER['REMOTE_ADDR'];
zrazy
źródło
2
Bardziej pomoże, jeśli podasz wyjaśnienie, dlaczego jest to preferowane rozwiązanie i wyjaśnisz, jak to działa. Chcemy uczyć, a nie tylko dostarczać kod. W obecnej sytuacji system oznacza go jako niskiej jakości, więc spróbuj go ulepszyć.
Tin Man
Dziękuje za twoją sugestię.
rashedcs