%PDF- %PDF-
Direktori : /www/varak.net/nextcloud.varak.net/3rdparty/mlocati/ip-lib/src/Address/ |
Current File : /www/varak.net/nextcloud.varak.net/3rdparty/mlocati/ip-lib/src/Address/IPv4.php |
<?php namespace IPLib\Address; use IPLib\ParseStringFlag; use IPLib\Range\RangeInterface; use IPLib\Range\Subnet; use IPLib\Range\Type as RangeType; /** * An IPv4 address. */ class IPv4 implements AddressInterface { /** * The string representation of the address. * * @var string * * @example '127.0.0.1' */ protected $address; /** * The byte list of the IP address. * * @var int[]|null */ protected $bytes; /** * The type of the range of this IP address. * * @var int|null */ protected $rangeType; /** * A string representation of this address than can be used when comparing addresses and ranges. * * @var string */ protected $comparableString; /** * An array containing RFC designated address ranges. * * @var array|null */ private static $reservedRanges; /** * Initializes the instance. * * @param string $address */ protected function __construct($address) { $this->address = $address; $this->bytes = null; $this->rangeType = null; $this->comparableString = null; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::__toString() */ public function __toString() { return $this->address; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getNumberOfBits() */ public static function getNumberOfBits() { return 32; } /** * @deprecated since 1.17.0: use the parseString() method instead. * For upgrading: * - if $mayIncludePort is true, use the ParseStringFlag::MAY_INCLUDE_PORT flag * - if $supportNonDecimalIPv4 is true, use the ParseStringFlag::IPV4_MAYBE_NON_DECIMAL flag * * @param string|mixed $address the address to parse * @param bool $mayIncludePort * @param bool $supportNonDecimalIPv4 * * @return static|null * * @see \IPLib\Address\IPv4::parseString() * @since 1.1.0 added the $mayIncludePort argument * @since 1.10.0 added the $supportNonDecimalIPv4 argument */ public static function fromString($address, $mayIncludePort = true, $supportNonDecimalIPv4 = false) { return static::parseString($address, 0 | ($mayIncludePort ? ParseStringFlag::MAY_INCLUDE_PORT : 0) | ($supportNonDecimalIPv4 ? ParseStringFlag::IPV4_MAYBE_NON_DECIMAL : 0)); } /** * Parse a string and returns an IPv4 instance if the string is valid, or null otherwise. * * @param string|mixed $address the address to parse * @param int $flags A combination or zero or more flags * * @return static|null * * @see \IPLib\ParseStringFlag * @since 1.17.0 */ public static function parseString($address, $flags = 0) { if (!is_string($address)) { return null; } $flags = (int) $flags; $matches = null; if ($flags & ParseStringFlag::ADDRESS_MAYBE_RDNS) { 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)) { $address = implode('.', array_reverse(explode('.', $matches[1]))); $flags = $flags & ~(ParseStringFlag::IPV4_MAYBE_NON_DECIMAL | ParseStringFlag::IPV4ADDRESS_MAYBE_NON_QUAD_DOTTED); } } if ($flags & ParseStringFlag::IPV4ADDRESS_MAYBE_NON_QUAD_DOTTED) { if (strpos($address, '.') === 0) { return null; } $lengthNonHex = '{1,11}'; $lengthHex = '{1,8}'; $chunk234Optional = true; } else { if (!strpos($address, '.')) { return null; } $lengthNonHex = '{1,3}'; $lengthHex = '{1,2}'; $chunk234Optional = false; } $rxChunk1 = "0?[0-9]{$lengthNonHex}"; if ($flags & ParseStringFlag::IPV4_MAYBE_NON_DECIMAL) { $rxChunk1 = "(?:0[Xx]0*[0-9A-Fa-f]{$lengthHex})|(?:{$rxChunk1})"; $onlyDecimal = false; } else { $onlyDecimal = true; } $rxChunk1 = "0*?({$rxChunk1})"; $rxChunk234 = "\.{$rxChunk1}"; if ($chunk234Optional) { $rxChunk234 = "(?:{$rxChunk234})?"; } $rx = "{$rxChunk1}{$rxChunk234}{$rxChunk234}{$rxChunk234}"; if ($flags & ParseStringFlag::MAY_INCLUDE_PORT) { $rx .= '(?::\d+)?'; } if (!preg_match('/^' . $rx . '$/', $address, $matches)) { return null; } $math = new \IPLib\Service\UnsignedIntegerMath(); $nums = array(); $maxChunkIndex = count($matches) - 1; for ($i = 1; $i <= $maxChunkIndex; $i++) { $numBytes = $i === $maxChunkIndex ? 5 - $i : 1; $chunkBytes = $math->getBytes($matches[$i], $numBytes, $onlyDecimal); if ($chunkBytes === null) { return null; } $nums = array_merge($nums, $chunkBytes); } return new static(implode('.', $nums)); } /** * Parse an array of bytes and returns an IPv4 instance if the array is valid, or null otherwise. * * @param int[]|array $bytes * * @return static|null */ public static function fromBytes(array $bytes) { $result = null; if (count($bytes) === 4) { $chunks = array_map( function ($byte) { return (is_int($byte) && $byte >= 0 && $byte <= 255) ? (string) $byte : false; }, $bytes ); if (in_array(false, $chunks, true) === false) { $result = new static(implode('.', $chunks)); } } return $result; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::toString() */ public function toString($long = false) { if ($long) { return $this->getComparableString(); } return $this->address; } /** * Get the octal representation of this IP address. * * @param bool $long * * @return string * * @since 1.10.0 * * @example if $long == false: if the decimal representation is '0.7.8.255': '0.7.010.0377' * @example if $long == true: if the decimal representation is '0.7.8.255': '0000.0007.0010.0377' */ public function toOctal($long = false) { $chunks = array(); foreach ($this->getBytes() as $byte) { if ($long) { $chunks[] = sprintf('%04o', $byte); } else { $chunks[] = '0' . decoct($byte); } } return implode('.', $chunks); } /** * Get the hexadecimal representation of this IP address. * * @param bool $long * * @return string * * @since 1.10.0 * * @example if $long == false: if the decimal representation is '0.9.10.255': '0.9.0xa.0xff' * @example if $long == true: if the decimal representation is '0.9.10.255': '0x00.0x09.0x0a.0xff' */ public function toHexadecimal($long = false) { $chunks = array(); foreach ($this->getBytes() as $byte) { if ($long) { $chunks[] = sprintf('0x%02x', $byte); } else { $chunks[] = '0x' . dechex($byte); } } return implode('.', $chunks); } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getBytes() */ public function getBytes() { if ($this->bytes === null) { $this->bytes = array_map( function ($chunk) { return (int) $chunk; }, explode('.', $this->address) ); } return $this->bytes; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getBits() */ public function getBits() { $parts = array(); foreach ($this->getBytes() as $byte) { $parts[] = sprintf('%08b', $byte); } return implode('', $parts); } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getAddressType() */ public function getAddressType() { return Type::T_IPv4; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getDefaultReservedRangeType() */ public static function getDefaultReservedRangeType() { return RangeType::T_PUBLIC; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getReservedRanges() */ public static function getReservedRanges() { if (self::$reservedRanges === null) { $reservedRanges = array(); foreach (array( // RFC 5735 '0.0.0.0/8' => array(RangeType::T_THISNETWORK, array('0.0.0.0/32' => RangeType::T_UNSPECIFIED)), // RFC 5735 '10.0.0.0/8' => array(RangeType::T_PRIVATENETWORK), // RFC 6598 '100.64.0.0/10' => array(RangeType::T_CGNAT), // RFC 5735 '127.0.0.0/8' => array(RangeType::T_LOOPBACK), // RFC 5735 '169.254.0.0/16' => array(RangeType::T_LINKLOCAL), // RFC 5735 '172.16.0.0/12' => array(RangeType::T_PRIVATENETWORK), // RFC 5735 '192.0.0.0/24' => array(RangeType::T_RESERVED), // RFC 5735 '192.0.2.0/24' => array(RangeType::T_RESERVED), // RFC 5735 '192.88.99.0/24' => array(RangeType::T_ANYCASTRELAY), // RFC 5735 '192.168.0.0/16' => array(RangeType::T_PRIVATENETWORK), // RFC 5735 '198.18.0.0/15' => array(RangeType::T_RESERVED), // RFC 5735 '198.51.100.0/24' => array(RangeType::T_RESERVED), // RFC 5735 '203.0.113.0/24' => array(RangeType::T_RESERVED), // RFC 5735 '224.0.0.0/4' => array(RangeType::T_MULTICAST), // RFC 5735 '240.0.0.0/4' => array(RangeType::T_RESERVED, array('255.255.255.255/32' => RangeType::T_LIMITEDBROADCAST)), ) as $range => $data) { $exceptions = array(); if (isset($data[1])) { foreach ($data[1] as $exceptionRange => $exceptionType) { $exceptions[] = new AssignedRange(Subnet::parseString($exceptionRange), $exceptionType); } } $reservedRanges[] = new AssignedRange(Subnet::parseString($range), $data[0], $exceptions); } self::$reservedRanges = $reservedRanges; } return self::$reservedRanges; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getRangeType() */ public function getRangeType() { if ($this->rangeType === null) { $rangeType = null; foreach (static::getReservedRanges() as $reservedRange) { $rangeType = $reservedRange->getAddressType($this); if ($rangeType !== null) { break; } } $this->rangeType = $rangeType === null ? static::getDefaultReservedRangeType() : $rangeType; } return $this->rangeType; } /** * Create an IPv6 representation of this address (in 6to4 notation). * * @return \IPLib\Address\IPv6 */ public function toIPv6() { $myBytes = $this->getBytes(); return IPv6::parseString('2002:' . sprintf('%02x', $myBytes[0]) . sprintf('%02x', $myBytes[1]) . ':' . sprintf('%02x', $myBytes[2]) . sprintf('%02x', $myBytes[3]) . '::'); } /** * Create an IPv6 representation of this address (in IPv6 IPv4-mapped notation). * * @return \IPLib\Address\IPv6 * * @since 1.11.0 */ public function toIPv6IPv4Mapped() { return IPv6::fromBytes(array_merge(array(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff), $this->getBytes())); } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getComparableString() */ public function getComparableString() { if ($this->comparableString === null) { $chunks = array(); foreach ($this->getBytes() as $byte) { $chunks[] = sprintf('%03d', $byte); } $this->comparableString = implode('.', $chunks); } return $this->comparableString; } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::matches() */ public function matches(RangeInterface $range) { return $range->contains($this); } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getAddressAtOffset() */ public function getAddressAtOffset($n) { if (!is_int($n)) { return null; } $boundary = 256; $mod = $n; $bytes = $this->getBytes(); for ($i = count($bytes) - 1; $i >= 0; $i--) { $tmp = ($bytes[$i] + $mod) % $boundary; $mod = (int) floor(($bytes[$i] + $mod) / $boundary); if ($tmp < 0) { $tmp += $boundary; } $bytes[$i] = $tmp; } if ($mod !== 0) { return null; } return static::fromBytes($bytes); } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getNextAddress() */ public function getNextAddress() { return $this->getAddressAtOffset(1); } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getPreviousAddress() */ public function getPreviousAddress() { return $this->getAddressAtOffset(-1); } /** * {@inheritdoc} * * @see \IPLib\Address\AddressInterface::getReverseDNSLookupName() */ public function getReverseDNSLookupName() { return implode( '.', array_reverse($this->getBytes()) ) . '.in-addr.arpa'; } }