Comment obtenir l'adresse IP du client dans Laravel 5+

136

J'essaye d'obtenir l'adresse IP du client dans Laravel.

Il est facile d'obtenir l'adresse IP d'un client en PHP en utilisant $_SERVER["REMOTE_ADDR"]. Cela fonctionne bien dans le noyau PHP, mais lorsque j'utilise la même chose dans Laravel, cela renvoie l'adresse IP du serveur au lieu de l'adresse IP du visiteur.

Amrinder Singh
la source

Réponses:

194

En regardant l' API Laravel :

Request::ip();

En interne, il utilise la getClientIpsméthode de l' objet de requête 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
la source
3
L'utilisation de l'objet Request ne fonctionne pas pour moi, il renvoie l'adresse de mon serveur Homestead. 192.168.10.10 qui n'est évidemment pas mon adresse IP.
Vince Kronlein
@VinceKronlein pour votre cas, vérifiez cette réponse stackoverflow.com/a/41769505/3437790
Sebastien Horin
3
@VinceKronlein dans votre cas, c'était très correct. Parce que vous accédiez à Homestead, dans votre réseau LOCAL, vous aviez tje 192. IP. si vous accédiez au serveur de la ferme de quelqu'un d'autre, via Internet, votre adresse IP serait transmise par votre FAI et votre adresse IP publique serait utilisée.
ied3vil
83

Si vous êtes sous un équilibreur de charge, Laravel renvoie \Request::ip() toujours l'adresse IP de l'équilibreur:

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

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

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

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

Cette méthode personnalisée renvoie l'IP du client réel:

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

En plus de cela, je vous suggère d'être très prudent en utilisant le middleware d' accélération de Laravel : il utiliseRequest::ip() , donc tous vos visiteurs seront identifiés comme le même utilisateur et vous atteindrez la limite des gaz très rapidement. J'ai vécu cela en direct et cela a causé de gros problèmes.

Pour résoudre ce problème:

Illuminate \ Http \ Request.php

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

Vous pouvez maintenant également utiliser Request::ip(), qui devrait renvoyer la véritable adresse IP en production.

Sébastien Horin
la source
1
est correct le if (filter_var ...) à l'intérieur de la seconde foreach? ce code ne sera jamais exécuté.
Mistre83
@ Mistre83 Oui vous avez raison, je pense que c'est un test de contrôle. Je le mets à jour!
Sebastien Horin le
6
cela fonctionne réellement avec laravel 5.4 Veuillez envisager de faire des PR sur github. Je pense que cela devrait être le comportement par défaut
Crystal
1
Cela a fonctionné un régal dans Laravel 5.3 lorsque la méthode ip () de l'objet de requête Laravel a continué à renvoyer 127.0.0.1
w5m
3
Vous ne pouvez pas résoudre ce problème avec des proxys de confiance? - laravel.com/docs/master/requests#configuring-trusted-proxies
user2722667
74

Utilisation request()->ip() .

D'après ce que je comprends, depuis Laravel 5, il est conseillé / bonne pratique d'utiliser les fonctions globales telles que:

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

Et, si quoi que ce soit, lorsque vous utilisez les fonctions au lieu de la notation statique, mon IDE ne s'allume pas comme un arbre de Noël.

Stan Smulders
la source
3
Vous avez raison, c'est requestune fonction "globale" - c'est l'une des fonctions d'assistance globales fournies par laravel. Cependant, la façade de demande, n'est pas statique (ni l'adresse IP de la méthode) - request()->foo, et Reqest::fooet $request->foosont tous identiques. Jetez un œil à cet essentiel pour un exemple: gist.github.com/cjke/026e3036c6a10c672dc5
Chris
1
Assez juste - les deux sont également corrects. Je pensais juste que le passage où vous avez dit "ce n'est Request::ippeut-être pas trompeur
Chris
3
Le problème est que ces fonctions globales ne sont pas facilement testables - elles ne peuvent pas être ridiculisées. Les façades peuvent l'être. J'essaie d'éviter les fonctions globales, car cela signifie fouiller jusqu'à la source de fonctions globale pour se moquer de ses appels, ce qui est un travail supplémentaire, ennuyeux et ne devrait pas être ma responsabilité.
hackel
1
Bien que request()->ip()correct, le texte qui l'entoure est vraiment trompeur - surtout pour dire "ce n'est pas le cas Request::ip.
Chris
1
@Chris Merci, vous avez absolument raison. Édité pour plus de clarté!
Stan Smulders
27

Ajouter un espace de noms

use Request;

Puis appelez la fonction

