toscho.design

PHP und Google-Maps: Latitude und Longitude finden

Gerade sitze ich an einem Projekt, für das ich etwa 300 statische Google-Karten erzeugen will.

Google Staticmap: Not found

Nichts gefunden

Hierzu habe ich ebenso viele Adressen zur Hand, die ich einfach der API übergeben könnte, auf daß Google selbst die passende Position finde. Problem: Wenn nichts gefunden wird, erfahre ich das im Script nicht, sondern erst beim Ansehen des Bildes.

Da gebe ich doch lieber kein Bild aus.

Also muß ich erst prüfen, ob Google einen Ort auf der Karte finden kann, indem ich die Ortsangabe in Breiten- und Längengrade (Latitude und Longitude) umwandeln lasse. Danke an Fabian Beiner für den Tipp dazu. Meine Googlekompetenz schien gestern so eingebrochen zu sein, daß ich das nicht selbst herausfinden konnte …

/**
 * Gets the coordinates (latitude and longitude) for a place.
 * Keeps the image URI short.
 * Thanks to Fabian Beiner - http://fabian-beiner.de/ - for the tip.
 *
 * @param  string $place
 * @return string|bool
 */
function coords_by_name($place)
{
    $place   = urlencode($place);
    $url     = "http://maps.google.com/maps/geo?output=xml&q=$place";

    $content = file_get_contents($url);

    // Kein Ergebnis
    if ( FALSE == strpos($content, 'Placemark') )
    {
        return FALSE;
    }

    $xml     = new SimpleXMLElement($content);

    return $xml->Response->Placemark->Point->coordinates[0];
}

Das Ergebnis sieht im Erfolgsfall so aus: "11.9658140,51.4821660,0".

Für die statische Karte brauchen wir die letzte Angabe – ,0 – nicht; obendrein akzeptiert die API nur Angaben mit einer Genauigkeit von sechs Dezimalstellen, nicht sieben. Und wir brauchen die beiden Angaben in umgekehrter Reihenfolge für den Mittelpunkt der Karte. Da hat wohl jemand lange nachgedacht und dann Mist gebaut …

Deshalb habe ich mir einen kleinen Helfer geschrieben:

/**
 * Fixes latitude longitude coordinates.
 *
 * @param  string $s
 * @return bool
 */
function fix_coords($s)
{
    $found = (bool) preg_match(
        "~^(-?\d{1,2}\.\d{0,6})\d?,(-?\d{1,2}\.\d{0,6})\d?~",
        $s, $match
    );

    if ( ! $found )
    {
        return FALSE;
    }

    return $match[2] . ',' . $match[1];
}

Das gibt uns "11.965814,51.482166" aus, und damit können wir eine vernünftige Karte bauen.

Aber Achtung: Die Positionen der Marker muß man in umgekehrter Reihenfolge angeben!

Den aktuellen Zwischenstand habe ich eben mal auf GitHub hochgeladen: class.Google_Static_Map. Der Code wurde mir dann doch ein bißchen zu lang für einen Blogbeitrag. Dort gibt es auch einen Bugtracker für eure Hinweise oder Vorschläge, und wer Code beitragen oder einen Fork anlegen möchte, ist dazu herzlich eingeladen.

10 Kommentare

  1. Patrick am 22.04.2010 · 09:20

    Genau die Funktion habe ich auch benutzt, um die Koordinaten für meine GoogleMaps-Blogroll auszulesen. Allerdings habe ich einfach die gesamte Antwort einfach ausgegeben und mir dann die Koordinaten rauskopiert - musste halt schnell gehen :)

    Aber ich werde mal deinen Code aufgreifen und eventuell irgendwann ein brauchbares GoogleMaps-Blogroll-Plugin entwickeln.

  2. Patrick am 22.04.2010 · 09:22

    Sry nochmal was: die Möglichkeit von statischen GoogleMaps kannte ich noch garnicht. Aber ist das im Grunde genommen nicht irgendwie auch wie ein Screenshot? Die liegen nämlich rechtlich in einer Grauzone (hier zu lesen).

  3. Thomas Scholz am 22.04.2010 · 09:33

    @Patrick: Nein, das ist kein Screenshot, sondern einfach ein Bild, das beim Request von Google zusammengebaut wird. Die API, deren englische Ausgabe frischer als die deutsche ist, steht ja ganz offiziell und gleichberechtigt zu den anderen im Netz. Kein Grund zur Sorge also. Das ist keine Grauzone.

  4. Patrick am 22.04.2010 · 09:35

    Sorgen mache ich mir da nicht :) Ich meinte nur, das was man damit erzeugt sieht eigentlich genauso aus, wie ein Screenshot... Wie sollen die das unterscheiden, wenn sie jemanden verklagen wollen? :P

  5. Thomas Scholz am 22.04.2010 · 09:40

    @Patrick: Anhand der URL im src-Attribut des Bildes: Zeigt die auf http://maps.google.com/maps/api/staticmap, so ist es legal.

  6. Patrick am 22.04.2010 · 09:48

    Ach verdammt, stimmt. Daran hab ich nun gar nicht gedacht :)
    Aber ich muss sagen die API zum ermitteln der Koordinaten ist schon geil... Einfach Straße + PLZ + Ortsname übergeben und der erzeugt dir die genauen Koordinaten

  7. Andreas Fritsch am 22.04.2010 · 16:05

    Ich habe früher gern die Klasse von Monte Ohrt genutzt. Diese nutzt auch file_get_contents, um die Koordinaten zu ermitteln. Das gab bei einigen Hostern Schwierigkeiten mit den Sicherheitseinstellungen. Folgende Erweiterung hat mir geholfen und ist vielleicht auch für deine Klasse nützlich:

    function fetchURL($url) 
    {
        
        if(ini_get('allow_url_fopen')==true)
                    {
                return file_get_contents($url);
                    }else{
                        return $this->curlFetchURL($url);
                    
                    }
                    
        }
    
    function curlFetchURL($url)
        {
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_HEADER, 0);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
                $content= curl_exec($ch);
                curl_close($ch);
                return $content;
            }
  8. Thomas Scholz am 22.04.2010 · 18:56

    @Andreas Fritsch: Vielen Dank, habe ich gleich eingebaut.

  9. Gerlach am 11.12.2010 · 15:09

    erbarmt sich hier jemand und sagt wie ich den Code coords_by_name nun einsetze? - Ich kann zwar php, js, ... aber zusammen mit google habe ich das noch nicht verwendet. Wo fange ich an?
    Gruss Eckard

  10. Thomas Scholz am 11.12.2010 · 17:53

    @Gerlach: Du bekommst die Koordinaten zu einem Ort durch die Kombination beider Funktionen:

    $place  = 'Berlin, Alexanderplatz';
    $coords = fix_coords( coords_by_name( $place ) );

    Ich rate dir aber zum Einsatz der PHP-Klasse; das ist der Code, den ich ab und zu pflege.