Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- class IPv6Address
- {
- /**
- * @var int[]
- */
- private $words;
- /**
- * @var string
- */
- private $binary;
- /**
- * @var string
- */
- private $fullString;
- /**
- * @var string
- */
- private $rfc5952String;
- /**
- * @param string[] $blocks
- * @param int $offset
- * @param int[] $words
- * @return int[]
- */
- private function parseBlocksWithNoEmptyBlockToWords($blocks, $offset = 0, $words = [])
- {
- foreach ($blocks as $i => $block) {
- if ($block === '') {
- throw new \InvalidArgumentException('Invalid address: cannot contain multiple empty blocks');
- }
- if (!preg_match('/^[0-9a-f]{1,4}$/i', $block)) {
- throw new \InvalidArgumentException('Invalid address: invalid data "' . $block . '" at block ' . ($offset + $i + 1));
- }
- $words[$offset + $i] = hexdec($block);
- }
- return $words;
- }
- /**
- * @param string $address
- * @return int[]
- */
- private function parseAddressWithEmptyBlockOnLeftToWords($address)
- {
- $blocks = explode(':', substr($address, 2));
- $offset = 8 - count($blocks);
- return $this->parseBlocksWithNoEmptyBlockToWords($blocks, $offset, array_fill(0, $offset, 0));
- }
- /**
- * @param string $address
- * @return int[]
- */
- private function parseAddressWithEmptyBlockOnRightToWords($address)
- {
- return array_pad($this->parseBlocksWithNoEmptyBlockToWords(explode(':', substr($address, 0, -2))), 8, 0);
- }
- /**
- * @param string $address
- * @return int[]
- * @throws \InvalidArgumentException
- */
- protected function parseAddressToWords($address)
- {
- if ($address === '::') {
- $words = [0, 0, 0, 0, 0, 0, 0, 0];
- } else if (substr($address, 0, 2) === '::') {
- $words = $this->parseAddressWithEmptyBlockOnLeftToWords($address);
- } else if (substr($address, -2) === '::') {
- $words = $this->parseAddressWithEmptyBlockOnRightToWords($address);
- } else {
- $haveEmptyBlock = false;
- $blocks = explode(':', $address);
- $words = [];
- foreach ($blocks as $i => $block) {
- if ($block === '') {
- if ($haveEmptyBlock) {
- throw new \InvalidArgumentException('Invalid address: cannot contain multiple empty blocks');
- }
- $haveEmptyBlock = true;
- $words = array_pad($words, 9 - (count($blocks) - $i), 0);
- } else if (preg_match('/^[0-9a-f]{1,4}$/i', $block)) {
- $words[] = hexdec($block);
- } else {
- throw new \InvalidArgumentException('Invalid address: invalid data "' . $block . '" at block ' . ($i + 1));
- }
- }
- }
- if (count($words) !== 8) {
- throw new \InvalidArgumentException('Invalid address: must contain exactly 8 blocks');
- }
- return $words;
- }
- /**
- * @param string $address
- * @throws \InvalidArgumentException
- */
- public function __construct($address)
- {
- $this->words = $this->parseAddressToWords($address);
- }
- /**
- * @return string
- */
- public function __toString()
- {
- return $this->getRFC5952String();
- }
- /**
- * @return string
- */
- public function getBinary()
- {
- return $this->binary ?: $this->binary = pack('n*', $this->words);
- }
- /**
- * @return int[]
- */
- public function getWords()
- {
- return $this->words;
- }
- /**
- * @return string
- */
- public function getFullString()
- {
- return $this->fullString ?: $this->fullString = implode(':', array_map(function($word) {
- return str_pad(dechex($word), 4, '0', STR_PAD_LEFT);
- }, $this->words));
- }
- /**
- * @return string
- */
- public function getRFC5952String()
- {
- if (isset($this->rfc5952String)) {
- return $this->rfc5952String;
- }
- $longestZeroBlockIndex = -1;
- $longestZeroBlockLength = -1;
- $currentZeroBlockIndex = -1;
- $currentZeroBlockLength = -1;
- foreach ($this->words as $i => $word) {
- if ($word !== 0) {
- if ($currentZeroBlockIndex !== -1 && $currentZeroBlockLength > $longestZeroBlockLength) {
- $longestZeroBlockIndex = $currentZeroBlockIndex;
- $longestZeroBlockLength = $currentZeroBlockLength;
- $currentZeroBlockIndex = -1;
- }
- } else if ($currentZeroBlockIndex === -1) {
- $currentZeroBlockIndex = $i;
- $currentZeroBlockLength = 1;
- } else {
- $currentZeroBlockLength++;
- }
- }
- if ($currentZeroBlockIndex !== -1 && $currentZeroBlockLength > $longestZeroBlockLength) {
- $longestZeroBlockIndex = $currentZeroBlockIndex;
- $longestZeroBlockLength = $currentZeroBlockLength;
- }
- $blocks = [];
- if ($longestZeroBlockLength === 8) {
- $blocks = ['', '', ''];
- } else if ($longestZeroBlockLength > 1) {
- for ($i = 0; $i < $longestZeroBlockIndex; $i++) {
- $blocks[] = dechex($this->words[$i]);
- }
- $blocks[] = '';
- if ($longestZeroBlockIndex === 0 || $longestZeroBlockIndex + $longestZeroBlockLength === 8) {
- $blocks[] = '';
- }
- for ($i = $longestZeroBlockIndex + $longestZeroBlockLength; $i < 8; $i++) {
- $blocks[] = dechex($this->words[$i]);
- }
- } else {
- $blocks = array_map('dechex', $this->words);
- }
- return $this->rfc5952String = implode(':', $blocks);
- }
- /**
- * @param IPv6Address|string $address
- * @return bool
- */
- public function equalTo($address)
- {
- if (!$address instanceof self) {
- $address = new self($address);
- }
- return $address->getWords() === $this->words;
- }
- /**
- * @param IPv6Address|string $address
- * @return bool
- */
- public function lessThan($address)
- {
- if (!$address instanceof self) {
- $address = new self($address);
- }
- foreach ($address->words as $i => $word) {
- if ($word < $this->words[$i]) {
- return false;
- } else if ($this->words[$i] < $word) {
- return true;
- }
- }
- return false;
- }
- /**
- * @param IPv6Address|string $address
- * @return bool
- */
- public function greaterThan($address)
- {
- if (!$address instanceof self) {
- $address = new self($address);
- }
- return $address->lessThan($this);
- }
- /**
- * @param IPv6Address|string $start
- * @param IPv6Address|string $end
- * @return bool
- */
- public function inRange($start, $end)
- {
- return ($this->greaterThan($start) || $this->equalTo($start))
- && ($this->lessThan($end) || $this->equalTo($end));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement