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.