[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[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 // :: 64 $ip = '0:0:0:0:0:0:0:0'; 65 } elseif ($c1 === -1) { 66 // ::xxx 67 $fill = str_repeat('0:', 7 - $c2); 68 $ip = str_replace('::', $fill, $ip); 69 } elseif ($c2 === -1) { 70 // xxx:: 71 $fill = str_repeat(':0', 7 - $c1); 72 $ip = str_replace('::', $fill, $ip); 73 } else { 74 // xxx::xxx 75 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); 76 $ip = str_replace('::', $fill, $ip); 77 } 78 79 return $ip; 80 } 81 82 /** 83 * Compresses an IPv6 address 84 * 85 * RFC 4291 allows you to compress consecutive zero pieces in an address to 86 * '::'. This method expects a valid IPv6 address and compresses consecutive 87 * zero pieces to '::'. 88 * 89 * Example: FF01:0:0:0:0:0:0:101 -> FF01::101 90 * 0:0:0:0:0:0:0:1 -> ::1 91 * 92 * @see \WpOrg\Requests\Ipv6::uncompress() 93 * 94 * @param string $ip An IPv6 address 95 * @return string The compressed IPv6 address 96 */ 97 public static function compress($ip) { 98 // Prepare the IP to be compressed. 99 // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method. 100 $ip = self::uncompress($ip); 101 $ip_parts = self::split_v6_v4($ip); 102 103 // Replace all leading zeros 104 $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]); 105 106 // Find bunches of zeros 107 if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) { 108 $max = 0; 109 $pos = null; 110 foreach ($matches[0] as $match) { 111 if (strlen($match[0]) > $max) { 112 $max = strlen($match[0]); 113 $pos = $match[1]; 114 } 115 } 116 117 $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max); 118 } 119 120 if ($ip_parts[1] !== '') { 121 return implode(':', $ip_parts); 122 } else { 123 return $ip_parts[0]; 124 } 125 } 126 127 /** 128 * Splits an IPv6 address into the IPv6 and IPv4 representation parts 129 * 130 * RFC 4291 allows you to represent the last two parts of an IPv6 address 131 * using the standard IPv4 representation 132 * 133 * Example: 0:0:0:0:0:0:13.1.68.3 134 * 0:0:0:0:0:FFFF:129.144.52.38 135 * 136 * @param string $ip An IPv6 address 137 * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part 138 */ 139 private static function split_v6_v4($ip) { 140 if (strpos($ip, '.') !== false) { 141 $pos = strrpos($ip, ':'); 142 $ipv6_part = substr($ip, 0, $pos); 143 $ipv4_part = substr($ip, $pos + 1); 144 return [$ipv6_part, $ipv4_part]; 145 } else { 146 return [$ip, '']; 147 } 148 } 149 150 /** 151 * Checks an IPv6 address 152 * 153 * Checks if the given IP is a valid IPv6 address 154 * 155 * @param string $ip An IPv6 address 156 * @return bool true if $ip is a valid IPv6 address 157 */ 158 public static function check_ipv6($ip) { 159 // Note: Input validation is handled in the `uncompress()` method, which is the first call made in this method. 160 $ip = self::uncompress($ip); 161 list($ipv6, $ipv4) = self::split_v6_v4($ip); 162 $ipv6 = explode(':', $ipv6); 163 $ipv4 = explode('.', $ipv4); 164 if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) { 165 foreach ($ipv6 as $ipv6_part) { 166 // The section can't be empty 167 if ($ipv6_part === '') { 168 return false; 169 } 170 171 // Nor can it be over four characters 172 if (strlen($ipv6_part) > 4) { 173 return false; 174 } 175 176 // Remove leading zeros (this is safe because of the above) 177 $ipv6_part = ltrim($ipv6_part, '0'); 178 if ($ipv6_part === '') { 179 $ipv6_part = '0'; 180 } 181 182 // Check the value is valid 183 $value = hexdec($ipv6_part); 184 if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) { 185 return false; 186 } 187 } 188 189 if (count($ipv4) === 4) { 190 foreach ($ipv4 as $ipv4_part) { 191 $value = (int) $ipv4_part; 192 if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) { 193 return false; 194 } 195 } 196 } 197 198 return true; 199 } else { 200 return false; 201 } 202 } 203 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |