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-адреса в базе данных?
Спасибо.
Ответы
Ответ 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.