【问题标题】:INET_ATON() and INET_NTOA() in PHP?PHP 中的 INET_ATON() 和 INET_NTOA()?
【发布时间】:2011-02-14 19:25:42
【问题描述】:

我想在我的数据库中存储 IP 地址,但我还需要在整个应用程序中使用它们。我阅读了有关在我的 MySQL 查询中使用 INET_ATON()INET_NTOA() 从 IP 地址中获取 32 位无符号整数的信息,这正是我想要的,因为它可以比使用 char(15) 更快地搜索数据库.

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

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

所以我测试了它:

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

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

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

谢谢。

【问题讨论】:

  • 忘记补充了,我正在使用本地主机,所以也许这就是 ip2long() 没有返回任何内容的原因?
  • 本地主机的 IPv4 仍然是 127.0.0.1,除非您使用 IPv6,否则它应该可以工作 - 检查我的答案。

标签: php sql mysql database ip-address


【解决方案1】:

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

注意:您应该将它们用于 IPv4 地址——确保在您的情况下,$_SERVER['REMOTE_ADDR'] 实际上包含一个有效的 IPv4 地址(而不是一些 IPv6 的东西)


尝试使用谷歌 IP 地址:

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

我得到以下输出:

int(3512066963)
string(14) "209.85.227.147" 

【讨论】:

    【解决方案2】:

    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,这可能会导致问题出现问题。如果必须转换,请将其转换为@987654335 @或float)

    【讨论】:

    • 像魅力一样工作。非常感谢您的提示。我从来没有意识到这一点。
    • ip2long 在 64 位系统上将给出无符号结果。不过,在这种情况下,“%u”仍然会做正确的事情。
    【解决方案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 会将它们转换为二进制并返回到最简单的表达式。

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

    HTH

    弗朗西斯科·萨拉博佐

    【讨论】:

    • 如果你必须用准备好的语句插入它们怎么办?不能给mysql函数绑定参数,INET_ATON(?),所以必须用php
    • @the_nuts 你在说什么?是的你可以。自己试试吧。
    【解决方案4】:

    对于 IPv4 和 IPv6 支持,请使用 inet_pton()inet_ntop(),它们自 PHP 5.1+ 起可用,并且完全模仿等效的 MySQL 函数。

    否则只使用ip2long()long2ip()

    【讨论】:

    • 我无法模仿这个。
    • inet_ntop( $ip ) 正是我在 PHP 中将 varbinary 值(来自 MYSQL)转换为可读 IP 地址所需的。谢谢。
    【解决方案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 进行环回。尝试打印 REMOTE_ADDR。

      【讨论】:

      • 啊,我明白为什么它现在不起作用了,$_SERVER['REMOTE_ADDR'] 返回:::1。可能是因为我在本地主机上。有没有办法防止这种情况?还是我必须检查它是否返回::1
      • ::1 是用于环回的 IPv6。您需要禁用 IPv6。对于 Linux,请遵循以下说明:blog.taragana.com/index.php/archive/…
      猜你喜欢
      • 2012-02-26
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      • 2014-05-30
      • 2012-07-18
      • 1970-01-01
      • 2014-05-30
      • 2011-01-31
      相关资源
      最近更新 更多