Récupérer les coordonnées GPS d’un visiteur

J’ai travaillé sur certains projets où le contenu devait être servi aux internautes en fonction de leurs positions géographiques. Un pré-requis à la mise en place d’un tel système est justement de connaître les coordonnées GPS des visiteurs d’un site web.

Dans cet article je vais vous présenter quelques méthodes pour recueillir ces informations.

geolocalisation par IP
Géolocaliser un utilisateur par son IP, ou par l’API geolocate

Geolocaliser un visiteur par son IP

Je vous propose de débuter le tour d’horizon des différentes techniques de récupération des coordonnées GPS par celle qui est la plus archaïque, mais la seule qui ne nécessite pas le consentement de l’internaute. Cette méthode n’est pas la plus précise, et présente deux inconvénients :

  • Il faut se procurer et installer une base de données des plages d’IP par ville (±190 mo) ;
  • Elle ne ressort pas des résultats très précis (de l’ordre de la ville) et est incapable de géolocaliser un «mobinaute».

Je vous invite tout de même à l’expérimenter, tout d’abord parce que c’est intéressant de comprendre comment cela marche, mais aussi car cette méthode nous servira d’alternative lorsque les autres ne fonctionneront pas.

Mise en place de la table

Pour commencer, il faut se procurer une base de Geo IP. Certains services de geolocalisation mettent à disposition gratuitement, pour un usage non-commercial, des versions allégées de leurs propres bases de données. Ces bases, bien que déjà relativement complètes, contiennent moins d’informations, et sont plus rarement mises à jour que leurs bases payantes ou sur abonnement.

J’ai testé une base «lite» fournie par le service ip2location. Vous pouvez vous la procurer ici en vous inscrivant gratuitement. Vous recevrez par email la liste des bases de données disponibles. Celle qu’il vous faut est la ip2location_db5 au format CSV. Elle contient les pages d’IP relatives à de nombreuses villes, ainsi que les coordonnées GPS correspondantes.

Pour l’utiliser, il faut insérer les informations qu’elle contient dans une nouvelle table de votre installation de WordPress. Il faut donc créer cette nouvelle table.

Tout d’abord, sauvegardez votre base de données.

Puis, connectez-vous à votre interface MySQL (via PHPMyAdmin, adminer, ou en SSH pour les puristes…), positionnez-vous dans la base de données de votre installation de WordPress, puis exécuter la requête suivante :

CREATE TABLE `wp_ip2location_db5`( `ip_from` INT(10) UNSIGNED, 
                               `ip_to` INT(10) UNSIGNED, 
                               `country_code` CHAR(2), 
                               `country_name` VARCHAR(64), 
                               `region_name` VARCHAR(128), 
                               `city_name` VARCHAR(128), 
                               `latitude` DOUBLE, 
                               `longitude` DOUBLE, 

                               INDEX `idx_ip_from` (`ip_from`), 
                               INDEX `idx_ip_to` (`ip_to`), 
                               INDEX `idx_ip_from_to` (`ip_from`, `ip_to`) ) 
ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

La table est maintenant créée, ne reste plus qu’à y insérer les données. Pour cela uploadez le fichier CSV sur votre serveur – par FTP ou autre – puis exécutez cette nouvelle requête :

LOAD DATA LOCAL INFILE '/home/www/public_html/sql/IP2LOCATION-LITE-DB5.CSV' 
INTO TABLE wp_ip2location_db5 
FIELDS TERMINATED BY ',' ENCLOSED BY '"' 
LINES TERMINATED BY '\r\n' 
IGNORE 0 LINES;

Bien sûr, il faut adapter le chemin du fichier pour cibler l’emplacement du CSV sur votre serveur 😛

Si tout s’est bien déroulé, vous ne devriez pas avoir de message d’erreur, et voir maintenant ± 1917071 lignes insérées dans votre nouvelle table.

Récupérer les coordonnées GPS à partir de l’IP

La table que l’on vient de mettre en place va nous servir à trouver les coordonnées géographiques approximatives d’un internaute en fonction de son IP, encore faut-il la connaitre…

La variable $_SERVER contient de nombreuses informations, dont l’adresse IP de connexion. Celle-ci est généralement accessible sous la clef «REMOTE_ADDR», mais dans certains cas – par exemple si votre site est servi derrière un proxy – l’IP retournée via REMOTE_ADDR ne sera pas correcte. D’autres entrées de la variable $_SERVER peuvent vous donner une IP plus pertinente.

Voici une fonction pour récupérer la véritable IP de votre visiteur, en testant chaque information disponible.

