我有一个由IP地址和子网掩码组成的多维数组:
array(4) {
[0]=>
array(3) {
["ip"]=>
string(12) "192.168.0.0"
["mask"]=>
int(22)
}
[1]=>
array(3) {
["ip"]=>
string(12) "192.168.0.0"
["mask"]=>
int(30)
}
[2]=>
array(3) {
["ip"]=>
string(12) "192.168.0.4"
["mask"]=>
int(31)
}
[3]=>
array(3) {
["ip"]=>
string(12) "192.168.0.4"
["mask"]=>
int(32)
}
}
阵列已按正确顺序排列。我需要做的是将此数组转换为分层列表,所需的输出应该是这样的:
192.168.0.0/22
- 192.168.0.0/30
- 192.168.0.4/31
-- 192.168.0.4/32
每次子网属于更大的子网时,缩进(' - ')必须增加1,如上面的输出所示。我没有使用预定义的父ID,因为子网列表可能随时更改。这种转换必须在运行中完成。
我希望我会尝试任何东西,但我不知道从哪里开始。我唯一能想到的是在每次迭代中通过数组比较2个子网。首先比较子网1和2,然后是2和3,然后是3和4,依此类推......
答案 0 :(得分:1)
我写了一个小类来处理CIDR逻辑(简化嵌套过程)。
<?php
class Cidr {
/**
* @var int
*/
private $subnet;
/**
* @var int
*/
private $mask;
/**
* @var int
*/
private $upperBound;
/**
* @var self[]
*/
private $children = [];
/**
* Cidr constructor
*
* @param string $subnet
* @param int $mask
*/
public function __construct($subnet, $mask) {
$this->subnet = ip2long($subnet);
$this->mask = (int) $mask;
$this->upperBound = $this->subnet + pow(2, 32 - $this->mask) - 1;
}
/**
* @param string $rangeStr
*
* @return Cidr
*/
public static function fromString($rangeStr) {
list($subnet, $mask) = explode('/', $rangeStr);
return new self($subnet, $mask);
}
/**
* @return string
*/
public function __toString() {
return "{$this->minIp()}/{$this->mask}";
}
/**
* @param Cidr $cidr
*
* @return bool
*/
public function addChild(self $cidr) {
if ($cidr === $this) {
return false;
}
if ($this->isRangeInRange($cidr)) {
foreach ($this->children as $child) {
if ($child->addChild($cidr)) {
return true;
}
}
$this->children[] = $cidr;
return true;
}
return false;
}
/**
* @return Cidr[]
*/
public function getChildren() {
return $this->children;
}
/**
* @return string
*/
public function minIp() {
return long2ip($this->subnet);
}
/**
* @return string
*/
public function maxIp() {
return long2ip($this->upperBound);
}
/**
* Check if an IP falls within this range
*
* @param string $ip
*
* @return bool
*/
public function isIpInRange($ip) {
$mask = -1 << (32 - $this->mask);
return (ip2long($ip) & $mask) === ($this->subnet & $mask);
}
/**
* @param Cidr $cidr
*
* @return bool
*/
public function isRangeInRange(self $cidr) {
return $cidr->subnet >= $this->subnet && $cidr->upperBound <= $this->upperBound;
}
/**
* @param self[] $cidrs
*/
public static function nestCidrs(array &$cidrs) {
foreach ($cidrs as $a) {
foreach ($cidrs as $k => $b) {
if ($a !== $b && $a->addChild($b)) {
unset($cidrs[$k]);
}
}
}
}
/**
* @param self[] $cidrs
* @param int $depth
*/
public static function displayCidrs(array $cidrs, $depth = 0) {
foreach ($cidrs as $cidr) {
echo str_repeat('-', $depth) . "{$cidr}\n";
self::displayCidrs($cidr->getChildren(), $depth + 1);
}
}
}
使用子网数组(如您在示例中所示):
$subnets = [
[
'ip' => '192.168.0.0',
'mask' => 22,
],
[
'ip' => '192.168.0.0',
'mask' => 30,
],
[
'ip' => '192.168.0.4',
'mask' => 31,
],
[
'ip' => '192.168.0.4',
'mask' => 32,
],
];
创建一个Cidr
个对象数组:
$cidrs = [];
foreach ($subnets as $subnet) {
$cidr = new Cidr($subnet['ip'], $subnet['mask']);
$cidrs[(string) $cidr] = $cidr;
}
运行嵌套功能(根据需要递归添加每个子网范围:
Cidr::nestCidrs($cidrs);
然后显示结果:
Cidr::displayCidrs($cidrs);
结果:
192.168.0.0/22
-192.168.0.0/30
-192.168.0.4/31
--192.168.0.4/32
答案 1 :(得分:-1)
您想要的示例示例
$h = array(
array("ip_bin"=>"192.168.0.0","mask"=>22),
array("ip_bin"=>"192.168.1.0","mask"=>30),
array("ip_bin"=>"192.168.4.0","mask"=>31),);
$dash = "";
foreach($h as $s){
$dash .="-";
echo $dash. $s['ip_bin']."/".$s['mask']."<br>";
}
输出
-192.168.0.0
--192.168.1.0
---192.168.4.0