Obtención de la IP real de una visita web en PHP

La forma más sencilla de obtener la dirección IP de un usuario en PHP es mediante la utilización de $_SERVER['REMOTE_ADDR'], sin embargo este valor no siempre es el que estamos buscando, hay veces en que las visitas llegan a nuestro web a través de proxys de que ocultan su dirección IP.

En la mayoría de los casos es aún posible obtener la dirección IP del usuario en estas situaciones, utilizando determinadas cabeceras. Pero antes conviene tener en cuenta las cabeceras que llegan al servidor web y los diferentes tipos de proxy que existen, para saber cómo funcionan y cómo obtener la dirección IP.

Cuando pedimos una página web el navegador se encarga de realizar la petición enviando una serie de cabeceras HTTP al servidor web. Estas cabeceras se hacen disponibles en el servidor web mediante variables de entorno que se añaden a las propias del servidor web, haciendo que tengamos disponibles variables como DOCUMENT_ROOT, HTTP_USER_AGENT, HTTP_ACCEPT_ENCODING, SERVER_ADDR, SERVER_PROTOCOL, HTTP_HOST… entre otras.

Aparte de estas variables de entorno provenientes tanto del cliente como del servidor, puede haber otras variables generadas a partir de cabeceras cuyo origen no es el cliente, si no algún sistema intermedio como proxys. En estos casos, cuando la petición web de un usuarios pasa a través de un proxy o anonimizador, estos pueden modificar las cabeceras del cliente o añadir nuevas, dependiendo del tipo de sistema que sea como veremos más adelante.

Para lo que nosotros necesitamos las siguientes son las variables de entorno más importantes:

  • REMOTE_ADDR: dirección ip del cliente
  • HTTP_X_FORWARDED_FOR: si no está vacío indica que se ha utilizado un proxy. Al pasar por el proxy lo que hace éste es poner su dirección IP como REMOTE_ADDR y añadir la que estaba como REMOTE_ADDR al final de esta cabecera. En el caso de que la petición pase por varios proxys cada uno repite la operación, por lo que tendremos una lista de direcciones IP que partiendo del REMOTE_ADDR original irá indicando los proxys por los que ha pasado.

Respecto al funcionamiento de los proxys y su interacción con la cabecera que genera la variable HTTP_X_FORWARDED_FOR, hay que tener en cuenta un par de cosas más. Por un lado la forma en la que los proxys concatenan la dirección del REMOTE_ADDR anterior al final de la cabecera no es siempre igual ya que en algunos casos se utiliza una coma y en otros un espacio. Por otro lado hay que tener en cuenta también que la primera dirección IP que viene en la variable HTTP_X_FORWARDED_FOR en algunas ocasiones es una dirección IP de las pertenecientes a los rangos de utilización privada. En estos casos partiendo de estas direcciones hay que continuar mirando el resto de direcciones disponibles hasta encontrar una del rango público.

Una vez vistas estas dos variables de entorno, conviene entender también, al menos de manera resumida, los diferentes tipos de proxy que existen.

Proxies transparentes

No ocultan la información IP de los clientes, únicamente la añaden a HTTP_X_FORWARDED_FOR dejando la suya en REMOTE_ADDR. El objetivo de estos proxys no es el de proporcionar anonimicidad en la red, sino la de cachear información o servir de punto de acceso común a Internet para varios equipos.

REMOTE_ADDR = IP-proxy
HTTP_X_FORWARDED_FOR = IP-cliente

Proxies anónimos

Estos proxies ocultan la dirección ip del cliente proporcionando una forma de navegar anónima. La forma en que ocultan la dirección ip del cliente hace que un proxy se clasifique en una de las siguientes categorías:

Simples

No se oculta el hecho de que se está utilizando un proxy, únicamente se guarda la dirección ip del proxy en ambos cabeceras, sin que aparezca por ningún sitio la del cliente.

REMOTE_ADDR = IP-proxy
HTTP_X_FORWARDED_FOR = IP-proxy

Proxys ruidosos

Son similares al anterior caso con la salvedad de que en vez de guardar su dirección ip HTTP_X_FORWARDED_FOR, guardan una generada aleatoriamente.

REMOTE_ADDR = IP-proxy
HTTP_X_FORWARDED_FOR = IP-aleatoria

Proxys de alta anonimicidad

