Cómo obtener la dirección IP del cliente en Laravel 5+

136

Estoy tratando de obtener la dirección IP del cliente en Laravel.

Es fácil obtener la IP de un cliente en PHP usando $_SERVER["REMOTE_ADDR"]. Funciona bien en el núcleo de PHP, pero cuando uso lo mismo en Laravel, devuelve la IP del servidor en lugar de la IP del visitante.

Amrinder Singh
fuente

Respuestas:

194

Mirando la API de Laravel :

Request::ip();

Internamente, utiliza el getClientIpsmétodo del Objeto de solicitud de 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
fuente
3
Usar el objeto Solicitud no me funciona, devuelve la dirección de mi servidor Homestead. 192.168.10.10 que obviamente no es mi dirección IP.
Vince Kronlein
@VinceKronlein para su caso, verifique esta respuesta stackoverflow.com/a/41769505/3437790
Sebastien Horin
3
@VinceKronlein en su caso fue muy correcto. Debido a que estaba accediendo a Homestead, en su red LOCAL, tenía tje 192. IP. Si estaba accediendo al servidor de la granja de otra persona, a través de Internet, su IP saldría a través de su ISP y se usaría su público.
ied3vil
83

Si está bajo un equilibrador de carga, Laravel \Request::ip() siempre devuelve la IP del equilibrador:

            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 devuelve la IP real del cliente:

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

Además de esto, le sugiero que tenga mucho cuidado al usar el middleware del acelerador de Laravel : también usa el de Laravel Request::ip(), por lo que todos sus visitantes serán identificados como el mismo usuario y alcanzará el límite del acelerador muy rápidamente. Experimenté esto en vivo y esto causó grandes problemas.

Para arreglar esto:

Iluminar \ Http \ Request.php

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

Ahora también puede usar Request::ip(), que debería devolver la IP real en producción.

Sebastien Horin
fuente
1
¿Es correcto el if (filter_var ...) dentro del segundo foreach? Este código nunca se ejecutará.
Mistre83
@ Mistre83 Sí, tienes razón, creo que es un descuido de prueba. ¡Lo actualizo!
Sebastien Horin
66
esto realmente funciona con laravel 5.4 Por favor considere hacer PR en github. Creo que este debería ser el comportamiento predeterminado
Crystal
1
Esto funcionó de maravilla en Laravel 5.3 cuando el método ip () del objeto de solicitud Laravel seguía devolviendo 127.0.0.1
w5m el
3
¿No puedes arreglar esto con proxys de confianza? - laravel.com/docs/master/requests#configuring-trusted-proxies
usuario2722667
74

Uso request()->ip().

Por lo que entiendo, desde Laravel 5 se recomienda / una buena práctica utilizar las funciones globales como:

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

Y, en todo caso, cuando uso las funciones en lugar de la notación estática, mi IDE no se ilumina como un árbol de Navidad.

Stan Smulders
fuente
3
Tiene razón en que requestes una función "global": es una de las funciones de ayuda global proporcionadas por laravel. Sin embargo, la fachada Solicitud, no es estática (ni el método ip) request()->foo, Reqest::fooy $request->fooson idénticos. Eche un vistazo a esta esencia para ver un ejemplo: gist.github.com/cjke/026e3036c6a10c672dc5
Chris
1
Es justo: ambos son igualmente correctos. Solo pensé en lo que dijiste "no Request::ippuede ser engañoso"
Chris
3
El problema es que estas funciones globales no son fácilmente comprobables, no se pueden burlar. Las fachadas pueden ser. Intento evitar las funciones globales, ya que significa buscar en la fuente de funciones globales para burlarse de sus llamadas, lo cual es un trabajo extra, molesto y no debería ser mi responsabilidad.
Hackel
1
A pesar de que request()->ip()es correcta, el texto que lo rodea es muy engañoso - en especial para decir "no lo es Request::ip.
Chris
1
@ Chris Gracias, tienes toda la razón. Editado para mayor claridad!
Stan Smulders el
27

