我正在尝试以一种高效的方式在MySQL 5.0中存储IPv6地址。我已经阅读了与此相关的其他问题,such as this one。这个问题的作者最终选择了两个BIGINT字段。我的搜索还发现了另一种常用的机制:使用十进制(39,0)来存储IPv6地址。我对此有两个问题。
发布于 2009-08-13 10:11:44
下面是我现在用来将IP地址从十进制(39,0)格式转换为十进制(39,0)格式的函数。它们被命名为inet_ptod和inet_dtop,表示“表示到小数”和“小数到表示”。它需要PHP中的IPv6和bcmath支持。
/**
* 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;
}
发布于 2009-10-25 06:18:14
我们改为使用VARBINARY(16)
列,并使用inet_pton()
和inet_ntop()
进行转换:
https://github.com/skion/mysql-udf-ipv6
这些函数可以加载到正在运行的MySQL服务器中,并将为您提供SQL语言中的INET6_NTOP
和INET6_PTON
,就像IPv4中熟悉的INET_NTOA
和INET_ATON
函数一样。
编辑:现在只有different names,MySQL中有兼容的函数。仅当您使用5.6版之前的MySQL并且正在寻找方便的未来升级途径时,才能使用上述选项。
发布于 2018-03-04 11:51:34
十进制(39)
优点:
缺点:
BINARY(16)...
优点:
对于具有基本索引的精确representation.
缺点:
对于display.
BINARY(39)...
这是针对完整地址的(即使对4in6也使用十六进制)。也可以是ascii而不是二进制。
优点:
前缀可读(如果您可以调用that).
缺点:
对于任何数学函数或operators.
奇怪之处:
如果你想要一些东西,比如case insensitive.
无符号* 2
优点:
prefix使用数学运算符和函数,但需要注意的是,当columns.
缺点:
奇怪之处:
摘要
人们会出于不同的原因使用不同的格式。向后兼容性可能是一个原因,这取决于为IPv4所做的事情。其他的则取决于地址的使用方式和优化方法。您可能会看到使用了多个方法。
B16是一种很好的默认方法,因为它是最高效、最省事的。
对于PHP中的转换,如果您研究以下内容,可以手动完成:
不过,我建议使用一个通用库来处理IPv6的各种显示格式。
https://stackoverflow.com/questions/1120371
复制相似问题