1 | <?php |
||
2 | |||
3 | namespace IPLib\Range; |
||
4 | |||
5 | use IPLib\Address\AddressInterface; |
||
6 | use IPLib\Address\IPv4; |
||
7 | use IPLib\Address\IPv6; |
||
8 | use IPLib\Address\Type as AddressType; |
||
9 | use IPLib\Factory; |
||
10 | use OutOfBoundsException; |
||
11 | |||
12 | /** |
||
13 | * Base class for range classes. |
||
14 | */ |
||
15 | abstract class AbstractRange implements RangeInterface |
||
16 | { |
||
17 | /** |
||
18 | * {@inheritdoc} |
||
19 | * |
||
20 | * @see \IPLib\Range\RangeInterface::getRangeType() |
||
21 | */ |
||
22 | 242 | public function getRangeType() |
|
23 | { |
||
24 | 242 | if ($this->rangeType === null) { |
|
25 | 242 | $addressType = $this->getAddressType(); |
|
26 | 242 | if ($addressType === AddressType::T_IPv6 && Subnet::get6to4()->containsRange($this)) { |
|
27 | 9 | $this->rangeType = Factory::getRangeFromBoundaries($this->fromAddress->toIPv4(), $this->toAddress->toIPv4())->getRangeType(); |
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
![]() |
|||
28 | } else { |
||
29 | 233 | switch ($addressType) { |
|
30 | case AddressType::T_IPv4: |
||
31 | 170 | $defaultType = IPv4::getDefaultReservedRangeType(); |
|
32 | 170 | $reservedRanges = IPv4::getReservedRanges(); |
|
33 | 170 | break; |
|
34 | case AddressType::T_IPv6: |
||
35 | 63 | $defaultType = IPv6::getDefaultReservedRangeType(); |
|
36 | 63 | $reservedRanges = IPv6::getReservedRanges(); |
|
37 | 63 | break; |
|
38 | default: |
||
39 | throw new \Exception('@todo'); // @codeCoverageIgnore |
||
40 | } |
||
41 | 233 | $rangeType = null; |
|
42 | 233 | foreach ($reservedRanges as $reservedRange) { |
|
43 | 233 | $rangeType = $reservedRange->getRangeType($this); |
|
44 | 233 | if ($rangeType !== null) { |
|
45 | 198 | break; |
|
46 | } |
||
47 | } |
||
48 | 233 | $this->rangeType = $rangeType === null ? $defaultType : $rangeType; |
|
49 | } |
||
50 | } |
||
51 | |||
52 | 242 | return $this->rangeType === false ? null : $this->rangeType; |
|
53 | } |
||
54 | |||
55 | /** |
||
56 | * {@inheritdoc} |
||
57 | * |
||
58 | * @see \IPLib\Range\RangeInterface::getAddressAtOffset() |
||
59 | */ |
||
60 | 15 | public function getAddressAtOffset($n) |
|
61 | { |
||
62 | 15 | if (!is_int($n)) { |
|
63 | 2 | return null; |
|
64 | } |
||
65 | |||
66 | 13 | $address = null; |
|
67 | 13 | if ($n >= 0) { |
|
68 | 8 | $start = Factory::parseAddressString($this->getComparableStartString()); |
|
69 | 8 | $address = $start->getAddressAtOffset($n); |
|
70 | } else { |
||
71 | 5 | $end = Factory::parseAddressString($this->getComparableEndString()); |
|
72 | 5 | $address = $end->getAddressAtOffset($n + 1); |
|
73 | } |
||
74 | |||
75 | 13 | if ($address === null) { |
|
76 | 1 | return null; |
|
77 | } |
||
78 | |||
79 | 12 | return $this->contains($address) ? $address : null; |
|
80 | } |
||
81 | |||
82 | /** |
||
83 | * {@inheritdoc} |
||
84 | * |
||
85 | * @see \IPLib\Range\RangeInterface::contains() |
||
86 | */ |
||
87 | 271 | public function contains(AddressInterface $address) |
|
88 | { |
||
89 | 271 | $result = false; |
|
90 | 271 | if ($address->getAddressType() === $this->getAddressType()) { |
|
91 | 271 | $cmp = $address->getComparableString(); |
|
92 | 271 | $from = $this->getComparableStartString(); |
|
93 | 271 | if ($cmp >= $from) { |
|
94 | 266 | $to = $this->getComparableEndString(); |
|
95 | 266 | if ($cmp <= $to) { |
|
96 | 222 | $result = true; |
|
97 | } |
||
98 | } |
||
99 | } |
||
100 | |||
101 | 271 | return $result; |
|
102 | } |
||
103 | |||
104 | /** |
||
105 | * {@inheritdoc} |
||
106 | * |
||
107 | * @see \IPLib\Range\RangeInterface::containsRange() |
||
108 | */ |
||
109 | 89 | public function containsRange(RangeInterface $range) |
|
110 | { |
||
111 | 89 | $result = false; |
|
112 | 89 | if ($range->getAddressType() === $this->getAddressType()) { |
|
113 | 89 | $myStart = $this->getComparableStartString(); |
|
114 | 89 | $itsStart = $range->getComparableStartString(); |
|
115 | 89 | if ($itsStart >= $myStart) { |
|
116 | 51 | $myEnd = $this->getComparableEndString(); |
|
117 | 51 | $itsEnd = $range->getComparableEndString(); |
|
118 | 51 | if ($itsEnd <= $myEnd) { |
|
119 | 21 | $result = true; |
|
120 | } |
||
121 | } |
||
122 | } |
||
123 | |||
124 | 89 | return $result; |
|
125 | } |
||
126 | |||
127 | /** |
||
128 | * {@inheritdoc} |
||
129 | * |
||
130 | * @see \IPLib\Range\RangeInterface::split() |
||
131 | */ |
||
132 | 65 | public function split($networkPrefix, $forceSubnet = false) |
|
133 | { |
||
134 | 65 | $networkPrefix = (int) $networkPrefix; |
|
135 | 65 | $myNetworkPrefix = $this->getNetworkPrefix(); |
|
136 | 65 | if ($networkPrefix === $myNetworkPrefix) { |
|
137 | return array( |
||
138 | 18 | $forceSubnet ? $this->asSubnet() : $this, |
|
139 | ); |
||
140 | } |
||
141 | 47 | if ($networkPrefix < $myNetworkPrefix) { |
|
142 | 16 | throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be smaller than the network prefix of the range ({$myNetworkPrefix})"); |
|
143 | } |
||
144 | 31 | $startIp = $this->getStartAddress(); |
|
145 | 31 | $maxPrefix = $startIp::getNumberOfBits(); |
|
146 | 31 | if ($networkPrefix > $maxPrefix) { |
|
147 | 13 | throw new OutOfBoundsException("The value of the \$networkPrefix parameter can't be larger than the maximum network prefix of the range ({$maxPrefix})"); |
|
148 | } |
||
149 | 18 | if ($startIp instanceof IPv4) { |
|
150 | 14 | $one = IPv4::fromBytes(array(0, 0, 0, 1)); |
|
151 | 4 | } elseif ($startIp instanceof IPv6) { |
|
152 | 4 | $one = IPv6::fromBytes(array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)); |
|
153 | } |
||
154 | 18 | $delta = $one->shift($networkPrefix - $maxPrefix); |
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
155 | 18 | $result = array(); |
|
156 | 18 | while (true) { |
|
157 | 18 | $range = Subnet::parseString("{$startIp}/{$networkPrefix}"); |
|
158 | 18 | if (!$forceSubnet && $this instanceof Pattern) { |
|
159 | 6 | $range = $range->asPattern() ?: $range; |
|
160 | } |
||
161 | 18 | $result[] = $range; |
|
162 | 18 | $startIp = $startIp->add($delta); |
|
163 | 18 | if ($startIp === null || !$this->contains($startIp)) { |
|
164 | 18 | break; |
|
165 | } |
||
166 | } |
||
167 | |||
168 | 18 | return $result; |
|
169 | } |
||
170 | } |
||
171 |