Agregar espacio de nombres

use Request;

Luego llama a la función

Request::ip();
shalini
fuente
1
Si ha usado el espacio de nombres: -> use Illuminate \ Http \ Request; negrita Renombrar espacio de nombres para solicitud ya que ambos se enfrentarán
shalini
La respuesta original es correcta. Debe importar use Requestporque está intentando usar la Fachada. El espacio de nombres que proporcionó es para la clase subyacente. Si importa que obtendrá un error porque ip()no se puede llamar estáticamente, para eso está la fachada.
jfadich
Si vas a molestar a la importación de la clase, se debe utilizar la fachada real, no el alias: use Illuminate\Support\Facades\Request. Si no, solo úsalo \Request::.
Hackel
18

Para Laravel 5 puede usar el objeto Solicitar. Simplemente llame a su ip()método, algo así como:

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

En Laravel 5

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

Hay dos cosas que cuidar:

  1. Obtenga una función auxiliar que devuelva ay Illuminate\Http\Requestllame al ->ip()método:

    request()->ip();
  2. Piense en la configuración de su servidor, puede usar un proxy o load-balancer, especialmente en una configuración de AWS ELB.

Si este es su caso, debe seguir " Configuración de servidores proxy de confianza " o incluso configurar una opción de "Confiar en todos los servidores proxy".

¿Por qué? Porque ser su servidor obtendrá su proxy /load-balancer IP en su lugar.

Si está en el cargador de equilibrio de AWS, vaya App\Http\Middleware\TrustProxiesy haga que la $proxiesdeclaración se vea así:

protected $proxies = '*';

Ahora pruébelo y celebre porque acaba de salvarse de tener problemas con el middleware del acelerador. También se basa enrequest()->ip() y sin configurar "TrustProxies", puede bloquear el inicio de sesión de todos sus usuarios en lugar de bloquear solo la IP del culpable.

Y debido a que el middleware del acelerador no se explica correctamente en la documentación, recomiendo ver el " tutorial de laravel 5.2 para principiantes, API Rate Limiting "

Probado en Laravel 5.7

Yevgeniy Afanasyev
fuente
7

En Laravel 5.4 no podemos llamar a ip static. Esta es una forma correcta de obtener la IP del usuario:

 use Illuminate\Http\Request;

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

Si llama a esta función, obtiene fácilmente la dirección IP del cliente. Ya he usado esto en mi proyecto 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
fuente
5

Si todavía obtiene 127.0.0.1 como IP, debe agregar su "proxy", ¡pero tenga en cuenta que debe cambiarlo antes de entrar en producción!

Lea " Configuración de servidores proxy de confianza ".

Y agrega esto:

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

Ahora request()->ip()te da la IP correcta.

Shadrix
fuente
4

Si desea la IP del cliente y su servidor está detrás de aws elb, use el siguiente código. Probado para laravel 5.3

$elbSubnet = '172.31.0.0/16';
Request::setTrustedProxies([$elbSubnet]);
$clientIp = $request->ip();
Aung Bo
fuente
1
Ya no funciona, ahora se necesita "TrustedHeaderSet"
Shadrix
para versiones "recientes" de laravel, consulte los documentos laravel.com/docs/5.5/requests#configuring-trusted-proxies
Sandra
0

Usé la función getIp de Sebastien Horin y request () -> ip () (a solicitud global), porque para localhost la función getIp devuelve nulo:

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

La función 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
fuente
-2

Cuando queremos el usuario ip_address:

$_SERVER['REMOTE_ADDR']

y quiere la dirección del servidor:

$_SERVER['SERVER_ADDR']
shashikant parmar
fuente
-2
  $ip = $_SERVER['REMOTE_ADDR'];
rashedcs
fuente
1
Ayuda más si proporciona una explicación de por qué esta es la solución preferida y explica cómo funciona. Queremos educar, no solo proporcionar código. Tal como está, el sistema lo señala como de baja calidad, así que trate de mejorarlo.
The Tin Man
Gracias por su sugerencia.
rashedcs