php 通过CIDR 计算ip段开始ip 适用ipv6与ipv4
/**
* CIDR 计算段开始ip
* @param string $ipData 格式 ipv4"xxx.xxx.xxx.xxx/xx"或 ipv6:"xxxx:xxxx::xxxx/xx"
* @return false|string
*/
function cidrHandle($ipData)
{
list($item['ip'], $item['mask']) = explode('/', $ipData);
$mask = (int)$item['mask'];
$ip = ipToBin($item['ip']);
if (filter_var($item['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
//ip4
if ($mask > 32) return false;
$mask = 0xFFFFFFFF << (32 - $mask) & 0xFFFFFFFF;
$mask = base_convert($mask, 10, 2);
$ipbin = ($ip & $mask);
} else {
if ($mask > 128) return false;
//一次做与运算数字长度128位,超过cpu位数,所以按32长度分成4段 ,
$binArr = str_split($ip, 32);
if ($mask <= 32) {
$bitIndex = 0;
$tagLen = 32;
} elseif ($mask <= 64) {
$bitIndex = 1;
$tagLen = 64;
} elseif ($mask <= 96) {
$bitIndex = 2;
$tagLen = 96;
} else {
$bitIndex = 3;
$tagLen = 128;
}
$mask = 0xFFFFFFFF << ($tagLen - $mask) & 0xFFFFFFFF;
$mask = base_convert($mask, 10, 2);
//做与运算的段,后面段直接置零
$binArr[$bitIndex] = ($binArr[$bitIndex] & $mask);
for ($i = $bitIndex + 1; $i <= 3; $i++) {
$binArr[$i] = str_repeat("0",32);
}
$ipbin = implode('', $binArr);
}
$ipStart = binToIp($ipbin);
$outIpData = $ipStart . '/' . $item['mask'];
return $outIpData;
}
/**
* IPv4|IPv6 转换 bin地址
* @param string $ip ipv4|ipv6
* @return false|string 字符串格式二进制数
*/
function ipToBin($ip)
{
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
$bin = base_convert(ip2long($ip), 10, 2);
$pad = 32 - strlen($bin);
for ($i = 1; $i <= $pad; $i++) {
$bin = "0" . $bin;
}
return $bin;
}
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
return false;
}
if (($ip_n = inet_pton($ip)) === false) {
return false;
}
// 16 x 8 bit = 128bit (ipv6)
$bits = 15;
$ipbin = "";
while ($bits >= 0) {
$bin = sprintf("%08b", (ord($ip_n[$bits])));
$ipbin = $bin . $ipbin;
$bits--;
}
return $ipbin;
}
/**
* 转换bin地址为IPv6 或IPv4
* @param string $bin 字符串格式二进制数
* @return false|string IPv4|IPv6地址
*/
function binToIp($bin)
{
if (strlen($bin) <= 32) // 32bits (ipv4)
{
return long2ip(base_convert($bin, 2, 10));
}
if (strlen($bin) != 128) {
return false;
}
$bits = 0;
$ipv6 = "";
while ($bits <= 7) {
$bin_part = substr($bin, ($bits * 16), 16);
$ipv6 .= dechex(bindec($bin_part)) . ":";
$bits++;
}
return inet_ntop(inet_pton(substr($ipv6, 0, -1)));
}