[ Index ] |
PHP Cross Reference of WordPress |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Dec 6 01:00:03 2021 | Cross-referenced by PHPXref 0.7.1 |