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

Владимир | | HTML, MySQL, PHP, Web разработка.

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 запроса.

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 в базе отсутствует 😉

До встречи!

  • Кстати есть еще решение от MaxMind

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

    • Спасибо за ссылку! Нужно будет попробовать.
      Насколько я понял из описания географических координат в ней тоже нет.

  • Кстати есть еще решение от MaxMind

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

    • Спасибо за ссылку! Нужно будет попробовать.
      Насколько я понял из описания географических координат в ней тоже нет.

  • Galchenkov

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

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

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

  • Galchenkov

    Есть отличный сервис с городами и странами и бесплатной БД:
    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 адресов?

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

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

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

  • Касательно 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 стоит запись центрального офиса этого гиганта, хотя как только этот кусочек будет делегирован местной фирме, то получит и местный адрес.

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

    • Спасибо! Еще одна полезная ссылка 🙂

    • Спасибо! Еще одна полезная ссылка 🙂

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

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

  • lenster

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

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

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

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

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

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

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

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

  • Big_Shark

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

    • Интересно… наверное, это лучший вариант для РФ. Особенно учитывая наличие данных о городах.

      • Big_Shark

        Там также есть и координатная сетка.
        Она в отдельном файле.

  • Big_Shark

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

    • Интересно… наверное, это лучший вариант для РФ. Особенно учитывая наличие данных о городах.

      • Big_Shark

        Там также есть и координатная сетка.
        Она в отдельном файле.

  • be3

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

  • be3

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

  • Vladzzz

    У Максвинд говно база там даже стран СНГ нет

  • IL

    Давно народ, видно, не писал по этому поводу.. так вот там сейчас уже всё есть. Это и ответ в формате json/jsonp, и ограничение на количество запросов снято, широта и долгота доступны. Искал вот такой сторонний сервис с флагами по IP и очень доволен. Сейчас у себя на сайте протестил и с базой локальной, и с GET запросами — работает без проблем. САМА ТО!

    • IL

      Хотя… я думаю, все и так об этом уже знают 🙂

  • MDNdemon

    Приложил бы к архиву и worldip.sql и worldip.lands.ru.sql   в качестве  примера….