1 | <?php |
||||||
2 | |||||||
3 | namespace IPLib; |
||||||
4 | |||||||
5 | use IPLib\Address\AddressInterface; |
||||||
6 | use IPLib\Range\Subnet; |
||||||
7 | use IPLib\Service\RangesFromBoundaryCalculator; |
||||||
8 | |||||||
9 | /** |
||||||
10 | * Factory methods to build class instances. |
||||||
11 | */ |
||||||
12 | class Factory |
||||||
13 | { |
||||||
14 | /** |
||||||
15 | * @deprecated since 1.17.0: use the parseAddressString() method instead. |
||||||
16 | * For upgrading: |
||||||
17 | * - if $mayIncludePort is true, use the ParseStringFlag::MAY_INCLUDE_PORT flag |
||||||
18 | * - if $mayIncludeZoneID is true, use the ParseStringFlag::MAY_INCLUDE_ZONEID flag |
||||||
19 | * - if $supportNonDecimalIPv4 is true, use the ParseStringFlag::IPV4_MAYBE_NON_DECIMAL flag |
||||||
20 | * |
||||||
21 | * @param string|mixed $address |
||||||
22 | * @param bool $mayIncludePort |
||||||
23 | * @param bool $mayIncludeZoneID |
||||||
24 | * @param bool $supportNonDecimalIPv4 |
||||||
25 | * |
||||||
26 | * @return \IPLib\Address\AddressInterface|null |
||||||
27 | * |
||||||
28 | * @see \IPLib\Factory::parseAddressString() |
||||||
29 | * @since 1.1.0 added the $mayIncludePort argument |
||||||
30 | * @since 1.3.0 added the $mayIncludeZoneID argument |
||||||
31 | * @since 1.10.0 added the $supportNonDecimalIPv4 argument |
||||||
32 | */ |
||||||
33 | 598 | public static function addressFromString($address, $mayIncludePort = true, $mayIncludeZoneID = true, $supportNonDecimalIPv4 = false) |
|||||
34 | { |
||||||
35 | 598 | return static::parseAddressString($address, 0 + ($mayIncludePort ? ParseStringFlag::MAY_INCLUDE_PORT : 0) + ($mayIncludeZoneID ? ParseStringFlag::MAY_INCLUDE_ZONEID : 0) + ($supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0)); |
|||||
36 | } |
||||||
37 | |||||||
38 | /** |
||||||
39 | * Parse an IP address string. |
||||||
40 | * |
||||||
41 | * @param string|mixed $address the address to parse |
||||||
42 | * @param int $flags A combination or zero or more flags |
||||||
43 | * |
||||||
44 | * @return \IPLib\Address\AddressInterface|null |
||||||
45 | * |
||||||
46 | * @see \IPLib\ParseStringFlag |
||||||
47 | * @since 1.17.0 |
||||||
48 | */ |
||||||
49 | 1620 | public static function parseAddressString($address, $flags = 0) |
|||||
50 | { |
||||||
51 | 1620 | $result = null; |
|||||
52 | 1620 | if ($result === null) { |
|||||
0 ignored issues
–
show
introduced
by
![]() |
|||||||
53 | 1620 | $result = Address\IPv4::parseString($address, $flags); |
|||||
54 | } |
||||||
55 | 1620 | if ($result === null) { |
|||||
56 | 735 | $result = Address\IPv6::parseString($address, $flags); |
|||||
57 | } |
||||||
58 | |||||||
59 | 1620 | return $result; |
|||||
60 | } |
||||||
61 | |||||||
62 | /** |
||||||
63 | * Convert a byte array to an address instance. |
||||||
64 | * |
||||||
65 | * @param int[]|array $bytes |
||||||
66 | * |
||||||
67 | * @return \IPLib\Address\AddressInterface|null |
||||||
68 | */ |
||||||
69 | 644 | public static function addressFromBytes(array $bytes) |
|||||
70 | { |
||||||
71 | 644 | $result = null; |
|||||
72 | 644 | if ($result === null) { |
|||||
0 ignored issues
–
show
|
|||||||
73 | 644 | $result = Address\IPv4::fromBytes($bytes); |
|||||
74 | } |
||||||
75 | 644 | if ($result === null) { |
|||||
76 | 300 | $result = Address\IPv6::fromBytes($bytes); |
|||||
77 | } |
||||||
78 | |||||||
79 | 644 | return $result; |
|||||
80 | } |
||||||
81 | |||||||
82 | /** |
||||||
83 | * @deprecated since 1.17.0: use the parseRangeString() method instead. |
||||||
84 | * For upgrading: |
||||||
85 | * - if $supportNonDecimalIPv4 is true, use the ParseStringFlag::IPV4_MAYBE_NON_DECIMAL flag |
||||||
86 | * |
||||||
87 | * @param string|mixed $range |
||||||
88 | * @param bool $supportNonDecimalIPv4 |
||||||
89 | * |
||||||
90 | * @return \IPLib\Range\RangeInterface|null |
||||||
91 | * |
||||||
92 | * @see \IPLib\Factory::parseRangeString() |
||||||
93 | * @since 1.10.0 added the $supportNonDecimalIPv4 argument |
||||||
94 | */ |
||||||
95 | 672 | public static function rangeFromString($range, $supportNonDecimalIPv4 = false) |
|||||
96 | { |
||||||
97 | 672 | return static::parseRangeString($range, $supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0); |
|||||
98 | } |
||||||
99 | |||||||
100 | /** |
||||||
101 | * Parse an IP range string. |
||||||
102 | * |
||||||
103 | * @param string $range |
||||||
104 | * @param int $flags A combination or zero or more flags |
||||||
105 | * |
||||||
106 | * @return \IPLib\Range\RangeInterface|null |
||||||
107 | * |
||||||
108 | * @see \IPLib\ParseStringFlag |
||||||
109 | * @since 1.17.0 |
||||||
110 | */ |
||||||
111 | 771 | public static function parseRangeString($range, $flags = 0) |
|||||
112 | { |
||||||
113 | 771 | $result = null; |
|||||
114 | 771 | if ($result === null) { |
|||||
0 ignored issues
–
show
|
|||||||
115 | 771 | $result = Range\Subnet::parseString($range, $flags); |
|||||
116 | } |
||||||
117 | 771 | if ($result === null) { |
|||||
118 | 155 | $result = Range\Pattern::parseString($range, $flags); |
|||||
119 | } |
||||||
120 | 771 | if ($result === null) { |
|||||
121 | 59 | $result = Range\Single::parseString($range, $flags); |
|||||
122 | } |
||||||
123 | |||||||
124 | 771 | return $result; |
|||||
125 | } |
||||||
126 | |||||||
127 | /** |
||||||
128 | * @deprecated since 1.17.0: use the getRangeFromBoundaries() method instead. |
||||||
129 | * For upgrading: |
||||||
130 | * - if $supportNonDecimalIPv4 is true, use the ParseStringFlag::IPV4_MAYBE_NON_DECIMAL flag |
||||||
131 | * |
||||||
132 | * @param string|\IPLib\Address\AddressInterface|mixed $from |
||||||
133 | * @param string|\IPLib\Address\AddressInterface|mixed $to |
||||||
134 | * @param bool $supportNonDecimalIPv4 |
||||||
135 | * |
||||||
136 | * @return \IPLib\Address\AddressInterface|null |
||||||
137 | * |
||||||
138 | * @see \IPLib\Factory::getRangeFromBoundaries() |
||||||
139 | * @since 1.2.0 |
||||||
140 | * @since 1.10.0 added the $supportNonDecimalIPv4 argument |
||||||
141 | */ |
||||||
142 | 35 | public static function rangeFromBoundaries($from, $to, $supportNonDecimalIPv4 = false) |
|||||
143 | { |
||||||
144 | 35 | return static::getRangeFromBoundaries($from, $to, ParseStringFlag::MAY_INCLUDE_PORT | ParseStringFlag::MAY_INCLUDE_ZONEID | ($supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0)); |
|||||
0 ignored issues
–
show
|
|||||||
145 | } |
||||||
146 | |||||||
147 | /** |
||||||
148 | * Create the smallest address range that comprises two addresses. |
||||||
149 | * |
||||||
150 | * @param string|\IPLib\Address\AddressInterface|mixed $from |
||||||
151 | * @param string|\IPLib\Address\AddressInterface|mixed $to |
||||||
152 | * @param int $flags A combination or zero or more flags |
||||||
153 | * |
||||||
154 | * @return \IPLib\Range\RangeInterface|null return NULL if $from and/or $to are invalid addresses, or if both are NULL or empty strings, or if they are addresses of different types |
||||||
155 | * |
||||||
156 | * @see \IPLib\ParseStringFlag |
||||||
157 | * @since 1.17.0 |
||||||
158 | */ |
||||||
159 | 44 | public static function getRangeFromBoundaries($from, $to, $flags = 0) |
|||||
160 | { |
||||||
161 | 44 | list($from, $to) = self::parseBoundaries($from, $to, $flags); |
|||||
162 | |||||||
163 | 44 | return $from === false || $to === false ? null : static::rangeFromBoundaryAddresses($from, $to); |
|||||
0 ignored issues
–
show
$from of type void is incompatible with the type IPLib\Address\AddressInterface|null expected by parameter $from of IPLib\Factory::rangeFromBoundaryAddresses() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() $to of type void is incompatible with the type IPLib\Address\AddressInterface|null expected by parameter $to of IPLib\Factory::rangeFromBoundaryAddresses() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
164 | } |
||||||
165 | |||||||
166 | /** |
||||||
167 | * @deprecated since 1.17.0: use the getRangesFromBoundaries() method instead. |
||||||
168 | * For upgrading: |
||||||
169 | * - if $supportNonDecimalIPv4 is true, use the ParseStringFlag::IPV4_MAYBE_NON_DECIMAL flag |
||||||
170 | * |
||||||
171 | * @param string|\IPLib\Address\AddressInterface|mixed $from |
||||||
172 | * @param string|\IPLib\Address\AddressInterface|mixed $to |
||||||
173 | * @param bool $supportNonDecimalIPv4 |
||||||
174 | * |
||||||
175 | * @return \IPLib\Range\Subnet[]|null |
||||||
176 | * |
||||||
177 | * @see \IPLib\Factory::getRangesFromBoundaries() |
||||||
178 | * @since 1.14.0 |
||||||
179 | */ |
||||||
180 | 34 | public static function rangesFromBoundaries($from, $to, $supportNonDecimalIPv4 = false) |
|||||
181 | { |
||||||
182 | 34 | return static::getRangesFromBoundaries($from, $to, ParseStringFlag::MAY_INCLUDE_PORT | ParseStringFlag::MAY_INCLUDE_ZONEID | ($supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0)); |
|||||
183 | } |
||||||
184 | |||||||
185 | /** |
||||||
186 | * Create a list of Range instances that exactly describes all the addresses between the two provided addresses. |
||||||
187 | * |
||||||
188 | * @param string|\IPLib\Address\AddressInterface $from |
||||||
189 | * @param string|\IPLib\Address\AddressInterface $to |
||||||
190 | * @param int $flags A combination or zero or more flags |
||||||
191 | * |
||||||
192 | * @return \IPLib\Range\Subnet[]|null return NULL if $from and/or $to are invalid addresses, or if both are NULL or empty strings, or if they are addresses of different types |
||||||
193 | * |
||||||
194 | * @see \IPLib\ParseStringFlag |
||||||
195 | * @since 1.17.0 |
||||||
196 | */ |
||||||
197 | 34 | public static function getRangesFromBoundaries($from, $to, $flags = 0) |
|||||
198 | { |
||||||
199 | 34 | list($from, $to) = self::parseBoundaries($from, $to, $flags); |
|||||
200 | 34 | if ($from === false || $to === false || ($from === null && $to === null)) { |
|||||
0 ignored issues
–
show
|
|||||||
201 | 5 | return null; |
|||||
202 | } |
||||||
203 | 29 | if ($from === null || $to === null) { |
|||||
204 | 2 | $address = $from ? $from : $to; |
|||||
205 | |||||||
206 | 2 | return array(new Subnet($address, $address, $address->getNumberOfBits())); |
|||||
207 | } |
||||||
208 | 27 | $numberOfBits = $from->getNumberOfBits(); |
|||||
209 | 27 | if ($to->getNumberOfBits() !== $numberOfBits) { |
|||||
210 | 1 | return null; |
|||||
211 | } |
||||||
212 | 26 | $calculator = new RangesFromBoundaryCalculator($numberOfBits); |
|||||
213 | |||||||
214 | 26 | return $calculator->getRanges($from, $to); |
|||||
215 | } |
||||||
216 | |||||||
217 | /** |
||||||
218 | * @param \IPLib\Address\AddressInterface|null $from |
||||||
219 | * @param \IPLib\Address\AddressInterface|null $to |
||||||
220 | * |
||||||
221 | * @return \IPLib\Range\RangeInterface|null |
||||||
222 | * |
||||||
223 | * @since 1.2.0 |
||||||
224 | */ |
||||||
225 | 41 | protected static function rangeFromBoundaryAddresses($from = null, $to = null) |
|||||
226 | { |
||||||
227 | 41 | if (!$from instanceof AddressInterface && !$to instanceof AddressInterface) { |
|||||
228 | 2 | $result = null; |
|||||
229 | 39 | } elseif (!$to instanceof AddressInterface) { |
|||||
230 | 2 | $result = Range\Single::fromAddress($from); |
|||||
0 ignored issues
–
show
It seems like
$from can also be of type null ; however, parameter $address of IPLib\Range\Single::fromAddress() does only seem to accept IPLib\Address\AddressInterface , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
231 | 39 | } elseif (!$from instanceof AddressInterface) { |
|||||
232 | 2 | $result = Range\Single::fromAddress($to); |
|||||
233 | } else { |
||||||
234 | 37 | $result = null; |
|||||
235 | 37 | $addressType = $from->getAddressType(); |
|||||
236 | 37 | if ($addressType === $to->getAddressType()) { |
|||||
237 | 36 | $cmp = strcmp($from->getComparableString(), $to->getComparableString()); |
|||||
238 | 36 | if ($cmp === 0) { |
|||||
239 | 11 | $result = Range\Single::fromAddress($from); |
|||||
240 | } else { |
||||||
241 | 25 | if ($cmp > 0) { |
|||||
242 | list($from, $to) = array($to, $from); |
||||||
243 | } |
||||||
244 | 25 | $fromBytes = $from->getBytes(); |
|||||
245 | 25 | $toBytes = $to->getBytes(); |
|||||
246 | 25 | $numBytes = count($fromBytes); |
|||||
247 | 25 | $sameBits = 0; |
|||||
248 | 25 | for ($byteIndex = 0; $byteIndex < $numBytes; $byteIndex++) { |
|||||
249 | 25 | $fromByte = $fromBytes[$byteIndex]; |
|||||
250 | 25 | $toByte = $toBytes[$byteIndex]; |
|||||
251 | 25 | if ($fromByte === $toByte) { |
|||||
252 | 24 | $sameBits += 8; |
|||||
253 | } else { |
||||||
254 | 25 | $differentBitsInByte = decbin($fromByte ^ $toByte); |
|||||
255 | 25 | $sameBits += 8 - strlen($differentBitsInByte); |
|||||
256 | 25 | break; |
|||||
257 | } |
||||||
258 | } |
||||||
259 | 25 | $result = static::parseRangeString($from->toString() . '/' . (string) $sameBits); |
|||||
260 | } |
||||||
261 | } |
||||||
262 | } |
||||||
263 | |||||||
264 | 41 | return $result; |
|||||
265 | } |
||||||
266 | |||||||
267 | /** |
||||||
268 | * @param string|\IPLib\Address\AddressInterface $from |
||||||
269 | * @param string|\IPLib\Address\AddressInterface $to |
||||||
270 | * @param int $flags |
||||||
271 | * |
||||||
272 | * @return \IPLib\Address\AddressInterface[]|null[]|false[] |
||||||
273 | */ |
||||||
274 | 78 | private static function parseBoundaries($from, $to, $flags = 0) |
|||||
275 | { |
||||||
276 | 78 | $result = array(); |
|||||
277 | 78 | foreach (array('from', 'to') as $param) { |
|||||
278 | 78 | $value = $$param; |
|||||
279 | 78 | if (!($value instanceof AddressInterface)) { |
|||||
280 | 69 | $value = (string) $value; |
|||||
281 | 69 | if ($value === '') { |
|||||
282 | 8 | $value = null; |
|||||
283 | } else { |
||||||
284 | 65 | $value = static::parseAddressString($value, $flags); |
|||||
285 | 65 | if ($value === null) { |
|||||
286 | 6 | $value = false; |
|||||
287 | } |
||||||
288 | } |
||||||
289 | } |
||||||
290 | 78 | $result[] = $value; |
|||||
291 | } |
||||||
292 | 78 | if ($result[0] && $result[1] && strcmp($result[0]->getComparableString(), $result[1]->getComparableString()) > 0) { |
|||||
293 | 51 | $result = array($result[1], $result[0]); |
|||||
294 | } |
||||||
295 | |||||||
296 | 78 | return $result; |
|||||
297 | } |
||||||
298 | } |
||||||
299 |