So erhalten Sie die Client-IP-Adresse in Laravel 5+

136

Ich versuche, die IP-Adresse des Kunden in Laravel abzurufen.

Es ist einfach, die IP eines Clients in PHP mithilfe von zu erhalten $_SERVER["REMOTE_ADDR"]. Es funktioniert gut in Core-PHP, aber wenn ich dasselbe in Laravel verwende, gibt es die Server-IP anstelle der Besucher-IP zurück.

Amrinder Singh
quelle

Antworten:

194

Betrachten der Laravel-API :

Request::ip();

Intern wird die getClientIpsMethode aus dem Symfony-Anforderungsobjekt verwendet :

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
quelle
3
Die Verwendung des Request-Objekts funktioniert bei mir nicht, es gibt die Adresse meines Homestead-Servers zurück. 192.168.10.10 das ist offensichtlich nicht meine IP-Adresse.
Vince Kronlein
@VinceKronlein für Ihren Fall überprüfen Sie diese Antwort stackoverflow.com/a/41769505/3437790
Sebastien Horin
3
@ PrinceKronlein in deinem Fall war es sehr richtig. Da Sie in Ihrem lokalen Netzwerk auf Homestead zugegriffen haben, hatten Sie die 192. IP. Wenn Sie über das Internet auf den Homestead-Server eines anderen zugreifen, wird Ihre IP-Adresse über Ihren Internetdienstanbieter gelöscht und Ihre öffentliche IP-Adresse wird verwendet.
ied3vil
81

Wenn Sie sich unter einem Load Balancer befinden, gibt Laravel's \Request::ip() immer die IP des Balancers zurück:

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

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

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

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

Diese benutzerdefinierte Methode gibt die tatsächliche Client-IP zurück:

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

Darüber hinaus empfehle ich Ihnen, mit der Gas- Middleware von Laravel sehr vorsichtig umzugehen : Sie verwendet auch die von Laravel Request::ip(), sodass alle Ihre Besucher als derselbe Benutzer identifiziert werden und Sie das Gaslimit sehr schnell erreichen. Ich habe das live erlebt und das hat große Probleme verursacht.

Um dies zu beheben:

Illuminate \ Http \ Request.php

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

Sie können jetzt auch verwenden Request::ip(), was die reale IP in der Produktion zurückgeben soll.

Sebastien Horin
quelle
1
Ist das if (filter_var ...) innerhalb der zweiten foreach korrekt? Dieser Code wird niemals ausgeführt.
Mistre83
@ Mistre83 Ja du hast recht, ich denke es ist ein Testversehen. Ich aktualisiere es!
Sebastien Horin
6
Dies funktioniert tatsächlich mit Laravel 5.4. Bitte erwägen Sie, PR auf Github zu machen. Ich denke, dies sollte Standardverhalten sein
Crystal
1
Dies war in Laravel 5.3 ein Vergnügen, als die ip () -Methode des Laravel-Anforderungsobjekts immer wieder 127.0.0.1
w5m
3
Können Sie dies nicht mit vertrauenswürdigen Proxys beheben? - laravel.com/docs/master/requests#configuring-trusted-proxies
user2722667
74

Verwenden Sie request()->ip().

Soweit ich weiß, wird seit Laravel 5 empfohlen, die globalen Funktionen wie folgt zu verwenden:

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

Und wenn überhaupt, leuchtet meine IDE bei Verwendung der Funktionen anstelle der statischen Notation nicht wie ein Weihnachtsbaum.

Stan Smulders
quelle
3
Sie haben Recht, das requestist eine "globale" Funktion - es ist eine der globalen Hilfsfunktionen, die von Laravel bereitgestellt werden. Allerdings, die Anfrage Fassade ist nicht statisch (noch ist die Methode ip) - request()->foo, und Reqest::foound $request->foosind alle identisch. Schauen Sie sich diesen Kern für ein Beispiel an: gist.github.com/cjke/026e3036c6a10c672dc5
Chris
1
Fair genug - beide sind gleichermaßen richtig. Ich dachte nur das bisschen, wo Sie sagten "es Request::ipkönnte nicht irreführend sein
Chris
3
Das Problem ist, dass diese globalen Funktionen nicht leicht zu testen sind - sie können nicht verspottet werden. Fassaden können sein. Ich versuche, globale Funktionen zu vermeiden, da dies bedeutet, die globale Funktionsquelle zu durchsuchen, um ihre Aufrufe zu verspotten. Dies ist zusätzliche Arbeit, ärgerlich und sollte nicht in meiner Verantwortung liegen.
Hackel
1
Obwohl request()->ip()korrekt ist, wird der umgebende Text wirklich irreführend - vor allem zu sagen , „es ist nicht Request::ip.
Chris
1
@ Chris Danke, du hast absolut recht. Aus Gründen der Übersichtlichkeit bearbeitet!
Stan Smulders
27

Namespace hinzufügen

use Request;

Rufen Sie dann die Funktion auf

