Геотаргетинг и геолокация на 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, Architect
PHP, JavaScript, Node.JS, Python, HTML 5, CSS 3, MySQL, Bash, Linux Admin
Заказать работу
предложить оффер

Моя книга
Книга. Веб-разработчик. Легкий вход в профессию
Печатная книга
Веб-разработчик.
Легкий вход в профессию
Купить за 159₽
Последние вопросы
Список вопросов
Последние комментарии
Меню

Archive

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