INET_ATON () и INET_NTOA () в PHP? - PullRequest
       14

INET_ATON () и INET_NTOA () в PHP?

32 голосов
/ 02 мая 2010

Я хочу хранить IP-адреса в своей базе данных, но мне также нужно использовать их во всем приложении. Я читал об использовании INET_ATON() и INET_NTOA() в своих запросах MySQL, чтобы получить 32-разрядное целое число без знака из IP-адреса, и это именно то, что мне нужно, поскольку это сделает поиск в базе данных быстрее, чем при использовании char (15) .

Дело в том, что я не могу найти функцию, которая делает то же самое в PHP. Единственное, с чем я столкнулся, это:

http://php.net/manual/en/function.ip2long.php

Итак, я проверил это:

$ip = $_SERVER['REMOTE_ADDR'];
echo ip2long($ip);

И ничего не выводит. В приведенном ими примере это работает, но опять же я не совсем уверен, что ip2long() делает то же самое, что и INET_ATON().

Кто-нибудь знает функцию PHP, которая будет это делать? Или даже совершенно новое решение для хранения IP-адреса в базе данных?

Спасибо.

Ответы [ 6 ]

35 голосов
/ 02 мая 2010

Функции ip2long() и long2ip() должны работать очень хорошо.

Примечание: вы должны использовать их для адресов IPv4 - убедитесь, что в вашем случае $_SERVER['REMOTE_ADDR'] действительно содержит действительный адрес IPv4 (а не некоторые IPv6-компоненты) .


Попытка на Google IP-адрес:

var_dump(ip2long('209.85.227.147'));
var_dump(long2ip(3512066963));

Я получаю следующий вывод:

int(3512066963)
string(14) "209.85.227.147" 
31 голосов
/ 06 сентября 2011

Существует важное различие между ip2long, long2ip и функциями MySQL.

PHP * ip2long и long2ip имеют дело со целыми числами со знаком.

См. http://php.net/manual/en/function.ip2long.php

"Поскольку целочисленный тип PHP подписан, а многие IP-адреса приводят к получению отрицательных целых чисел на 32-разрядных архитектурах, вам необходимо использовать форматер '% u' в sprintf () или printf () для получения строкового представления неподписанный IP-адрес. "

MySQL INET_ATON() и INET_NTOA() имеют дело с целыми числами без знака

См. http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-aton

"Для хранения значений, сгенерированных INET_ATON (), используйте столбец INT UNSIGNED вместо INT, который подписан. Если вы используете столбец со знаком, значения, соответствующие IP-адресам, для которых первый октет больше 127, не могут быть сохранены правильно ".

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

Если вы вставили в базу данных MySQL IP-адрес с помощью INET_ATON(), вы можете преобразовать его обратно в PHP с помощью следующего:

long2ip(sprintf("%d", $ip_address));

И вы можете преобразовать его, чтобы сохранить в базе данных из PHP, используя это:

sprintf("%u", ip2long($ip_address));

(Также важно, не набирайте $ip_address на int, так как это может вызвать проблемы при переносе числа, если оно больше MAX_INT. Если вам нужно привести его, приведите к long или float)

17 голосов
/ 13 марта 2013

Вы не должны иметь дело с этим внутри PHP, для этого и предназначены собственные функции MySQL. Смотрите этот пример:

create table iptable (
    ip int(32) unsigned not null,
    comment varchar(32) not null
);

insert into iptable (ip, comment) values (inet_aton('10.0.0.3'), 'This is 10.0.0.3');

select * from iptable;

+-----------+------------------+
| ip        | comment          |
+-----------+------------------+
| 167772163 | This is 10.0.0.3 |
+-----------+------------------+

select inet_ntoa(ip) as ip, comment from iptable;

+----------+------------------+
| ip       | comment          |
+----------+------------------+
| 10.0.0.3 | This is 10.0.0.3 |
+----------+------------------+

Если вы хотите работать с ipv4 и ipv6 в одном поле и используете Mysql 5.6 или выше, вы можете использовать varbinary (16) и функции inet6_aton и inet6_ntoa. Это лучший пример того, почему вы должны использовать функции MySQL, а не иметь дело с двоичными данными внутри PHP:

create table iptable2 (
    ip varbinary(16) not null,
    comment varchar(32) not null
);

insert into iptable2 (ip, comment) values
    (inet6_aton('192.168.1.254'), 'This is router 192.168.1.254'),
    (inet6_aton('::1'), 'This is ipv6 localhost ::1'),
    (inet6_aton('FE80:0000:0000:0000:0202:B3FF:FE1E:8329'), 'This is some large ipv6 example')
;

select * from iptable2;
+------------------+---------------------------------+
| ip               | comment                         |
+------------------+---------------------------------+
| +¿?¦             | This is router 192.168.1.254    |
|                ? | This is ipv6 localhost ::1      |
| ¦Ç      ??¦ ¦?â) | This is some large ipv6 example |
+------------------+---------------------------------+

select inet6_ntoa(ip) as ip, comment from iptable2;
+--------------------------+---------------------------------+
| ip                       | comment                         |
+--------------------------+---------------------------------+
| 192.168.1.254            | This is router 192.168.1.254    |
| ::1                      | This is ipv6 localhost ::1      |
| fe80::202:b3ff:fe1e:8329 | This is some large ipv6 example |
+--------------------------+---------------------------------+

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

Я знаю, что этот вопрос существует уже более 2 лет, но я хочу, чтобы эта информация была полезна для других, с кем сталкиваюсь.

НТН

Франциско Сарабосо

11 голосов
/ 02 мая 2010

Для поддержки IPv4 и IPv6 используйте inet_pton() и inet_ntop(), они доступны начиная с PHP 5.1+ и имитируют в точности эквивалентные функции MySQL.

В противном случае просто используйте ip2long() и long2ip().

3 голосов
/ 08 апреля 2013

Здесь альтернативные функции PHP (простое копирование / вставка в вашу программу) -

function inet_aton($ip)
{
    $ip = trim($ip);
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return 0;
    return sprintf("%u", ip2long($ip));  
}


function inet_ntoa($num)
{
    $num = trim($num);
    if ($num == "0") return "0.0.0.0";
    return long2ip(-(4294967295 - ($num - 1))); 
}
1 голос
/ 02 мая 2010

ip2long эквивалентен inet_aton ().

ip2long работает только с IPv4. Я подозреваю, что ваша система использует IPv6 для обратной связи. Попробуйте напечатать REMOTE_ADDR.

...