Geocoding to przeliczenie adresu na współrzędne – długość i szerokość geograficzną. Z pomocą przyjdzie nam google i nie tylko.
Zdarza się, że mamy bazę klientów, sklepów itp, którzy podają adresy. Chcemy pokazać ich na mapie. Możemy oczywiście znajdować każdy z adresów w google maps a potem ręcznie przepisywać współrzędne. Ale nie tędy droga. Skorzystamy z automatu.
Google geocoder
Google API udostępnia nam usługę geocodingu. Jeśli mamy adres, np nazwę miejscowości „Kozia Wólka”, możemy wywołać specjalny adres:
https://maps.googleapis.com/maps/api/geocode/json?address=Kozia+Wólka
W odpowiedzi dostaniemy JSON. Jeśli pole status będzie zawierać „OK” to możemy odczytać współrzędne w results[0].geometry.location.lat
i results[0].geometry.location.lon
. Pełny JSON jest dość spory i wygląda tak:
{ "results" : [ { "address_components" : [ { "long_name" : "Kozia Wólka", "short_name" : "Kozia Wólka", "types" : [ "locality", "political" ] }, { "long_name" : "Gmina Małdyty", "short_name" : "Gmina Małdyty", "types" : [ "administrative_area_level_3", "political" ] }, { "long_name" : "Ostróda County", "short_name" : "Ostróda County", "types" : [ "administrative_area_level_2", "political" ] }, { "long_name" : "Warmian-Masurian Voivodeship", "short_name" : "Warmian-Masurian Voivodeship", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "Poland", "short_name" : "PL", "types" : [ "country", "political" ] } ], "formatted_address" : "Kozia Wólka, Poland", "geometry" : { "location" : { "lat" : 53.9205064, "lng" : 19.8601681 }, "location_type" : "APPROXIMATE", "viewport" : { "northeast" : { "lat" : 53.9336464, "lng" : 19.8921829 }, "southwest" : { "lat" : 53.9073623, "lng" : 19.8281533 } } }, "place_id" : "ChIJzdU8wvmh4kYRF5i4KWQ7I5E", "types" : [ "locality", "political" ] } ], "status" : "OK" }
Zamiast OK możemy dostać inne statusy. Np „ZERO_RESULTS„, „OVER_QUERY_LIMIT„, „REQUEST_DENIED” itp.
Właśnie status OVER_QUERY_LIMIT jest interesujący. Google nie pozwala na wysyłanie więcej niż 2500 zapytań dziennie i więcej niż 5 na sekundę.
Lepiej jest zapisać dane do cache. Radzę też nie testować działania na dużych paczkach danych bo szybko wyczerpiemy limit.
Geocoder w PHP
Zamiast pytać google, lepiej użyć gotowca. W sieci dostępna jest świetna biblioteka geocoder-php/Geocoder. Dzięki niej możemy korzystać z wielu różnych serwisów do geocodingu.
Instalujemy bibliotekę composerem:
composer require willdurand/geocoder
A potem w pliku, np. index.php dekodujemy:
require 'vendor/autoload.php'; // potrzebujemy bibliotekę pobierającą http w standardzie PSR-7 $curl = new \Ivory\HttpAdapter\CurlHttpAdapter(); // tworzymy geocoder do google maps $geocoder = new \Geocoder\Provider\GoogleMaps($curl); // dekodujemy $result = $geocoder->geocode("Kozia Wólka"); // zobaczmy co dostaniemy var_dump($result);
W ten sposób pobraliśmy dane z Google Map. Biblioteka daje nam więcej providerów. Wystarczy napisać:
$geocoder = new \Geocoder\Provider\OpenStreetMap($curl); $result = $geocoder->geocode("Kozia Wólka");
Jeśli zechcemy korzystać z kilku providerów naraz – nic nie stoi na przeszkodzie. Dostępny jest agregator:
$geocoder = new \Geocoder\ProviderAggregator(); $geocoder->registerProviders([ new \Geocoder\Provider\OpenStreetMap($curl), new \Geocoder\Provider\GoogleMaps($curl) ]);
Możemy teraz pobierać dane wybierając provider:
$result = $geocoder->with('openstreetmap')->geocode('Kozia Wólka');
Co dalej?
Warto poczytać dokumentację biblioteki geocoder. Do dyspozycji mamy kilkanaście providerów. Jeśli jeszcze nam mało, możemy dołączyć Geocoder Extra z kolejnymi. Możemy też skorzystać z gotowego bundla dla Symfony BazingaGeocoderBundle.
Warto poczytać dokumentację bibloteki. Wszystkie providery zwracają dane w tym samym formacie. Możemy definiować limity liczby odpowiedzi itd. Bundle dla symfony pozwala nam też zdefiniować cache.