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

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 разработка Комментарии (22) »

]]>

Комментарии (22)

Вы можете отслеживать обсуждение записи с помощью RSS 2.0 rss link

Вы также можете оставить комментарий, или трекбек с Вашего сайта.

]]>
  1. Кстати есть еще решение от MaxMind

    Также можно взять бесплатную БД, обновляющуюся первого числа каждого месяца. плюс хороший API

  2. Galchenkov

    Есть отличный сервис с городами и странами и бесплатной БД:
    ip2city.ru

    Так как это, скажем так, Open Source продукт создаваемый сообществом, то там есть следы гопарта в названиях городов и стран. Но в целом очень хорошо.

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

  3. Касательно 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 адресов?

  4. Cпасибо, как только так сразу и попробую))
    Бедные люди в интернете, все о них знают)))

  5. Слушайте, а можно ведь как-нибудь скрыться?

    • Можно, используя анонимный прокси сервер. Правда страницы через них загружаются обычно медленнее.
      И, честно говоря, я не вижу большой беды от того, что кто-то узнает в какой стране вы находитесь.

  6. оу :) отличный аналог сервиса IPLoc :) главное, что интерфейс очень простой в использовании :) спасибо за подсказку

  7. так он только страну выдает или более точные координаты может

  8. Big_Shark

    Вот база от whois сервера NIC.ru http://ipgeobase.ru

  9. be3

    Запрос в гугле "php геотаргетинг" 3е место +) Хорошо устроился +)
    Спасибо комментаторам, актуальная информация.

  10. вряд ли максминд пошевелит чем, ведь у них база и так "99% точности" :) (а точность по городам вообще без комментариев), они скорее хорошо вложились в маркетинг, и им просто тупо верят. не мудрено, столько лет практически единственные крупные на этом рынке. а нам пара месяцев и о нас еще мало кто знает, а кто знает, очень даже качают :)

    про дробления действительно так. просто максминд предоставляет данные с whois, т.е расположения владельцев подсетей, а мы – реальные расположения самих подсетей.
    Почти все хостеры делают для каждого своего клиента запись в whois и пишут туда адреса этих фирм, а сервера ставят в своих датацентрах.
    А еще есть сети крупных международных сетевых провайдеров, где идет чередование пустых мест и присвоенных местным фирмам. И на пустых местах в whois стоит запись центрального офиса этого гиганта, хотя как только этот кусочек будет делегирован местной фирме, то получит и местный адрес.

  11. Конкуренция – это всегда хорошо. Удачи вам!

]]>

Оставить комментарий

* - обязательные для заполнения поля

]]>