【问题标题】:Storing IPv6 Addresses in MySQL在 MySQL 中存储 IPv6 地址
【发布时间】:2011-10-21 07:18:57
【问题描述】:

正如“ipv6-capable inet_aton and inet_ntoa functions needed”中所要求的,目前没有用于存储 IPv6 地址的 MySQL 功能。存储/插入的推荐数据类型/功能是什么? (我不打算将它们存储为字符串)。我也不想将 IPv6 地址分成 2 个 INT。

【问题讨论】:

标签: mysql sql


【解决方案1】:

怎么样:

BINARY(16)

这应该足够有效。

目前没有在 MySQL 服务器中将文本 IPv6 地址从/转换为二进制的功能,如该错误报告中所述。您需要在您的应用程序中执行此操作,或者可能在 MySQL 服务器中创建一个 UDF(用户定义函数)来执行此操作。

更新:

MySQL 5.6.3 支持 IPv6 地址,请参阅以下内容:“INET6_ATON(expr)”。

数据类型是VARBINARY(16),而不是我之前建议的BINARY(16)。唯一的原因是 MySQL 函数适用于 IPv6 和 IPv4 地址。 BINARY(16) 适合仅存储 IPv6 地址并节省一个字节。处理 IPv6 和 IPv4 地址时应使用VARBINARY(16)

旧版本 MySQL 和 MariaDB 的实现,请参见以下内容:“EXTENDING MYSQL 5 WITH IPV6 FUNCTIONS”。

【讨论】:

  • 完美时机!在我发布问题后仅一个月左右:P
【解决方案2】:

没有人发布完整的工作答案(许多示例使用 Windows ::1 这对于实时(或“生产”)环境可能非常误导)任何地方(至少我可以找到)所以这里是:

  1. 存储格式。
  2. INSERT 查询示例使用相当复杂的 IPv6 IP 地址。
  3. 例如SELECT查询,您将能够echo将IPv6 IP地址返回给客户端。
  4. 故障排除以确保您没有遗漏任何旧代码。

我将所有列名更改为 ipv6,以反映它们正确支持 IPv6(这使您可以保持旧列 ip 不变)。可以将ip 列存储在ipv6 列中,然后在确定转换成功后将DROP 存储在ip 列中;当我真正有时间的时候,我会把它添加到这篇文章中。

IPv6 数据类型

如前所述,VARBINARY 16 是理想的方式,直到 AMD 为我们提供 128 位 CPU 并更新数据库以支持 128 位整数(我说得对吗?)。 IPv6 是 128 位,而不是 64 位。

CREATE TABLE `example`
(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`ipv6` VARBINARY(16) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8mb4_unicode_520_ci'
ENGINE=InnoDB;

IPv6 INSERT 查询

SELECT 之前,我们显然需要存储一个 IPv6 IP 地址;这是 PHP / SQL 代码:

$ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
$query1 = "INSERT INTO example (ipv6) VALUES (INET6_ATON('$ipv6'));";

IPv6 SELECT 查询

PHP/SQL 代码:

$ipv6 = mysqli_real_escape_string($db,'FE80:0000:0000:0000:0202:B3FF:FE1E:8329');
$query2 = "SELECT INET6_NTOA(ipv6) AS ipv6 FROM example WHERE ipv6=INET6_ATON('$ipv6');";

这将返回fe80::202:b3ff:fe1e:8329;不,不是完整的 IPv6(即FE80:0000:0000:0000:0202:B3FF:FE1E:8329),它是一个浓缩/速记版本。有代码可以使它成为正式的完整版本,但这是为了节省我自己和其他人的时间,因为这个 Q/A 是一个不断出现的问题。

重要提示:只是因为一些 IPv6 地址看起来就像它们适合bigint 一样 暗示两分钟后拥有更大 IPv6 地址的人不会停下来并造成严重破坏。

希望这将使一些人免于打开另外两打标签的疯狂。以后有时间时,我将添加额外的 PHP 代码,将压缩的 IPv6 扩展为完整的正式格式。


疑难解答

如果由于某种原因无法存储和/或检索 IPv6 地址,请为自己获取一份 Advanced Find and Replace 的副本(在 Wine 中的运行速度比 Linux 的原生 grep 更快); 主要使用这个来查找,而不是替换。确保您的代码在您的软件中的任何地方都一致

  • 所有$ip 变量必须转换为$ipv6,这样你就知道你已经掌握了这一点。
  • 在接下来的四个步骤中,不要忘记删除结尾 )
  • 搜索 PHP inet_pton( 函数的所有实例并将其删除。
  • 搜索所有 PHP inet_ntop( 函数实例并将其删除。
  • 搜索所有 SQL INET_ATON( 函数实例并将其删除。
  • 搜索所有 SQL INET_NTOA( 函数实例并将其删除。
  • 搜索$ipv6 的所有实例并确保所有IP-IN-TO-SQL 实例都使用INET6_ATON('$ipv6'),并且IP-FROM-SQL 的所有实例都使用INET6_NTOA(ipv6) AS ipv6
  • 搜索$row1['ip'] 的所有实例并将它们替换为$row1['ipv6']
  • 确保$ipv6 = 的所有实例都使用以下代码(您的数据库对象引用已更改):$ipv6 = (isset($_SERVER['REMOTE_ADDR']) && strlen($_SERVER['REMOTE_ADDR']) > 0) ? mysqli_real_escape_string($db,$_SERVER['REMOTE_ADDR']) : mysqli_real_escape_string($db,getenv('REMOTE_ADDR'));
  • 如果您在开始调试之前发现有问题,请确保您的测试使用测试过的 IP 地址,而不是可能存在拙劣的版本。

【讨论】:

    【解决方案3】:

    很好的例子,但我注意到以下内容。 这仅适用于mysql 的版本具有INET6_ATON 的功能。 否则错误消息可能类似于:FUNCTIONDOESNOTEXIST

    【讨论】:

    • 你是对的,我的版本真的很老,没有那个能力:(Ver 14.14 Distrib 5.1.41)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 2012-05-22
    • 1970-01-01
    • 2014-05-03
    • 2016-09-18
    • 2011-09-08
    • 2014-12-19
    相关资源
    最近更新 更多