О двух способах работы геолокации (GeoIP) в PHP
Мы начинаем потихоньку привыкать к Web 2.0 сайтам. Удобный (местами минималистический) дизайн, скруглённые уголки, тени, контент, генерируемый пользователем. А что главное с точки зрения юзабилити в w2.0-сайте? Не заставлять пользователя совершать лишние движения. Надо максимально облегчить ему процесс использования сайтом. Например, если в форме регистрации можно автоматически определить страну и город – зачем заставлять пользователя листать километровые списки?
В этой статье пойдёт речь о геолокации (определении местоположения пользователя) средствами PHP.
В нашей компании встала задача рефакторинга форм. Визуально они слишком перегружены, много лишних (но нужных) полей. Например, поля выбора страны и города. Список как стран, таки городов довольно внушителен, и пользователь тратит много времени, чтобы выбрать подходящий пункт. Это может оттолкнуть его от заполнения формы. Наша задача – определить его страну и город автоматически.
Задачу можно решить двумя способами: на уровне сервера приложений (PHP) и ну уровне веб-сервера (Nginx). Сам я рекомендую вам вариант с Nginx, а первый вы можете посмотреть в качестве альтернативы.
Геолокация на PHP
1. Качаем базу стран (в пакете geoip-database), городов, модуль для php и устанавливаем их в систему. Используется база MaxMind.
1 2 3 4 5 |
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) и перезагружаем интерпретатор
1 |
sudo service php5-fpm restart |
3. Проверяем установку, запустив в броузере скриптик.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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) } |
Узнать код страны можно с помощью этой команды:
1 |
$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-пакете, города качаем отдельно.
1 2 3 4 5 |
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 строки:
1 2 3 4 5 6 7 |
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 веб-приложения:
1 2 3 4 5 6 7 8 9 |
# 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. Перезапускаем сервер, пишем простенький скрипт:
1 |
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
Блин как эту красоту еще на фряху вкрячить
Дык ну точно так же:
Install a port providing the database. For example in FreeBSD the port is called “GeoIP”.
cd /usr/ports/net/GeoIP
make install clean
См. линку
Какой из этих варинатов более производительный?
По идее примерно одинаково, но я бы предпочёл вариант с nginx.
Идея конечно замечательная.
Но к сожалению, некоторые IP не находит.
Базу надо обновлять …
А более произовтельный вариант это забор гео api, сохранение юзверю отметку что он и кто он, потом просто не юзать это…
Ну кэширование никто не отменял 🙂
2. Проверяем, чтобы расширение php было подключено (/etc/php5/fpm/conf.d) и перезагружаем интерпретатор
Как проверяем?! ЧТо там должно быть? Как подключить, если не подключено?
Создать файл /etc/php5/fpm/conf.d/geoip.ini со следующим содержанием:
[geoip]
extension=geoip.so
Перезагрузить интерпретатор командой sudo service php5-fpm restart
Открыть в браузере скрипт и проверить, чтобы там была секция geoip.
Как-то так, Саша.
Спасибо, уже сделал. Теперь проблема, что города все на английском, а нужны названия на русском.
Библиотека nikolaevevgeGeoIp для Bitrix, Joomla, WordPress. Определяет регион посетителя сайта, город и страну. Не требует скачивания базы. Использует API для получения информации с дальнейшим кешированием “свежей” информации в базу данных.
Скачать можно здесь http://blog.ivru.net/?id=82
Бред вы пишите. Если юзеру надо зарегаться, то он это сделает, а вы только напрягаете код. На большинстве сайтов моя страна, а город никогда вообще не верно определяется и я сразу бегу от такого ужаса. Сайты сначала нормальные научитесь делать.
О, вы откопали мою статью 11-летней давности 🙂 Зашел, прочитал, прослезился. Так вот, все равно не вижу проблемы. Там речь идет о предзаполнении форм, так что все норм. Некорректно определилось – выбираете что нужно, не нужна страна и город – ну так выпилите эти поля из формы просто.