Este tipo de proxys oculta el hecho de que se esté utilizando un proxy para realizar la petición. Para ello sustituyen la dirección IP existente en REMOTE_ADDR por la suya y no lo indican mediante ninguna otra cabecera, por lo que no es posible saber que se está utilizando un proxy.

REMOTE_ADDR = IP-proxy
HTTP_X_FORWARDED_FOR = sin-determinar

Código PHP

Una vez explicados esta serie de conceptos ya estamos en disposición de poder entender el siguiente código, cuyo objetivo es el de obtener la dirección IP real del usuario.

function getRealIP()
{
 
   if( $_SERVER['HTTP_X_FORWARDED_FOR'] != '' )
   {
      $client_ip = 
         ( !empty($_SERVER['REMOTE_ADDR']) ) ? 
            $_SERVER['REMOTE_ADDR'] 
            : 
            ( ( !empty($_ENV['REMOTE_ADDR']) ) ? 
               $_ENV['REMOTE_ADDR'] 
               : 
               "unknown" );
 
      // los proxys van añadiendo al final de esta cabecera
      // las direcciones ip que van "ocultando". Para localizar la ip real
      // del usuario se comienza a mirar por el principio hasta encontrar 
      // una dirección ip que no sea del rango privado. En caso de no 
      // encontrarse ninguna se toma como valor el REMOTE_ADDR
 
      $entries = preg_split('/[, ]/', $_SERVER['HTTP_X_FORWARDED_FOR']);
 
      reset($entries);
      while (list(, $entry) = each($entries)) 
      {
         $entry = trim($entry);
         if ( preg_match("/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/", $entry, $ip_list) )
         {
            // http://www.faqs.org/rfcs/rfc1918.html
            $private_ip = array(
                  '/^0\./', 
                  '/^127\.0\.0\.1/', 
                  '/^192\.168\..*/', 
                  '/^172\.((1[6-9])|(2[0-9])|(3[0-1]))\..*/', 
                  '/^10\..*/');
 
            $found_ip = preg_replace($private_ip, $client_ip, $ip_list[1]);
 
            if ($client_ip != $found_ip)
            {
               $client_ip = $found_ip;
               break;
            }
         }
      }
   }
   else
   {
      $client_ip = 
         ( !empty($_SERVER['REMOTE_ADDR']) ) ? 
            $_SERVER['REMOTE_ADDR'] 
            : 
            ( ( !empty($_ENV['REMOTE_ADDR']) ) ? 
               $_ENV['REMOTE_ADDR'] 
               : 
               "unknown" );
   }
 
   return $client_ip;
 
}

Básicamente lo que hace la función es partiendo de la dirección indicada en REMOTE_ADDR obtener la dirección IP real. Si HTTP_X_FORWARDED_FOR es vacío la dirección que hemos obtenido previamente es la real (a no ser que se esté utilizando un proxy de alta anonimicidad). En caso contrario lo que se hace es obtener la lista de direcciones IP almacenada en HTTP_X_FORWARDED_FOR y buscar la primera que sea del rango público.

Más información

Twitter Digg Delicious Stumbleupon Technorati Facebook Email

