PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


GeoLocation mit modernen Browsern

with 8 comments

Der ein oder andere von euch hat vielleicht schonmal mit GeoLocations experimentiert. Es gibt freie GeoDatenbanken und GeoIP-Datenbanken, mit denen man eine IP-Adresse umwandeln kann in einen Ort (bzw. Region/Land).

Als ich nun vor einigen Monaten hörte, dass der Firefox bald eine neue GeoLocation-Funktionalität erhält, womit dann viele neue standortabhängige Dienste möglich sind, war ich gespannt was tolles neues dabei rauskommt. Zuerst dachte ich, dass man im Browser seine Daten eingibt, und dann sendet das der Browser an die Webseite, falls die das wissen möchte.

Doch ich habe die Rechnung ohne die ganzen mobilen Geräte gemacht, für die das Feature primär interessant ist (ich selbst habe zwar einen PDA, aber keinen Internet-Daten-Tarif, deshalb hab ich daran nicht wirklich gedacht).

Was kann das Feature nun? Es passiert folgendes: Falls die Webseite die GeoLocation ermitteln möchte, bekommt der Benutzer eine Frage präsentiert:

geolocation1

Man kann dann entscheiden, ob man diese Informationen senden möchte oder nicht. Falls man „Ja“ klickt, wird die IP-Adresse an einen Google-Service geschickt. Außerdem werden noch GPS-Informationen und erreichbare WLAN-Netze (incl. ermittelter Empfangsstärke) versendet an Google Location Services. Daraus kann Google dann eine mehr oder weniger genaue Position ermitteln (bei GPS natürlich sehr genau bis auf wenige Meter, bei WLAN-Informationen kann es auch schon sehr ungenau werden, je nachdem wieviele WLANs da sind und ob diese bereits kartographiert wurden).

Diese Standort-Information erhält dann der Browser, und dann kann diese Information mittels Javascript API abgefragt werden. Das hier sind die Informationen, die man erhält:

geolocation3

Man erhält also die Angaben in Form von Latitude und Longitude, sowie evtl. weitere GPS-Informationen wie Höhe, Geschwindigkeit usw. Falls man diese Informationen in einen Ortsnamen umwandeln möchte, benötigt man entweder wieder eine Datenbank mit Informationen oder man nutzt einen Webservice, der das selbe tut.
In meiner Demo nutze ich letzteres, und lasse anhand der Latitude/Longitude den Namen der Stadt ermitteln, dazu nutze ich www.geonames.org.

Inklusive Stadt sieht das Endergebnis dann so aus:

geolocation5

Wie sieht das nun im Quelltext aus? Eigentlich sehr übersichtlich:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>

    <title>PHP Gangsta Geolocation</title>
    <SCRIPT TYPE="text/javascript" SRC="http://ajax.googleapis.com/ajax/libs/dojo/1.3/dojo/dojo.xd.js"></SCRIPT>

    <script type="text/javascript">
        function startgeolocation() {
            // Check for geoLocation Support
            if (navigator.geolocation) {
                // the location is looked up only once
                navigator.geolocation.getCurrentPosition(renderPosition, renderError);
                // every time the location changes
                // navigator.geolocation.watchPosition(renderPosition, renderError);
            } else {
            	dojo.byId('geoResults').innerHTML = '<p>Your browser does not support geolocation.</p>';
            }
        }

        // I use Dojo to render the output and do an AJAX call to get city name
        function renderPosition(position) {
            if (!window.count) window.count = 0;

            count ++;
            // var urlJSON = 'http://ws.geonames.org/findNearbyPlaceNameJSON?lat=-36.9104718&lng=174.9133483';
            var urlJSON = 'geonames.php?lat='+position.coords.latitude+'&lon='+position.coords.longitude;

            dojo.byId('d').innerHTML = '<div id="results" style="width: 200px; height: 200px; text-align: left"><p>'
                            + 'Latitude: ' + position.coords.latitude + '<br />'
                            + 'Longitude: ' + position.coords.longitude + '<br />'
                            + 'Accuracy: ' + position.coords.accuracy + '<br />'
                            + 'Update number: ' + count + '<br />'
                            + 'Altitude: ' + position.coords.altitude + '<br />'
                            + 'Altitude accuracy: ' + position.coords.altitudeAccuracy + '<br />'
                            + 'Heading: ' + position.coords.heading + '<br />'
                            + 'Speed: ' + position.coords.speed + '<br />'
                            + 'Google Maps: <a href="http://maps.google.com/maps?geocode=&q=' +
                            			position.coords.latitude + '+' + position.coords.longitude +
                            			'">Click</a><br />'
                            + '</p></div>';

            // now get the XML reverse geo data
           dojo.xhrGet( { //
		        // The following URL must match that used to test the server.
		        url: urlJSON,
		        handleAs: "json",
		        timeout: 5000, // Time in milliseconds
		        // The LOAD function will be called on a successful response.
		        load: function(responseObject, ioArgs) {
		        	for each (var item in responseObject.geonames) {
		        		dojo.byId('jsonResults').innerHTML = '<p>You live in: ' + item.name + '</p>';
		        	}
		          	return responseObject;
		        },
		        // The ERROR function will be called in an error case.
		        error: function(responseObject, ioArgs) { //
		          	console.error("HTTP status code: ", ioArgs.xhr.status); //
		          	return responseObject;
	          	}
		    });
        }

        function renderError() {
        	dojo.byId('geoResults').innerHTML = '<p>The page could not get your location.</p>';
        }
    </script>
