存储和检索 IPv4 和 IPv6 地址

Storing and retrieving IPv4 and IPv6 addresses

关于在 PHP/MySQL 设置上存储 IPv4 和 IPv6 地址的最佳方式,SO 上有一百万个问题,但答案要么已过时(仅 IPv4),要么是 contradictory/incomplete.

我提出这个问题是为了给您一个明确的答案,为您提供您需要知道的一切。

当您只需要担心 IPv4 时,您可以使用 PHP 的 ip2longlong2ip 快速轻松地将 IP 地址转换为整数。然而,现在几乎每个人都应该期望在某个时候遇到一些 IPv6 地址,而且这种情况只会增加。

一个通用且有效的解决方案是使用 PHPinet_pton function(它同时处理 IPv4 和 v6),然后存储结果在数据库的 VARBINARY(16) 列中。

所以,假设我们有一个 IPv6 地址:FE80:0000:0000:0000:0202:B3FF:FE1E:8329

当使用 inet_pton 转换并存储在 VARBINARY(16) 列中时,它看起来像这样:

0xfe800000000000000202b3fffe1e8329

然后您可以从数据库中检索它并使用 inet_ntop 显示它。

例如:

echo inet_ntop($ipAddressFromDB);

这是一种在 MySQL 数据库中存储 IP 地址的快速有效方法。

在这个时间点,如果您不构建您的应用程序以适应 IPv6,那么您就是在伤害自己,并且随着时间的推移,这将变得更加真实。出于这个原因,我已经开始以 IPv6 格式存储 所有 IP 地址,并对 IPv4 地址使用 6to4 表示法。

6to4 的 TL;DR 是:

The first 16 bits of the prefix are always 2002:, the next 32 bits are the IPv4 address, and the last 16 bits of the prefix are [not important for this purpose]

假设您的 IP 地址是 222.173.190.239,我们通过以下方式将其转换为 6to4 表示法:

sprintf('2002:%s::', implode(':', str_split(str_pad(dechex(ip2long($addr)), 8, '0', STR_PAD_LEFT), 2)));

变成:2002:de:ad:be:ef::

您通过以下方式将其转换为二进制形式进行存储:inet_pton('2002:de:ad:be:ef::');

给出 16 字节二进制:0x200200de00ad00be00ef000000000000

应该易于存储和搜索。

我之前为此编写了一个帮助程序 class,我只是将它推到 Github and Packagist 以防其他人发现它有用。