|
|
|
| Есть база данных всех IP адресов в мире.
Как определить с помощью этой базы страну пользователя?
База имеет структуру:
ip start|ip end|numip start|numip end|country
|
Пример одной строчки:
93.158.128.0|93.158.255.255|1570668544|1570701311|RU
|
Спасибо. | |
|
|
|
|
|
|
|
для: 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'";
/* Ну, а дальше как полагается */
?>
|
| |
|
|
|
|
|
|
|
для: IceGhost
(10.01.2010 в 01:48)
| | Можно узнать, что такое 16777216, 65536 и 256?
И ещё, когда я сказал «база», я не имел ввиду, что типа MySQL. Она у меня в файлах — я их больше люблю, но спасибо всё равно — я понял суть. | |
|
|
|
|
|
|
|
для: Vyacheslav Tsv.
(10.01.2010 в 15:16)
| | 16777216 = 256*256*256
65536 = 256*256
256 = 256 | |
|
|
|
|
|
|
|
для: elenaki
(10.01.2010 в 15:31)
| | все равно не понятно :) а что это ? :) | |
|
|
|
|
автор: [0] (10.01.2010 в 15:51) |
|
|
для: t3ma
(10.01.2010 в 15:42)
| | Приведение 256-ричного числа в 10-тичное. | |
|
|
|
|
|
|
|
для: t3ma
(10.01.2010 в 15:42)
| | Это один с способов указания IP адреса, статья на эту тему:
http://habrahabr.ru/blogs/sysadm/69587/ | |
|
|
|
|
|
|
|
для: 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.
(10.01.2010 в 15:16)
| | Ну, вроде подразобрался, но... увы и ах — база моя оказалась не столь велика. При IP, который начинался на 95 моя страна определена не была :( А на 92 и 78 — да. Обидно. 6 Мб в текстовом файле тоже оказывается не хватает. | |
|
|
|
|
|
|
|
для: 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 | |
|
|
|
|
|
|
|
для: IceGhost
(10.01.2010 в 01:48)
| | Лучше перепарсить базу с использованием http://php.net/manual/en/function.ip2long.php и не использовать все эти операции каждый раз. | |
|
|
|
|
|
|
|
для: @ndry
(11.01.2010 в 04:26)
| | Перечитайте внимательно первый пост. В базе уже есть это. | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 06:23)
| | В результате функции получаем число со знаком, перевести числа в базе в такой-же формат и работать удобными и созданными именно для этих целей методами. | |
|
|
|
|
|
|
|
для: @ndry
(11.01.2010 в 11:33)
| | Повторю ещё раз. В базе уже есть представление IP-адреса в unsigned int форме. | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 13:18)
| | Повторяю ещё раз. Постоянно выполнять самописное преобразование IP в unsigned int намного хуже, чем применять стандартные методы. Если вы хотите сказать, что один раз перепарсить базу будет хуже, чем постоянно использовать приведение (sprintf в вашем примере ниже), то мне с вами спорить, как с программистом, не о чем.
Ваш подход допустим только если автор пишет скрипт для одноразового использования, если же он хочет чему-то научится, то нужно учится делать это правильно. | |
|
|
|
|
|
|
|
для: @ndry
(11.01.2010 в 14:34)
| | ОМГ. База-то тут при чём? | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 14:52)
| | Если база находится в руках разработчика, то вполне может с ней сделать то, что захочет. Вот причём. Или мне ещё раз нужно повторить пост выше чтобы вы таки поняли что я рекомендую сделать? | |
|
|
|
|
|
|
|
для: @ndry
(11.01.2010 в 14:59)
| | Кто-нибудь объясните ему! Меня он не понимает. Trianon? | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 15:12)
| | Ладно, давайте буду с вами говорить как в детсаде, по пунктикам.
1. У человека есть база, на руках.
2. В ней хранятся адреса в форме unsigned int
3. В PHP есть функция, которая переводит IP адрес к виду signed int (по определённым причинам PHP вообще не поддерживает unsigned int как тип).
Я предлагаю провести операцию с базой и привести её в удобный для нас вид, таким образом преобразование int в unsigned int будет произведено 1 раз над каждой строчкой.
Вы предлагаете проводить эту операцию над адресом поиска не трогая базу, таким образом применять её при каждом вызове поиска, те 1 запрос - 1 преобразование.
На продакшине, где количество запросов явно должно превышать кол-во строк в базе, ваш метод будет не оптимален. Это экономия на спичках, но в некоторых местах она может оказаться значительным преимуществом. | |
|
|
|
|
|
|
|
для: @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. Получаем результат | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 15:38)
| | > преобразование int в unsigned int
Опечатка, наоборот, в базе uns int, а нам нужно чтобы хранился int
Может почитайте внимательно что я сказал выше?
У вас будет:
$num_ip = sprintf('%u', ip2long($ip));
У меня будет:
$num_ip = ip2long($ip); | |
|
|
|
|
|
|
|
для: @ndry
(11.01.2010 в 15:42)
| | Ах вот оно что! Стоит ли нарушать совместимость со всеми существующими geoip базами ради сомнительной, ничем не подтверждённой, выгоды? Я считаю что нет. | |
|
|
|
|
|
|
|
для: @ndry
(11.01.2010 в 15:42)
| | Может я чего не понимаю, но ip в int не влезает... | |
|
|
|
|
|
|
|
для: Loki
(11.01.2010 в 16:23)
| | Влезает. Int в РНР 4-байтный (8-байтный на 64-битных платформах). | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 16:32)
| | Влезает если без знака, а @ndry предлагает как раз наоборот: "в базе uns int, а нам нужно чтобы хранился int" | |
|
|
|
|
|
|
|
для: Loki
(11.01.2010 в 17:36)
| | Если я правильно понял что вы имели ввиду, то следует понимать PHP вообще такого понятия как uns int не существует и то, в каком виде мы получаем int из базы ничего не изменит (будет ли там значение знака или нет PHP обрабатывает его как int). В самой же базе IP вполне поместится. | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 15:12)
| | Пусть делает, как считает нужным.
:) | |
|
|
|
|
|
|
|
для: 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));
|
| |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 07:21)
| | Стыдно признаться — никогда не слышал об ip2long, но с ним и правда тоже работает, сокращение до одной строки для поиска соответствия — вообще шикарно. Спасибо. | |
|
|
|
|
|
|
|
для: Vyacheslav Tsv.
(11.01.2010 в 12:50)
| | Не стыдно быть нубом, стыдно им оставаться. | |
|
|
|
|
|
|
|
для: Саня
(11.01.2010 в 13:40)
| | Спасибо, за понимание и советы, но всё же не стоит, права, не стоит. | |
|
|
|
|
|
|
|
для: Vyacheslav Tsv.
(11.01.2010 в 12:50)
| | Есть еще INET_ATON() (из списка функций MySQL) | |
|
|
|
|
|
|
|
для: Trianon
(11.01.2010 в 13:53)
| | Посмотрим! | |
|
|
|