PageRenderTime 60ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/SimplePie/Net/IPv6.php

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