function get_user_ip() {
	// On test les variables serveur…
    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 ) {
    	// … si elles existes…
        if ( array_key_exists( $key, $_SERVER ) === true ) {
        	// … et pour chacune de leurs valeurs…
            foreach ( explode( ',', $_SERVER[ $key ] ) as $ip ) {
                $ip = trim( $ip );
                // … si c'est une adresse IP, mais pas une interne (ex : 192.0.0.1)…
                if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) !== false 
                  // … ou une adresse de loopback (ex : 127.0.0.1)…
                  && ( ( ip2long( $ip ) & 0xff000000 ) != 0x7f000000 ) ) {
                  	// … on la retourne 🙂
                    return $ip;
                }
            }
        }
    }
    // Si aucune valeur n'est correte on renvoie false
    return false;
}

Afin d’interroger la table pour trouver les coordonnées de notre utilisateur, il faut convertir l’IP – que l’on a obtenu au format numérique – au format littéral. Il existe une fonction PHP toute faite :

// Mon ip
$ip = '78.202.225.85';
return ip2long( $ip ); 
// ip2long() retourne l'adresse au format littéral

// … cela revient ± à faire :
$ip = explode( '.', $ip );
return $ip1[0] * pow( 256, 3 ) 
		+ $ip1[1] * pow( 256, 2 ) 
		+ $ip1[2] * 256 
		+ $ip1[3];

Maintenant que nous disposons de toutes les informations nécessaires, il ne nous reste plus qu’à faire une requête en base de données pour obtenir les coordonnées de l’utilisateur.

Construisons une fonction pour cela :

  1. En premier lieu elle récupère l’IP numérique de l’internaute ;
  2. ensuite elle convertie son adresse au format littéral ;
  3. et enfin, en passant par l’API sql de WordPress, on récupère la ligne de la table correspondant à la plage d’IP.
function get_user_coords() {
	// L'IP de notre utilisateur
	$ip = get_user_ip();
	if ( ! $ip ) {
		return false;
	}
		
	// … au format littéral
	$ip = ip2long( $ip );
	if ( ! $ip ) {
		return false;
	}

	global $wpdb;
	$infos = $wpdb->get_row( 
    			$wpdb->prepare( 
    				"SELECT * FROM {$wpdb->prefix}ip2location_db5 WHERE %d BETWEEN ip_from AND ip_to", 
    				$ip ) );
	if ( $infos ) {
		return array(
		'lat' => $infos->latitude;
		'lng' => $infos->longitude;
		);
		// Nous obtenons aussi :
		// La ville : $infos->city_name;
		// La région : $infos->region_name;
		// Le pays : $infos->country_name;
		// Le code Pays : $infos->country_code;
	}
}

Nous avons donc obtenu les informations recherchées. Mais comme je l’évoquais en introduction, il est possible que les coordonnées retournées ne correspondent pas réellement à la localisation du visiteur, notamment s’il se connecte à partir d’un téléphone cellulaire. Si tel est le cas vous n’obtiendrez que les coordonnées de la ville où se situe le central de l’opérateur.

Cette méthode est donc à utiliser seulement dans le cas où celle dont je vais parler maintenant n’est pas disponible.

En javascript via le navigateur

Cette façon de faire est beaucoup plus simple. Elle est également relativement plus précise, puisque nous pourrons récupérer des coordonnées relatives à l’adresse exacte – et non plus de l’ordre de la ville.

Cependant, cette technique nécessite d’avoir le consentement de l’internaute pour recueillir son positionnement. Le navigateur demandera au visiteur de cliquer sur un bouton, et il nous faudra donc attendre avant de lui servir un contenu souhaité.

Nous ne pourrons donc pas précharger de contenu personnalisé pour l’internaute.

Prenons l’exemple d’un annuaire : si vous souhaitez afficher les prestataires proche du domicile de votre utilisateur, il faudra recueillir son consentement en javascript, puis charger les fiches en ajax.

L’autre petit défaut de cette méthode est qu’elle n’est accessible qu’à 97% des internautes français (IE9+).

Depuis HTML5, l’objet navigator comprend une API geolocation. C’est à elle que nous allons faire appel. Pour cela, on vérifie sa présence puis on utilise la méthode getCurrentPosition pour envoyer les coordonnées de l’internaute à une fonction javascript.

// On vérifie que la méthode est implémenté dans le navigateur
if ( navigator.geolocation ) {
	// On demande d'envoyer la position courante à la fonction callback
	navigator.geolocation.getCurrentPosition( callback, erreur );
} else {
	// Function alternative sinon
	alternative();
}

