balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

IPv6.php (5010B)


      1 <?php
      2 /**
      3  * Class to validate and to work with IPv6 addresses
      4  *
      5  * @package Requests
      6  * @subpackage Utilities
      7  */
      8 
      9 /**
     10  * Class to validate and to work with IPv6 addresses
     11  *
     12  * This was originally based on the PEAR class of the same name, but has been
     13  * entirely rewritten.
     14  *
     15  * @package Requests
     16  * @subpackage Utilities
     17  */
     18 class Requests_IPv6 {
     19 	/**
     20 	 * Uncompresses an IPv6 address
     21 	 *
     22 	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
     23 	 * '::'. This method expects a valid IPv6 address and expands the '::' to
     24 	 * the required number of zero pieces.
     25 	 *
     26 	 * Example:  FF01::101   ->  FF01:0:0:0:0:0:0:101
     27 	 *           ::1         ->  0:0:0:0:0:0:0:1
     28 	 *
     29 	 * @author Alexander Merz <alexander.merz@web.de>
     30 	 * @author elfrink at introweb dot nl
     31 	 * @author Josh Peck <jmp at joshpeck dot org>
     32 	 * @copyright 2003-2005 The PHP Group
     33 	 * @license http://www.opensource.org/licenses/bsd-license.php
     34 	 * @param string $ip An IPv6 address
     35 	 * @return string The uncompressed IPv6 address
     36 	 */
     37 	public static function uncompress($ip) {
     38 		if (substr_count($ip, '::') !== 1) {
     39 			return $ip;
     40 		}
     41 
     42 		list($ip1, $ip2) = explode('::', $ip);
     43 		$c1              = ($ip1 === '') ? -1 : substr_count($ip1, ':');
     44 		$c2              = ($ip2 === '') ? -1 : substr_count($ip2, ':');
     45 
     46 		if (strpos($ip2, '.') !== false) {
     47 			$c2++;
     48 		}
     49 		// ::
     50 		if ($c1 === -1 && $c2 === -1) {
     51 			$ip = '0:0:0:0:0:0:0:0';
     52 		}
     53 		// ::xxx
     54 		elseif ($c1 === -1) {
     55 			$fill = str_repeat('0:', 7 - $c2);
     56 			$ip   = str_replace('::', $fill, $ip);
     57 		}
     58 		// xxx::
     59 		elseif ($c2 === -1) {
     60 			$fill = str_repeat(':0', 7 - $c1);
     61 			$ip   = str_replace('::', $fill, $ip);
     62 		}
     63 		// xxx::xxx
     64 		else {
     65 			$fill = ':' . str_repeat('0:', 6 - $c2 - $c1);
     66 			$ip   = str_replace('::', $fill, $ip);
     67 		}
     68 		return $ip;
     69 	}
     70 
     71 	/**
     72 	 * Compresses an IPv6 address
     73 	 *
     74 	 * RFC 4291 allows you to compress consecutive zero pieces in an address to
     75 	 * '::'. This method expects a valid IPv6 address and compresses consecutive
     76 	 * zero pieces to '::'.
     77 	 *
     78 	 * Example:  FF01:0:0:0:0:0:0:101   ->  FF01::101
     79 	 *           0:0:0:0:0:0:0:1        ->  ::1
     80 	 *
     81 	 * @see uncompress()
     82 	 * @param string $ip An IPv6 address
     83 	 * @return string The compressed IPv6 address
     84 	 */
     85 	public static function compress($ip) {
     86 		// Prepare the IP to be compressed
     87 		$ip       = self::uncompress($ip);
     88 		$ip_parts = self::split_v6_v4($ip);
     89 
     90 		// Replace all leading zeros
     91 		$ip_parts[0] = preg_replace('/(^|:)0+([0-9])/', '\1\2', $ip_parts[0]);
     92 
     93 		// Find bunches of zeros
     94 		if (preg_match_all('/(?:^|:)(?:0(?::|$))+/', $ip_parts[0], $matches, PREG_OFFSET_CAPTURE)) {
     95 			$max = 0;
     96 			$pos = null;
     97 			foreach ($matches[0] as $match) {
     98 				if (strlen($match[0]) > $max) {
     99 					$max = strlen($match[0]);
    100 					$pos = $match[1];
    101 				}
    102 			}
    103 
    104 			$ip_parts[0] = substr_replace($ip_parts[0], '::', $pos, $max);
    105 		}
    106 
    107 		if ($ip_parts[1] !== '') {
    108 			return implode(':', $ip_parts);
    109 		}
    110 		else {
    111 			return $ip_parts[0];
    112 		}
    113 	}
    114 
    115 	/**
    116 	 * Splits an IPv6 address into the IPv6 and IPv4 representation parts
    117 	 *
    118 	 * RFC 4291 allows you to represent the last two parts of an IPv6 address
    119 	 * using the standard IPv4 representation
    120 	 *
    121 	 * Example:  0:0:0:0:0:0:13.1.68.3
    122 	 *           0:0:0:0:0:FFFF:129.144.52.38
    123 	 *
    124 	 * @param string $ip An IPv6 address
    125 	 * @return string[] [0] contains the IPv6 represented part, and [1] the IPv4 represented part
    126 	 */
    127 	protected static function split_v6_v4($ip) {
    128 		if (strpos($ip, '.') !== false) {
    129 			$pos       = strrpos($ip, ':');
    130 			$ipv6_part = substr($ip, 0, $pos);
    131 			$ipv4_part = substr($ip, $pos + 1);
    132 			return array($ipv6_part, $ipv4_part);
    133 		}
    134 		else {
    135 			return array($ip, '');
    136 		}
    137 	}
    138 
    139 	/**
    140 	 * Checks an IPv6 address
    141 	 *
    142 	 * Checks if the given IP is a valid IPv6 address
    143 	 *
    144 	 * @param string $ip An IPv6 address
    145 	 * @return bool true if $ip is a valid IPv6 address
    146 	 */
    147 	public static function check_ipv6($ip) {
    148 		$ip                = self::uncompress($ip);
    149 		list($ipv6, $ipv4) = self::split_v6_v4($ip);
    150 		$ipv6              = explode(':', $ipv6);
    151 		$ipv4              = explode('.', $ipv4);
    152 		if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4) {
    153 			foreach ($ipv6 as $ipv6_part) {
    154 				// The section can't be empty
    155 				if ($ipv6_part === '') {
    156 					return false;
    157 				}
    158 
    159 				// Nor can it be over four characters
    160 				if (strlen($ipv6_part) > 4) {
    161 					return false;
    162 				}
    163 
    164 				// Remove leading zeros (this is safe because of the above)
    165 				$ipv6_part = ltrim($ipv6_part, '0');
    166 				if ($ipv6_part === '') {
    167 					$ipv6_part = '0';
    168 				}
    169 
    170 				// Check the value is valid
    171 				$value = hexdec($ipv6_part);
    172 				if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF) {
    173 					return false;
    174 				}
    175 			}
    176 			if (count($ipv4) === 4) {
    177 				foreach ($ipv4 as $ipv4_part) {
    178 					$value = (int) $ipv4_part;
    179 					if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF) {
    180 						return false;
    181 					}
    182 				}
    183 			}
    184 			return true;
    185 		}
    186 		else {
    187 			return false;
    188 		}
    189 	}
    190 }