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.

43 pensamientos en “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, 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!

  3. 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…

  4. 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.

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

  6. 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 🙂

  7. 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 ^^

  8. 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! ^^

  9. 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 🙁 )

  10. 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);

    ?>

  11. 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

  12. 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

  13. 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.

  14. 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

    • 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

  15. 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 una respuesta

Tu dirección de correo electrónico no será publicada.