[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/Requests/ -> Ipv6.php (source)

   1  <?php
   2  /**
   3   * Class to validate and to work with IPv6 addresses
   4   *
   5   * @package Requests\Utilities
   6   */
   7  
   8  namespace WpOrg\Requests;
   9  
  10  use WpOrg\Requests\Exception\InvalidArgument;
  11  use WpOrg\Requests\Utility\InputValidator;
  12  
  13  /**
  14   * Class to validate and to work with IPv6 addresses
  15   *
  16   * This was originally based on the PEAR class of the same name, but has been
  17   * entirely rewritten.
  18   *
  19   * @package Requests\Utilities
  20   */
  21  final class Ipv6 {
  22      /**
  23       * Uncompresses an IPv6 address
  24       *
  25       * RFC 4291 allows you to compress consecutive zero pieces in an address to
  26       * '::'. This method expects a valid IPv6 address and expands the '::' to
  27       * the required number of zero pieces.
  28       *
  29       * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
  30       *           ::1         ->  0:0:0:0:0:0:0:1
  31       *
  32       * @author Alexander Merz <alexander.merz@web.de>
  33       * @author elfrink at introweb dot nl
  34       * @author Josh Peck <jmp at joshpeck dot org>
  35       * @copyright 2003-2005 The PHP Group
  36       * @license https://opensource.org/licenses/bsd-license.php
  37       *
  38       * @param string|Stringable $ip An IPv6 address
  39       * @return string The uncompressed IPv6 address
  40       *
  41       * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed argument is not a string or a stringable object.
  42       */
  43  	public static function uncompress($ip) {
  44          if (InputValidator::is_string_or_stringable($ip) === false) {
  45              throw InvalidArgument::create(1, '$ip', 'string|Stringable', gettype($ip));
  46          }
  47  
  48          $ip = (string) $ip;
  49  
  50          if (substr_count($ip, '::') !== 1) {
  51              return $ip;
  52          }
  53  
  54          list($ip1, $ip2) = explode('::', $ip);
  55          $c1              = ($ip1 === '') ? -1 : substr_count($ip1, ':');
  56          $c2              = ($ip2 === '') ? -1 : substr_count($ip2, ':');
  57  
  58          if (strpos($ip2, '.') !== false) {
  59              $c2++;
  60          }
  61          // ::
  62          if ($c1 === -1 && $c2 === -1) {
  63              $ip = '0:0:0:0:0:0:0:0';
  64          }
  65          // ::xxx
  66          elseif ($c1 === -1) {
  67              $fill = str_repeat('0:', 7 - $c2);
  68              $ip   = str_replace('::', $fill, $ip);
  69          }
  70          // xxx::
  71          elseif ($c2 === -1) {
  72              $fill = str_repeat(':0', 7 - $c1);
  73              $ip   = str_replace('::', $fill, $ip);
  74          }
  75          // xxx::xxx
  76          else {
  77              $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
  78              $ip   = str_replace('::', $fill, $ip);
  79          }
  80          return $ip;
  81      }
  82  
  83      /**
  84       * Compresses an IPv6 address
  85       *
  86       * RFC 4291 allows you to compress consecutive zero pieces in an address to
  87       * '::'. This method expects a valid IPv6 address and compresses consecutive
  88       * zero pieces to '::'.
  89       *
  90       * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
  91       *           0:0:0:0:0:0:0:1        ->  ::1
  92       *
  93       * @see \WpOrg\Requests\IPv6::uncompress()
  94       *
  95       * @param string $ip An IPv6 address
  96       * @return string The compressed IPv6 address
  97       */
  98  	public static function compress($ip) {
  99          // Prepare the IP to be compressed.
 100          // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
 101          $ip       = self::uncompress($ip);
 102          $ip_parts = self::split_v6_v4($ip);
 103  
 104          // Replace all leading zeros
 105          $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
 106  
 107          // Find bunches of zeros
 108          if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
 109              $max = 0;
 110              $pos = null;
 111              foreach ($matches[0] as $match) {
 112                  if (strlen($match[0]) > $max) {
 113                      $max = strlen($match[0]);
 114                      $pos = $match[1];
 115                  }
 116              }
 117  
 118              $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
 119          }
 120  
 121          if ($ip_parts[1] !== '') {
 122              return implode(':', $ip_parts);
 123          }
 124          else {
 125              return $ip_parts[0];
 126          }
 127      }
 128  
 129      /**
 130       * Splits an IPv6 address into the IPv6 and IPv4 representation parts
 131       *
 132       * RFC 4291 allows you to represent the last two parts of an IPv6 address
 133       * using the standard IPv4 representation
 134       *
 135       * Example:  0:0:0:0:0:0:13.1.68.3
 136       *           0:0:0:0:0:FFFF:129.144.52.38
 137       *
 138       * @param string $ip An IPv6 address
 139       * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
 140       */
 141  	private static function split_v6_v4($ip) {
 142          if (strpos($ip, '.') !== false) {
 143              $pos       = strrpos($ip, ':');
 144              $ipv6_part = substr($ip, 0, $pos);
 145              $ipv4_part = substr($ip, $pos + 1);
 146              return [$ipv6_part, $ipv4_part];
 147          }
 148          else {
 149              return [$ip, ''];
 150          }
 151      }
 152  
 153      /**
 154       * Checks an IPv6 address
 155       *
 156       * Checks if the given IP is a valid IPv6 address
 157       *
 158       * @param string $ip An IPv6 address
 159       * @return bool true if $ip is a valid IPv6 address
 160       */
 161  	public static function check_ipv6($ip) {
 162          // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method.
 163          $ip                = self::uncompress($ip);
 164          list($ipv6, $ipv4) = self::split_v6_v4($ip);
 165          $ipv6              = explode(':', $ipv6);
 166          $ipv4              = explode('.', $ipv4);
 167          if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
 168              foreach ($ipv6 as $ipv6_part) {
 169                  // The section can't be empty
 170                  if ($ipv6_part === '') {
 171                      return false;
 172                  }
 173  
 174                  // Nor can it be over four characters
 175                  if (strlen($ipv6_part) > 4) {
 176                      return false;
 177                  }
 178  
 179                  // Remove leading zeros (this is safe because of the above)
 180                  $ipv6_part = ltrim($ipv6_part, '0');
 181                  if ($ipv6_part === '') {
 182                      $ipv6_part = '0';
 183                  }
 184  
 185                  // Check the value is valid
 186                  $value = hexdec($ipv6_part);
 187                  if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
 188                      return false;
 189                  }
 190              }
 191              if (count($ipv4) === 4) {
 192                  foreach ($ipv4 as $ipv4_part) {
 193                      $value = (int) $ipv4_part;
 194                      if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
 195                          return false;
 196                      }
 197                  }
 198              }
 199              return true;
 200          }
 201          else {
 202              return false;
 203          }
 204      }
 205  }


Generated: Mon Dec 6 01:00:03 2021 Cross-referenced by PHPXref 0.7.1