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