139 Respuestas para “Obtención de la IP real de una visita web en PHP”

  1. Hola necesito ver la ip de un correo de hotmail alguien puede decirme como se ahce se lo agradecere mucho

  2. Hola Patricia.

    Muy bueno el articulo y el script, gracias.

    Me pasa algo muy gracioso, pero que ya me tiene al borde del colapso existencial… y es que tu script me funcionaba perfectamente hasta hace poco, y de repente… empezo a mostrar un error en tiempo de ejecución…por sintaxis… justo en esta linea:

    reset($entries);

    lo que es extraño, pues antes funcionaba y ahora dice que hay error de sintaxis… y justo en esta linea donde no se ve nada…

    Que crees que pueda estar pasando?

    Saludos

  3. Hola
    Necesito ayuda,
    Ok ya tengo el php, yo quiero algo sencillo, que en una pagina html se muestre el ip de la persona que la abra.

    Gracias

    PD patricia y roberto lo que piden se hace muy sencillo, al bajar los correos por el outlook (tanto yahoo como hotmail se pueden bajar) solo tienes que dar click derecho al mensaje en outlook y ver las propiedades, en los detalles… origen del mensaje… y ya tienes al victimario

  4. Gracias Ya logre resolver

  5. Patxi
    perdona mi ignorancia, pero en el codigo que pones al principio, ¿que he de hacer para todas las IP que recoja, volcarlas en una base de datos?
    Gracias

  6. Mi nombre de dominio hacia que las IP de los usuarios fueran siempre una (que era la misma de la ip del dominio). Y bueno busque en google y me encontre con tu código, lo porbe y funciono de lujo. Ahora recien lo subi a mi web y lo encontre de maravilla, te lo agradesco mucho.

    Saludos. Null.

  7. Hola quiero redireccionar una pagina segun la procedencia (eeuu,europa o latinoamer.)del visitante ¿esto se hace detectando el ip? una ves detectado el ip como se redirecciona gcs

  8. Hola soy de linux. ¿Como puedo crear una regla para que de 11 a 12 de la mañana de lunes a viernes el acceso al proxy pueda realizarse desde cualquier dirección IP privada?

  9. Muchas gracias. En mi directorio web estoy teniendo un problema con los accesos indevidos, se suponía que registraba la ip pero creo que usaban algún proxi, espero que esto funcione. Muchas gracias por tu colaboración.

    Pd: Si quieres puedes añadir tu blog a http://www.cincolinks.com

  10. Gracias muy buena función, me funciono genial
    saludos

  11. hey que tal… oye… que crees que tengo un problema
    cuando corro el código me aparece el siguiente error:
    «Notice: Undefined index: HTTP_X_FORWARDED_FOR … on line: 51»
    a que crees que se deba?
    gracias por la atención… saludos!

  12. hola omarin1, no se trata de un error sino de un «Notice» que dice que el array $_SERVER no tiene definida la posición HTTP_X_FORWARDED_FOR. Puedes resolverlo mediante error_reporting para decir que no te muestre los notice o comprobar que exista el índice mediante un isset.

  13. Haber si me aclaro
    Si pongo este codigo en el php de mi web donde se supone que debo «recoger» la ip, o aparecera en la web??

  14. Saludos, muy bueno este post, patxi o alguno de los otros que aqui responden estoy en la busqueda de como hacer para redireccionar a una pagina segun la ip ejemplo con la funcion de get ip puedo determinar la ip del usuario pero aparte de ello me gustaria conocer de que pais viene y segun esto poderlo redireccionar a una de las paginas ejemplo si vine de colombia enviarlo a la pagina de colombia si viene de argentina enviarlo a la pagina de argentina y asi consecutivamente

    muchas gracias,

    en espera de su respuesta

  15. Hola Dario, visita esta página: http://www.maxmind.com/app/php

    Maxmind dispone de varias bases de datos de geolocalización de IPs para países e incluso ciudades. Ofrece de forma gratuita versiones reducidas de estas bases de datos (por ejempmo http://www.maxmind.com/app/geolitecountry).

  16. var gaJsHost = ((«https:» == document.location.protocol) ? «https://ssl.» : «http://www.»);
    document.write(unescape(«%3Cscript src='» + gaJsHost + «google-analytics.com/ga.js’ type=’text/javascript’%3E%3C/script%3E»));

    try {
    var pageTracker = _gat._getTracker(«UA-6831341-14»);
    pageTracker._trackPageview();
    } catch(err) {}

  17. Gonzalo a tu pregunta espero poder responder con esto…

    la ip la recoges en la funsion que se llama getRealIP() ..esta al principio. y al final del codigo solo agregas una variable donde recogeras el resultado de getRealIP()quedando la ultima parte asi..

    else
    {
    $client_ip =
    ( !empty($_SERVER[‘REMOTE_ADDR’]) ) ?
    $_SERVER[‘REMOTE_ADDR’]
    :
    ( ( !empty($_ENV[‘REMOTE_ADDR’]) ) ?
    $_ENV[‘REMOTE_ADDR’]
    :
    «unknown» );
    }

    return $client_ip;

    }

    $ip= getRealIP();
    //esto es lo que agregamos aqui esta la ip para que puedas ponerla donde quieras o escribirla en tu base de datos

    //por ejemplo yo hago esto, primero leo las cookies porque me iteresa el user qeu tengo registrado solo a ese le guardo la ip

    mysql_connect(«tu_hostde_basededatos»,»tuusuario_de_bd»,»tupass_de_bd»»);

    mysql_select_db(«tu_basede_datos»);

    if(isset($HTTP_COOKIE_VARS[«usNick»]) && isset($HTTP_COOKIE_VARS[«usPass»]) )
    {
    $result = mysql_query(«SELECT * FROM usuarios WHERE nick='».
    $HTTP_COOKIE_VARS[«usNick»].»‘ AND password='».$HTTP_COOKIE_VARS[«usPass»].»‘»);

    if($row = mysql_fetch_array($result))
    {
    $nickip = $row[«nick»];

    //aqui es donde actualizo el campo de la ip en mi base d datos y //como ves uso la variable donde he recogido la ip osea $ip

    $sql = «UPDATE usuarios SET ip = ‘$ip’ WHERE nick=’$nickip'»;
    mysql_query($sql);
    }
    else
    {

    //aki si no encuentro nada en la bd no hace nada
    }

    espero te sirva como ejemplo para saber como usar la el ip que obtienes. saludos… DragonFire

  18. Algun Colgao Listillo 05. Ago, 2010 en 5:02 pm

    Bastante interesante, no obstante tengo algunas objecciones y aclaraciones, si estoy equivocado en algo, por favor, decidmelo:

    El rango de Ips que tu consideras de intranet, no tiene por que ser ese, es mas cualquiera que entienda un poco no pondria el rango estandar por cuestiones de seguridad.

    Ademas se pueden modificar las cabeceras http antes de enviarlas añadiendo la ip que yo quiera y aria creer a tu script que soy quien quiera.
    Yo para esto uso la extension Modify Headers para firefox.

    Para aclarar algunas ideas, obtener la ip real a traves de proxys anonimos reales, solo se puede o pirateando el proxy, o bien snifando el trafico y deduciendo a posteriori.

    Pero esto no esta al alcance de la mayoria de nosostros, yo incluido, salvo fallo de seguridad conocido y dejadez del administrador del proxy.

    No obstante cuando alguien te visita a traves de un proxy anonimo, es posible saber que lo hace a traves de un proxy.

    Normalmente bastaria con añadir al script codigo que al recibir la peticion, enviara una peticion al proxy y ver que responde, aunque para que fuera 100% efectivo seria muy lento pues habria que hacer la peticion a todos los puertos. aunque se puede acelerar perdiendo efectividad aciendo peticion a los puertos mas usados por los proxys.

    Creo que es todo, un saludo.

  19. Hola listillo 😉

    El rango de direcciones privadas es el que se indica en «RFC1918 – Address Allocation for Private Internets».

    En cuanto a la modificación de las cabeceras, tienes razón en que se pueden modificar, es una carcterística del protocolo HTTP.

    Un saludo

  20. Gran post, muy buena ayuda, y tú Patxi, un crack!!
    ¿Respondiendo a todas las dudas de los comentarios?
    No me lo creo :O, debes de ser de los pocos que lo hacen.
    Saludos!

  21. Genial codigo Patxi,

    Por favor al guien puede poner un codigo entero, en PHP sin javascript para redireccionar a los usuarios a una web diferente dependiento del pais desde el que entren.

    Llevo un par de días itentandolo.
    Mil gracias!

  22. como puedo obtener el ip de la maquina que entro a una web que esta dentro de una intranet (los visitantes estan en una intranet)
    use el codigo que pusieron pero eso me retorna el proxi y no la ip que tienen las pcs

    gracias

  23. mi pregunta es simple, aunque no creo que la solucion lo sea tanto……………
    es posible descubrir a una persona oculta tras multiproxys?
    en este caso la necesidad es real, ya que se trata de un delicuente, no solo informatico………..
    es posible, como?????
    pd- poseo mas de 300 ips, de sus conexiones ( con todos los nodos o «saltos» dados)
    gracias desde barna

  24. Ese codigo PHP es muy trucho. Probalo hasta con http://www.anonymouse.org y vas a ver como no funciona.

  25. Tú sí que eres trucho… esa url que indicas actúa como proxy de alta anonimicidad y ya indico explícitamente que el código no puede funcionar con este tipo de proxies.

  26. esto es urgente una persona muy mala hackeo el correo de mi marido y me manda mensajes a traves de ese correo, pero se identifica como otra persona… esta haciendo mucho daño y necesito saber como hacer para averiguar realmente desde q computadora envia los envia los e-mail solo asi podre saber quien realmente envia estos e-mails por favor ayuda!!! gracias

  27. envio el ip del ultimo mail recibido por si logran loalizar la direccion..186.59.20.183..por favor estoy desesperada! necesito parar esto!

  28. Excelente tutorial superbien explicado. Lo he probado y funciona perfectamente. Solamente tengo un problema. Para crear un script que me sirva de contador de visitantes, he creado una tabla Mysql en donde guardo la un id autoincrement, que me sirve de contador de visitas, la dirección ip – evidentemente – y la fecha y la hora. Funciona perfectamente salvo en que – curiosamente – crea dis registros, uno con mi ip y itro con otra ip que no se cual es ( supongo que sera la del servidor Mysql ), pero no comprendo porque ocurre esto ya que la función que explicais aqui, solo devuleve un valor y – ademas – yo solo realizo un INSERT INTO una vez. Si me pudierais explicar y ayudar estaria muy agradecido. Atentamente:

    Pau COmpany

  29. tengo una intranet necesito hacer una tabla con los logs de los usuario como puedo saber la ip local uso la funcion getRealIP() pero me guarda el proxy yo quiero saber la ip local del usuario que ingreso a ejecutar mi intranet interna

  30. Muy bueno, no leí todos los comentarios pero dejo esto por las dudas, para que no tire error en una red privada solo cambiar
    if( $_SERVER[‘HTTP_X_FORWARDED_FOR’] != » )
    por
    if((isset($_SERVER[‘HTTP_X_FORWARDED_FOR’])) && ($_SERVER[‘HTTP_X_FORWARDED_FOR’] != » ))

    solo pregunto antes si esta definida la variable
    Saludos Tongalin

  31. lindo tutorias exepto por la desubicada esa que dice que le hakearon la cuenta al marido aqui estamos para arender codigos
    para mujorar las cosas que hacemos y no para resolver problemas matrimoniales ya sea de la indole que sea deberia buscar una solucion en otro sitio
    yo la solucion que te doy es que te crees otra cuenta de e-mail si ya no queres resivir correo de esa persona o simplemenye ponelo como no deseado y listo

    y en cuanto a tu marido la solucion que le doy es que se divorcie de vos loca pocesiva

  32. BUG!! IMPORTANTE cuando usas la funcion SLIP en servidor php 5, no funciona el sript.
    Pero al reemplazar SPLIP() por la funcion EXPLODE(), el codigo funciona perfecto.
    Saludos y espero lean esto! 🙂

  33. Patxi Echarte 07. Feb, 2012 en 3:56 pm

    Efectivamente, split ha sido marcada en PHP 5.3.0 como Deprecated. Modifico el código, gracias.

  34. a mi me funciono de lo mas bien… a su vez lo ingrese en el footer, dejo el codigo para aquello que no le funciono…

    llamo la clase de esta forma..

    y esta es la clase apate
    footer.inc.php

    Copyright ©©

    | Política de Privacidad |
    Disenado por: venezuela |

  35. Hola Paxi, quiero subir mí pagina a la parte de publicidad de Google y deseo saber si hay algún programa que me identidique los ip que se repiten y después de un par de visitas en la pagina de pago, los redireccione a la pagina. La idea es que la competencia no me fusile a cliks y al final me salga más caro el collar que el perro.

  36. Alguien puede poner ejemplos.
    1-Este código va aquí,
    2.Para recoger las ip deber tener algo así.
    3. Y las recoges aquí.
    Alguno de los que lo ha probado y le ha funcionado, desea tirarle un cabo al resto que no es programador y necesita este programa. Un saludo.

  37. Muy buen código, me ha sido útil.
    Gracias.

  38. hola estimados

    es muy ineteresante el codigo para visuliazar la ip de los usuarios.
    pero me gustaria saber como realizar una captura de la ip del usuario y darle permiso a ese usuario que solo puede ingresar 2 veces al sitio web, luego de esto mostrar un mesaje y derivarlo automaticamente a otro sitio.

    Espero que me puedan ayudar.

    Saludos

Trackbacks/Pingbacks

  1. Modify Headers: Interesante plugin para Firefox | Quanaxblog - 31. Mar, 2010

    […] Obtener la IP real con PHP: http://www.eslomas.com/index.php/archives/2005/04/26/obtencion-ip-real-php/ […]