Создаем собственный сервис геотаргетинга

Некоторое время назад я рассказывал об использовании Яндекс.Карт и сервиса IPLoc, который позволяет определить географические координаты посетителя по его IP адресу.
К сожалению, этот сервис сейчас практически все время недоступен. И эта ситуация наглядно показывает, насколько опасно полностью полагаться на сторонние сервисы.
Конечно, проблемы бывают у всех. Но если не работает собственный ресурс, можно попытаться что-то сделать, а тут остается только ждать.
Кроме того, есть ещё одна отрицательная сторона использования сторонних сервисов – время отклика. На отправку запроса и получение ответа (даже очень короткого) уйдет некоторое время, и оно наверняка будет больше чем обращение к локальным ресурсам.
В общем, глядя на сложившуюся ситуацию, я начал искать локальную альтернативу IPLoc, т.е. готовую базу данных. Т.к. платные варианты меня не устраивали, то искать пришлось довольно долго
В результате я остановился на сервисе WIPmania.com. Он предоставляет и API для получения данных, и базу данных.
Правда полноценной заменой IPLoc его считать нельзя, т.к. он позволяет определить только страну посетителя, а географические координаты (широта и долгота) отсутствуют. Тем не менее, более полные базы я видел только в платных вариантах.
Ограничения WIPmania.
Версия базы данных для скачивания обновляется один раз в два месяца.
Если вы используете API, то всегда работаете с самой новой версией, но существует ограничение на количество запросов в месяц.
Т.к. использование API практически не отличается от IPLoc, в этой статье я расскажу только о работе с БД.
1) Загружаем базу данных с официального сайта, тут же можно скачать архив с флагами стран.
Я выбрал архив с SQL версией базы.
Нам нужны 2 файла worldip.sql и worldip.lands.ru.sql. Создаем базу данных и импортируем их.
В результате будут созданы две таблицы:
worldip_land и worldip
В первой таблице хранятся диапазоны IP адресов и двухбуквенные коды соответствующих им стран.
Во второй таблице – двухбуквенные коды и полные названия стран.
Я использовал таблицу с русскими названиями, но в дистрибутив также входят переводы на английский, немецкий и испанский.
Есть несколько нюансов при импортировании таблиц.
Во-первых, импортирование я выполнял с помощью команды
mysql --user=имя --password=пароль название_базы < имя_файла
Во-вторых, практически весь Файл worldip.sql занимает один SQL запрос, размер которого больше 1 МБ. И при попытке импорта возникала ошибка «MySQL server has gone away».
Чтобы её исправить добавьте в конфигурационный файл (my.ini) строку
max_allowed_packet = 4M
(в раздел [mysqld]).
2) Получение данных
Как не сложно догадаться, в большинстве случаев нам нужно будет определять название страны по известному IP. Кроме того, для того, чтобы показать флаг страны, нужен её двухбуквенный код.
Выполнить эту операцию можно с помощью следующего SQL запроса.
-
SELECT wl.code, wl.country FROM worldip w LEFT JOIN worldip_land wl ON (w.code=wl.code) WHERE w.start<=ip AND w.end>=ip
Чтобы понять, как работает запрос нужно представлять структуру таблиц в базе.
Таблица worldip_land содержит 2 поля:
code – двухбуквенный код страны;
country – название страны.
Таблица worldip содержит 3 поля:
start – начало диапазона IP адресов;
end – конец диапазона IP адресов;
code – двухбуквенный код страны.
Думаю вы догадались, что для связи между таблицами используется поле code.
Теперь разберем запрос. Сначала будет выполнен поиск в таблице worldip диапазона адресов, в который входит заданный ip. Затем его результаты используются для поиска названия страны в таблице worldip_land.
Примечание. На этой странице вы найдете примеры наиболее распространенных запросов.
И в заключение приведу пример небольшого скрипта, который выводит IP адрес посетителя, название страны и её флаг.
-
<?php
-
//определяем IP посетителя
-
$visitorIP = $_SERVER['REMOTE_ADDR'];
-
-
//подключение к БД
-
$dbHost = 'localhost';
-
$dbName = 'db_name';
-
$dbUser = 'db_user';
-
$dbPass = 'db_pass';
-
-
try {
-
$dbh = new PDO('mysql:host='.$dbHost.';dbname='.$dbName, $dbUser, $dbPass);
-
//преобразовываем IP в целое число
-
$ip = ip2long($visitorIP);
-
if ($ip !== FALSE) {
-
//определяем в какой стране находится посетитель и получаем
-
$stmt = $dbh->prepare('SELECT wl.code, wl.country FROM worldip w LEFT JOIN worldip_land wl ON (w.code=wl.code) WHERE w.start<=? and w.end>=?');
-
$stmt->bindParam(1, $ip);
-
$stmt->bindParam(2, $ip);
-
$stmt->execute();
-
$res = $stmt->fetch(PDO::FETCH_ASSOC);
-
if ($res === FALSE) {
-
$errMes = 'Местоположение данного IP неизвестно';
-
}
-
}
-
$dbh = null;
-
}
-
catch (PDOException $e) {
-
$errMes = 'Ошибка: '.$e->getMessage();
-
}
-
?>
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
-
-
<head>
-
<title>WIPmania</title>
-
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
-
<meta http-equiv="Content-Style-Type" content="text/css" />
-
</head>
-
-
<body>
-
<p>Ваш IP адрес: <?php echo $visitorIP; ?></p>
-
<p>
-
<?php
-
if (isset($errMes)) {
-
echo $errMes;
-
}
-
else {
-
//вставляем название страны и рисунок с флагом
-
?>
-
<img src="flags/<?php echo $res['code']; ?>.png" title="флаг" />
-
<?php
-
echo $res['country'];
-
}
-
?>
-
</p>
-
</body>
-
</html>
Общий алгоритм работы скрипта следующий.
1) Определяем IP адрес. И преобразуем его в целочисленную форму (с помощью функции ip2long, строка 14).
2) Отправляем запрос. В этом примере я использовал PDO, но, естественно, вы можете использовать любую другую библиотеку. О принципе работы запроса я уже рассказал.
3) Формируем страницу и показываем на ней:
- IP адрес посетителя (строка 43);
- сообщение об ошибке (если она возникла);
- флаг страны (строка 52);
- и её название (строка 54).
Обратите внимание на вставку рисунка с флагом. Я распаковал архив в папку flags. Имена файлов совпадают с двухбуквенными кодами стран. К ним нужно только добавить расширение (.png).
Если есть желание поэкспериментировать со скриптом – качайте архив с примером.
И в заключение маленькое замечание – адрес 127.0.0.1 в базе отсутствует
До встречи!
Понравилась статья? Подписывайтесь на продолжение
!
Опубликовано в HTML, MySQL, PHP, Web разработка Комментарии (22) »
Комментарии (22)
Вы можете отслеживать обсуждение записи с помощью RSS 2.0 ![]()
Вы также можете оставить комментарий, или трекбек с Вашего сайта.