Request::ip();
Shalini
quelle
1
Wenn Sie einen Namespace verwenden: -> verwenden Sie Illuminate \ Http \ Request; fett Benenne den Namespace für die Anfrage um, da beide zusammenstoßen
shalini
Die ursprüngliche Antwort ist richtig. Sie müssen importieren, use Requestweil Sie versuchen, die Fassade zu verwenden. Der von Ihnen angegebene Namespace gilt für die zugrunde liegende Klasse. Wenn Sie importieren, dass Sie eine Fehlermeldung erhalten, weil ip()sie nicht statisch aufgerufen werden kann, ist die Fassade dafür gedacht.
Jfadich
Wenn Sie die Klasse importieren möchten, sollten Sie die eigentliche Fassade verwenden, nicht den Alias ​​: use Illuminate\Support\Facades\Request. Wenn nicht, einfach verwenden \Request::.
Hackel
18

Für Laravel 5 können Sie das Request-Objekt verwenden. Nennen Sie einfach seine ip()Methode, so etwas wie:

$request->ip();
Todor Todorov
quelle
16

In Laravel 5

public function index(Request $request) {
  $request->ip();
}
Govind Samrow
quelle
12

Es gibt zwei Dinge zu erledigen:

  1. Holen Sie sich eine Hilfsfunktion, die a zurückgibt, Illuminate\Http\Requestund rufen Sie die ->ip()Methode auf:

    request()->ip();
  2. Denken Sie an Ihre Serverkonfiguration, sie verwendet möglicherweise einen Proxy oder load-balancerinsbesondere in einer AWS ELB-Konfiguration.

In diesem Fall müssen Sie " Konfigurieren vertrauenswürdiger Proxies " befolgen oder sogar die Option "Vertrauenswürdige Proxies" festlegen.

Warum? Weil Sie als Server stattdessen Ihren Proxy / Ihre load-balancerIP erhalten.

Wenn Sie sich im AWS Balance-Loader befinden, gehen Sie zu App\Http\Middleware\TrustProxiesund lassen Sie die $proxiesDeklaration folgendermaßen aussehen:

protected $proxies = '*';

Testen Sie es jetzt und feiern Sie, weil Sie sich gerade vor Problemen mit der Gas-Middleware bewahrt haben. Es ist auch request()->ip()abhängig von und ohne "TrustProxies" einzurichten, können Sie alle Ihre Benutzer daran hindern, sich anzumelden, anstatt nur die IP des Täters zu blockieren.

Und da die Gas-Middleware in der Dokumentation nicht richtig erklärt wird, empfehle ich, das " Laravel 5.2-Tutorial für Anfänger, API Rate Limiting " zu lesen.

Getestet in Laravel 5.7

Jewgenij Afanasjew
quelle
7

In Laravel 5.4 können wir ip static nicht aufrufen. Dies ist ein korrekter Weg, um die IP des Benutzers zu erhalten:

 use Illuminate\Http\Request;

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

Wenn Sie diese Funktion aufrufen, erhalten Sie leicht die IP-Adresse des Clients. Ich habe dies bereits in meinem bestehenden Projekt verwendet:

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;
    }
Dev216
quelle
5

Wenn Sie immer noch 127.0.0.1 als IP erhalten, müssen Sie Ihren "Proxy" hinzufügen, aber beachten Sie, dass Sie ihn ändern müssen, bevor Sie mit der Produktion beginnen!

Lesen Sie " Konfigurieren vertrauenswürdiger Proxies ".

Und füge dies hinzu:

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

Jetzt request()->ip()gibt Ihnen die richtige IP.

Shadrix
quelle
4

Wenn Sie die Client-IP möchten und Ihr Server hinter aws elb steht, geben Sie den folgenden Code ein. Getestet auf Laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Aung Bo
quelle
1
Funktioniert nicht mehr, jetzt ist "trustHeaderSet" erforderlich
Shadrix
"Aktuelle" Laravel-Versionen finden Sie in den Dokumenten laravel.com/docs/5.5/requests#configuring-trusted-proxies
Sandra
0

Wenn Sie wie CDN + Load Balancer über mehrere Layer-Proxys verfügen.
Bei Verwendung der Funktion Laravel Request :: ip () wird die Proxy-IP ganz rechts, jedoch nicht die Client-IP abgerufen.
Sie können versuchen, folgende Lösung.

app / Http / Middleware / TrustProxies.php

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

Referenz: https://github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215

Bing
quelle
0

Ich habe die Sebastien Horin-Funktion getIp und request () -> ip () (auf globale Anfrage) verwendet, da die getIp-Funktion für localhost null zurückgibt:

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

Die getIp-Funktion:

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.la
quelle
-2

Wenn wir wollen, dass der Benutzer ip_address:

$_SERVER['REMOTE_ADDR']

und Serveradresse wollen:

$_SERVER['SERVER_ADDR']
Shashikant Parmar
quelle
-2
  $ip = $_SERVER['REMOTE_ADDR'];
Hautausschläge
quelle
1
Es ist hilfreicher, wenn Sie erklären, warum dies die bevorzugte Lösung ist, und erklären, wie es funktioniert. Wir wollen aufklären, nicht nur Code bereitstellen. Das System kennzeichnet es als minderwertig. Versuchen Sie daher, es zu verbessern.
der Blechmann
Danke für deinen Vorschlag.
Rashedcs