Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Есть база данных всех IP адресов в мире. Как определить с помощью этой базы страну пользователя?
 
 автор: Vyacheslav Tsv.   (10.01.2010 в 00:43)   письмо автору
 
 

Есть база данных всех IP адресов в мире.
Как определить с помощью этой базы страну пользователя?

База имеет структуру:
ip start|ip end|numip start|numip end|country

Пример одной строчки:
93.158.128.0|93.158.255.255|1570668544|1570701311|RU

Спасибо.

  Ответить  
 
 автор: IceGhost   (10.01.2010 в 01:48)   письмо автору
 
   для: Vyacheslav Tsv.   (10.01.2010 в 00:43)
 

<?php
  $ip 
"93.158.255.255";
  
$arr explode("."$ip);
  
$num_ip 16777216 $arr[0] +
            
65536 $arr[1] +
            
256 $arr[2] + 
            
$arr[3];
       
  
$sql "SELECT country FROM table_name
          WHERE numip_start <= '
$num_ip' AND numip_end >= '$num_ip'";
  
/* Ну, а дальше как полагается  */
?>

  Ответить  
 
 автор: Vyacheslav Tsv.   (10.01.2010 в 15:16)   письмо автору
 
   для: IceGhost   (10.01.2010 в 01:48)
 

Можно узнать, что такое 16777216, 65536 и 256?

И ещё, когда я сказал «база», я не имел ввиду, что типа MySQL. Она у меня в файлах — я их больше люблю, но спасибо всё равно — я понял суть.

  Ответить  
 
 автор: elenaki   (10.01.2010 в 15:31)   письмо автору
 
   для: Vyacheslav Tsv.   (10.01.2010 в 15:16)
 

16777216 = 256*256*256
65536 = 256*256
256 = 256

  Ответить  
 
 автор: t3ma   (10.01.2010 в 15:42)   письмо автору
 
   для: elenaki   (10.01.2010 в 15:31)
 

все равно не понятно :) а что это ? :)

  Ответить  
 
 автор: [0]   (10.01.2010 в 15:51)
 
   для: t3ma   (10.01.2010 в 15:42)
 

Приведение 256-ричного числа в 10-тичное.

  Ответить  
 
 автор: @ndry   (11.01.2010 в 04:27)   письмо автору
 
   для: t3ma   (10.01.2010 в 15:42)
 

Это один с способов указания IP адреса, статья на эту тему:
http://habrahabr.ru/blogs/sysadm/69587/

  Ответить  
 
 автор: Саня   (10.01.2010 в 15:57)   письмо автору
 
   для: Vyacheslav Tsv.   (10.01.2010 в 15:16)
 

> Можно узнать, что такое 16777216, 65536 и 256?
Умножение на эти числа является аналогом битового сдвига влево.

Суть данных махинаций является представление IP-адреса 32-битным числом. В обычном виде IP представлен 4 десятичными числами, разделёнными точкой. Но, как вы сами понимаете, такой вид не является оптимальным для компьютера, так как операции над строками стоят дороже операций над числами.

Приведённый выше код можно заменить этим:
<?
$ip 
"93.158.128.0"
$arr explode("."$ip); 
$num_ip = ($arr[0] << 24) + 
          (
$arr[1] << 16) + 
          (
$arr[2] << 8) +  
          
$arr[3];

Если перевести полученное число $num_ip в двоичный вид, то всё становится на свои места:
93.      158.     128.     0
01011101 10011110 10000000 00000000

Грубо говоря операцию "93 << X" можно описать как "добавить Х нулей справа к двоичному представлению числа 93".

  Ответить  
 
 автор: Vyacheslav Tsv.   (11.01.2010 в 01:29)   письмо автору
 
   для: Vyacheslav Tsv.   (10.01.2010 в 15:16)
 

