La forma tradicional: según la dirección IP

De hecho, hasta hace un tiempo esta era la única forma de saber la procedencia de un visitante: tomar la dirección IP (pública) desde la cual recibimos la petición y compararla con una base de datos de IPs con sus posibles localizaciones. Para determinar la IP desde la cual nos visita el usuario, desde de php sería:

$ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) 
    ? $_SERVER['HTTP_X_FORWARDED_FOR'] 
    : $_SERVER['REMOTE_ADDR'];

Esta ip no representa el nodo real desde el cual nos visitan, pero usualmente es una buena aproximación del origen del usuario.

Existen varias bases de datos dedicadas a recopilar este tipo de información, quizás la más popular sea la versión gratuita de IPligence (mientras no se use para fines comerciales y se les dé el crédito). Esta versión incluye 150,000 referencias por país, Microsiervos hizo un experimento en el que determinaron que es 95% exacta.

Hay que tener en cuenta que IPligence te da su base de datos en formato CSV y con las IP’s convertidas a número enteros, pero ellos explican como hacer la conversión de IPs y como cargar estos datos hacia un gestor de base de datos.

Otra opción son los datos de Hostip, un proyecto abierto que con ayuda de la comunidad y algunos ISPs ha ido recolectando sus datos. Puedes descargar la base de datos de IP’s, o usar su API incluso.

Deja que el mismo usuario te diga con HTML5

Una de las nuevas funcionalidades de HTML5, es la posibilidad de saber la ubicación del usuario (una vez este lo autorice). Obviamente los navegadores aún tienen que implementar la especificación de Geolocalización del W3C, que hasta el momento Firefox 3.5, el iPhone OS, Android y Google Chrome, entre otros, ya ofrecen esta opción.

Si nos basamos en la especificación del W3C, para detectar la ubicación del usuario es bastante sencillo:

if (typeof navigator.geolocation == 'object'){
    navigator.geolocation.getCurrentPosition(mostrar_ubicacion);
}

function mostrar_ubicacion(p)
{
    alert('posición: '+p.coords.latitude+','+p.coords.longitude );
}

La exactitud dependerá del agente con el cual se intente detectar la ubicación, los móviles que cuentan con GPS obviamente serán mucho más exactos que si se usan las redes WIFI cercanas para adivinar la ubicación.

Tal vez convenga usar geo-location-javascript, un framework que agrupa varias propuestas de Geolocalización (aparte de la del W3C) en un solo lugar. Usarlo es igual de sencillo:

if(geo_position_js.init()){
   geo_position_js.getCurrentPosition(success_callback,error_callback);
}
else{
   alert("Functionality not available");
}

function success_callback() {...}
function error_callback() {...}

Hice un pequeño ejemplo usando este framework para que lo prueben en su navegador. Para ver como funciona, solo vean el código fuente o bien pueden bajarlo desde github ;)

Base de datos de IP’s vs HTML5

Usar una base de datos de IP’s tiene la ventaja que todo funciona detrás, el usuario no debe autorizar el compartir su ubicación ni debe usar un navegador moderno; lo malo que estos datos son precisos solo a nivel de país y si el hardware del usuario ya cuenta con un GPS no lo estamos aprovechando. Dependiendo de lo que queramos hacer, probablemente el mejor enfoque sea usar una base de datos de IP’s sencilla y a la vez preguntarle al usuario que nos comparta su ubicación.