Si l’API n’est pas supportée par le navigateur, on utilisera une fonction alternative, passant par la table SQL.

En cas d’erreur, tel que le refus de l’internaute d’accéder à sa position, on passera aussi par la fonction alternative (mais nous pouvons en savoir davantage sur le soucis rencontré).

function erreur( error ) {
	switch( error.code ) {
		case error.PERMISSION_DENIED:
			console.log( 'L\'utilisateur a refusé la demande' );
			break;     
		case error.POSITION_UNAVAILABLE:
			console.log( 'Position indéterminée' );
			break;
		case error.TIMEOUT:
			console.log( 'Réponse trop lente' );
			break;
	}
	// Function alternative
	alternative();
};

Si tout va bien, la fonction de callback reçoit un objet avec quelques informations dont la latitude et la longitude du visiteur, mais également son altitude ou son sens de déplacement si celui-ci est en mouvement. Bref, cette API n’est pas vraiment compliquée 🙂

function callback( position ) {
    var lat = position.coords.latitude;
    var lng = position.coords.longitude;
    console.log( lat, lng );
    // Do stuff
}

Notre alternative utilise ce que nous avons fait au premier chapitre. On construit une fonction qui sera appelée en ajax, via admin-ajax.php, et qui renverra les coordonnées de la ville de l’internaute au format json à notre script.

add_action( 'wp_ajax_get_user_coords', 'get_user_coords_json' );
add_action( 'wp_ajax_nopriv_get_user_coords', 'get_user_coords_json' );
function get_user_coords_json() {
	$coords = get_user_coords();
	if ( $coords ) {
		wp_send_json_success( $coords );
	} else {
		wp_send_json_error();
	}
}

Notez que, comme dans tout appel à admin-ajax, il est nécessaire de pousser dans une variable javascript l’URL de la page PHP qui reçoit la requête. Pour cela il faudra utiliser la fonction wp_localize_script.

function alternative() {
	$.ajax({
		// pensez à définir le chemin vers admin-ajax.php…
		// … en front via localize_script()…
		// … au moment de l'enqueue de votre script
		url:adminajax,
		data:{
			action:get_user_coords
		}
	}).done( function( data ){
		if ( data.success ) {
			var lat = data.data.lat;
			var lat = data.data.lng;
    		console.log( lat, lng );
			// Do stuff
		}
	});
}

Vous disposez maintenant d’une technique complète pour récolter les coordonnées GPS de vos visiteurs 😀

Formulaire et API de geocoding

Il reste tout de même une ultime approche à aborder : parfois nous ne souhaitons pas réellement les coordonnées de l’internaute, mais plutôt la position du lieu qui l’intéresse. C’est le cas sur un site d’immobilier, lorsque le visiteur sélectionne une zone géographique dans laquelle il aimerait s’installer.

Bien sûr, pour parvenir à nos fins on pourrait opter pour un tri par taxonomies – et les tax_query qui vont avec – mais si la liste des villes proposées par l’agent immobilier est très complète, et le nombre de biens conséquents, nous n’allons tout de même pas demander à l’utilisateur de saisir la liste exhaustive des zones qui l’intéresse. Il pourrait en omettre et passer à côté de son rêve 😉

Le plus simple est de lui demander une ville, qui sera le point central, et trouver les coordonnées associées à cet endroit. Nous pourrons alors faire des requêtes géolocalisées pour trouver les résultats correspondants.

Nous avons besoin d’un formulaire dans lequel l’utilisateur pourra saisir sa recherche.

<form method="post" action="/">
	<label for="adresse">Recherche par adresse : </label> 
	<input type="text" name="adresse" id="adresse">	
	<button type="submit">Rechercher</button>
</form>

À la soumission de ce formulaire nous allons récupérer l’adresse voulue, envoyer une requête à l’API de geocoding de Google, et retenir la position GPS du premier résultat trouvé.

<?php
add_action( 'init', 'get_coords_from_form' );
function get_coords_from_form() {
	if ( ! is_admin()
	  && isset( $_POST['adresse'] ) ) {
	  	// On construit une URL pour envoyer une requête à l'API Google
	  	$url = 'https://maps.googleapis.com/maps/api/geocode/json';
	  	$adresse = sanitize_text_field( $_POST['adresse'] );
	  	$url = add_query_arg( array( 'address', $adresse ), $url );

	  	$requete = wp_remote_get( $url );
	  	if ( 200 == wp_remote_retrieve_response_code( $requete ) ) {
	  		$result = json_decode( wp_remote_retrieve_body( $requete ) );
	  		if ( isset( $results->results[0]->geometry->location->lat,
	  			  $results->results[0]->geometry->location->lng ) ) {
	  			$lat = $results->results[0]->geometry->location->lat;
	  			$lng = $results->results[0]->geometry->location->lng;
	  			// Do stuff
	  		}
	  	}
	}
}

