Como obter o endereço IP do cliente no Laravel 5+

136

Estou tentando obter o endereço IP do cliente no Laravel.

É fácil obter o IP de um cliente em PHP usando $_SERVER["REMOTE_ADDR"]. Está funcionando bem no núcleo do PHP, mas quando uso a mesma coisa no Laravel, ele retorna o IP do servidor em vez do IP do visitante.

Amrinder Singh
fonte

Respostas:

194

Olhando para a API do Laravel :

Request::ip();

Internamente, ele usa o getClientIpsmétodo do Symfony Request Object :

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
fonte
3
O uso do objeto Request não funciona para mim; ele retorna o endereço do meu servidor Homestead. 192.168.10.10 que obviamente não é o meu endereço IP.
Vince Kronlein
@VinceKronlein para o seu caso, verifique esta resposta stackoverflow.com/a/41769505/3437790
Sebastien Horin
3
@VinceKronlein no seu caso, foi muito correto. Como você estava acessando Homestead, em sua rede LOCAL, tinha o 192. IP. se você estivesse acessando o servidor de outra pessoa, pela Internet, seu IP sairia pelo ISP e o seu público seria usado.
precisa saber é o seguinte
83

Se você estiver com um balanceador de carga, o Laravel \Request::ip() sempre retornará o IP do balanceador:

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

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

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

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

Este método personalizado retorna o ip do cliente real:

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

Além disso, sugiro que você tenha muito cuidado com o middleware do acelerador do Laravel : ele usa oRequest::ip() , para que todos os seus visitantes sejam identificados como o mesmo usuário e você atingirá o limite do acelerador rapidamente. Eu experimentei isso ao vivo e isso causou grandes problemas.

Para corrigir isso:

Iluminar \ Http \ Request.php

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

Agora você também pode usar Request::ip(), o que deve retornar o IP real na produção.

Sebastien Horin
fonte
1
está correto o if (filter_var ...) dentro do segundo foreach? esse código nunca será executado.
Mistre83
@ Mistre83 Sim, você está certo, acho que é uma supervisão de teste. Eu atualizo!
Sebastien Horin 02/02
6
isso realmente funciona com o laravel 5.4 Por favor, considere criar PR no github. Eu acho que isso deve ser o comportamento padrão
Cristal
1
Isso funcionou um deleite em Laravel 5.3 quando ip o pedido do objeto Laravel () método voltava 127.0.0.1
w5m
3
Você não pode corrigir isso com proxys confiáveis? - laravel.com/docs/master/requests#configuring-trusted-proxies
user2722667:
74

Use request()->ip().

Pelo que entendi, desde o Laravel 5 é aconselhável / boa prática usar funções globais como:

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

E, se for o caso, ao usar as funções em vez da notação estática, meu IDE não acende como uma árvore de Natal.

Stan Smulders
fonte
3
Você está certo de que requesté uma função "global" - é uma das funções auxiliares globais fornecidas pelo laravel. No entanto, a fachada Request, não é estática (nem é o ip método) - request()->foo, e Reqest::fooe $request->foosão todos idênticos. Dê uma olhada nesta lista principal para obter um exemplo: gist.github.com/cjke/026e3036c6a10c672dc5
Chris
1
Justo - ambos são igualmente corretos. Eu apenas pensei que a parte em que você disse "não é Request::ippode ser enganosa
Chris
3
O problema é que essas funções globais não são facilmente testáveis ​​- elas não podem ser ridicularizadas. Fachadas podem ser. Eu tento evitar funções globais, pois significa procurar na fonte de função global para zombar de suas chamadas, o que é um trabalho extra, irritante e não deve ser minha responsabilidade.
Hackel
1
Embora request()->ip()esteja correto, o texto circundante é realmente enganosa - especialmente a dizer "não é Request::ip.
Chris
1
@ Chris Obrigado, você está absolutamente certo. Editado para maior clareza!
Stan Smulders
27

Adicionar espaço para nome

use Request;

Então chame a função

