PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/simplepie/library/SimplePie/Net/IPv6.php

https://bitbucket.org/fivefilters/full-text-rss
PHP | 275 lines | 136 code | 13 blank | 126 comment | 28 complexity | 23689d2377c48c13c6ccb57d442d74d1 MD5 | raw file
  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, Geoffrey 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, Geoffrey Sneddon, Ryan McCue
  37. * @author Ryan Parman
  38. * @author Geoffrey 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 Geoffrey 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. else
  170. {
  171. return $ip_parts[0];
  172. }
  173. }
  174. /**
  175. * Splits an IPv6 address into the IPv6 and IPv4 representation parts
  176. *
  177. * RFC 4291 allows you to represent the last two parts of an IPv6 address
  178. * using the standard IPv4 representation
  179. *
  180. * Example: 0:0:0:0:0:0:13.1.68.3
  181. * 0:0:0:0:0:FFFF:129.144.52.38
  182. *
  183. * @param string $ip An IPv6 address
  184. * @return array [0] contains the IPv6 represented part, and [1] the IPv4 represented part
  185. */
  186. private static function split_v6_v4($ip)
  187. {
  188. if (strpos($ip, '.') !== false)
  189. {
  190. $pos = strrpos($ip, ':');
  191. $ipv6_part = substr($ip, 0, $pos);
  192. $ipv4_part = substr($ip, $pos + 1);
  193. return array($ipv6_part, $ipv4_part);
  194. }
  195. else
  196. {
  197. return array($ip, '');
  198. }
  199. }
  200. /**
  201. * Checks an IPv6 address
  202. *
  203. * Checks if the given IP is a valid IPv6 address
  204. *
  205. * @param string $ip An IPv6 address
  206. * @return bool true if $ip is a valid IPv6 address
  207. */
  208. public static function check_ipv6($ip)
  209. {
  210. $ip = self::uncompress($ip);
  211. list($ipv6, $ipv4) = self::split_v6_v4($ip);
  212. $ipv6 = explode(':', $ipv6);
  213. $ipv4 = explode('.', $ipv4);
  214. if (count($ipv6) === 8 && count($ipv4) === 1 || count($ipv6) === 6 && count($ipv4) === 4)
  215. {
  216. foreach ($ipv6 as $ipv6_part)
  217. {
  218. // The section can't be empty
  219. if ($ipv6_part === '')
  220. return false;
  221. // Nor can it be over four characters
  222. if (strlen($ipv6_part) > 4)
  223. return false;
  224. // Remove leading zeros (this is safe because of the above)
  225. $ipv6_part = ltrim($ipv6_part, '0');
  226. if ($ipv6_part === '')
  227. $ipv6_part = '0';
  228. // Check the value is valid
  229. $value = hexdec($ipv6_part);
  230. if (dechex($value) !== strtolower($ipv6_part) || $value < 0 || $value > 0xFFFF)
  231. return false;
  232. }
  233. if (count($ipv4) === 4)
  234. {
  235. foreach ($ipv4 as $ipv4_part)
  236. {
  237. $value = (int) $ipv4_part;
  238. if ((string) $value !== $ipv4_part || $value < 0 || $value > 0xFF)
  239. return false;
  240. }
  241. }
  242. return true;
  243. }
  244. else
  245. {
  246. return false;
  247. }
  248. }
  249. /**
  250. * Checks if the given IP is a valid IPv6 address
  251. *
  252. * @codeCoverageIgnore
  253. * @deprecated Use {@see SimplePie_Net_IPv6::check_ipv6()} instead
  254. * @see check_ipv6
  255. * @param string $ip An IPv6 address
  256. * @return bool true if $ip is a valid IPv6 address
  257. */
  258. public static function checkIPv6($ip)
  259. {
  260. return self::check_ipv6($ip);
  261. }
  262. }