这是对已接受答案的修复,该答案错误地假设“第一个地址”应与输入的字符串相同。相反,它需要通过AND运算符根据其掩码修改其值。
为了演示该问题,请考虑以下示例输入:2001:db8:abc:1403::/54
First: 2001:db8:abc:1400::
Run Code Online (Sandbox Code Playgroud)
实际结果:
First: 2001:db8:abc:1403::
Run Code Online (Sandbox Code Playgroud)
计算给定 4 位序列的掩码的相关数学是:
// Calculate the subnet mask. min() prevents the comparison from being negative
$mask = 0xf << (min(4, $flexbits));
// AND the original against its mask
$newval = $origval & $mask;
Run Code Online (Sandbox Code Playgroud)
First: 2001:db8:abc:1400::
Run Code Online (Sandbox Code Playgroud)
输出:
Prefix: 2001:db8:abc:1403::/54
First: 2001:db8:abc:1400::
Last: 2001:db8:abc:17ff:ffff:ffff:ffff:ffff
Run Code Online (Sandbox Code Playgroud)
首先:IPv6没有网络和广播地址.您可以使用前缀中的所有地址.第二:在局域网上,前缀长度总是(好,99.x%的时间)a/64.路由a/68会破坏无状态自动配置等IPv6功能.
以下是IPv6前缀计算器的详细实现:
<?php
/*
* This is definitely not the fastest way to do it!
*/
// An example prefix
$prefix = '2001:db8:abc:1400::/54';
// Split in address and prefix length
list($firstaddrstr, $prefixlen) = explode('/', $prefix);
// Parse the address into a binary string
$firstaddrbin = inet_pton($firstaddrstr);
// Convert the binary string to a string with hexadecimal characters
# unpack() can be replaced with bin2hex()
# unpack() is used for symmetry with pack() below
$firstaddrhex = reset(unpack('H*', $firstaddrbin));
// Overwriting first address string to make sure notation is optimal
$firstaddrstr = inet_ntop($firstaddrbin);
// Calculate the number of 'flexible' bits
$flexbits = 128 - $prefixlen;
// Build the hexadecimal string of the last address
$lastaddrhex = $firstaddrhex;
// We start at the end of the string (which is always 32 characters long)
$pos = 31;
while ($flexbits > 0) {
// Get the character at this position
$orig = substr($lastaddrhex, $pos, 1);
// Convert it to an integer
$origval = hexdec($orig);
// OR it with (2^flexbits)-1, with flexbits limited to 4 at a time
$newval = $origval | (pow(2, min(4, $flexbits)) - 1);
// Convert it back to a hexadecimal character
$new = dechex($newval);
// And put that character back in the string
$lastaddrhex = substr_replace($lastaddrhex, $new, $pos, 1);
// We processed one nibble, move to previous position
$flexbits -= 4;
$pos -= 1;
}
// Convert the hexadecimal string to a binary string
# Using pack() here
# Newer PHP version can use hex2bin()
$lastaddrbin = pack('H*', $lastaddrhex);
// And create an IPv6 address from the binary string
$lastaddrstr = inet_ntop($lastaddrbin);
// Report to user
echo "Prefix: $prefix\n";
echo "First: $firstaddrstr\n";
echo "Last: $lastaddrstr\n";
?>
Run Code Online (Sandbox Code Playgroud)
它应该输出:
Prefix: 2001:db8:abc:1400::/54
First: 2001:db8:abc:1400::
Last: 2001:db8:abc:17ff:ffff:ffff:ffff:ffff
Run Code Online (Sandbox Code Playgroud)