О двух способах работы геолокации (GeoIP) в PHP

// Май 10th, 2011 // PHP, Веб-разработка

Мы начинаем потихоньку привыкать к Web 2.0 сайтам. Удобный (местами минималистический) дизайн, скруглённые уголки, тени, контент, генерируемый пользователем. А что главное с точки зрения юзабилити в w2.0-сайте? Не заставлять пользователя совершать лишние движения. Надо максимально облегчить ему процесс использования сайтом. Например, если в форме регистрации можно автоматически определить страну и город — зачем заставлять пользователя листать километровые списки?

В этой статье пойдёт речь о геолокации (определении местоположения пользователя) средствами PHP.

В нашей компании встала задача рефакторинга форм. Визуально они слишком перегружены, много лишних (но нужных) полей. Например, поля выбора страны и города. Список как стран, таки городов довольно внушителен, и пользователь тратит много времени, чтобы выбрать подходящий пункт. Это может оттолкнуть его от заполнения формы. Наша задача — определить его страну и город автоматически.

Задачу можно решить двумя способами: на уровне сервера приложений (PHP) и ну уровне веб-сервера (Nginx). Сам я рекомендую вам вариант с Nginx, а первый вы можете посмотреть в качестве альтернативы.

Геолокация на PHP

 

1. Качаем базу стран (в пакете geoip-database), городов, модуль для php и устанавливаем их в систему. Используется база MaxMind.

sudo apt-get install geoip-database libgeoip-dev php5-geoip
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
sudo mkdir -v /usr/share/GeoIP
sudo mv -v GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat

2. Проверяем, чтобы расширение php было подключено (/etc/php5/fpm/conf.d) и перезагружаем интерпретатор

sudo service php5-fpm restart

3. Проверяем установку, запустив в броузере скриптик.

array(11) {
  ["continent_code"]=>
  string(2) "AS"
  ["country_code"]=>
  string(2) "RU"
  ["country_code3"]=>
  string(3) "RUS"
  ["country_name"]=>
  string(18) "Russian Federation"
  ["region"]=>
  string(2) "48"
  ["city"]=>
  string(6) "Moscow"
  ["postal_code"]=>
  string(0) ""
  ["latitude"]=>
  float(55.752201080322)
  ["longitude"]=>
  float(37.615600585938)
  ["dma_code"]=>
  int(0)
  ["area_code"]=>
  int(0)
}

Узнать код страны можно с помощью этой команды:

$country_code = geoip_record_by_name($_SERVER['REMOTE_ADDR']);

Также есть много других интересных функций этого расширения.

  • geoip_continent_code_by_name — Получить двухбуквенный код континента
  • geoip_country_code_by_name — Получить двухбуквенный код страны
  • geoip_country_code3_by_name — Получить трехбуквенный код страны
  • geoip_country_name_by_name — Возаращает полное название страны
  • geoip_database_info — Получить версию БД GeoIP
  • geoip_db_avail — Проверить доступность БД GeoIP
  • geoip_db_filename — Возвращает имя файла БД GeoIP
  • geoip_db_get_all_info — Возвращает всю информацию о файлах БД в виде многомерного массива
  • geoip_id_by_name — Возвращает скоростную метрику интернет-канала пользователя (GEOIP_UNKNOWN_SPEED/GEOIP_DIALUP_SPEED/GEOIP_CABLEDSL_SPEED/GEOIP_CORPORATE_SPEED ).
  • geoip_isp_by_name — Возвращает имя провайдера (ISP) пользователя
  • geoip_org_by_name — Возвращает имя организации, за которой закреплен IP пользователя.
  • geoip_record_by_name — Возвращает информацию о местоположении пользователя (континент, страна, город, широта и долгота).
  • geoip_region_by_name — Возвращает код страны и региона
  • geoip_region_name_by_code — Возвращает название региона страны и код региона
  • geoip_time_zone_by_country_and_region — Возвращает часовой пояс клиента (по вычисленной стране и региону).

