Geolokalizacja w PHP

#TeamSpeednet
January 6, 2016

Co możemy zyskać?

Informacje o tym, gdzie jestem? Gdzie jest najbliższy sklep i czy jest otwarty? Gdzie i kiedy jest najbliższa msza? Gdzie jest najbliższy bankomat mojego banku? Gdzie jest najbliższy przystanek SKM i za ile mam kolejkę?

Na te wszystkie pytania może odpowiedzieć właśnie geolokalizacja, jeśli tylko potrafimy stworzyć odpowiednią bazę danych, która wykorzysta dane geo.
Wtedy wystarczy, że użytkownik wejdzie na adres naszej aplikacji i od razu zobaczy odpowiedź. Nie musi nic dodatkowo robić. Szybko, przyjemnie, bez dodatkowych narzutów.

Czy to trudne?

Wydaje mi się, że większość z nas nigdy nie rozpoczęła przygody z geolokalizacją, ponieważ uważa że jest to trudne w implementacji. To jest błędne myślenie. Cały trud obecnie jest przerzucony na takie firmy jak IP2Location czy MaxMind, które dostarczają nam bazy danych z informacjami wiążącymi adresy IP z położeniem geograficznym.

Implementacja

Obecnie najprościej jest skorzystać z rozwiązania firmy IP2Location, która dostarcza kompletną bibliotekę dla języka PHP. Wystarczy w Composer dodać wymaganie dla pakietu “ip2location/ip2location-php” w wersji “7.*”.
Dodatkowo musimy w aplikacji lub systemie umieścić plik binarny z informacjami dot. lokalizacji bazującej na adresie IP. Wersje “demo” bibliotek prezentowane na stronie są dla nas (Polaków) bezużyteczne, ponieważ zawierają dane tylko w zakresie 0.0.0.0-99.255.255.255.
Ale nic straconego. Można pobrać wersję “Lite” bazy, polecam DB11.Lite. Po podaniu naszych danych na ich stronie internetowej na wskazany przez nas adres e-mail zostanie wysłany link do pliku.

Gdy już posiadamy bazę danych, nasz przykładowy kod w PHP może wyglądać następująco:

require 'vendor/autoload.php';

$ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '213.192.107.210';
$dbFile = './databases/IP2LOCATION-LITE-DB11.BIN';

$db = new IP2LocationDatabase($dbFile, IP2LocationDatabase::FILE_IO);
$records = $db->lookup($ip, IP2LocationDatabase::ALL);

echo 'IP Address            : ' . $records['ipAddress'] . PHP_EOL;
echo 'Country Code          : ' . $records['countryCode'] . PHP_EOL;
echo 'Country Name          : ' . $records['countryName'] . PHP_EOL;
echo 'Region Name           : ' . $records['regionName'] . PHP_EOL;
echo 'City Name             : ' . $records['cityName'] . PHP_EOL;
echo 'Latitude              : ' . $records['latitude'] . PHP_EOL;
echo 'Longitude             : ' . $records['longitude'] . PHP_EOL;

Gdy wykonamy powyższy kod, to dowiemy się, że Speednet (IP: 213.192.107.210) mieści się w Gdyni wg bazy danych IP2Location:

$ php geo.php
IP Address            : 213.192.107.210
Country Code          : PL
Country Name          : Poland
Region Name           : Pomorskie
City Name             : Gdynia
Latitude              : 54.518890380859
Longitude             : 18.531879425049

Oczywiście dokładność lokalizacji (jeśli tak można się wyrazić) zależy od aktualności naszej bazy danych. Osobiście nie spotkałem się jeszcze z problemem rozwinięcia adresu IP na lokalizację, jeśli odbywało się to dla stacjonarnego połączenia internetowego.
W przypadku mobilnego połączenia, bez możliwości GPS, powinniśmy dodatkowo w naszej aplikacji umożliwić lokalizację użytkownika samemu wg wskazania np. na mapie.

Lokalizacja na podstawie współrzędnych

W przypadku gdy łączy się z nami przeglądarka mobilna (rozpoznanie na poziomie serwera, lub warunki na USER-AGENT w aplikacji) od razu możemy spróbować wydobyć od użytkownika współrzędne geograficzne. W Internecie jest wiele przykładów jak pobrać dane lokalizacyjne Lat/Lon w JavaScript. HTML5 udostępnia prosty mechanizm navigator.geolocation.getCurrentPosition (przykład na GitHub).
Gdy już posiadamy w aplikacji zmienne Lat/Lon możemy posłużyć się GuzzleHttp i spróbować pobrać dane o lokalizacji np. z serwisu OpenStreetMap, który zwraca prosty w przetwarzaniu JSON.

Plusem posiadania danych Lat/Lon jest dokładniejsza lokalizacja. Na podstawie adresu IP dostajemy tylko współrzędne centrum miasta, w przypadku gdy uzyskujemy Lat/Lon z GPSa wiemy “dokładnie” na jakiej ulicy znajduje się użytkownik. A oto przykład w PHP:

require 'vendor/autoload.php';

$lat = 54.49;
$lon = 18.54;

$uri = 'https://nominatim.openstreetmap.org/reverse?format=json&zoom=18&lat=' . $lat . '&lon=' . $lon;
$client = new GuzzleHttpClient();
$response = $client->request('GET', $uri);
$content = $response->getBody()->getContents();

$json = json_decode($content);
if (!is_object($json) || !property_exists($json, 'address')) {
    die('Problem with response from OpenStreetMap' . PHP_EOL);
}

echo 'Country Code          : ' . $json->address->country_code . PHP_EOL;
echo 'Country Name          : ' . $json->address->country . PHP_EOL;
echo 'Region Name           : ' . $json->address->state . PHP_EOL;
echo 'City Name             : ' . $json->address->city . PHP_EOL;
echo 'Street                : ' . $json->address->road . PHP_EOL;

Gdy wykonamy powyższy kod otrzymamy następujące dane:

$ php coordinates.php
Country Code          : pl
Country Name          : Polska
Region Name           : pomorskie
City Name             : Gdynia
Street                : Aleja Zwycięstwa

Teraz wiemy, że firma Speednet nie tylko znajduje się w Gdyni, ale również przy Al. Zwycięstwa.

Przykładowy kod znajdziecie na naszym GitHubie.

Chcesz poznać nas lepiej? Dowiedz się, co nas wyróżnia.