Come ottenere l'indirizzo IP del client in Laravel 5+


136

Sto cercando di ottenere l'indirizzo IP del client in Laravel.

È facile ottenere l'IP di un client in PHP usando $_SERVER["REMOTE_ADDR"]. Funziona bene nel core PHP, ma quando uso la stessa cosa in Laravel, restituisce l'IP del server invece dell'IP del visitatore.

Risposte:


194

Guardando l' API Laravel :

Request::ip();

Internamente, utilizza il getClientIpsmetodo dall'oggetto richiesta di 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);
} 

3
L'uso dell'oggetto Request non funziona per me, ma restituisce l'indirizzo del mio server Homestead. 192.168.10.10 che ovviamente non è il mio indirizzo IP.
Vince Kronlein,

@VinceKronlein per il tuo caso controlla questa risposta stackoverflow.com/a/41769505/3437790
Sebastien Horin

3
@VinceKronlein nel tuo caso è stato molto corretto. Dato che stavi accedendo a Homestead, nella tua rete LOCAL, hai avuto 192. IP. se si stesse accedendo al server della casa di qualcun altro, tramite Internet, il proprio IP sarebbe uscito attraverso il proprio ISP e quello pubblico sarebbe stato utilizzato.
ied3vil,

83

Se sei sotto un bilanciamento del carico, Laravel's restituisce \Request::ip() sempre l'IP del bilanciatore:

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

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

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

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

Questo metodo personalizzato restituisce l'ip client reale:

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

Inoltre, ti suggerisco di stare molto attento usando il middleware del throttle di Laravel : usa quello di LaravelRequest::ip() , quindi tutti i tuoi visitatori saranno identificati come lo stesso utente e raggiungerai il limite dell'acceleratore molto rapidamente. L'ho vissuto dal vivo e questo ha causato grossi problemi.

Per risolvere questo problema:

Illuminate \ Http \ Request.php

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

Ora puoi anche usare Request::ip(), che dovrebbe restituire l'IP reale in produzione.


1
è corretto if (filter_var ...) all'interno del secondo foreach? questo codice non verrà mai eseguito.
Mistre83,

@ Mistre83 Sì, hai ragione, penso che sia una svista di prova. Lo aggiorno!
Sebastien Horin

6
questo funziona effettivamente con laravel 5.4 Si prega di considerare di fare PR su github. Penso che questo dovrebbe essere un comportamento predefinito
Crystal

1
Questo ha funzionato a meraviglia in Laravel 5.3 quando il metodo ip () dell'oggetto richiesta Laravel ha continuato a tornare 127.0.0.1
w5m

3
Non riesci a risolvere questo problema con proxy affidabili? - laravel.com/docs/master/requests#configuring-trusted-proxies
user2722667

74

Usa request()->ip().

Da quello che ho capito, dal momento che Laravel 5 è consigliabile / buona pratica utilizzare le funzioni globali come:

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

E, semmai, quando si usano le funzioni invece della notazione statica il mio IDE non si illumina come un albero di Natale.


3
Hai ragione che requestè una funzione "globale" - è una delle funzioni di aiuto globali fornite da laravel. Tuttavia, la richiesta di facciata, non è statica (non è il metodo ip) - request()->foo, ed Reqest::fooe $request->foosono tutti uguali. Dai
Chris

1
Abbastanza giusto - entrambi sono ugualmente corretti. Ho solo pensato che un po 'dove hai detto "non Request::ippotrebbe essere fuorviante
Chris

3
Il problema è che queste funzioni globali non sono facilmente verificabili, non possono essere derise. Le facciate possono essere. Cerco di evitare le funzioni globali, dal momento che significa scavare nella fonte delle funzioni globali per deridere le sue chiamate, che è un lavoro extra, fastidioso e non dovrebbe essere la mia responsabilità.
hackel,

1
Anche se request()->ip()è corretto, il testo circostante è davvero fuorviante, soprattutto per dire "non lo è Request::ip.
Chris