</head>

<body onload="startgeolocation();">

	<div align="center">
	<h1>GeoLocation Demo</h1>
	<div id="geoResults">
	    <div id="d"><img src="loadingAnimation.gif" /></div>
	    <div id="jsonResults">city information are fetched...</div>
	</div>

</body>
</html>

Das einzig verwunderliche ist vielleicht der AJAX-Aufruf. Ich hatte ja geschrieben, dass ich den Namen der Stadt von geonames.org holen möchte. Da die Cross-Domain-Policy nur einen Ajax-Aufruf zum selben Server erlaubt, brauchen wir ein kleines „Proxy-Script“, welches so aussieht:

<?php
echo file_get_contents('http://ws.geonames.org/findNearbyPlaceNameJSON?lat='.$_GET['lat'].'&lng='.$_GET['lon']);
?>

Damit umgehen wir die Cross-Domain-Policy und erhalten unser Ergebnis in JSON-Form. Das war auch schon der ganze Zauber.

Aktuell beherrschen meines Wissens nach der Firefox 3.5, Chrome und die aktuellen Beta-Versionen von Safari und Opera diese Funktionalität. Google Gears bietet eine ähnliche Funktionalität (browserübergreifend), aber ich kennen niemanden, der Gears installiert hat.
Man kann übrigens im Firefox den Location Service ändern, falls man Google nicht mag:
geolocation4

Falls ihr ein Handy mit Internet habt, könnt ihr auch mal Google Maps Mobile ausprobieren. Außerdem könnt ihr hier mein Demo-Script ausprobieren.

Ich bin gespannt, was für interessante Dienste da bald aus dem Boden sprießen. Ich meine schonmal etwas gehört zu haben von „gucken wo Freunde gerade sind“ und sowas. Ich bin auch gespannt, wann ich endlich ein neues Handy mit Datentarif bekomme…

Written by Michael Kliewe

September 10th, 2009 at 10:33 am

Posted in PHP

Tagged with , ,

8 Responses to 'GeoLocation mit modernen Browsern'

Subscribe to comments with RSS or TrackBack to 'GeoLocation mit modernen Browsern'.

  1. Das Demo-Script kann nicht auf dem iPhone ausgeführt werden. Bekomme nichtmal das Abfrage-Popup ob ich „meinen Standort übermitteln“ möchte. 🙂
    Das iPhone ist jedoch die momentan wichtigeste Platform für eine GPS-Basierte Webanwendung wie ich finde.

    Hier ist etwas, das sehr gut funktioniert:
    http://smithsrus.com/gps-geolocation-in-safari-on-iphone-os-3-0/

    Sven

    10 Sep 09 at 10:58

  2. Hi

    welchen Browser hast du denn da in welcher Version?

    Die Seite, die du da genannt hast, basiert auf den selben JavaScript-Funktionen. Eigentlich müßte entweder beides oder keines funktionieren…

    Bekommst du JavaScript-Fehlermeldungen? Kann der Browser evtl. kein Ajax (würde mich stark wundern)?

    Michael Kliewe

    10 Sep 09 at 11:26

  3. Auf dem iPhone läuft ein Safari. Hab mal die Fehlerconsole eingeschaltet und hier findest du die Ausgabe:

    http://s2.directupload.net/file/d/1913/sii4wi58_jpg.htm

    Sven

    10 Sep 09 at 12:13

  4. OK, danke dafür!

    Es ist anscheinend die Zeile 51 im HTML-Code, die in deinem Safari Probleme macht:
    for each (var item in responseObject.geonames) {

    Im Firefox kommt es da nicht zu einem Parse-Error. Wie dem auch sei, ich habe die Zeile mal geändert:
    for (item in responseObject.geonames) {

    Bitte probier es nochmal aus. Im Firefox funktioniert es nach wie vor. Achte darauf, dass auch die neue Version geladen wird (prüfe den Quelltext in Zeile 51).

    Bin gespannt!

    Michael Kliewe

    10 Sep 09 at 12:21

  5. Klappt nun – nur das er meinen Ort nicht gefunden hat.

    „You live in: undefined“
    🙂

    Sven

    10 Sep 09 at 12:33

  6. Gab es noch Javascript-Fehler?
    Dann gib mal deine Longitude und Latitude, dann schau ich mal warum geonames da nichts liefert…

    Michael Kliewe

    10 Sep 09 at 12:36

  7. An geonames liegt es nicht, der liefert mit den Standort richtig zurück. Hab es eben selbst mal getestet mit den Longitude und Latitude-Werten die ich angezeigt bekomme. Auch er Maps-Link funktioniert.

    Leider hat der Safari 4.0.x für Windows und Mac noch keine Geounterstützung, daher fällt das debuggen flach. Wenn ich mir den Code genauer anschaue, könnte es höchstens sein das Dojo für den XHR-Request eine vollständige URL benötigt, also mit vorangestellten „http://“… sonst hab ich grad keine Idee.

    Sven

    10 Sep 09 at 12:57

  8. Ups, Fehlermeldungen gibt es keine. Dachte ich hätte das schon vorhin erwähnt. Habs wohl vergessen zu schreiben 🙂

    Sven

    10 Sep 09 at 12:58

Leave a Reply

You can add images to your comment by clicking here.