Request::ip();
shalini
la source
1
Si vous avez utilisé un espace de noms: -> utilisez Illuminate \ Http \ Request; bold Renommer l'espace de noms pour la demande car les deux vont s'affronter
shalini
La réponse originale est correcte. Vous devez importer use Requestparce que vous essayez d'utiliser la façade. L'espace de noms que vous avez fourni est pour la classe sous-jacente. Si vous importez cela, vous obtiendrez une erreur car ip()il ne peut pas être appelé statiquement, c'est à cela que sert la façade.
jfadich le
Si vous allez la peine d' importer la classe, vous devez utiliser la façade réelle, et non l'alias: use Illuminate\Support\Facades\Request. Sinon, utilisez simplement \Request::.
hackel
18

Pour Laravel 5, vous pouvez utiliser l'objet Request. Appelez simplement sa ip()méthode, quelque chose comme:

$request->ip();
Todor Todorov
la source
16

Dans Laravel 5

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

Il y a deux choses à prendre en compte:

  1. Obtenez une fonction d'assistance qui renvoie a Illuminate\Http\Requestet appelez la ->ip()méthode:

    request()->ip();
  2. Pensez à la configuration de votre serveur, il peut utiliser un proxy ou load-balancer, en particulier dans une configuration AWS ELB.

Si c'est votre cas, vous devez suivre « Configurer les proxies de confiance » ou peut-être même définir une option «Faire confiance à tous les proxies».

Pourquoi? Parce qu'être votre serveur obtiendra votre proxy / load-balancerIP à la place.

Si vous êtes sur le chargeur d'équilibrage AWS, accédez à App\Http\Middleware\TrustProxieset faites en sorte que la $proxiesdéclaration ressemble à ceci:

protected $proxies = '*';

Maintenant, testez-le et célébrez-le parce que vous venez de vous éviter des problèmes avec le middleware d'accélérateur. Il repose également surrequest()->ip() et sans paramétrer "TrustProxies", vous pourriez empêcher tous vos utilisateurs de se connecter au lieu de bloquer uniquement l'adresse IP du coupable.

Et comme le middleware de throttle n'est pas expliqué correctement dans la documentation, je recommande de regarder le " tutoriel laravel 5.2 pour débutant, API Rate Limiting "

Testé dans Laravel 5.7

Yevgeniy Afanasyev
la source
7

Dans Laravel 5.4, nous ne pouvons pas appeler ip static. C'est une manière correcte d'obtenir l'adresse IP de l'utilisateur:

 use Illuminate\Http\Request;

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

Si vous appelez cette fonction, vous obtenez facilement l'adresse IP du client. J'ai déjà utilisé ceci dans mon projet existant:

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
la source
5

Si vous obtenez toujours 127.0.0.1 comme IP, vous devez ajouter votre "proxy", mais sachez que vous devez le changer avant de passer en production!

Lisez « Configuration des proxys approuvés ».

Et ajoutez ceci:

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

request()->ip()Vous donne maintenant la bonne adresse IP.

Shadrix
la source
4

Si vous voulez une adresse IP client et que votre serveur est derrière aws elb, utilisez le code suivant. Testé pour laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Aung Bo
la source
1
Ne fonctionne plus, maintenant "trustedHeaderSet" est nécessaire
Shadrix
pour les versions "récentes" de laravel, voir les docs laravel.com/docs/5.5/requests#configuring-trusted-proxies
Sandra
0

Si vous avez plusieurs proxys de couche comme CDN + Load Balancer.
L'utilisation de la fonction Laravel Request :: ip () obtiendra l'IP proxy le plus à droite mais pas l'IP client.
Vous pouvez essayer la solution suivante.

app / Http / Middleware / TrustProxies.php

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

Référence: https://github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215

Bing
la source
0

J'ai utilisé la fonction Sebastien Horin getIp et request () -> ip () (à la demande globale), car pour localhost la fonction getIp renvoie null:

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

La fonction 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.la
la source
-2

Lorsque nous voulons que l'utilisateur ip_address:

$_SERVER['REMOTE_ADDR']

et souhaitez l'adresse du serveur:

$_SERVER['SERVER_ADDR']
shashikant parmar
la source
-2
  $ip = $_SERVER['REMOTE_ADDR'];
éruptions cutanées
la source
1
Cela aide davantage si vous expliquez pourquoi c'est la solution préférée et expliquez son fonctionnement. Nous voulons éduquer, pas seulement fournir du code. En l'état, le système le signale comme étant de mauvaise qualité, alors essayez de l'améliorer.
the Tin Man
Merci pour votre suggestion.
rashedcs