[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 // SPDX-FileCopyrightText: 2004-2023 Ryan Parman, Sam Sneddon, Ryan McCue 4 // SPDX-License-Identifier: BSD-3-Clause 5 6 declare(strict_types=1); 7 8 namespace SimplePie\Net; 9 10 /** 11 * Class to validate and to work with IPv6 addresses. 12 * 13 * @copyright 2003-2005 The PHP Group 14 * @license http://www.opensource.org/licenses/bsd-license.php 15 * @link http://pear.php.net/package/Net_IPv6 16 * @author Alexander Merz <alexander.merz@web.de> 17 * @author elfrink at introweb dot nl 18 * @author Josh Peck <jmp at joshpeck dot org> 19 * @author Sam Sneddon <geoffers@gmail.com> 20 */ 21 class IPv6 22 { 23 /** 24 * Uncompresses an IPv6 address 25 * 26 * RFC 4291 allows you to compress consecutive zero pieces in an address to 27 * '::'. This method expects a valid IPv6 address and expands the '::' to 28 * the required number of zero pieces. 29 * 30 * Example: FF01::101 -> FF01:0:0:0:0:0:0:101 31 * ::1 -> 0:0:0:0:0:0:0:1 32 * 33 * @author Alexander Merz <alexander.merz@web.de> 34 * @author elfrink at introweb dot nl 35 * @author Josh Peck <jmp at joshpeck dot org> 36 * @copyright 2003-2005 The PHP Group 37 * @license http://www.opensource.org/licenses/bsd-license.php 38 * @param string $ip An IPv6 address 39 * @return string The uncompressed IPv6 address 40 */ 41 public static function uncompress(string $ip) 42 { 43 $c1 = -1; 44 $c2 = -1; 45 if (substr_count($ip, '::') === 1) { 46 [$ip1, $ip2] = explode('::', $ip); 47 if ($ip1 === '') { 48 $c1 = -1; 49 } else { 50 $c1 = substr_count($ip1, ':'); 51 } 52 if ($ip2 === '') { 53 $c2 = -1; 54 } else { 55 $c2 = substr_count($ip2, ':'); 56 } 57 if (strpos($ip2, '.') !== false) { 58 $c2++; 59 } 60 // :: 61 if ($c1 === -1 && $c2 === -1) { 62 $ip = '0:0:0:0:0:0:0:0'; 63 } 64 // ::xxx 65 elseif ($c1 === -1) { 66 $fill = str_repeat('0:', 7 - $c2); 67 $ip = str_replace('::', $fill, $ip); 68 } 69 // xxx:: 70 elseif ($c2 === -1) { 71 $fill = str_repeat(':0', 7 - $c1); 72 $ip = str_replace('::', $fill, $ip); 73 } 74 // xxx::xxx 75 else { 76 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1); 77 $ip = str_replace('::', $fill, $ip); 78 } 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 uncompress() 94 * @param string $ip An IPv6 address 95 * @return string The compressed IPv6 address 96 */ 97 public static function compress(string $ip) 98 { 99 // Prepare the IP to be compressed 100 $ip = self::uncompress($ip); 101 $ip_parts = self::split_v6_v4($ip); 102 103 // Replace all leading zeros 104 $ip_parts[0] = (string) 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 assert($pos !== null, 'For PHPStan: Since the regex matched, there is at least one match. And because the pattern is non-empty, the loop will always end with $pos ≥ 1.'); 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 125 return $ip_parts[0]; 126 } 127 128 /** 129 * Splits an IPv6 address into the IPv6 and IPv4 representation parts 130 * 131 * RFC 4291 allows you to represent the last two parts of an IPv6 address 132 * using the standard IPv4 representation 133 * 134 * Example: 0:0:0:0:0:0:13.1.68.3 135 * 0:0:0:0:0:FFFF:129.144.52.38 136 * 137 * @param string $ip An IPv6 address 138 * @return array{string, string} [0] contains the IPv6 represented part, and [1] the IPv4 represented part 139 */ 140 private static function split_v6_v4(string $ip): array 141 { 142 if (strpos($ip, '.') !== false) { 143 $pos = strrpos($ip, ':'); 144 assert($pos !== false, 'For PHPStan: IPv6 address must contain colon, since split_v6_v4 is only ever called after uncompress.'); 145 $ipv6_part = substr($ip, 0, $pos); 146 $ipv4_part = substr($ip, $pos + 1); 147 return [$ipv6_part, $ipv4_part]; 148 } 149 150 return [$ip, '']; 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(string $ip) 162 { 163 $ip = self::uncompress($ip); 164 [$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 ($value < 0 || $value > 0xFFFF) { 188 return false; 189 } 190 assert(is_int($value), 'For PHPStan: $value is only float when $ipv6_part > PHP_INT_MAX'); 191 if (dechex($value) !== strtolower($ipv6_part)) { 192 return false; 193 } 194 } 195 if (count($ipv4) === 4) { 196 foreach ($ipv4 as $ipv4_part) { 197 $value = (int) $ipv4_part; 198 if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) { 199 return false; 200 } 201 } 202 } 203 return true; 204 } 205 206 return false; 207 } 208 209 /** 210 * Checks if the given IP is a valid IPv6 address 211 * 212 * @codeCoverageIgnore 213 * @deprecated Use {@see IPv6::check_ipv6()} instead 214 * @see check_ipv6 215 * @param string $ip An IPv6 address 216 * @return bool true if $ip is a valid IPv6 address 217 */ 218 public static function checkIPv6(string $ip) 219 { 220 return self::check_ipv6($ip); 221 } 222 } 223 224 class_alias('SimplePie\Net\IPv6', 'SimplePie_Net_IPv6');
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Fri Oct 10 08:20:03 2025 | Cross-referenced by PHPXref |