Ну, вроде подразобрался, но... увы и ах — база моя оказалась не столь велика. При IP, который начинался на 95 моя страна определена не была :( А на 92 и 78 — да. Обидно. 6 Мб в текстовом файле тоже оказывается не хватает.

  Ответить  
 
 автор: Саня   (11.01.2010 в 06:29)   письмо автору
 
   для: Vyacheslav Tsv.   (11.01.2010 в 01:29)
 

Есть один очень известный составитель geoip баз — компания maxmind. У неё есть две базы. Первая определяет только страну, вторая страну и город. Есть бесплатные версии этих баз, мало чем отличающиеся от платной версии. http://www.maxmind.com/app/ip-location

Есть и другие базы:
http://www.wipmania.com/ru/base/
http://ipinfodb.com/ip_database.php
http://ipgeobase.ru/cgi-bin/Archive.cgi

  Ответить  
 
 автор: @ndry   (11.01.2010 в 04:26)   письмо автору
 
   для: IceGhost   (10.01.2010 в 01:48)
 

Лучше перепарсить базу с использованием http://php.net/manual/en/function.ip2long.php и не использовать все эти операции каждый раз.

  Ответить  
 
 автор: Саня   (11.01.2010 в 06:23)   письмо автору
 
   для: @ndry   (11.01.2010 в 04:26)
 

Перечитайте внимательно первый пост. В базе уже есть это.

  Ответить  
 
 автор: @ndry   (11.01.2010 в 11:33)   письмо автору
 
   для: Саня   (11.01.2010 в 06:23)
 

В результате функции получаем число со знаком, перевести числа в базе в такой-же формат и работать удобными и созданными именно для этих целей методами.

  Ответить  
 
 автор: Саня   (11.01.2010 в 13:18)   письмо автору
 
   для: @ndry   (11.01.2010 в 11:33)
 

Повторю ещё раз. В базе уже есть представление IP-адреса в unsigned int форме.

  Ответить  
 
 автор: @ndry   (11.01.2010 в 14:34)   письмо автору
 
   для: Саня   (11.01.2010 в 13:18)
 

Повторяю ещё раз. Постоянно выполнять самописное преобразование IP в unsigned int намного хуже, чем применять стандартные методы. Если вы хотите сказать, что один раз перепарсить базу будет хуже, чем постоянно использовать приведение (sprintf в вашем примере ниже), то мне с вами спорить, как с программистом, не о чем.

Ваш подход допустим только если автор пишет скрипт для одноразового использования, если же он хочет чему-то научится, то нужно учится делать это правильно.

  Ответить  
 
 автор: Саня   (11.01.2010 в 14:52)   письмо автору
 
   для: @ndry   (11.01.2010 в 14:34)
 

ОМГ. База-то тут при чём?

  Ответить  
 
 автор: @ndry   (11.01.2010 в 14:59)   письмо автору
 
   для: Саня   (11.01.2010 в 14:52)
 

Если база находится в руках разработчика, то вполне может с ней сделать то, что захочет. Вот причём. Или мне ещё раз нужно повторить пост выше чтобы вы таки поняли что я рекомендую сделать?

  Ответить  
 
 автор: Саня   (11.01.2010 в 15:12)   письмо автору
 
   для: @ndry   (11.01.2010 в 14:59)
 

Кто-нибудь объясните ему! Меня он не понимает. Trianon?

  Ответить  
 
 автор: @ndry   (11.01.2010 в 15:25)   письмо автору
 
   для: Саня   (11.01.2010 в 15:12)
 

Ладно, давайте буду с вами говорить как в детсаде, по пунктикам.

1. У человека есть база, на руках.
2. В ней хранятся адреса в форме unsigned int
3. В PHP есть функция, которая переводит IP адрес к виду signed int (по определённым причинам PHP вообще не поддерживает unsigned int как тип).

Я предлагаю провести операцию с базой и привести её в удобный для нас вид, таким образом преобразование int в unsigned int будет произведено 1 раз над каждой строчкой.

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

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

  Ответить  
 
 автор: Саня   (11.01.2010 в 15:38)   письмо автору
 
   для: @ndry   (11.01.2010 в 15:25)
 

> У человека есть база ... В ней хранятся адреса в форме unsigned int
> ...
> Я предлагаю провести операцию с базой ... преобразование int в unsigned int
No comments.

IP-адрес посетителя (не важно откуда получим, скорее всего из REMOTE_ADDR) всегда будет в формате xxx.xxx.xxx.xxx. Чтобы проще искалось нужно перевести его в uint и выполнить запрос.

Ещё раз, по пунктикам:
1. Получаем IP-адрес посетителя сайта
2. Полученный адрес переводим в uint
3. Производим поиск по базе, в которой все диапазоны записаны в uint
4. Получаем результат

  Ответить  
 
 автор: @ndry   (11.01.2010 в 15:42)   письмо автору
 
   для: Саня   (11.01.2010 в 15:38)
 

> преобразование int в unsigned int
Опечатка, наоборот, в базе uns int, а нам нужно чтобы хранился int

Может почитайте внимательно что я сказал выше?

У вас будет:
$num_ip = sprintf('%u', ip2long($ip));

У меня будет:
$num_ip = ip2long($ip);

  Ответить  
 
 автор: Саня   (11.01.2010 в 16:10)   письмо автору
 
   для: @ndry   (11.01.2010 в 15:42)
 

Ах вот оно что! Стоит ли нарушать совместимость со всеми существующими geoip базами ради сомнительной, ничем не подтверждённой, выгоды? Я считаю что нет.

  Ответить  
 
 автор: Loki   (11.01.2010 в 16:23)   письмо автору
 
   для: @ndry   (11.01.2010 в 15:42)
 

Может я чего не понимаю, но ip в int не влезает...

  Ответить  
 
 автор: Саня   (11.01.2010 в 16:32)   письмо автору
 
   для: Loki   (11.01.2010 в 16:23)
 

Влезает. Int в РНР 4-байтный (8-байтный на 64-битных платформах).

  Ответить  
 
 автор: Loki   (11.01.2010 в 17:36)   письмо автору
 
   для: Саня   (11.01.2010 в 16:32)
 

Влезает если без знака, а @ndry предлагает как раз наоборот: "в базе uns int, а нам нужно чтобы хранился int"

  Ответить  
 
 автор: @ndry   (11.01.2010 в 18:25)   письмо автору
 
   для: Loki   (11.01.2010 в 17:36)
 

Если я правильно понял что вы имели ввиду, то следует понимать PHP вообще такого понятия как uns int не существует и то, в каком виде мы получаем int из базы ничего не изменит (будет ли там значение знака или нет PHP обрабатывает его как int). В самой же базе IP вполне поместится.

  Ответить  
 
 автор: Trianon   (11.01.2010 в 17:15)   письмо автору
 
   для: Саня   (11.01.2010 в 15:12)
 

Пусть делает, как считает нужным.
:)

  Ответить  
 
 автор: Саня   (11.01.2010 в 07:21)   письмо автору
 
   для: Vyacheslav Tsv.   (10.01.2010 в 00:43)
 

