PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.15.2
Independent Analytics – WordPress Analytics Plugin v2.15.2
2.15.4 2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / mlocati / ip-lib / src / Address / IPv4.php
independent-analytics / vendor / mlocati / ip-lib / src / Address Last commit date
AddressInterface.php 2 weeks ago AssignedRange.php 1 year ago IPv4.php 2 weeks ago IPv6.php 2 weeks ago Type.php 2 weeks ago
IPv4.php
530 lines
1 <?php
2
3 namespace IAWPSCOPED\IPLib\Address;
4
5 use IAWPSCOPED\IPLib\ParseStringFlag;
6 use IAWPSCOPED\IPLib\Range\RangeInterface;
7 use IAWPSCOPED\IPLib\Range\Subnet;
8 use IAWPSCOPED\IPLib\Range\Type as RangeType;
9 use IAWPSCOPED\IPLib\Service\BinaryMath;
10 use IAWPSCOPED\IPLib\Service\NumberInChunks;
11 /**
12 * An IPv4 address.
13 *
14 * @phpstan-consistent-constructor
15 * @internal
16 */
17 class IPv4 implements AddressInterface
18 {
19 /**
20 * The string representation of the address.
21 *
22 * @var string
23 *
24 * @example '127.0.0.1'
25 */
26 protected $address;
27 /**
28 * The byte list of the IP address.
29 *
30 * @var int[]|null
31 */
32 protected $bytes;
33 /**
34 * The type of the range of this IP address.
35 *
36 * @var int|null
37 */
38 protected $rangeType;
39 /**
40 * A string representation of this address than can be used when comparing addresses and ranges.
41 *
42 * @var string|null
43 */
44 protected $comparableString;
45 /**
46 * An array containing RFC designated address ranges.
47 *
48 * @var \IPLib\Address\AssignedRange[]|null
49 */
50 private static $reservedRanges;
51 /**
52 * Initializes the instance.
53 *
54 * @param string $address
55 */
56 protected function __construct($address)
57 {
58 $this->address = $address;
59 $this->bytes = null;
60 $this->rangeType = null;
61 $this->comparableString = null;
62 }
63 /**
64 * {@inheritdoc}
65 *
66 * @see \IPLib\Address\AddressInterface::__toString()
67 */
68 public function __toString()
69 {
70 return $this->address;
71 }
72 /**
73 * {@inheritdoc}
74 *
75 * @see \IPLib\Address\AddressInterface::getNumberOfBits()
76 */
77 public static function getNumberOfBits()
78 {
79 return 32;
80 }
81 /**
82 * @deprecated since 1.17.0: use the parseString() method instead.
83 * For upgrading:
84 * - if $mayIncludePort is true, use the ParseStringFlag::MAY_INCLUDE_PORT flag
85 * - if $supportNonDecimalIPv4 is true, use the ParseStringFlag::IPV4_MAYBE_NON_DECIMAL flag
86 *
87 * @param string|mixed $address the address to parse
88 * @param bool $mayIncludePort
89 * @param bool $supportNonDecimalIPv4
90 *
91 * @return static|null
92 *
93 * @see \IPLib\Address\IPv4::parseString()
94 * @since 1.1.0 added the $mayIncludePort argument
95 * @since 1.10.0 added the $supportNonDecimalIPv4 argument
96 */
97 public static function fromString($address, $mayIncludePort = \true, $supportNonDecimalIPv4 = \false)
98 {
99 return static::parseString($address, 0 | ($mayIncludePort ? ParseStringFlag::MAY_INCLUDE_PORT : 0) | ($supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0));
100 }
101 /**
102 * Parse a string and returns an IPv4 instance if the string is valid, or null otherwise.
103 *
104 * @param string|mixed $address the address to parse
105 * @param int $flags A combination or zero or more flags
106 *
107 * @return static|null
108 *
109 * @see \IPLib\ParseStringFlag
110 * @since 1.17.0
111 */
112 public static function parseString($address, $flags = 0)
113 {
114 if (!\is_string($address)) {
115 return null;
116 }
117 $flags = (int) $flags;
118 $matches = null;
119 if ($flags & ParseStringFlag::ADDRESS_MAYBE_RDNS) {
120 if (\preg_match('/^([12]?[0-9]{1,2}\\.[12]?[0-9]{1,2}\\.[12]?[0-9]{1,2}\\.[12]?[0-9]{1,2})\\.in-addr\\.arpa\\.?$/i', $address, $matches)) {
121 $address = \implode('.', \array_reverse(\explode('.', $matches[1])));
122 $flags = $flags & ~(ParseStringFlag::IPV4_MAYBE_NON_DECIMAL | ParseStringFlag::IPV4ADDRESS_MAYBE_NON_QUAD_DOTTED);
123 }
124 }
125 if ($flags & ParseStringFlag::IPV4ADDRESS_MAYBE_NON_QUAD_DOTTED) {
126 if (\strpos($address, '.') === 0) {
127 return null;
128 }
129 $lengthNonHex = '{1,11}';
130 $lengthHex = '{1,8}';
131 $chunk234Optional = \true;
132 } else {
133 if (!\strpos($address, '.')) {
134 return null;
135 }
136 $lengthNonHex = '{1,3}';
137 $lengthHex = '{1,2}';
138 $chunk234Optional = \false;
139 }
140 $rxChunk1 = "0?[0-9]{$lengthNonHex}";
141 if ($flags & ParseStringFlag::IPV4_MAYBE_NON_DECIMAL) {
142 $rxChunk1 = "(?:0[Xx]0*[0-9A-Fa-f]{$lengthHex})|(?:{$rxChunk1})";
143 $onlyDecimal = \false;
144 } else {
145 $onlyDecimal = \true;
146 }
147 $rxChunk1 = "0*?({$rxChunk1})";
148 $rxChunk234 = "\\.{$rxChunk1}";
149 if ($chunk234Optional) {
150 $rxChunk234 = "(?:{$rxChunk234})?";
151 }
152 $rx = "{$rxChunk1}{$rxChunk234}{$rxChunk234}{$rxChunk234}";
153 if ($flags & ParseStringFlag::MAY_INCLUDE_PORT) {
154 $rx .= '(?::\\d+)?';
155 }
156 if (!\preg_match('/^' . $rx . '$/', $address, $matches)) {
157 return null;
158 }
159 $math = new \IAWPSCOPED\IPLib\Service\UnsignedIntegerMath();
160 $nums = array();
161 $maxChunkIndex = \count($matches) - 1;
162 for ($i = 1; $i <= $maxChunkIndex; $i++) {
163 $numBytes = $i === $maxChunkIndex ? 5 - $i : 1;
164 $chunkBytes = $math->getBytes($matches[$i], $numBytes, $onlyDecimal);
165 if ($chunkBytes === null) {
166 return null;
167 }
168 $nums = \array_merge($nums, $chunkBytes);
169 }
170 return new static(\implode('.', $nums));
171 }
172 /**
173 * Parse an array of bytes and returns an IPv4 instance if the array is valid, or null otherwise.
174 *
175 * @param array<int|mixed> $bytes
176 *
177 * @return static|null
178 */
179 public static function fromBytes(array $bytes)
180 {
181 $result = null;
182 if (\count($bytes) === 4) {
183 $chunks = \array_map(function ($byte) {
184 return \is_int($byte) && $byte >= 0 && $byte <= 255 ? (string) $byte : \false;
185 }, $bytes);
186 if (\in_array(\false, $chunks, \true) === \false) {
187 $result = new static(\implode('.', $chunks));
188 }
189 }
190 return $result;
191 }
192 /**
193 * {@inheritdoc}
194 *
195 * @see \IPLib\Address\AddressInterface::toString()
196 */
197 public function toString($long = \false)
198 {
199 if ($long) {
200 return $this->getComparableString();
201 }
202 return $this->address;
203 }
204 /**
205 * Get the octal representation of this IP address.
206 *
207 * @param bool $long
208 *
209 * @return string
210 *
211 * @since 1.10.0
212 *
213 * @example if $long == false: if the decimal representation is '0.7.8.255': '0.7.010.0377'
214 * @example if $long == true: if the decimal representation is '0.7.8.255': '0000.0007.0010.0377'
215 */
216 public function toOctal($long = \false)
217 {
218 $chunks = array();
219 foreach ($this->getBytes() as $byte) {
220 if ($long) {
221 $chunks[] = \sprintf('%04o', $byte);
222 } else {
223 $chunks[] = '0' . \decoct($byte);
224 }
225 }
226 return \implode('.', $chunks);
227 }
228 /**
229 * Get the hexadecimal representation of this IP address.
230 *
231 * @param bool $long
232 *
233 * @return string
234 *
235 * @since 1.10.0
236 *
237 * @example if $long == false: if the decimal representation is '0.9.10.255': '0.9.0xa.0xff'
238 * @example if $long == true: if the decimal representation is '0.9.10.255': '0x00.0x09.0x0a.0xff'
239 */
240 public function toHexadecimal($long = \false)
241 {
242 $chunks = array();
243 foreach ($this->getBytes() as $byte) {
244 if ($long) {
245 $chunks[] = \sprintf('0x%02x', $byte);
246 } else {
247 $chunks[] = '0x' . \dechex($byte);
248 }
249 }
250 return \implode('.', $chunks);
251 }
252 /**
253 * {@inheritdoc}
254 *
255 * @see \IPLib\Address\AddressInterface::getBytes()
256 */
257 public function getBytes()
258 {
259 if ($this->bytes === null) {
260 $this->bytes = \array_map(function ($chunk) {
261 return (int) $chunk;
262 }, \explode('.', $this->address));
263 }
264 return $this->bytes;
265 }
266 /**
267 * {@inheritdoc}
268 *
269 * @see \IPLib\Address\AddressInterface::getBits()
270 */
271 public function getBits()
272 {
273 $parts = array();
274 foreach ($this->getBytes() as $byte) {
275 $parts[] = \sprintf('%08b', $byte);
276 }
277 return \implode('', $parts);
278 }
279 /**
280 * {@inheritdoc}
281 *
282 * @see \IPLib\Address\AddressInterface::getAddressType()
283 */
284 public function getAddressType()
285 {
286 return Type::T_IPv4;
287 }
288 /**
289 * {@inheritdoc}
290 *
291 * @see \IPLib\Address\AddressInterface::getDefaultReservedRangeType()
292 */
293 public static function getDefaultReservedRangeType()
294 {
295 return RangeType::T_PUBLIC;
296 }
297 /**
298 * {@inheritdoc}
299 *
300 * @see \IPLib\Address\AddressInterface::getReservedRanges()
301 */
302 public static function getReservedRanges()
303 {
304 if (self::$reservedRanges === null) {
305 $reservedRanges = array();
306 foreach (array(
307 // RFC 5735
308 '0.0.0.0/8' => array(RangeType::T_THISNETWORK, array('0.0.0.0/32' => RangeType::T_UNSPECIFIED)),
309 // RFC 5735
310 '10.0.0.0/8' => array(RangeType::T_PRIVATENETWORK),
311 // RFC 6598
312 '100.64.0.0/10' => array(RangeType::T_CGNAT),
313 // RFC 5735
314 '127.0.0.0/8' => array(RangeType::T_LOOPBACK),
315 // RFC 5735
316 '169.254.0.0/16' => array(RangeType::T_LINKLOCAL),
317 // RFC 5735
318 '172.16.0.0/12' => array(RangeType::T_PRIVATENETWORK),
319 // RFC 5735
320 '192.0.0.0/24' => array(RangeType::T_RESERVED),
321 // RFC 5735
322 '192.0.2.0/24' => array(RangeType::T_RESERVED),
323 // RFC 5735
324 '192.88.99.0/24' => array(RangeType::T_ANYCASTRELAY),
325 // RFC 5735
326 '192.168.0.0/16' => array(RangeType::T_PRIVATENETWORK),
327 // RFC 5735
328 '198.18.0.0/15' => array(RangeType::T_RESERVED),
329 // RFC 5735
330 '198.51.100.0/24' => array(RangeType::T_RESERVED),
331 // RFC 5735
332 '203.0.113.0/24' => array(RangeType::T_RESERVED),
333 // RFC 5735
334 '224.0.0.0/4' => array(RangeType::T_MULTICAST),
335 // RFC 5735
336 '240.0.0.0/4' => array(RangeType::T_RESERVED, array('255.255.255.255/32' => RangeType::T_LIMITEDBROADCAST)),
337 ) as $range => $data) {
338 $exceptions = array();
339 if (isset($data[1])) {
340 foreach ($data[1] as $exceptionRange => $exceptionType) {
341 $subnet = Subnet::parseString($exceptionRange);
342 /** @var Subnet $subnet */
343 $exceptions[] = new AssignedRange($subnet, $exceptionType);
344 }
345 }
346 $subnet = Subnet::parseString($range);
347 /** @var Subnet $subnet */
348 $reservedRanges[] = new AssignedRange($subnet, $data[0], $exceptions);
349 }
350 self::$reservedRanges = $reservedRanges;
351 }
352 return self::$reservedRanges;
353 }
354 /**
355 * {@inheritdoc}
356 *
357 * @see \IPLib\Address\AddressInterface::getRangeType()
358 */
359 public function getRangeType()
360 {
361 if ($this->rangeType === null) {
362 $rangeType = null;
363 foreach (static::getReservedRanges() as $reservedRange) {
364 $rangeType = $reservedRange->getAddressType($this);
365 if ($rangeType !== null) {
366 break;
367 }
368 }
369 $this->rangeType = $rangeType === null ? static::getDefaultReservedRangeType() : $rangeType;
370 }
371 return $this->rangeType;
372 }
373 /**
374 * Create an IPv6 representation of this address (in 6to4 notation).
375 *
376 * @return \IPLib\Address\IPv6
377 */
378 public function toIPv6()
379 {
380 $myBytes = $this->getBytes();
381 $ipv6 = IPv6::parseString('2002:' . \sprintf('%02x', $myBytes[0]) . \sprintf('%02x', $myBytes[1]) . ':' . \sprintf('%02x', $myBytes[2]) . \sprintf('%02x', $myBytes[3]) . '::');
382 /** @var IPv6 $ipv6 */
383 return $ipv6;
384 }
385 /**
386 * Create an IPv6 representation of this address (in IPv6 IPv4-mapped notation).
387 *
388 * @return \IPLib\Address\IPv6
389 *
390 * @since 1.11.0
391 */
392 public function toIPv6IPv4Mapped()
393 {
394 $ipv6 = IPv6::fromBytes(\array_merge(array(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff), $this->getBytes()));
395 /** @var IPv6 $ipv6 */
396 return $ipv6;
397 }
398 /**
399 * {@inheritdoc}
400 *
401 * @see \IPLib\Address\AddressInterface::getComparableString()
402 */
403 public function getComparableString()
404 {
405 if ($this->comparableString === null) {
406 $chunks = array();
407 foreach ($this->getBytes() as $byte) {
408 $chunks[] = \sprintf('%03d', $byte);
409 }
410 $this->comparableString = \implode('.', $chunks);
411 }
412 return $this->comparableString;
413 }
414 /**
415 * {@inheritdoc}
416 *
417 * @see \IPLib\Address\AddressInterface::matches()
418 */
419 public function matches(RangeInterface $range)
420 {
421 return $range->contains($this);
422 }
423 /**
424 * {@inheritdoc}
425 *
426 * @see \IPLib\Address\AddressInterface::getAddressAtOffset()
427 */
428 public function getAddressAtOffset($n)
429 {
430 if (\is_int($n)) {
431 $thatChunks = NumberInChunks::fromInteger($n, NumberInChunks::CHUNKSIZE_BYTES);
432 } elseif (($s = BinaryMath::getInstance()->normalizeIntegerString($n)) !== '') {
433 $thatChunks = NumberInChunks::fromNumericString($s, NumberInChunks::CHUNKSIZE_BYTES);
434 } else {
435 return null;
436 }
437 $myBytes = $this->getBytes();
438 while (isset($myBytes[1]) && $myBytes[0] === 0) {
439 \array_shift($myBytes);
440 }
441 $myChunks = new NumberInChunks(\false, $myBytes, NumberInChunks::CHUNKSIZE_BYTES);
442 $result = $myChunks->add($thatChunks);
443 if ($result->negative || \count($result->chunks) > 4) {
444 return null;
445 }
446 return static::fromBytes(\array_pad($result->chunks, -4, 0));
447 }
448 /**
449 * {@inheritdoc}
450 *
451 * @see \IPLib\Address\AddressInterface::getNextAddress()
452 */
453 public function getNextAddress()
454 {
455 return $this->getAddressAtOffset(1);
456 }
457 /**
458 * {@inheritdoc}
459 *
460 * @see \IPLib\Address\AddressInterface::getPreviousAddress()
461 */
462 public function getPreviousAddress()
463 {
464 return $this->getAddressAtOffset(-1);
465 }
466 /**
467 * {@inheritdoc}
468 *
469 * @see \IPLib\Address\AddressInterface::getReverseDNSLookupName()
470 */
471 public function getReverseDNSLookupName()
472 {
473 return \implode('.', \array_reverse($this->getBytes())) . '.in-addr.arpa';
474 }
475 /**
476 * {@inheritdoc}
477 *
478 * @see \IPLib\Address\AddressInterface::shift()
479 */
480 public function shift($bits)
481 {
482 $bits = (int) $bits;
483 if ($bits === 0) {
484 return $this;
485 }
486 $absBits = \abs($bits);
487 if ($absBits >= 32) {
488 return new self('0.0.0.0');
489 }
490 $pad = \str_repeat('0', $absBits);
491 $paddedBits = $this->getBits();
492 if ($bits > 0) {
493 $paddedBits = $pad . \substr($paddedBits, 0, -$bits);
494 } else {
495 $paddedBits = \substr($paddedBits, $absBits) . $pad;
496 }
497 $bytes = \array_map('bindec', \str_split($paddedBits, 8));
498 return new static(\implode('.', $bytes));
499 }
500 /**
501 * {@inheritdoc}
502 *
503 * @see \IPLib\Address\AddressInterface::add()
504 */
505 public function add(AddressInterface $other)
506 {
507 if (!$other instanceof self) {
508 return null;
509 }
510 $myBytes = $this->getBytes();
511 $otherBytes = $other->getBytes();
512 $sum = \array_fill(0, 4, 0);
513 $carry = 0;
514 for ($index = 3; $index >= 0; $index--) {
515 $byte = $myBytes[$index] + $otherBytes[$index] + $carry;
516 if ($byte > 0xff) {
517 $carry = $byte >> 8;
518 $byte &= 0xff;
519 } else {
520 $carry = 0;
521 }
522 $sum[$index] = $byte;
523 }
524 if ($carry !== 0) {
525 return null;
526 }
527 return new static(\implode('.', $sum));
528 }
529 }
530