PHP中的INET_ATON()和INET_NTOA()?

时间:2010-05-02 17:45:05

标签: php sql mysql database ip-address

我想在我的数据库中存储IP地址,但我还需要在整个应用程序中使用它们。我读到在MySQL查询中使用INET_ATON()INET_NTOA()来获取IP地址中的32位无符号整数,这正是我想要的,因为它将比使用数据库更快地搜索数据库炭(15)。

问题是,我找不到一个在PHP中做同样事情的函数。我遇到的唯一一件事是:

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

所以我测试了它:

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

它什么也没输出。在他们给出的示例中似乎有效,但是我再次确定ip2long()是否与INET_ATON()做同样的事情。

有人知道会执行此操作的PHP函数吗?甚至是一个将IP地址存储在数据库中的全新解决方案?

感谢。

6 个答案:

答案 0 :(得分:35)

ip2long()long2ip()函数应该可以正常工作。

注意:您应该将这些用于IPv4地址 - 在您的情况下,请确保$_SERVER['REMOTE_ADDR']实际上包含有效的IPv4地址(而不是某些IPv6内容)。< / p>


试用谷歌IP地址:

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

我得到以下输出:

int(3512066963)
string(14) "209.85.227.147" 

答案 1 :(得分:31)

ip2longlong2ip和MySQL函数之间存在重要区别。

PHP的ip2longlong2ip处理有符号整数。

请参阅http://php.net/manual/en/function.ip2long.php

  

“因为PHP的整数类型是有符号的,并且许多IP地址将在32位体系结构上产生负整数,所以需要使用sprintf()或printf()的'%u'格式化程序来获取字符串表示形式未签名的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(已签名)。如果使用带符号列,则无法存储与第一个八位字节大于127的IP地址对应的值正确“。

以下是一些可用于在两者之间工作的功能。

如果您使用INET_ATON()将一个IP插入MySQL数据库,您可以使用以下内容将其转换回PHP:

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

您可以将其转换为使用以下方法将其保存在PHP数据库中:

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

(同样重要的是,不要将$ip_address输入到int,因为如果数字大于MAX_INT,可能会导致问题。如果必须强制转换,将其投放到longfloat

答案 2 :(得分:17)

你不应该在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将它们转换为二进制并返回到最简单的表达式。

我知道这个问题已经有两年多了,但我想让这些信息对遇到的其他人有用。

HTH

Francisco Zarabozo

答案 3 :(得分:11)

对于IPv4和IPv6支持使用inet_pton()inet_ntop(),这些可用于PHP 5.1+并且完全模仿等效的MySQL函数。否则只需使用ip2long()和{ {1}}。

答案 4 :(得分:3)

这里的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))); 
}

答案 5 :(得分:1)

ip2long相当于inet_aton()。

ip2long仅适用于IPv4。我怀疑你的系统正在使用IPv6进行环回。尝试打印REMOTE_ADDR。