由于最近业务需要,写了个获取网段内所有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']);//24 $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']);//24 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; }