Кстати есть еще решение от MaxMind
Также можно взять бесплатную БД, обновляющуюся первого числа каждого месяца. плюс хороший API
Спасибо за ссылку! Нужно будет попробовать.
Насколько я понял из описания географических координат в ней тоже нет.
Есть отличный сервис с городами и странами и бесплатной БД:
ip2city.ru
Так как это, скажем так, Open Source продукт создаваемый сообществом, то там есть следы гопарта в названиях городов и стран. Но в целом очень хорошо.
Спасибо!
Похоже искать базы я не умею
Кстати, очень интересная база. Есть данные о городах. Правда стран почему-то только 44 (в процессе наполнения?)
Касательно 127.0.0.1 и подобным адресам – в базе отсутствуют несуществующие диапазоны и внутренние сети, потому как смысла забивать MySQL мусором нет – извне по этим адресам никто не придет, а если кто-то будет, то, скорее всего, это совсем новая сеть, которая попадет в следующий апдейт.
Для такого случая можно при возврате из базы пустого значения ставить XX, там и флажок есть соответствующий.
Также в базе нет некоторых сателлитных провайдеров, они доступны только через AIP. Но и в этом случае также можно использовать XX – потому как страну в данном случае почти невозможно определить.
Есть решения от многих компаний, точность баз которых одна выше другой ) к сожалению, пользователю остается лишь тупо довериться обещаниям, потому как проверить это почти невозможно.
платные версии тоже не всегда лучше фри, на главной странице того же максминда можно в этом убедиться, проверьте даже эти примеры
О 127.0.0.1 я написал только по тому, что скрипт при запуске на локальном сервере выдает "Местоположение данного IP неизвестно". Кстати, я в том предложении смайлик поставил
Понятно, что определить местоположение 127.0.0.1 в принципе не возможно.
А вот тут у меня есть идея (наверное, не очень оригинальная
). Если взять 2 базы, то несложно сделать сопоставительный анализ. В результате получится список не совпадающих IP. После этого нужно будет узнать их реальное расположение (честно говоря, плохо представляю насколько будет трудоемкой последняя операция).
Вот независимое сравнение было, правда, здесь только сравнение сетей, но не их реальное расположение.
Вот некоторые самые типичные примеры (первая страна – мы, вторая – максминд). Проверить можно через traceroute, с любым адресом внутри диапазона.
1) примеры сетей, которые не существуют вообще, но есть у максминда:
2.6.190.56-2.6.190.63 XX GB
198.17.112.0-198.17.112.255 XX AU
206.123.0.0-206.123.0.255 XX CA
216.21.16.0-216.21.16.255 XX US
2) страны различные, самые распространенные случаи
78.140.135.0-78.140.135.63 NL CY
80.77.93.0-80.77.94.255 US RU
81.176.78.96-81.176.78.111 RU CY
92.122.12.0-92.122.15.255 IL EU
208.250.29.192-208.250.29.207 US DE
212.123.125.144-212.123.125.151 DE AE
217.112.35.0-217.112.35.255 RU GB
221.133.219.24-221.133.219.31 AU AS
3) типичные ошибки в whois, и перенесенные в платную базу максминда
77.89.154.136-77.89.154.143 GB BG
190.241.44.0-190.241.44.255 CR CO
217.172.118.0 217.172.120.255 AE UA
4) сеть есть в whois и у максминда, но реальных путей нет – или "мертвая" сеть, или совсем новая, не прописанная в маршрутизаторах
95.71.192.0-95.71.207.255 XX RU (новая)
207.209.106.0-207.209.106.255 XX PH (мертвая)
209.127.96.0-209.127.96.255 XX US (мертвая)
5) тоже интересные случаи, когда сети нет даже в whois, но они существуют на самом деле – "серые" сети
208.38.192.0-208.38.255.255 US XX
Очень интересно.
, но может есть идеи?
Правда возникает вопрос. Почему максминд не может (или не хочет) взять вашу базу и откорректировать отличающиеся подсети?
Я понимаю, что это вопрос к ним, а не к вам
И не понятно зачем кому-то платить им 50$ за базу + по 12$/мес за обновления если можно раз в 2 мес качать базу у вас.
Кстати, в сравнении (на которое вы дали ссылку) указывалось, что объем базы максминда в 2 раза больше, но количество IP практически совпадает. Т.е. получается, что они более мелко дробят диапазоны IP адресов?
http://boombick.org/blog/posts/55 гео-база
Спасибо! Еще одна полезная ссылка
Cпасибо, как только так сразу и попробую))
Бедные люди в интернете, все о них знают)))
Слушайте, а можно ведь как-нибудь скрыться?
Можно, используя анонимный прокси сервер. Правда страницы через них загружаются обычно медленнее.
И, честно говоря, я не вижу большой беды от того, что кто-то узнает в какой стране вы находитесь.
оу
отличный аналог сервиса IPLoc
главное, что интерфейс очень простой в использовании
спасибо за подсказку
так он только страну выдает или более точные координаты может
Вот база от whois сервера NIC.ru http://ipgeobase.ru
Интересно… наверное, это лучший вариант для РФ. Особенно учитывая наличие данных о городах.
Там также есть и координатная сетка.
Она в отдельном файле.
Запрос в гугле "php геотаргетинг" 3е место +) Хорошо устроился +)
Спасибо комментаторам, актуальная информация.
Стараюсь
вряд ли максминд пошевелит чем, ведь у них база и так "99% точности"
(а точность по городам вообще без комментариев), они скорее хорошо вложились в маркетинг, и им просто тупо верят. не мудрено, столько лет практически единственные крупные на этом рынке. а нам пара месяцев и о нас еще мало кто знает, а кто знает, очень даже качают
про дробления действительно так. просто максминд предоставляет данные с whois, т.е расположения владельцев подсетей, а мы – реальные расположения самих подсетей.
Почти все хостеры делают для каждого своего клиента запись в whois и пишут туда адреса этих фирм, а сервера ставят в своих датацентрах.
А еще есть сети крупных международных сетевых провайдеров, где идет чередование пустых мест и присвоенных местным фирмам. И на пустых местах в whois стоит запись центрального офиса этого гиганта, хотя как только этот кусочек будет делегирован местной фирме, то получит и местный адрес.
Конкуренция – это всегда хорошо. Удачи вам!