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

9 февраля, 2009
wipmania

Некоторое время назад я рассказывал об использовании Яндекс.Карт и сервиса 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 запроса.

  1. 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 адрес посетителя, название страны и её флаг.

  1. <?php
  2. //определяем IP посетителя
  3. $visitorIP = $_SERVER['REMOTE_ADDR'];
  4.  
  5. //подключение к БД
  6. $dbHost = 'localhost';
  7. $dbName = 'db_name';
  8. $dbUser = 'db_user';
  9. $dbPass = 'db_pass';
  10.  
  11. try {
  12.     $dbh = new PDO('mysql:host='.$dbHost.';dbname='.$dbName, $dbUser, $dbPass);
  13.     //преобразовываем IP в целое число
  14.     $ip = ip2long($visitorIP);
  15.     if ($ip !== FALSE) {
  16.         //определяем в какой стране находится посетитель и получаем
  17.         $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>=?');
  18.         $stmt->bindParam(1, $ip);
  19.         $stmt->bindParam(2, $ip);
  20.         $stmt->execute();
  21.         $res = $stmt->fetch(PDO::FETCH_ASSOC);
  22.         if ($res === FALSE) {
  23.             $errMes = 'Местоположение данного IP неизвестно';
  24.         }
  25.     }
  26.     $dbh = null;
  27. }
  28. catch (PDOException $e) {
  29.     $errMes = 'Ошибка: '.$e->getMessage();
  30. }
  31. ?>
  32. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  33.         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  34. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru" lang="ru">
  35.  
  36. <head>
  37.     <title>WIPmania</title>
  38.     <meta http-equiv="content-type" content="text/html;charset=utf-8" />
  39.     <meta http-equiv="Content-Style-Type" content="text/css" />
  40. </head>
  41.  
  42. <body>
  43. <p>Ваш IP адрес: <?php echo $visitorIP; ?></p>
  44. <p>
  45. <?php
  46. if (isset($errMes)) {
  47.     echo $errMes;
  48. }
  49. else {
  50.     //вставляем название страны и рисунок с флагом
  51. ?>
  52.     <img src="flags/<?php echo $res['code']; ?>.png" title="флаг" />
  53. <?php
  54.     echo $res['country'];
  55. }
  56. ?>
  57. </p>
  58. </body>
  59. </html>

Общий алгоритм работы скрипта следующий.

1) Определяем IP адрес. И преобразуем его в целочисленную форму (с помощью функции ip2long, строка 14).

2) Отправляем запрос. В этом примере я использовал PDO, но, естественно, вы можете использовать любую другую библиотеку. О принципе работы запроса я уже рассказал.

3) Формируем страницу и показываем на ней:
- IP адрес посетителя (строка 43);
- сообщение об ошибке (если она возникла);
- флаг страны (строка 52);
- и её название (строка 54).

Обратите внимание на вставку рисунка с флагом. Я распаковал архив в папку flags. Имена файлов совпадают с двухбуквенными кодами стран. К ним нужно только добавить расширение (.png).

Если есть желание поэкспериментировать со скриптом – качайте архив с примером.

И в заключение маленькое замечание – адрес 127.0.0.1 в базе отсутствует ;)

До встречи!

Понравилась статья? Подписывайтесь на продолжение rss link !

Или на мой твиттер twitter link

]]>

Добавьте эту страницу в google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

]]>

Опубликовано в HTML, MySQL, PHP, Web разработка View Comments

]]>
  • Vladzzz
    У Максвинд говно база там даже стран СНГ нет
  • be3
    Запрос в гугле "php геотаргетинг" 3е место +) Хорошо устроился +)
    Спасибо комментаторам, актуальная информация.
  • Хорошо устроился +)


    Стараюсь :)
  • Big_Shark
    Вот база от whois сервера NIC.ru http://ipgeobase.ru
  • Интересно... наверное, это лучший вариант для РФ. Особенно учитывая наличие данных о городах.
  • Big_Shark
    Там также есть и координатная сетка.
    Она в отдельном файле.
  • так он только страну выдает или более точные координаты может
  • оу :) отличный аналог сервиса IPLoc :) главное, что интерфейс очень простой в использовании :) спасибо за подсказку
  • lenster
    Слушайте, а можно ведь как-нибудь скрыться?
  • Можно, используя анонимный прокси сервер. Правда страницы через них загружаются обычно медленнее.
    И, честно говоря, я не вижу большой беды от того, что кто-то узнает в какой стране вы находитесь.
  • Cпасибо, как только так сразу и попробую))
    Бедные люди в интернете, все о них знают)))
  • Спасибо! Еще одна полезная ссылка :)
  • Касательно 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 адресов?
  • вряд ли максминд пошевелит чем, ведь у них база и так "99% точности" :) (а точность по городам вообще без комментариев), они скорее хорошо вложились в маркетинг, и им просто тупо верят. не мудрено, столько лет практически единственные крупные на этом рынке. а нам пара месяцев и о нас еще мало кто знает, а кто знает, очень даже качают :)

    про дробления действительно так. просто максминд предоставляет данные с whois, т.е расположения владельцев подсетей, а мы - реальные расположения самих подсетей.
    Почти все хостеры делают для каждого своего клиента запись в whois и пишут туда адреса этих фирм, а сервера ставят в своих датацентрах.
    А еще есть сети крупных международных сетевых провайдеров, где идет чередование пустых мест и присвоенных местным фирмам. И на пустых местах в whois стоит запись центрального офиса этого гиганта, хотя как только этот кусочек будет делегирован местной фирме, то получит и местный адрес.
  • Конкуренция - это всегда хорошо. Удачи вам!
  • Galchenkov
    Есть отличный сервис с городами и странами и бесплатной БД:
    ip2city.ru

    Так как это, скажем так, Open Source продукт создаваемый сообществом, то там есть следы гопарта в названиях городов и стран. Но в целом очень хорошо.
  • Спасибо!
    Похоже искать базы я не умею :)
    Кстати, очень интересная база. Есть данные о городах. Правда стран почему-то только 44 (в процессе наполнения?)
  • Кстати есть еще решение от MaxMind

    Также можно взять бесплатную БД, обновляющуюся первого числа каждого месяца. плюс хороший API
  • Спасибо за ссылку! Нужно будет попробовать.
    Насколько я понял из описания географических координат в ней тоже нет.
blog comments powered by Disqus ]]>