1 | <?php |
||
5 | class SubMuncher |
||
6 | { |
||
7 | /** |
||
8 | * This class should not be instantiated. |
||
9 | */ |
||
10 | private function __construct() |
||
13 | |||
14 | /** |
||
15 | * @param array $ipsArray |
||
16 | * @param int $max max number of rules returned |
||
17 | * @return array |
||
18 | */ |
||
19 | public static function consolidate($ipsArray, $max = null) |
||
20 | { |
||
21 | $consolidatedSubnets = []; |
||
22 | $subnetStart = null; |
||
23 | |||
24 | $ips = array_unique($ipsArray); |
||
25 | $sortedIPs = Util::sort_addresses($ips); |
||
26 | |||
27 | foreach ($sortedIPs as $index => $ipv4) { |
||
28 | // first IP |
||
29 | if ($index == 0) { |
||
30 | $subnetStart = $ipv4; |
||
31 | } |
||
32 | // last IP |
||
33 | if (!isset($sortedIPs[$index + 1])) { |
||
34 | if ($subnetStart) { |
||
35 | $result = self::ip_range_to_subnet_array($subnetStart, $ipv4); |
||
36 | $consolidatedSubnets = array_merge($consolidatedSubnets, $result); |
||
37 | } else { |
||
38 | $consolidatedSubnets[]= $ipv4.'/32'; |
||
39 | $subnetStart = null; |
||
40 | } |
||
41 | // if the next IP is sequential, we want this as part of the subnet |
||
42 | } elseif ($sortedIPs[$index + 1] == Util::ip_after($ipv4)) { |
||
43 | // if we've already started, just keep going, else kick one off |
||
44 | $subnetStart = $subnetStart ?: $ipv4; |
||
45 | // if not the first IP and the previous IP is sequential, we're at the end of a subnet |
||
46 | } elseif (isset($sortedIPs[$index - 1]) && $ipv4 == Util::ip_after($sortedIPs[$index - 1])) { |
||
47 | $result = self::ip_range_to_subnet_array($subnetStart, $ipv4); |
||
48 | $consolidatedSubnets = array_merge($consolidatedSubnets, $result); |
||
49 | $subnetStart = null; |
||
50 | // otherwise we are a lone /32, so add it straight in |
||
51 | } else { |
||
52 | $consolidatedSubnets[]= $ipv4.'/32'; |
||
53 | $subnetStart = null; |
||
54 | } |
||
55 | } |
||
56 | |||
57 | if ($max === null || count($consolidatedSubnets) <= $max) { |
||
58 | return $consolidatedSubnets; |
||
59 | } |
||
60 | |||
61 | return self::ultra_compression($consolidatedSubnets, $max); |
||
62 | } |
||
63 | |||
64 | /** |
||
65 | * @param string $startip an IPv4 address |
||
66 | * @param string $endip an IPv4 address |
||
67 | * |
||
68 | * @return string[] list of subnets that cover the ip range specified |
||
69 | */ |
||
70 | public static function ip_range_to_subnet_array($startip, $endip) |
||
148 | |||
149 | |||
150 | /** |
||
151 | * Should be an array of CIDRS eg ['1.1.1.0/24', '2.2.2.2/31'] |
||
152 | * |
||
153 | * @param string[] $subnetsArray |
||
154 | * @param int $max |
||
155 | */ |
||
156 | public static function consolidate_subnets($subnetsArray, $max = null) |
||
165 | |||
166 | /** |
||
167 | * Function to figure out the least problematic subnets to combine based on |
||
168 | * fewest additional IPs introduced. Then combines them as such, and runs |
||
169 | * it back through the consolidator with one less subnet - until we have |
||
170 | * reduced it down to the maximum number of rules |
||
171 | * |
||
172 | * @param array $subnetsArray array of cidrs |
||
173 | * @param int $max |
||
174 | * |
||
175 | * @return array |
||
176 | */ |
||
177 | public static function ultra_compression($subnetsArray, $max = null) |
||
246 | } |
||
247 |
If you define a variable conditionally, it can happen that it is not defined for all execution paths.
Let’s take a look at an example:
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.
Available Fixes
Check for existence of the variable explicitly:
Define a default value for the variable:
Add a value for the missing path: