Подтвердить что ты не робот

INET_ATON() и INET_NTOA() в PHP?

Я хочу хранить 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-адреса в базе данных?

Спасибо.

4b9b3361

Ответ 1

ip2long() и long2ip() функции должны работать нормально.

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


Попытка использования IP-адреса google:

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

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

int(3512066963)
string(14) "209.85.227.147" 

Ответ 2

Существует важное различие между функциями 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)

Ответ 3

Вам не нужно иметь дело с тем, что внутри 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 преобразует их в двоичные и обратно в их простое выражение.

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

НТН

Франсиско Зарабозо

Ответ 4

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

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

Ответ 5

Здесь альтернативные функции 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))); 
}

Ответ 6

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

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