La premier résultat retourné est le plus pertinent selon Google, mais attention : les villes ont des homonymes ! Pour plus de pertinence, conseillez à vos utilisateurs de saisir des adresses précises, contenant le code postal, par exemple…

Proposer des villes via l’auto-complétion

Pour éviter toute erreur de saisie et pour aider l’internaute, il est relativement simple de mettre en place un système d’auto-complétion sur le champ de saisie d’adresse.

L’API Google Maps Places met à disposition un système d’auto-complétion facile à installer.

Pour cela, dans votre fichier javascript, appelez la librairie, puis une fois qu’elle est chargée appliquez la méthode Autocomplete sur votre champ de saisie.

function doAutoComplete() {
	// On cible notre input
	var input = document.getElementById('adresse');
	var options = {
	  types: ['(cities)'], // Ne proposer que les villes
	  componentRestrictions: {country: 'fr'} // uniqument les villes françaises, d'ailleurs
	};

	autocomplete = new google.maps.places.Autocomplete( input, options );
}

// Chargement asynchrone de la librairie Goole Maps places
window.onload = function() {
	var script = document.createElement('script');
	script.type = 'text/javascript';
	script.src = 'https://maps.googleapis.com/maps/api/js?libraries=places&callback=doAutoComplete';
	document.body.appendChild(script);	
}

Il est aussi possible d’affiner l’auto-complétion, comme dans cet exemple, en restrayant les suggestions aux villes d’un pays.

Voilà, nous avons fait le tour des quelques méthodes qui vous seront utiles pour récupérer la position de vos utilisateurs, en vue certainement de les utiliser dans le cadre de requêtes WordPress par coordonnées géographiques.

8 commentaires
mo, il y a 2 années
merci , cela fonction on smartphone ?
michael, il y a 2 années
Bonjour et merci pour le tuto complet qui rentre bien dans un de mes projets mais une question me taraude :
Dans le cas d’un smartphone, un site mobile-friendly … dans mon cas, j’obtiens une localisation parisienne alors que je suis au bord de la grande bleue. Y a-t-il une astuce pour un geolocalisation plus précise ou bien la solution ne peut-être qu’une appli qui récupérerait la localisation GPS du téléphone ?
Antoine Brossault, il y a 2 années
Le fait de servir un contenu en fonction de la localisation n’est il pas dangereux pour le SEO du site ?
Google pourrait prendre cela pour du cloaking, non ?

Avez vous mis en place des noms de domaines selon les différentes versions ?

Merci de l’article en tous cas 🙂

Antoine

Willy Bahuaud, il y a 2 années
Non, je ne pense pas que Google considère cela comme du cloaking, c’est juste du contenu personnalisé en fonction de la localisation. Pour Google, rien ne changera (chaque moteur aura toujours une page de résultat locale).
Willy Bahuaud, il y a 2 années
, comme précisé dans l’article, la première méthode, qui se base sur un base d’IP ne peut pas fonctionné avec un smartphone car les IP sont attribuées au niveau central de l’opérateur téléphonique. Il vaut donc se baser sur le navigateur du client (qui lui utilisera le GPS du téléphone).
Vincent, il y a 7 mois
Salut,
si on oublie les mobiles, est-ce que selon toi, une application comme par exemple WifiMapper (elle scanne les réseaux Wifi qui sont à la portés du smartphone) peut très bien connaitre les coordonnées GPS exactes d’un internaute utilisant un desktop si ils couplent ça avec un service comme Googlemap ?
Willy Bahuaud, il y a 7 mois
J’avoue que je n’ai pas compris la question… comment une appli cellulaire pourrait détecter la position d’un utilisateur desktop ?

Les ordinateurs fixes peuvent sans soucis être géolocalisés avec les méthode décrites dans ce tutoriel. S’il s’agit de recouper ces infos de positionnement avec celle des utilisateurs mobiles (issue d’une autre système de géolocalisation), je ne vois pas le soucis. Ais-je répondu à ta question ?

Lionel, il y a 3 mois
Vraiment intéressant et complet cet article sur la géolocalisation et le traçage des visiteurs, même si cela est un légèrement trop technique pour moi, cela peut apporter des informations cruciales sur le visiteur et ainsi lui apporter une solution ultra ciblée.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Publié le 08 avril 2015
par Willy Bahuaud
Catégorie Développement WordPress