Detectar pais del visitante en PHP

PHP Logo Los webmasters nos preocupamos mucho por saber quienes son los que visitan nuestras páginas, para ello utilizamos herramientas muy útiles como contadores de visitas, analizadores de tráfico, etc., pero no siempre tenemos lo que queremos, no hay como hacer un script con tus propias manos.

Hace mucho tiempo encontré una base de datos (actualizada periódicamente) que contiene todos la mayoría de números IP que se pueden encontrar en la red. Estos están almacenados en forma de rangos y contiene el dato que nos interesa el País. Con esta base de datos es fácil determinar el país de procedencia del visitante a partir del numero  IP.

MaxMind es una empresa que provee este tipo de servicios y nos brinda un archivo libre (pero limitado) que podemos aprovechar.  http://www.maxmind.com/app/geolitecountry , solo tenemos que descargar el archivo e instalarlo en nuestra base de datos MySQL, sigan los pasos:

Paso 1: Descargar y Descomprimir la base de datos MaxMind (formato .csv):

wget http://www.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip
unzip GeoIPCountryCSV.zip  #contiene el archivo GeoIPCountryWhois.csv

Esta es una vista previa del archivo GeoIPCountryWhois.csv

...
"190.8.128.0","190.8.159.255","3188228096","3188236287","PE","Peru"
"190.8.160.0","190.8.163.255","3188236288","3188237311","PA","Panama"
"190.8.164.0","190.8.167.255","3188237312","3188238335","VE","Venezuela"
"190.8.176.0","190.8.179.255","3188240384","3188241407","CO","Colombia"
"190.8.180.0","190.8.183.255","3188241408","3188242431","EC","Ecuador"
"190.8.184.0","190.8.191.255","3188242432","3188244479","AR","Argentina"
"190.8.192.0","190.8.255.255","3188244480","3188260863","CO","Colombia"
"190.9.0.0","190.9.31.255","3188260864","3188269055","AR","Argentina"
"190.9.32.0","190.9.47.255","3188269056","3188273151","VE","Venezuela"
...

Luego debemos crear la tabla donde vamos a importar esos datos en formato csv:

CREATE TABLE ipdatabase
(
  str_ip_from varchar(15),
  str_ip_to varchar(15),
  ip_from int unsigned,
  ip_to int unsigned,
  country_code2 char(2),
  country_name varchar(50),
  KEY ip_from (ip_from),
  KEY ip_to (ip_to)
);

Es importante que los campos ip_from e ip_to sean int unsigned por que guardaremos números realmente grandes.

LOAD DATA LOCAL INFILE '/ruta_hacia/GeoIPCountryWhois.csv'
INTO TABLE ipdatabase
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n';

Para poder mostrar las imágenes debemos tener las imágenes de las banderas de todos los países, pueden descargar un pack banderas en diferentes tamaños de: http://speckyboy.com/2010/08/04/top-10-country-flag-icon-sets/

Ahora todo esta listo para que podamos escribir el código PHP que determinara el registro al cual pertenece un determinado numero de IP:

$link = mysql_connect("localhost" , "ipdatabase", "pwd");
mysql_select_db("ipdatabase",$link);
$sql = "SELECT lcase(country_code2) as code,country_name as name ".
"FROM ipdatabase ".
"WHERE ip_from <= inet_aton('{$_SERVER['REMOTE_ADDR']}') ".        
"AND ip_to >= inet_aton('{$_SERVER['REMOTE_ADDR']}') ";
if($res = mysql_query($sql,$link)) 
{
if(mysql_affected_rows($link) > 0 && $row = mysql_fetch_array($res))
    $im = imagecreatefrompng("../images/flags/".$row['code'].".png");
else
    $im = imagecreatefrompng("../images/flags/-.png");
header('Content-Type: image/png');
imagepng($im);
imagedestroy($im);
mysql_free_result($res);
}
else
{
echo mysql_error($link);
}
mysql_close($link);

