Геотаргетинг и геолокация на PHP

Author Автор: Роман Чернышов    Опубликовано: 6 октября 2012

Одной из очень полезных функций может послужить возможность определения географического расположения пользователя вошедшего, к примеру, на ваш сайт. Такая возможность часто используется в сайтах с несколькими языками или валютами, если речь идет об интернет магазине. Все что нужно в таком случае это определить страну и город вошедшего пользователя и отобразить соответствующие ему данные, язык, валюту или погоду в его городе.

В 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

Данный скрипт использовался мною при разработке одного из финансовых порталов, где и по сей день замечательно справляется со своими обязанностями, при трафике несколько тысяч уников в сутки.

Надеюсь данный пост-заметка будет полезным для вас.

3 комментария to “Геотаргетинг и геолокация на PHP”

  • Конструктор 25.09.2016 в 1:55 дп

    Может есть смысл закешировать все IP у себя в базе и отдавать данные уже из нее?
    А по ночам неторопясь обновлять эти данные из оригинального источника.

    Насколько точная информация по городам России?

    • Роман Чернышов 05.10.2016 в 5:20 пп

      Да, смысл кеширования есть, можно реализовать. Точность определения зависит от актуальности данных в базе Geoplugin, думаю она на приемлемом уровне, но разумеется не 100%.

  • Дмитрий 04.11.2016 в 1:52 дп

    Код проверил, всё работает, но не так как хотелось бы. Через выделенку — ошибка в 70км город выдал, а Билайн вообще не дал даже регион…Но всё же возьму на заметку, прикольный прибамбас можно соорудить. Спасибо))

Оставить комментарий

Автор блога
Чернышов Роман
Роман Чернышов
Веб-разработчик, Full Stack
Senior, Architector
PHP, JavaScript, Python, HTML 5, CSS 3, MySQL, Bash, Linux Admin
Заказать работу
предложить оффер

Последние вопросы
Список вопросов
Последние комментарии
Меню

Archive

Мои проекты
Insurance CMS Love Crm CMS Совместные покупки Мой PHP Framework Хостинг для моих клиентов Лицензии на мой софт и поддержка