1
@Chris Grazie, hai assolutamente ragione. A cura di chiarezza!
Stan Smulders,

27

Aggiungi spazio dei nomi

use Request;

Quindi chiamare la funzione

Request::ip();

1
Se hai utilizzato lo spazio dei nomi: -> usa Illuminate \ Http \ Request; grassetto Rinomina spazio dei nomi per richiesta poiché entrambi si scontreranno
shalini il

La risposta originale è corretta Devi importare use Requestperché stai cercando di utilizzare la facciata. Lo spazio dei nomi fornito è per la classe sottostante. Se importi che otterrai un errore perché ip()non può essere chiamato staticamente, ecco a cosa serve la facciata.
jfadich,

Se avete intenzione di disturbare l'importazione della classe, è necessario utilizzare la facciata attuale, non l'alias: use Illuminate\Support\Facades\Request. In caso contrario, basta usare \Request::.
hackel,

18

Per Laravel 5 è possibile utilizzare l'oggetto Richiesta. Basta chiamare il suo ip()metodo, qualcosa del tipo:

$request->ip();

16

In Laravel 5

public function index(Request $request) {
  $request->ip();
}

12

Ci sono due cose di cui occuparsi:

  1. Ottieni una funzione di supporto che restituisce a Illuminate\Http\Requeste chiama il ->ip()metodo:

    request()->ip();
  2. Pensa alla configurazione del tuo server, potrebbe utilizzare un proxy o load-balancer, soprattutto in una configurazione ELB AWS.

Se questo è il tuo caso, devi seguire " Configurazione dei proxy attendibili " o magari impostare un'opzione "Trusting All Proxies".

Perché? Perché essendo il tuo server otterrai invece il tuo proxy / load-balancerIP.

Se utilizzi il bilanciatore AWS, vai a App\Http\Middleware\TrustProxiese fai in modo che la $proxiesdichiarazione assomigli a questo:

protected $proxies = '*';

Ora provalo e festeggia perché ti sei appena salvato dai problemi con il middleware dell'acceleratore. Si basa anche su request()->ip()e senza impostare "TrustProxies", è possibile bloccare l'accesso di tutti gli utenti anziché bloccare solo l'IP del colpevole.

E poiché il middleware del throttle non è spiegato correttamente nella documentazione, raccomando di guardare " tutorial laravel 5.2 per principianti, Limitazione della velocità API "

Testato su Laravel 5.7


7

In Laravel 5.4 non possiamo chiamare ip statico. Questo è un modo corretto per ottenere l'IP dell'utente:

 use Illuminate\Http\Request;

public function contactUS(Request $request)
    {
        echo $request->ip();
        return view('page.contactUS');
    }

7

Se si chiama questa funzione, si ottiene facilmente l'indirizzo IP del client. L'ho già usato nel mio progetto esistente:

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

5

Se stai ancora ottenendo 127.0.0.1 come IP, devi aggiungere il tuo "proxy", ma tieni presente che devi cambiarlo prima di andare in produzione!

Leggi " Configurazione dei proxy attendibili ".

E aggiungi questo:

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

Ora request()->ip()ti dà l'IP corretto.




0

Ho usato la funzione Sebastien Horin getIp e request () -> ip () (su richiesta globale), perché per localhost la funzione getIp restituisce null:

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

La funzione 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;
            }
        }
    }
}

}


-2

Quando vogliamo l'utente ip_address:

$_SERVER['REMOTE_ADDR']

e vuoi l'indirizzo del server:

$_SERVER['SERVER_ADDR']

-2
  $ip = $_SERVER['REMOTE_ADDR'];

1
Aiuta di più se fornisci una spiegazione del perché questa è la soluzione preferita e spiega come funziona. Vogliamo educare, non solo fornire codice. Così com'è, il sistema lo sta segnalando come di bassa qualità, quindi cerca di migliorarlo.
l'Uomo di latta il

Grazie per il tuo suggerimento.
rashedcs,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.