El resultado del script anterior es el siguiente:

Usted nos esta visitando desde :

Ustedes pueden personalizar el código PHP para publicarlo en sus paginas web.

Espero les sirva.

41 Responses to Detectar pais del visitante en PHP

  1. Esta muy bueno el script en su demostracion a pesar de que no muestra la bandera del pais siendo que tiene dicha opsion.

    En cuanto al script te comentare que soy nuevo en php y todavia no he hecho ninguna funcionalidad con base de datos, asi que te agradeceria si me explicaras como llenar una base de datos, como volcar el archivo exel que muestras en el link para ponerlo en la base de datos, desde ya muchas gracias.
    Elias

  2. Hola Master:
    Muy buena la info, estoy probando este ejemplo, mucha buena suerte.
    Saludos totales. :)

  3. Hola, me parece excelente que compartas esta información y tu código, nadamas tengo un a preguntita… veo q aparece la banderita del pais, de donde se sacan esas las descargas una por una o como? en el archivo q bajé solo viene el csv pero como puedo obtener todas las banderas???
    gracias!

  4. bueno ya las encontre, estan disponibles en esta dirección:
    http://ip-to-country.webhosting.info/node/view/91

  5. Está excelente este script que ya he visto en varios sites y me imáginaba que era como el que tienes aqui publicado, pero necesitaba la BD del enlace, en algunos sites he visto que hay incluso las ciudades no tendrás idea de como las obtienen, será que hay otra BD por ahi más especifica?…

    Bueno seguire buscando a ver…

  6. Llevo días intentando descifras diferentes códigos y el tuyo es realmente fácil y asequible. Gracias por tu ayuda.
    Aprovecho para solicitarte me indiques si conoces algún código php para averiguar la hora del sistema local del visitante de mi página, de forma que pueda calcular la diferencia horaria entre su máquina y mi servidor.
    Gracias de nuevo.

  7. fangosto,

    La hora del cliente puedes obtenerla con JavaScript, ya que PHP se ejecuta en el servidor y JavaScript en el cliente.

  8. Latin, lo que me comentas ya lo sabía. Necesitaba el código para, desde mi Servidor, averiguar la hora del PC/Cliente y así conocer la diferencia horaria entre ellos.

    Al final no encontré la solución y me lo tuve que diseñar yo. Si alguien está interesado tendrá que visitar mi página e ir a LasUtilidades/UsoHoraCliente.php.

    Os pondría el código aquí, pero no sé copiar código y pegarlo formateado. De paso si me lo indicáis os lo agradecerá.

    Un abrazo.

  9. pero cuales son los nombres de las columans del cvs ? para poder importarlo con Load Data en mysql

  10. Quisiera saber una forma sencilla de saber el IP y luego a que PC corresponde de los mails recibidos, porque recibo mucha basura.
    Gracias

  11. Hey buen codigo… creo que esta muy bien.. solo que tengo una duda… como lleno la tablas con los datos de la bandera y su ip correspondiente con el nombre del pais… sabran una fuente para sacar eso..

    Saludos y se le agradece :)

  12. como volcar el archivo exel que muestras en el link para ponerlo en la base de datos, desde ya muchas gracias.

  13. Ya he actualizado el post para que puedan leerlo.

    Gracias por las sugerencias.

    Saludos.

  14. Ok, Gracias!!!

  15. tengo un pequeño problema, cuando importo en BD con LOAD DATA me sale error y no se importa….

    Me ayudan???

    Gracias.

    Saludos!!!

  16. Excelente, … Gracias

  17. logro hacer el paso 1, pero despues en el 2º paso me da siempre “error” … y al parecer a “web” le pasa/le sale el mismo error que a mi en el paso 2…

  18. concretamente me da este error:

    #2 – File ‘ip-to-country.csv’ not found (Errcode: 2)

  19. para mi que esto ya ha dejado de funcionar porque, me he pateado el culo buscando formas de hacerlo de otras maneras y no hay formas:

    si pongo LOAD DATA LOCAL INFILE, me sale que no encuentra el archivo (el error que puse mas arriba)

    si cambio los de “test_table” por el nombre de la tabla “iptocountry” sigue sin encontrar el archivo

    si pongo el en vez de LOAD DATA LOCAL INFILE ‘ip-to-country’ y pongo el path UNIX del servidor donde tengo alojado el archivo CSV, tampoco lo encuentra y me da el mismo error (el path es algo asi como /home/USERNAME/public_html/ip-to-country.csv)

    si cambio LOAD DATA LOCAL INFILE por LOAD DATA INFILE, me dice que ” USERNAME@Localhost no tiene permiso…

    he hechado ya más 6 horas pa esto, y no logro ninguna solución, no soluciono lo del paso número 2… Estoy por coger un ODIO TREMENDO a esto del diseño web o programación y declararme a favor de que esto del diseño es para menter priviliguiadas porque vamos… el dolor de cabeza que estoy pillando es de cagarse y no doy a basto para tantas aspirinas (-*_*-) … (por cierto, tengo que confesar que nunca en mi vida he dado ninguna clase o enseñanza relacionada con ordenadores, y eso que tengo 20 años… ya es raro, pero vamos me han contado que esto de diseño y tal era facil y ya veo que es lo mas complicado del mundo…. me es mas facil hacer un plan Financiero-producción-marketing que esto de diseño la verdad)

    aqui un novato en Extremis.apuros ^^

  20. ok, ya está todo solucionado… he tenido que hacer las siguientes cosas:

    1º bajarme el archivo ip-to-country.csv
    2º subirlo a mi servidor host (pero SIN colocarlo en ninguna subcarpeta
    3º cambiar permisos a 777 (ò 0777 si uso el FireFTP)
    4º cambiarle el nombre al archivo por uno más corto y sin guiones (le cambie el nombre de “ip-to-country.csv” a “ip.csv”)
    5ºusar el siguiente comando un vez creado la carpeta:

    LOAD DATA LOCAL INFILE ‘/home/USERNAME/ip.csv’
    INTO TABLE iptocountry
    FIELDS TERMINATED BY ‘,’
    LINES TERMINATED BY ‘\r\n';

    *notas*:

    – donde pone “… INFILE ‘/home/USERNAME/ip.csv’…”,
    se deberia poner la ruta UNIX de cada uno.. eso se pregunta al dueño del servicio de hosting claro.

    – donde pone “… TABLE iptocountry …”, he cambiado lo de test_table por iptocountry (vamos por el nombre de la tabla sino, no sale)

    saludos! ^^

  21. Gracias. Muy util. Buen estilo¡¡¡

  22. necesito ayuda:

    ¿os sale algo en mi direccion de iptocountry, http://www.zen4rox.cheaphostdirect.com/ip.php ?

    es que no se donde esta el fallo, pero yo no veo nada… y no se si el fallo está aqui en el codigo php:

    =inet_aton(‘$REMOTE_ADDR’)”;

    if( $res = mysql_query($sql,$link))
    {
    $row =mysql_fetch_row($res);
    echo “Dirección IP: $REMOTE_ADDR:“;
    echo “País : “.$row[0].” – “.$row[1];
    echo “”;
    mysql_free_result($res);
    }
    else
    {
    echo mysql_error($link);
    }
    mysql_close($link);

    ?>

    despues de el tiempo que le exé para hacer la tabla en SQL y poder subir los datos del archivo ip-to-country.csv… ahora esto no función… (me va a dar una depresión con todo esto :( )

  23. perdon.. pero no se porque, pero el codigo PHP que acabo de poner arriba a salido imcompleto. es este:

    =inet_aton(‘$REMOTE_ADDR’)”;

    if( $res = mysql_query($sql,$link))
    {
    $row =mysql_fetch_row($res);
    echo “Dirección IP: $REMOTE_ADDR:“;
    echo “País : “.$row[0].” – “.$row[1];
    echo “”;
    mysql_free_result($res);
    }
    else
    {
    echo mysql_error($link);
    }
    mysql_close($link);

    ?>

  24. Hola, me parece muy bueno, me costo lograr subir tanto peso del archivo .csv, pero ya esta en la BD, tengo un problema eh puesto mi IP como default pero me da como pais ESTADOS UNIDOS, alguien me puede pasar el archivo exportado de esa tabla en *.sql para montarlo por si es error en la subidad por partes que eh hecho.

    Gracias

  25. Hola, me parece muy bueno, me costo lograr subir tanto peso del archivo .csv, pero ya esta en la BD, tengo un problema eh puesto mi IP como default pero me da como pais ESTADOS UNIDOS, alguien me puede pasar el archivo exportado de esa tabla en *.sql para montarlo por si es error en la subidad por partes que eh hecho.

    Gracias

  26. Hola prueben el link de mi web, no me bien los paises.

  27. Probe el script y yo estoy en venezuela y me dice que estoy en Colombia !!!

  28. despues de muchos intentos no logrosubir el .csv a mi BD porfavor si alquien puede pasarnos el .sql
    Intente todas las sugerencias de los comentarios y nada. gracias.

  29. Muy bueno, voy a intentar integrarlo a un nuevo proyecto.

  30. Hola a todos .. quisiera saber como hacer un contador por paises en php .. sin necesidad de registrarme en otra web etc …si alguien pudiera manda el codigo,base de datos etc …gracias

  31. Buenísimo y muy sencillo el ejemplo. Gracias.

    Es perfecto para el uso que le quiero dar: redireccionar al usuario desde un dominio genérico a un dominio territorial (“.es”, “.de”, “.uk”…) dependiendo de su localización.

  32. alguien tiene esa db en sql
    y si alguien tuvieje el php ya corregido me gustaria que lo colgara

  33. alguien tiene esa db en sql
    y si alguien tuvieje el php ya corregido me gustaria que lo colgara
    este es mi correo:
    alan2002930@hotmail.com

  34. Las columnas ip_from e ip_to me las rellenaba con ceros. Para corregirlo le tuve que añadir esto ENCLOSED BY ‘”‘

    LOAD DATA LOCAL INFILE ‘ip-to-country.csv’
    INTO TABLE test_table
    FIELDS TERMINATED BY ‘,’
    ENCLOSED BY ‘”‘
    LINES TERMINATED BY ‘\r\n';

    Gracias por el aporte. Esta muy claro

  35. Esta muy pero no me muestra las imagenes de los paises, ke me faltaria, lo copie tal y como esta, pero veo ke le falta el nombre de la imagen,

    • Fácil te falta crear la carpeta /images/flags/ y ponerle las imagenes de cada bandera con nombre $row[0].”.gif” ($row[0] es country_code2) y te aparecerán las imágenes xD, El te ha dado el código no las imágenes xD

  36. Funciona muy bien y la base de datos es bastante grande. Lastima que salgan los paises en inglés.

  37. me gustaria saber porque usamos “FROM hp_ipdatabase ” ?
    a mi me da un error que pone Table ‘paises.hp_ipdatabase’ doesn’t exist.
    Lo cual es verdad, no? la tabla se llama ipdatabase, sin hp.

    por otro lado no me crea el $res, si que me encuentra un resultado buscando en la base de datos, pero no me muestra nada cuando lo hago a través del código.

    alguna sugerencia? gracias

    • Hola,

      Gracias por el dato, ya he corregido el bug, lo correcto es usar la tabla ipdatabase, el resto debería funcionar (perdona no puede probarlo) si hay algún otro “horror” por favor me avisas.

      Saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">

Go back to top