Ещё одно замечание.
Так как тип int в PHP знаковый, то все IP-адреса, начиная с 128.0.0.0 и выше будут давать отрицательные числа. В базах используют беззнаковый int, поэтому нужно привести полученное число к беззнаковому целому:
<?
$ip 
"93.158.128.0";  
$arr explode("."$ip);  
$num_ip = ($arr[0] << 24) +  
          (
$arr[1] << 16) +  
          (
$arr[2] << 8) +   
          
$arr[3];
$num_ip sprintf('%u'$num_ip);

Или ещё короче:
<?
$ip 
"93.158.128.0";
$num_ip sprintf('%u'ip2long($ip));

  Ответить  
 
 автор: Vyacheslav Tsv.   (11.01.2010 в 12:50)   письмо автору
 
   для: Саня   (11.01.2010 в 07:21)
 

Стыдно признаться — никогда не слышал об ip2long, но с ним и правда тоже работает, сокращение до одной строки для поиска соответствия — вообще шикарно. Спасибо.

  Ответить  
 
 автор: Саня   (11.01.2010 в 13:40)   письмо автору
 
   для: Vyacheslav Tsv.   (11.01.2010 в 12:50)
 

Не стыдно быть нубом, стыдно им оставаться.

  Ответить  
 
 автор: Vyacheslav Tsv.   (12.01.2010 в 09:42)   письмо автору
 
   для: Саня   (11.01.2010 в 13:40)
 

Спасибо, за понимание и советы, но всё же не стоит, права, не стоит.

  Ответить  
 
 автор: Trianon   (11.01.2010 в 13:53)   письмо автору
 
   для: Vyacheslav Tsv.   (11.01.2010 в 12:50)
 

Есть еще INET_ATON() (из списка функций MySQL)

  Ответить  
 
 автор: Vyacheslav Tsv.   (15.01.2010 в 23:00)   письмо автору
 
   для: Trianon   (11.01.2010 в 13:53)
 

Посмотрим!

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования