Геотаргетинг и геолокация на PHP
Одной из очень полезных функций может послужить возможность определения географического расположения пользователя вошедшего, к примеру, на ваш сайт. Такая возможность часто используется в сайтах с несколькими языками или валютами, если речь идет об интернет магазине. Все что нужно в таком случае это определить страну и город вошедшего пользователя и отобразить соответствующие ему данные, язык, валюту или погоду в его городе.
В PHP существует целый ряд функций для работы с геолокацией и геотаргетингом, так называемые: GeoIP Функции, позволяющие определить все необходимые нам параметры расположения посетителя. Но для их работы требуется соответствующий модуль PHP, который зачастую отключен и не поддерживается на большинстве недорого хостинга.
В виду чего, хочу познакомить вас с PHP скриптом(классом), который работает по принципу определения гео-информации о посетителе, путем отправки запроса с указанием IP адреса, на сторонний сервер geoplugin.net, который в свою очередь возвращает исчерпывающую информацию о месторасположении.
Благодаря данному скрипту, есть возможность получения следующей информации по IP аресу пользователя:
- Город расположения пользователя
- Регион расположения пользователя
- Почтовый индекс
- Код страны
- Координаты широты и долготы
- Символ валюты
- Курс местной валюты по отношению к доллару Сша
Одним из приятных дополнением является возможность получения информации о ближайших населенных пунктах, что можно использовать также в собственных целях.
Пример работы скрипта
require_once('geoplugin.class.php'); $geoplugin = new geoPlugin(); //locate the IP $geoplugin->locate(); // думаю нижеследующий блок не нуждается в пояснениях, из его кода видно какие значения возвращает нам скрипт echo "Geolocation results for {$geoplugin->ip}: <br />\n". "City: {$geoplugin->city} <br />\n". "Region: {$geoplugin->region} <br />\n". "Area Code: {$geoplugin->areaCode} <br />\n". "DMA Code: {$geoplugin->dmaCode} <br />\n". "Country Name: {$geoplugin->countryName} <br />\n". "Country Code: {$geoplugin->countryCode} <br />\n". "Longitude: {$geoplugin->longitude} <br />\n". "Latitude: {$geoplugin->latitude} <br />\n". "Currency Code: {$geoplugin->currencyCode} <br />\n". "Currency Symbol: {$geoplugin->currencySymbol} <br />\n". "Exchange Rate: {$geoplugin->currencyConverter} <br />\n"; |
Обратите внимание на метод $geoplugin->locate(), он вызывается с пустым значением, в результате чего IP берется из переменной $_SERVER, но мы можем передать в этоть метод собственное значение, например IP адрес из базы данных(сохраненный ранее), пример: $geoplugin->locate(‘123.123.255.255’), в результате получим информацию по нему.
Листинг класса geoPlugin
class geoPlugin { //the geoPlugin server var $host = 'http://www.geoplugin.net/php.gp?ip={IP}&base_currency={CURRENCY}'; //the default base currency var $currency = 'USD'; //initiate the geoPlugin vars var $ip = null; var $city = null; var $region = null; var $areaCode = null; var $dmaCode = null; var $countryCode = null; var $countryName = null; var $continentCode = null; var $latitute = null; var $longitude = null; var $currencyCode = null; var $currencySymbol = null; var $currencyConverter = null; function geoPlugin() { } function locate($ip = null) { global $_SERVER; if ( is_null( $ip ) ) { $ip = $_SERVER['REMOTE_ADDR']; } $host = str_replace( '{IP}', $ip, $this->host ); $host = str_replace( '{CURRENCY}', $this->currency, $host ); $data = array(); $response = $this->fetch($host); $data = unserialize($response); //set the geoPlugin vars $this->ip = $ip; $this->city = $data['geoplugin_city']; $this->region = $data['geoplugin_region']; $this->areaCode = $data['geoplugin_areaCode']; $this->dmaCode = $data['geoplugin_dmaCode']; $this->countryCode = $data['geoplugin_countryCode']; $this->countryName = $data['geoplugin_countryName']; $this->continentCode = $data['geoplugin_continentCode']; $this->latitude = $data['geoplugin_latitude']; $this->longitude = $data['geoplugin_longitude']; $this->currencyCode = $data['geoplugin_currencyCode']; $this->currencySymbol = $data['geoplugin_currencySymbol']; $this->currencyConverter = $data['geoplugin_currencyConverter']; } function fetch($host) { if ( function_exists('curl_init') ) { //use cURL to fetch data $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $host); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_USERAGENT, 'geoPlugin PHP Class v1.0'); $response = curl_exec($ch); curl_close ($ch); } else if ( ini_get('allow_url_fopen') ) { //fall back to fopen() $response = file_get_contents($host, 'r'); } else { trigger_error ('geoPlugin class Error: Cannot retrieve data. Either compile PHP with cURL support or enable allow_url_fopen in php.ini ', E_USER_ERROR); return; } return $response; } function convert($amount, $float=2, $symbol=true) { //easily convert amounts to geolocated currency. if ( !is_numeric($this->currencyConverter) || $this->currencyConverter == 0 ) { trigger_error('geoPlugin class Notice: currencyConverter has no value.', E_USER_NOTICE); return $amount; } if ( !is_numeric($amount) ) { trigger_error ('geoPlugin class Warning: The amount passed to geoPlugin::convert is not numeric.', E_USER_WARNING); return $amount; } if ( $symbol === true ) { return $this->currencySymbol . round( ($amount * $this->currencyConverter), $float ); } else { return round( ($amount * $this->currencyConverter), $float ); } } function nearby($radius=10, $limit=null) { if ( !is_numeric($this->latitude) || !is_numeric($this->longitude) ) { trigger_error ('geoPlugin class Warning: Incorrect latitude or longitude values.', E_USER_NOTICE); return array( array() ); } $host = "http://www.geoplugin.net/extras/nearby.gp?lat=" . $this->latitude . "&long=" . $this->longitude . "&radius={$radius}"; if ( is_numeric($limit) ) $host .= "&limit={$limit}"; return unserialize( $this->fetch($host) ); } } |
Недостатки данного решения
— Зависимость от стороннего сервиса, при его недоступности соответственно будет недоступна гео информация.
— Скорость получения данных не так высока, в сравнении если бы они хранились в БД
Преимущества данного решения
— Всегда актуальные данные, не нужно заботиться об обновлении баз IP
— Расширенные сведения, которые было-бы не так просто хранить и модерировать в собственной БД
— Простота исполнения и подключения к любому сайту, не требуются ни какие дополнительные модули PHP
Данный скрипт использовался мною при разработке одного из финансовых порталов, где и по сей день замечательно справляется со своими обязанностями, при трафике несколько тысяч уников в сутки.
Надеюсь данный пост-заметка будет полезным для вас.

Автор:







Может есть смысл закешировать все IP у себя в базе и отдавать данные уже из нее?
А по ночам неторопясь обновлять эти данные из оригинального источника.
Насколько точная информация по городам России?
Да, смысл кеширования есть, можно реализовать. Точность определения зависит от актуальности данных в базе Geoplugin, думаю она на приемлемом уровне, но разумеется не 100%.
Код проверил, всё работает, но не так как хотелось бы. Через выделенку — ошибка в 70км город выдал, а Билайн вообще не дал даже регион…Но всё же возьму на заметку, прикольный прибамбас можно соорудить. Спасибо))