由于最近业务需要,写了个获取网段内所有IP的函数,以及分配可用子网段的函数

/**
* 根据网段获取计算所有IP
* @param string $segment 网段 '139.217.0.1/24'
* @return array IP列表 ['139.217.0.1','139.217.0.2'……]
*/
function getIpBySegment($segment)
{
$segmentInfo = explode("/", $segment);//['139.217.0.1',24]
$beginIpArray = explode(".", $segmentInfo[0]);//[139,217,0,1]
$mask = intval($segmentInfo['1']);//
$endIp = array();
foreach ($beginIpArray as $ipKey => $item) {
$beginFlag = 8 * ($ipKey);//0 8 16 24
$endFlag = 8 * ($ipKey + 1);//8 16 24 32
$decbinItem = str_pad(decbin($item), 8, "0", STR_PAD_LEFT);
$endIp[] = $mask >= $endFlag ? $item : ($mask > $beginFlag ? bindec(str_pad(substr($decbinItem, 0, $mask - $beginFlag), 8, "1", STR_PAD_RIGHT)) : ($ipKey <= 2 ? pow(2, 8) - 1 : pow(2, 8) - 1));
}
$ipArray = array();
for ($beginIp[0] = $beginIpArray[0]; $beginIp[0] <= $endIp[0]; $beginIp[0]++) {
for ($beginIp[1] = $beginIpArray[1]; $beginIp[1] <= $endIp[1]; $beginIp[1]++) {
for ($beginIp[2] = $beginIpArray[2]; $beginIp[2] <= $endIp[2]; $beginIp[2]++) {
for ($beginIp[3] = $beginIpArray[3]; $beginIp[3] <= $endIp[3]; $beginIp[3]++) {
$ipArray[] = implode(".", $beginIp);
}
}
}
}
return $ipArray;
}
/**
* 在指定网段中分配子网段
* @param string $segment 指定网段
* @param int $ipNum 需要的IP数
* @param array $usedIpArray 不可用(已经使用)的IP,默认为空数组
* @return bool|string 成功则返回分配的网段
*/
function allocateSegment($segment, $ipNum, $usedIpArray = [])
{
$usedIpArray = empty($usedIpArray) ? [] : array_flip($usedIpArray);
//计算需要多少个IP
$i = 0;
$ipCount = pow(2, $i);
while ($ipCount < $ipNum) {
$i++;
$ipCount = pow(2, $i);
}
$newMask = 32 - $i;
//大网段的开始和结束IP
$segmentInfo = explode("/", $segment);//['139.217.0.1',24]
$beginIpArray = explode(".", $segmentInfo[0]);//[139,217,0,1]
$mask = intval($segmentInfo['1']);//
if ($newMask < $mask) {
return false;
}
$endIp = array();
$step = [];
foreach ($beginIpArray as $ipKey => $item) {
$beginFlag = 8 * ($ipKey);//0 8 16 24
$endFlag = 8 * ($ipKey + 1);//8 16 24 32
$step[$ipKey] = $newMask > $endFlag ? 1 : ($endFlag - $newMask < 8 ? pow(2, $endFlag - $newMask) : pow(2, 8));
$decbinItem = str_pad(decbin($item), 8, "0", STR_PAD_LEFT);
$endIp[] = $mask >= $endFlag ? $item : ($mask > $beginFlag ? bindec(str_pad(substr($decbinItem, 0, $mask - $beginFlag), 8, "1", STR_PAD_RIGHT)) : ($ipKey <= 2 ? pow(2, 8) - 1 : pow(2, 8) - 1));
}
//遍历生成网段
for ($beginIp[0] = $beginIpArray[0]; $beginIp[0] <= $endIp[0]; $beginIp[0] += $step[0]) {
for ($beginIp[1] = $beginIpArray[1]; $beginIp[1] <= $endIp[1]; $beginIp[1] += $step[1]) {
for ($beginIp[2] = $beginIpArray[2]; $beginIp[2] <= $endIp[2]; $beginIp[2] += $step[2]) {
for ($beginIp[3] = $beginIpArray[3]; $beginIp[3] <= $endIp[3]; $beginIp[3] += $step[3]) {
$newSegment = implode('.', $beginIp) . '/' . $newMask;
//获取该网段所有的IP
$ipArray = getIpBySegment($newSegment);
$canUse = true;
//判断该网段是否可用
if (!empty($usedIpArray)) {
foreach ($ipArray as $ip) {
if (isset($usedIpArray[$ip])) {
$canUse = false;
break;
}
}
}
if ($canUse) {
return $newSegment;
}
}
}
}
}
return false;
}
05-11 20:08