【发布时间】:2011-10-21 07:18:57
【问题描述】:
正如“ipv6-capable inet_aton and inet_ntoa functions needed”中所要求的,目前没有用于存储 IPv6 地址的 MySQL 功能。存储/插入的推荐数据类型/功能是什么? (我不打算将它们存储为字符串)。我也不想将 IPv6 地址分成 2 个 INT。
【问题讨论】:
正如“ipv6-capable inet_aton and inet_ntoa functions needed”中所要求的,目前没有用于存储 IPv6 地址的 MySQL 功能。存储/插入的推荐数据类型/功能是什么? (我不打算将它们存储为字符串)。我也不想将 IPv6 地址分成 2 个 INT。
【问题讨论】:
怎么样:
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”。
【讨论】:
没有人发布完整的工作答案(许多示例使用 Windows ::1 这对于实时(或“生产”)环境可能非常误导)任何地方(至少我可以找到)所以这里是:
INSERT 查询示例使用相当复杂的 IPv6 IP 地址。SELECT查询,您将能够echo将IPv6 IP地址返回给客户端。我将所有列名更改为 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,这样你就知道你已经掌握了这一点。):inet_pton( 函数的所有实例并将其删除。inet_ntop( 函数实例并将其删除。INET_ATON( 函数实例并将其删除。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'));。【讨论】:
很好的例子,但我注意到以下内容。
这仅适用于mysql 的版本具有INET6_ATON 的功能。
否则错误消息可能类似于:FUNCTIONDOESNOTEXIST。
【讨论】: