我想储存IPv6地址在MySQL5.0在一个有效的方式。我读过其他的问题与此相关, 如此一个.提交人的这一问题的最终选择了两个BIGINT领域。我的搜索也变成了另一个经常使用的机制:使用十进制(39,0)储存IPv6地址。我有两个问题有关。

  1. 有哪些优点和缺点使用的小数(39,0)过其他方法,如2*BIGINT?
  2. 我怎样转换(在PHP)从二元格式,因为返回的 inet_pton() 一个小数字符串可使用的格式通过MySQL,以及如何做我转换回来所以我可以很漂亮-印有inet_ntop()?
有帮助吗?

解决方案 2

这里是职能,我现在使用以把IP地址,并从小数(39,0)的格式。他们被命名为inet_ptod和inet_dtop为"演讲到小数"和"小数以介绍".它需要IPv6和bcmath支持在PHP.

/**
 * Convert an IP address from presentation to decimal(39,0) format suitable for storage in MySQL
 *
 * @param string $ip_address An IP address in IPv4, IPv6 or decimal notation
 * @return string The IP address in decimal notation
 */
function inet_ptod($ip_address)
{
    // IPv4 address
    if (strpos($ip_address, ':') === false && strpos($ip_address, '.') !== false) {
        $ip_address = '::' . $ip_address;
    }

    // IPv6 address
    if (strpos($ip_address, ':') !== false) {
        $network = inet_pton($ip_address);
        $parts = unpack('N*', $network);

        foreach ($parts as &$part) {
            if ($part < 0) {
                $part = bcadd((string) $part, '4294967296');
            }

            if (!is_string($part)) {
                $part = (string) $part;
            }
        }

        $decimal = $parts[4];
        $decimal = bcadd($decimal, bcmul($parts[3], '4294967296'));
        $decimal = bcadd($decimal, bcmul($parts[2], '18446744073709551616'));
        $decimal = bcadd($decimal, bcmul($parts[1], '79228162514264337593543950336'));

        return $decimal;
    }

    // Decimal address
    return $ip_address;
}

/**
 * Convert an IP address from decimal format to presentation format
 *
 * @param string $decimal An IP address in IPv4, IPv6 or decimal notation
 * @return string The IP address in presentation format
 */
function inet_dtop($decimal)
{
    // IPv4 or IPv6 format
    if (strpos($decimal, ':') !== false || strpos($decimal, '.') !== false) {
        return $decimal;
    }

    // Decimal format
    $parts = array();
    $parts[1] = bcdiv($decimal, '79228162514264337593543950336', 0);
    $decimal = bcsub($decimal, bcmul($parts[1], '79228162514264337593543950336'));
    $parts[2] = bcdiv($decimal, '18446744073709551616', 0);
    $decimal = bcsub($decimal, bcmul($parts[2], '18446744073709551616'));
    $parts[3] = bcdiv($decimal, '4294967296', 0);
    $decimal = bcsub($decimal, bcmul($parts[3], '4294967296'));
    $parts[4] = $decimal;

    foreach ($parts as &$part) {
        if (bccomp($part, '2147483647') == 1) {
            $part = bcsub($part, '4294967296');
        }

        $part = (int) $part;
    }

    $network = pack('N4', $parts[1], $parts[2], $parts[3], $parts[4]);
    $ip_address = inet_ntop($network);

    // Turn IPv6 to IPv4 if it's IPv4
    if (preg_match('/^::\d+.\d+.\d+.\d+$/', $ip_address)) {
        return substr($ip_address, 2);
    }

    return $ip_address;
}

其他提示

我们去 VARBINARY(16) 列,而不是使用 inet_pton()inet_ntop() 要做到的转换:

https://github.com/skion/mysql-udf-ipv6

功能可以装载到一个运行MySQL server和会给你 INET6_NTOPINET6_PTON 在SQL,只是作为熟悉的 INET_NTOAINET_ATON 功能IPv4。

编辑:有兼容的功能在MySQL现在,只是 不同的 名称.只有使用上述,如果你是在预5.6MySQL和正在寻找一个方便今后升级的道路。

小数(39)

赞成:

  • 工作有基本的算术运营商(例如+和-).
  • 工作与基本索引(确切或范围)。
  • 格式显示友好。

缺点:

  • 可以接受的范围值IPv6。
  • 是不是一个非常有效的储存机构。
  • 可能会导致混乱,数学运算符或职能工作及其不。

二进制(16)...

赞成:

  • 最有效的格式为确切的表示。
  • 工作与基本索引(确切和范围)。
  • 与前缀索引用的前缀的倍数的8位。
  • 商店的唯一有效的IPv6值(虽然不能保证有效的解决).
  • MySQL在以后的版本有功能,支持转换为这个格式和IPv6陈述(但不4in6).

缺点:

  • 不友好的显示。
  • 不友好的经营者或功能意味着数字。

二进制(39)...

这是为全面地址(使用hexdec甚至4in6).也可以ascii而不是二进制的。

赞成:

  • 人类可读的(如果可以的话IPv6)。
  • 支持基本索引(确切和范围)。
  • 支持前缀索引多4位。
  • 直接IPv6兼容。没有转换的需要。

缺点:

  • 不会的工作以及与任何数学的功能或经营者。
  • 最低效率的储存。
  • 可以允许无效的陈述。

古怪:

  • 变得复杂,如果你想要的东西,如情况不敏感。
  • IPv6有其他的显示格式虽然使用这些使得更多的复杂性这样的因为你可以有两种表述的同一地址,或者你失去范围内查找。甚至可以结束了有45个字节或使用varchar/varbinary。
  • 差异,这可以支持保留地址,如最初收到。这可能很少可以期望,但是当你失去了很多的好处。
  • 删除分离器有充分的格式,只是储存是为hex string少麻烦和更多一点的效率。你可以把这个很长的路,如果前缀索引是重要的(二元(128)).

BIGINT UNSIGNED*2

赞成:

  • 工作与数学运算符和职能的警告不得不做额外周围的事物这两栏。
  • 有效的,但再次告诫说,它在两个的列将增加一些开销。
  • 适用的基本指数(精确,范围)。
  • 与前缀指数当前缀为64位。
  • 显示友好的格式。

缺点:

  • 两列使非原子和手段增加一倍的很多操作。

古怪:

  • 许多现代语言和系统得到64位整数,但不是无符号。签名是有问题的。负数表现为低于积极的,但他们的位序列实际上是较高的。由于这个原因,它是共同的,而不是使用4*INT无符号。
  • 同样人们可能会打破它为前缀的索引和你可以去至少为8比特(指定列的值未签名).有些人也可能使用的位(1个)类型完整的前缀索引,假设MySQL共断定索引位类型的正确。
  • 再次同样有四列一些行动,需要的东西喜欢载着从上到另一个是具有讽刺意味的是更容易由于松弛位期间计算(中间值计算,仍可64位)。

摘要

人们将使用不同格式的原因不同。向后兼容性可以是一个原因,取决于什么是正在做IPv4。其他依赖于如何将地址的正在使用和优化。你可以看到一个以上方法是使用。

B16是一个很好的默认方法,因为它是最有效和免费的麻烦。

转换PHP你可以做的如果你的研究:

  • gmp或bcmath
  • PHP的数量的处理和bitwise operators,要特别注意限制int或浮动以及功能,取决于他们能否则似乎有用的
  • IPv6格式
  • 包装/拆包,bin2hex/hex2bin.

我会推荐,但是使用一个共用图书馆处理IPv6的各种的显示格式。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top