| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | declare(strict_types=1);
 | 
        
           |  |  | 4 | /**
 | 
        
           |  |  | 5 |  * SimplePie
 | 
        
           |  |  | 6 |  *
 | 
        
           |  |  | 7 |  * A PHP-Based RSS and Atom Feed Framework.
 | 
        
           |  |  | 8 |  * Takes the hard work out of managing a complete RSS/Atom solution.
 | 
        
           |  |  | 9 |  *
 | 
        
           |  |  | 10 |  * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors
 | 
        
           |  |  | 11 |  * All rights reserved.
 | 
        
           |  |  | 12 |  *
 | 
        
           |  |  | 13 |  * Redistribution and use in source and binary forms, with or without modification, are
 | 
        
           |  |  | 14 |  * permitted provided that the following conditions are met:
 | 
        
           |  |  | 15 |  *
 | 
        
           |  |  | 16 |  * 	* Redistributions of source code must retain the above copyright notice, this list of
 | 
        
           |  |  | 17 |  * 	  conditions and the following disclaimer.
 | 
        
           |  |  | 18 |  *
 | 
        
           |  |  | 19 |  * 	* Redistributions in binary form must reproduce the above copyright notice, this list
 | 
        
           |  |  | 20 |  * 	  of conditions and the following disclaimer in the documentation and/or other materials
 | 
        
           |  |  | 21 |  * 	  provided with the distribution.
 | 
        
           |  |  | 22 |  *
 | 
        
           |  |  | 23 |  * 	* Neither the name of the SimplePie Team nor the names of its contributors may be used
 | 
        
           |  |  | 24 |  * 	  to endorse or promote products derived from this software without specific prior
 | 
        
           |  |  | 25 |  * 	  written permission.
 | 
        
           |  |  | 26 |  *
 | 
        
           |  |  | 27 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 | 
        
           |  |  | 28 |  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
        
           |  |  | 29 |  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
 | 
        
           |  |  | 30 |  * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
        
           |  |  | 31 |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
        
           |  |  | 32 |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
        
           |  |  | 33 |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 | 
        
           |  |  | 34 |  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
        
           |  |  | 35 |  * POSSIBILITY OF SUCH DAMAGE.
 | 
        
           |  |  | 36 |  *
 | 
        
           |  |  | 37 |  * @package SimplePie
 | 
        
           |  |  | 38 |  * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue
 | 
        
           |  |  | 39 |  * @author Ryan Parman
 | 
        
           |  |  | 40 |  * @author Sam Sneddon
 | 
        
           |  |  | 41 |  * @author Ryan McCue
 | 
        
           |  |  | 42 |  * @link http://simplepie.org/ SimplePie
 | 
        
           |  |  | 43 |  * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 | 
        
           |  |  | 44 |  */
 | 
        
           |  |  | 45 |   | 
        
           |  |  | 46 | namespace SimplePie\Net;
 | 
        
           |  |  | 47 |   | 
        
           |  |  | 48 | /**
 | 
        
           |  |  | 49 |  * Class to validate and to work with IPv6 addresses.
 | 
        
           |  |  | 50 |  *
 | 
        
           |  |  | 51 |  * @package SimplePie
 | 
        
           |  |  | 52 |  * @subpackage HTTP
 | 
        
           |  |  | 53 |  * @copyright 2003-2005 The PHP Group
 | 
        
           |  |  | 54 |  * @license http://www.opensource.org/licenses/bsd-license.php
 | 
        
           |  |  | 55 |  * @link http://pear.php.net/package/Net_IPv6
 | 
        
           |  |  | 56 |  * @author Alexander Merz <alexander.merz@web.de>
 | 
        
           |  |  | 57 |  * @author elfrink at introweb dot nl
 | 
        
           |  |  | 58 |  * @author Josh Peck <jmp at joshpeck dot org>
 | 
        
           |  |  | 59 |  * @author Sam Sneddon <geoffers@gmail.com>
 | 
        
           |  |  | 60 |  */
 | 
        
           |  |  | 61 | class IPv6
 | 
        
           |  |  | 62 | {
 | 
        
           |  |  | 63 |     /**
 | 
        
           |  |  | 64 |      * Uncompresses an IPv6 address
 | 
        
           |  |  | 65 |      *
 | 
        
           |  |  | 66 |      * RFC 4291 allows you to compress concecutive zero pieces in an address to
 | 
        
           |  |  | 67 |      * '::'. This method expects a valid IPv6 address and expands the '::' to
 | 
        
           |  |  | 68 |      * the required number of zero pieces.
 | 
        
           |  |  | 69 |      *
 | 
        
           |  |  | 70 |      * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
 | 
        
           |  |  | 71 |      *           ::1         ->  0:0:0:0:0:0:0:1
 | 
        
           |  |  | 72 |      *
 | 
        
           |  |  | 73 |      * @author Alexander Merz <alexander.merz@web.de>
 | 
        
           |  |  | 74 |      * @author elfrink at introweb dot nl
 | 
        
           |  |  | 75 |      * @author Josh Peck <jmp at joshpeck dot org>
 | 
        
           |  |  | 76 |      * @copyright 2003-2005 The PHP Group
 | 
        
           |  |  | 77 |      * @license http://www.opensource.org/licenses/bsd-license.php
 | 
        
           |  |  | 78 |      * @param string $ip An IPv6 address
 | 
        
           |  |  | 79 |      * @return string The uncompressed IPv6 address
 | 
        
           |  |  | 80 |      */
 | 
        
           |  |  | 81 |     public static function uncompress($ip)
 | 
        
           |  |  | 82 |     {
 | 
        
           |  |  | 83 |         $c1 = -1;
 | 
        
           |  |  | 84 |         $c2 = -1;
 | 
        
           |  |  | 85 |         if (substr_count($ip, '::') === 1) {
 | 
        
           |  |  | 86 |             [$ip1, $ip2] = explode('::', $ip);
 | 
        
           |  |  | 87 |             if ($ip1 === '') {
 | 
        
           |  |  | 88 |                 $c1 = -1;
 | 
        
           |  |  | 89 |             } else {
 | 
        
           |  |  | 90 |                 $c1 = substr_count($ip1, ':');
 | 
        
           |  |  | 91 |             }
 | 
        
           |  |  | 92 |             if ($ip2 === '') {
 | 
        
           |  |  | 93 |                 $c2 = -1;
 | 
        
           |  |  | 94 |             } else {
 | 
        
           |  |  | 95 |                 $c2 = substr_count($ip2, ':');
 | 
        
           |  |  | 96 |             }
 | 
        
           |  |  | 97 |             if (strpos($ip2, '.') !== false) {
 | 
        
           |  |  | 98 |                 $c2++;
 | 
        
           |  |  | 99 |             }
 | 
        
           |  |  | 100 |             // ::
 | 
        
           |  |  | 101 |             if ($c1 === -1 && $c2 === -1) {
 | 
        
           |  |  | 102 |                 $ip = '0:0:0:0:0:0:0:0';
 | 
        
           |  |  | 103 |             }
 | 
        
           |  |  | 104 |             // ::xxx
 | 
        
           |  |  | 105 |             elseif ($c1 === -1) {
 | 
        
           |  |  | 106 |                 $fill = str_repeat('0:', 7 - $c2);
 | 
        
           |  |  | 107 |                 $ip = str_replace('::', $fill, $ip);
 | 
        
           |  |  | 108 |             }
 | 
        
           |  |  | 109 |             // xxx::
 | 
        
           |  |  | 110 |             elseif ($c2 === -1) {
 | 
        
           |  |  | 111 |                 $fill = str_repeat(':0', 7 - $c1);
 | 
        
           |  |  | 112 |                 $ip = str_replace('::', $fill, $ip);
 | 
        
           |  |  | 113 |             }
 | 
        
           |  |  | 114 |             // xxx::xxx
 | 
        
           |  |  | 115 |             else {
 | 
        
           |  |  | 116 |                 $fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
 | 
        
           |  |  | 117 |                 $ip = str_replace('::', $fill, $ip);
 | 
        
           |  |  | 118 |             }
 | 
        
           |  |  | 119 |         }
 | 
        
           |  |  | 120 |         return $ip;
 | 
        
           |  |  | 121 |     }
 | 
        
           |  |  | 122 |   | 
        
           |  |  | 123 |     /**
 | 
        
           |  |  | 124 |      * Compresses an IPv6 address
 | 
        
           |  |  | 125 |      *
 | 
        
           |  |  | 126 |      * RFC 4291 allows you to compress concecutive zero pieces in an address to
 | 
        
           |  |  | 127 |      * '::'. This method expects a valid IPv6 address and compresses consecutive
 | 
        
           |  |  | 128 |      * zero pieces to '::'.
 | 
        
           |  |  | 129 |      *
 | 
        
           |  |  | 130 |      * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
 | 
        
           |  |  | 131 |      *           0:0:0:0:0:0:0:1        ->  ::1
 | 
        
           |  |  | 132 |      *
 | 
        
           |  |  | 133 |      * @see uncompress()
 | 
        
           |  |  | 134 |      * @param string $ip An IPv6 address
 | 
        
           |  |  | 135 |      * @return string The compressed IPv6 address
 | 
        
           |  |  | 136 |      */
 | 
        
           |  |  | 137 |     public static function compress($ip)
 | 
        
           |  |  | 138 |     {
 | 
        
           |  |  | 139 |         // Prepare the IP to be compressed
 | 
        
           |  |  | 140 |         $ip = self::uncompress($ip);
 | 
        
           |  |  | 141 |         $ip_parts = self::split_v6_v4($ip);
 | 
        
           |  |  | 142 |   | 
        
           |  |  | 143 |         // Replace all leading zeros
 | 
        
           |  |  | 144 |         $ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
 | 
        
           |  |  | 145 |   | 
        
           |  |  | 146 |         // Find bunches of zeros
 | 
        
           |  |  | 147 |         if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
 | 
        
           |  |  | 148 |             $max = 0;
 | 
        
           |  |  | 149 |             $pos = null;
 | 
        
           |  |  | 150 |             foreach ($matches[0] as $match) {
 | 
        
           |  |  | 151 |                 if (strlen($match[0]) > $max) {
 | 
        
           |  |  | 152 |                     $max = strlen($match[0]);
 | 
        
           |  |  | 153 |                     $pos = $match[1];
 | 
        
           |  |  | 154 |                 }
 | 
        
           |  |  | 155 |             }
 | 
        
           |  |  | 156 |   | 
        
           |  |  | 157 |             $ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
 | 
        
           |  |  | 158 |         }
 | 
        
           |  |  | 159 |   | 
        
           |  |  | 160 |         if ($ip_parts[1] !== '') {
 | 
        
           |  |  | 161 |             return implode(':', $ip_parts);
 | 
        
           |  |  | 162 |         }
 | 
        
           |  |  | 163 |   | 
        
           |  |  | 164 |         return $ip_parts[0];
 | 
        
           |  |  | 165 |     }
 | 
        
           |  |  | 166 |   | 
        
           |  |  | 167 |     /**
 | 
        
           |  |  | 168 |      * Splits an IPv6 address into the IPv6 and IPv4 representation parts
 | 
        
           |  |  | 169 |      *
 | 
        
           |  |  | 170 |      * RFC 4291 allows you to represent the last two parts of an IPv6 address
 | 
        
           |  |  | 171 |      * using the standard IPv4 representation
 | 
        
           |  |  | 172 |      *
 | 
        
           |  |  | 173 |      * Example:  0:0:0:0:0:0:13.1.68.3
 | 
        
           |  |  | 174 |      *           0:0:0:0:0:FFFF:129.144.52.38
 | 
        
           |  |  | 175 |      *
 | 
        
           |  |  | 176 |      * @param string $ip An IPv6 address
 | 
        
           |  |  | 177 |      * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
 | 
        
           |  |  | 178 |      */
 | 
        
           |  |  | 179 |     private static function split_v6_v4($ip)
 | 
        
           |  |  | 180 |     {
 | 
        
           |  |  | 181 |         if (strpos($ip, '.') !== false) {
 | 
        
           |  |  | 182 |             $pos = strrpos($ip, ':');
 | 
        
           |  |  | 183 |             $ipv6_part = substr($ip, 0, $pos);
 | 
        
           |  |  | 184 |             $ipv4_part = substr($ip, $pos + 1);
 | 
        
           |  |  | 185 |             return [$ipv6_part, $ipv4_part];
 | 
        
           |  |  | 186 |         }
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |         return [$ip, ''];
 | 
        
           |  |  | 189 |     }
 | 
        
           |  |  | 190 |   | 
        
           |  |  | 191 |     /**
 | 
        
           |  |  | 192 |      * Checks an IPv6 address
 | 
        
           |  |  | 193 |      *
 | 
        
           |  |  | 194 |      * Checks if the given IP is a valid IPv6 address
 | 
        
           |  |  | 195 |      *
 | 
        
           |  |  | 196 |      * @param string $ip An IPv6 address
 | 
        
           |  |  | 197 |      * @return bool true if $ip is a valid IPv6 address
 | 
        
           |  |  | 198 |      */
 | 
        
           |  |  | 199 |     public static function check_ipv6($ip)
 | 
        
           |  |  | 200 |     {
 | 
        
           |  |  | 201 |         $ip = self::uncompress($ip);
 | 
        
           |  |  | 202 |         [$ipv6, $ipv4] = self::split_v6_v4($ip);
 | 
        
           |  |  | 203 |         $ipv6 = explode(':', $ipv6);
 | 
        
           |  |  | 204 |         $ipv4 = explode('.', $ipv4);
 | 
        
           |  |  | 205 |         if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
 | 
        
           |  |  | 206 |             foreach ($ipv6 as $ipv6_part) {
 | 
        
           |  |  | 207 |                 // The section can't be empty
 | 
        
           |  |  | 208 |                 if ($ipv6_part === '') {
 | 
        
           |  |  | 209 |                     return false;
 | 
        
           |  |  | 210 |                 }
 | 
        
           |  |  | 211 |   | 
        
           |  |  | 212 |                 // Nor can it be over four characters
 | 
        
           |  |  | 213 |                 if (strlen($ipv6_part) > 4) {
 | 
        
           |  |  | 214 |                     return false;
 | 
        
           |  |  | 215 |                 }
 | 
        
           |  |  | 216 |   | 
        
           |  |  | 217 |                 // Remove leading zeros (this is safe because of the above)
 | 
        
           |  |  | 218 |                 $ipv6_part = ltrim($ipv6_part, '0');
 | 
        
           |  |  | 219 |                 if ($ipv6_part === '') {
 | 
        
           |  |  | 220 |                     $ipv6_part = '0';
 | 
        
           |  |  | 221 |                 }
 | 
        
           |  |  | 222 |   | 
        
           |  |  | 223 |                 // Check the value is valid
 | 
        
           |  |  | 224 |                 $value = hexdec($ipv6_part);
 | 
        
           |  |  | 225 |                 if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
 | 
        
           |  |  | 226 |                     return false;
 | 
        
           |  |  | 227 |                 }
 | 
        
           |  |  | 228 |             }
 | 
        
           |  |  | 229 |             if (count($ipv4) === 4) {
 | 
        
           |  |  | 230 |                 foreach ($ipv4 as $ipv4_part) {
 | 
        
           |  |  | 231 |                     $value = (int) $ipv4_part;
 | 
        
           |  |  | 232 |                     if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
 | 
        
           |  |  | 233 |                         return false;
 | 
        
           |  |  | 234 |                     }
 | 
        
           |  |  | 235 |                 }
 | 
        
           |  |  | 236 |             }
 | 
        
           |  |  | 237 |             return true;
 | 
        
           |  |  | 238 |         }
 | 
        
           |  |  | 239 |   | 
        
           |  |  | 240 |         return false;
 | 
        
           |  |  | 241 |     }
 | 
        
           |  |  | 242 |   | 
        
           |  |  | 243 |     /**
 | 
        
           |  |  | 244 |      * Checks if the given IP is a valid IPv6 address
 | 
        
           |  |  | 245 |      *
 | 
        
           |  |  | 246 |      * @codeCoverageIgnore
 | 
        
           |  |  | 247 |      * @deprecated Use {@see IPv6::check_ipv6()} instead
 | 
        
           |  |  | 248 |      * @see check_ipv6
 | 
        
           |  |  | 249 |      * @param string $ip An IPv6 address
 | 
        
           |  |  | 250 |      * @return bool true if $ip is a valid IPv6 address
 | 
        
           |  |  | 251 |      */
 | 
        
           |  |  | 252 |     public static function checkIPv6($ip)
 | 
        
           |  |  | 253 |     {
 | 
        
           |  |  | 254 |         return self::check_ipv6($ip);
 | 
        
           |  |  | 255 |     }
 | 
        
           |  |  | 256 | }
 | 
        
           |  |  | 257 |   | 
        
           |  |  | 258 | class_alias('SimplePie\Net\IPv6', 'SimplePie_Net_IPv6');
 |