1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace IpNetCalc; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Class IpNetCalc |
7
|
|
|
* |
8
|
|
|
* Compute the common mask from multiple IP addresses |
9
|
|
|
* |
10
|
|
|
* @author Alexander Over <[email protected]> |
11
|
|
|
*/ |
12
|
|
|
class IpNetCalc |
13
|
|
|
{ |
14
|
|
|
/** |
15
|
|
|
* @param array $ips |
16
|
|
|
* @return string |
17
|
|
|
*/ |
18
|
4 |
|
public function calcNetSum(array $ips) |
|
|
|
|
19
|
|
|
{ |
20
|
4 |
|
if (count($ips) < 2) { |
21
|
|
|
throw new \InvalidArgumentException('too few arguments'); |
22
|
|
|
} |
23
|
|
|
|
24
|
4 |
|
$validated = $n = $s = []; |
|
|
|
|
25
|
4 |
|
$isV4 = $isV6 = false; |
26
|
|
|
|
27
|
4 |
|
foreach ($ips as $ip) { |
28
|
4 |
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && !$isV6) { |
29
|
2 |
|
$isV4 = true; |
30
|
2 |
|
$validated[] = $ip; |
31
|
4 |
|
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && !$isV4) { |
32
|
1 |
|
$isV6 = true; |
33
|
1 |
|
$validated[] = $ip; |
34
|
1 |
|
} else { |
|
|
|
|
35
|
1 |
|
throw new \InvalidArgumentException('mixing of IPs not allowed'); |
36
|
|
|
} |
37
|
3 |
|
} |
38
|
|
|
|
39
|
3 |
|
$mask = (($isV4) ? 32 : 128); |
40
|
3 |
|
$ipType = (($isV4) ? 4 : 6); |
41
|
|
|
|
42
|
3 |
|
asort($validated); |
43
|
|
|
|
44
|
|
|
// we need only smalest and biggest ip |
45
|
|
|
$compare = [ |
46
|
3 |
|
array_shift($validated), |
47
|
3 |
|
array_pop($validated) |
48
|
3 |
|
]; |
49
|
|
|
|
50
|
3 |
|
foreach ($compare as $key => $ip) { |
51
|
3 |
|
$s[$key] = implode('', $this->bitCalcIP($ip, $ipType)); |
52
|
3 |
|
} |
53
|
|
|
|
54
|
3 |
|
$t = ''; |
|
|
|
|
55
|
|
|
|
56
|
3 |
|
if ($s[0] === $s[1]) { |
57
|
1 |
|
$t = $s[0]; |
58
|
1 |
|
$i = $mask; |
59
|
1 |
|
} else { |
|
|
|
|
60
|
2 |
|
$o = ''; |
|
|
|
|
61
|
2 |
|
for ($i = 0, $len = strlen($s[0]); $i < $len; $i++) { |
62
|
2 |
|
if (substr($s[0], $i, 1) == substr($s[1], $i, 1)) { |
63
|
2 |
|
$o .= substr($s[0], $i, 1); |
64
|
2 |
|
} else { |
|
|
|
|
65
|
2 |
|
$t = str_pad($o, $mask, 0, STR_PAD_RIGHT); |
66
|
2 |
|
break; |
67
|
|
|
} |
68
|
2 |
|
} |
69
|
|
|
} |
70
|
|
|
|
71
|
3 |
|
$q = str_split($t, 8); |
|
|
|
|
72
|
|
|
|
73
|
3 |
|
if ($isV4) { |
74
|
2 |
|
foreach ($q as $b) { |
75
|
2 |
|
$n[] = bindec($b); |
76
|
2 |
|
} |
77
|
2 |
|
$n = implode('.', $n); |
78
|
2 |
|
} else { |
|
|
|
|
79
|
1 |
|
for ($j = 0, $len = count($q); $j < $len; $j += 2) { |
80
|
1 |
|
$n[$j] = dechex(bindec($q[$j])) . |
81
|
1 |
|
str_pad(dechex(bindec($q[$j + 1])), 2, 0, STR_PAD_LEFT); |
82
|
1 |
|
} |
83
|
1 |
|
$n = inet_ntop(inet_pton(implode(':', $n))); |
84
|
|
|
} |
85
|
|
|
|
86
|
3 |
|
return $n . '/' . $i; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* @param string $ip |
91
|
|
|
* @param integer $ipType |
92
|
|
|
* |
93
|
|
|
* @return array |
94
|
|
|
*/ |
95
|
3 |
|
private function bitCalcIP($ip, $ipType) |
|
|
|
|
96
|
|
|
{ |
97
|
3 |
|
$r = []; |
|
|
|
|
98
|
|
|
|
99
|
3 |
|
if (6 == $ipType) { |
100
|
1 |
|
$e = $this->handleV6($ip); |
|
|
|
|
101
|
1 |
|
} else { |
|
|
|
|
102
|
2 |
|
$e = explode('.', $ip); |
103
|
|
|
} |
104
|
|
|
|
105
|
3 |
|
foreach ($e as $b) { |
106
|
3 |
|
$r[] = str_pad(decbin($b), 8, 0, STR_PAD_LEFT); |
107
|
3 |
|
} |
108
|
|
|
|
109
|
3 |
|
return $r; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* @param string $ip |
114
|
|
|
* @return array |
115
|
|
|
*/ |
116
|
1 |
|
private function handleV6($ip) |
|
|
|
|
117
|
|
|
{ |
118
|
1 |
|
$n = []; |
|
|
|
|
119
|
1 |
|
$unpack = unpack('H*', inet_pton($ip)); |
120
|
1 |
|
$e = str_split($unpack[1], 4); |
|
|
|
|
121
|
1 |
|
for ($i = 0; $i < 8; $i++) { |
122
|
1 |
|
$n[] = hexdec(substr($e[$i], 0, 2)); |
123
|
1 |
|
$n[] = hexdec(substr($e[$i], 2, 2)); |
124
|
1 |
|
} |
125
|
1 |
|
return $n; |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
A high number of execution paths generally suggests many nested conditional statements and make the code less readible. This can usually be fixed by splitting the method into several smaller methods.
You can also find more information in the “Code” section of your repository.