Геолокация в NGINX

 

Первый вариант геолокации весьма неплох. Это PECL расширение (geoip.so) поэтому, думается, оно работает довольно шустро. Однако может понадобиться вариант, когда нужно проводить маршрутизацию запросов веб-приложения в зависимости от местоположения (или языка) пользователя. Тут нам на помощь придёт модуль nginx HttpGeoIPModule. Устанока будет производиться на Nginx +php5_fpm (и у меня уже есть его конфиг).

1. Ставим базу GeoIP. Страны есть в deb-пакете, города качаем отдельно.

sudo apt-get install geoip-database libgeoip-dev
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
sudo mkdir -v /usr/share/GeoIP
sudo mv -v GeoLiteCity.dat /usr/share/GeoIP/GeoIPCity.dat

2. Добавляем в /etc/nginx/nginx.conf в секцию http строки:

http {
....
    # GeoIP
    geoip_country  /usr/share/GeoIP/GeoIP.dat; # the country IP database
    geoip_city     /usr/share/GeoIP/GeoLiteCity.dat; # the city IP database
..
}

2. В файл /etc/nginx/fastcgi_params добавляем переменные, котоыре будут прокидываться в массив $_SERVER веб-приложения:

# For GeoIP
fastcgi_param GEOIP_COUNTRY_CODE 	$geoip_country_code;
fastcgi_param GEOIP_COUNTRY_NAME 	$geoip_country_name;
fastcgi_param GEOIP_REGION		$geoip_region;
fastcgi_param GEOIP_CITY		$geoip_city;
fastcgi_param GEOIP_POSTAL_CODE 	$geoip_postal_code;
fastcgi_param GEOIP_CITY_CONTINENT_CODE $geoip_city_continent_code;
fastcgi_param GEOIP_LATITUDE    	$geoip_latitude;
fastcgi_param GEOIP_LONGITUDE		$geoip_longitude;

Важно, чтобы инклюд этого файла «include /etc/nginx/fastcgi_params;» был указан в location секциях конфига вашего виртуального хоста Nginx.

3. Перезапускаем сервер, пишем простенький скрипт:

sudo service nginx restart

Варианты ответов:

  • ‘RU’ — всё работает. Ваша страна — Россия.
  • NULL — библиотека не подключена (смотрите конфиги)
  • string(») — страну определить не удалось (бывает в случае, когда вы тестите на локальном компьютере, ведь в базе нет адреса 127.0.0.1 :-)

Теперь в массиве $_SERVER доступны данные геолокации с префиксом «GEOIP_».

Обновление базы

База со странами (GeoIP.dat) обновляется вместе с пакетами, а базу городов (GeoLiteCity.dat) придётся обновлять вручную, ну или написать небольшой скрипт для автоматизации.

Литература

http://blo.in.ua/2009/09/22/php-geoip-extension/
http://wiki.nginx.org/HttpGeoIPModule
http://kbeezie.com/view/apache-mod_geoip-nginx/
http://www.maxmind.com/app/ip-location

Share

Спасибо!


Если вам помогла статья, или вы хотите поддержать мои исследования и блог - вот лучший способ сделать это:


6 Responses to “О двух способах работы геолокации (GeoIP) в PHP”

  1. craz:

    Блин как эту красоту еще на фряху вкрячить

    • google.com Андрей Токарчук:

      Дык ну точно так же:

      Install a port providing the database. For example in FreeBSD the port is called «GeoIP».

      cd /usr/ports/net/GeoIP
      make install clean

      См. линку

  2. Андрей:

    Какой из этих варинатов более производительный?

  3. Виктор:

    Идея конечно замечательная.
    Но к сожалению, некоторые IP не находит.
    Базу надо обновлять …
    А более произовтельный вариант это забор гео api, сохранение юзверю отметку что он и кто он, потом просто не юзать это…

Комментировать