Request::ip();
shalini
fonte
1
Se você usa o namespace: -> use Illuminate \ Http \ Request; negrito namespace Rename para o pedido uma vez que ambos vão se enfrentar
shalini
A resposta original está correta. Você precisa importar use Requestporque está tentando usar a Fachada. O espaço para nome que você forneceu é para a classe subjacente. Se você importar que receberá um erro porque ip()não pode ser chamado estaticamente, é para isso que serve a fachada.
Jfadich
Se você estiver indo para se preocupar importando a classe, você deve usar a fachada real, não o alias: use Illuminate\Support\Facades\Request. Se não, basta usar \Request::.
Hackel
18

Para o Laravel 5, você pode usar o objeto Request. Apenas chame seu ip()método, algo como:

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

No Laravel 5

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

Há duas coisas para cuidar:

  1. Obtenha uma função auxiliar que retorne ae Illuminate\Http\Requestchame o ->ip()método:

    request()->ip();
  2. Pense na configuração do servidor, ele pode usar um proxy ou load-balancer, especialmente em uma configuração do AWS ELB.

Se esse for o seu caso, você precisa seguir " Configurando proxies confiáveis " ou talvez até definir a opção "Confiando em todos os proxies".

Por quê? Porque ser seu servidor estará obtendo seu proxy / load-balancerIP.

Se você estiver no balance loader da AWS, acesse App\Http\Middleware\TrustProxiese faça a $proxiesdeclaração parecer com esta:

protected $proxies = '*';

Agora teste e comemore porque você acabou de se livrar de ter problemas com o middleware do acelerador. Ele também conta com request()->ip()e sem configurar "TrustProxies", você pode impedir que todos os usuários façam login, em vez de bloquear apenas o IP do culpado.

E como o middleware do acelerador não é explicado corretamente na documentação, recomendo assistir "o tutorial do laravel 5.2 para iniciantes, limitação de taxa de API "

Testado no Laravel 5.7

Yevgeniy Afanasyev
fonte
7

No Laravel 5.4, não podemos chamar IP estático. Esta é uma maneira correta de obter o IP do usuário:

 use Illuminate\Http\Request;

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

Se você chamar esta função, obterá facilmente o endereço IP do cliente. Eu já usei isso no meu projeto existente:

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
fonte
5

Se você ainda estiver obtendo 127.0.0.1 como IP, precisará adicionar seu "proxy", mas lembre-se de que precisa alterá-lo antes de entrar em produção!

Leia " Configurando proxies confiáveis ".

E adicione isso:

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

Agora request()->ip()fornece o IP correto.

Shadrix
fonte
4

Se você deseja o IP do cliente e seu servidor está atrás do aws elb, use o código a seguir. Testado para laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Aung Bo
fonte
1
Não funciona mais, agora "trustedHeaderSet" é neeed
Shadrix
para versões "recentes" do laravel, consulte os documentos laravel.com/docs/5.5/requests#configuring-trusted-proxies
Sandra
0

Se você possui proxies de várias camadas, como o CDN + Load Balancer.
O uso da função Request :: ip () do Laravel obterá o IP do proxy mais à direita, mas não o IP do cliente.
Você pode tentar seguir a solução.

app / Http / Middleware / TrustProxies.php

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

Referência: https://github.com/fideloper/TrustedProxy/issues/107#issuecomment-373065215

Bing
fonte
0

Eu usei a função SebastIi Horin getIp e request () -> ip () (a pedido global), porque para localhost a função getIp retorna nulo:

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

A função 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
fonte
-2

Quando queremos o usuário ip_address:

$_SERVER['REMOTE_ADDR']

e deseja o endereço do servidor:

$_SERVER['SERVER_ADDR']
shashikant parmar
fonte
-2
  $ip = $_SERVER['REMOTE_ADDR'];
rashedcs
fonte
1
Isso ajuda mais se você fornecer uma explicação sobre por que essa é a solução preferida e explicar como ela funciona. Queremos educar, não apenas fornecer código. Como é, o sistema está sinalizando como de baixa qualidade, então tente melhorá-lo.
the Tin Man
Obrigado pela sua sugestão.
Rashedcs