Index: trunk/phase3/includes/IP.php |
— | — | @@ -3,18 +3,18 @@ |
4 | 4 | * Functions and constants to play with IP addresses and ranges |
5 | 5 | * |
6 | 6 | * @file |
7 | | - * @author "Ashar Voultoiz" <hashar@altern.org> |
| 7 | + * @author Ashar Voultoiz <hashar@altern.org> |
8 | 8 | * @license GPL v2 or later |
9 | 9 | */ |
10 | 10 | |
11 | 11 | // Some regex definition to "play" with IP address and IP address blocks |
12 | 12 | |
13 | 13 | // An IP is made of 4 bytes from x00 to xFF which is d0 to d255 |
14 | | -define( 'RE_IP_BYTE', '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])'); |
| 14 | +define( 'RE_IP_BYTE', '(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|0?[0-9]?[0-9])' ); |
15 | 15 | define( 'RE_IP_ADD' , RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.' . RE_IP_BYTE . '\.' . RE_IP_BYTE ); |
16 | 16 | // An IPv4 block is an IP address and a prefix (d1 to d32) |
17 | | -define( 'RE_IP_PREFIX', '(3[0-2]|[12]?\d)'); |
18 | | -define( 'RE_IP_BLOCK', RE_IP_ADD . '\/' . RE_IP_PREFIX); |
| 17 | +define( 'RE_IP_PREFIX', '(3[0-2]|[12]?\d)' ); |
| 18 | +define( 'RE_IP_BLOCK', RE_IP_ADD . '\/' . RE_IP_PREFIX ); |
19 | 19 | // For IPv6 canonicalization (NOT for strict validation; these are quite lax!) |
20 | 20 | define( 'RE_IPV6_WORD', '([0-9A-Fa-f]{1,4})' ); |
21 | 21 | define( 'RE_IPV6_GAP', ':(?:0+:)*(?::(?:0+:)*)?' ); |
— | — | @@ -52,27 +52,33 @@ |
53 | 53 | * @return string |
54 | 54 | */ |
55 | 55 | public static function isIPAddress( $ip ) { |
56 | | - if ( !$ip ) return false; |
| 56 | + if ( !$ip ) { |
| 57 | + return false; |
| 58 | + } |
57 | 59 | if ( is_array( $ip ) ) { |
58 | | - throw new MWException( "invalid value passed to " . __METHOD__ ); |
| 60 | + throw new MWException( 'invalid value passed to ' . __METHOD__ ); |
59 | 61 | } |
60 | 62 | // IPv6 IPs with two "::" strings are ambiguous and thus invalid |
61 | | - return preg_match( '/^' . IP_ADDRESS_STRING . '$/', $ip) && ( substr_count($ip, '::') < 2 ); |
| 63 | + return preg_match( '/^' . IP_ADDRESS_STRING . '$/', $ip ) && ( substr_count( $ip, '::' ) < 2 ); |
62 | 64 | } |
63 | 65 | |
64 | 66 | public static function isIPv6( $ip ) { |
65 | | - if ( !$ip ) return false; |
| 67 | + if ( !$ip ) { |
| 68 | + return false; |
| 69 | + } |
66 | 70 | if( is_array( $ip ) ) { |
67 | | - throw new MWException( "invalid value passed to " . __METHOD__ ); |
| 71 | + throw new MWException( 'invalid value passed to ' . __METHOD__ ); |
68 | 72 | } |
69 | | - $doubleColons = substr_count($ip, '::'); |
| 73 | + $doubleColons = substr_count( $ip, '::' ); |
70 | 74 | // IPv6 IPs with two "::" strings are ambiguous and thus invalid |
71 | | - return preg_match( '/^' . RE_IPV6_ADD . '(\/' . RE_IPV6_PREFIX . '|)$/', $ip) |
72 | | - && ( $doubleColons == 1 || substr_count($ip,':') == 7 ); |
| 75 | + return preg_match( '/^' . RE_IPV6_ADD . '(\/' . RE_IPV6_PREFIX . '|)$/', $ip ) |
| 76 | + && ( $doubleColons == 1 || substr_count( $ip, ':' ) == 7 ); |
73 | 77 | } |
74 | 78 | |
75 | 79 | public static function isIPv4( $ip ) { |
76 | | - if ( !$ip ) return false; |
| 80 | + if ( !$ip ) { |
| 81 | + return false; |
| 82 | + } |
77 | 83 | return preg_match( '/^' . RE_IP_ADD . '(\/' . RE_IP_PREFIX . '|)$/', $ip); |
78 | 84 | } |
79 | 85 | |
— | — | @@ -84,9 +90,13 @@ |
85 | 91 | * @return string |
86 | 92 | */ |
87 | 93 | public static function IPv4toIPv6( $ip ) { |
88 | | - if ( !$ip ) return null; |
| 94 | + if ( !$ip ) { |
| 95 | + return null; |
| 96 | + } |
89 | 97 | // Convert only if needed |
90 | | - if ( self::isIPv6( $ip ) ) return $ip; |
| 98 | + if ( self::isIPv6( $ip ) ) { |
| 99 | + return $ip; |
| 100 | + } |
91 | 101 | // IPv4 CIDRs |
92 | 102 | if ( strpos( $ip, '/' ) !== false ) { |
93 | 103 | $parts = explode( '/', $ip, 2 ); |
— | — | @@ -110,10 +120,12 @@ |
111 | 121 | * @return string |
112 | 122 | */ |
113 | 123 | public static function toUnsigned6( $ip ) { |
114 | | - if ( !$ip ) return null; |
115 | | - $ip = explode(':', self::sanitizeIP( $ip ) ); |
| 124 | + if ( !$ip ) { |
| 125 | + return null; |
| 126 | + } |
| 127 | + $ip = explode( ':', self::sanitizeIP( $ip ) ); |
116 | 128 | $r_ip = ''; |
117 | | - foreach ($ip as $v) { |
| 129 | + foreach ( $ip as $v ) { |
118 | 130 | $r_ip .= str_pad( $v, 4, 0, STR_PAD_LEFT ); |
119 | 131 | } |
120 | 132 | $r_ip = wfBaseConvert( $r_ip, 16, 10 ); |
— | — | @@ -128,11 +140,17 @@ |
129 | 141 | */ |
130 | 142 | public static function sanitizeIP( $ip ) { |
131 | 143 | $ip = trim( $ip ); |
132 | | - if ( $ip === '' ) return null; |
| 144 | + if ( $ip === '' ) { |
| 145 | + return null; |
| 146 | + } |
133 | 147 | // Trim and return IPv4 addresses |
134 | | - if ( self::isIPv4($ip) ) return $ip; |
| 148 | + if ( self::isIPv4( $ip ) ) { |
| 149 | + return $ip; |
| 150 | + } |
135 | 151 | // Only IPv6 addresses can be expanded |
136 | | - if ( !self::isIPv6($ip) ) return $ip; |
| 152 | + if ( !self::isIPv6( $ip ) ) { |
| 153 | + return $ip; |
| 154 | + } |
137 | 155 | // Remove any whitespaces, convert to upper case |
138 | 156 | $ip = strtoupper( $ip ); |
139 | 157 | // Expand zero abbreviations |
— | — | @@ -140,15 +158,21 @@ |
141 | 159 | if ( $abbrevPos !== false ) { |
142 | 160 | // If the '::' is at the beginning... |
143 | 161 | if( $abbrevPos == 0 ) { |
144 | | - $repeat = '0:'; $extra = ''; $pad = 9; // 7+2 (due to '::') |
| 162 | + $repeat = '0:'; |
| 163 | + $extra = ''; |
| 164 | + $pad = 9; // 7+2 (due to '::') |
145 | 165 | // If the '::' is at the end... |
146 | | - } else if( $abbrevPos == (strlen($ip)-2) ) { |
147 | | - $repeat = ':0'; $extra = ''; $pad = 9; // 7+2 (due to '::') |
| 166 | + } elseif( $abbrevPos == ( strlen( $ip ) - 2 ) ) { |
| 167 | + $repeat = ':0'; |
| 168 | + $extra = ''; |
| 169 | + $pad = 9; // 7+2 (due to '::') |
148 | 170 | // If the '::' is at the end... |
149 | 171 | } else { |
150 | | - $repeat = ':0'; $extra = ':'; $pad = 8; // 6+2 (due to '::') |
| 172 | + $repeat = ':0'; |
| 173 | + $extra = ':'; |
| 174 | + $pad = 8; // 6+2 (due to '::') |
151 | 175 | } |
152 | | - $ip = str_replace('::', str_repeat($repeat, $pad-substr_count($ip,':')).$extra, $ip); |
| 176 | + $ip = str_replace( '::', str_repeat( $repeat, $pad - substr_count( $ip, ':' ) ) . $extra, $ip ); |
153 | 177 | } |
154 | 178 | // Remove leading zereos from each bloc as needed |
155 | 179 | $ip = preg_replace( '/(^|:)0+' . RE_IPV6_WORD . '/', '$1$2', $ip ); |
— | — | @@ -162,11 +186,11 @@ |
163 | 187 | */ |
164 | 188 | public static function toOctet( $ip_int ) { |
165 | 189 | // Convert to padded uppercase hex |
166 | | - $ip_hex = wfBaseConvert($ip_int, 10, 16, 32, false); |
| 190 | + $ip_hex = wfBaseConvert( $ip_int, 10, 16, 32, false ); |
167 | 191 | // Separate into 8 octets |
168 | 192 | $ip_oct = substr( $ip_hex, 0, 4 ); |
169 | | - for ($n=1; $n < 8; $n++) { |
170 | | - $ip_oct .= ':' . substr($ip_hex, 4*$n, 4); |
| 193 | + for ( $n = 1; $n < 8; $n++ ) { |
| 194 | + $ip_oct .= ':' . substr( $ip_hex, 4 * $n, 4 ); |
171 | 195 | } |
172 | 196 | // NO leading zeroes |
173 | 197 | $ip_oct = preg_replace( '/(^|:)0+' . RE_IPV6_WORD . '/', '$1$2', $ip_oct ); |
— | — | @@ -183,7 +207,7 @@ |
184 | 208 | return self::hexToQuad( $hex ); |
185 | 209 | } |
186 | 210 | } |
187 | | - |
| 211 | + |
188 | 212 | /** |
189 | 213 | * Given a hexadecimal number, returns to an IPv6 address in octet notation |
190 | 214 | * @param $ip_hex string hex IP |
— | — | @@ -191,22 +215,22 @@ |
192 | 216 | */ |
193 | 217 | public static function hextoOctet( $ip_hex ) { |
194 | 218 | // Convert to padded uppercase hex |
195 | | - $ip_hex = str_pad( strtoupper($ip_hex), 32, '0'); |
| 219 | + $ip_hex = str_pad( strtoupper( $ip_hex ), 32, '0' ); |
196 | 220 | // Separate into 8 octets |
197 | 221 | $ip_oct = substr( $ip_hex, 0, 4 ); |
198 | | - for ($n=1; $n < 8; $n++) { |
199 | | - $ip_oct .= ':' . substr($ip_hex, 4*$n, 4); |
| 222 | + for ( $n = 1; $n < 8; $n++ ) { |
| 223 | + $ip_oct .= ':' . substr( $ip_hex, 4 * $n, 4 ); |
200 | 224 | } |
201 | 225 | // NO leading zeroes |
202 | 226 | $ip_oct = preg_replace( '/(^|:)0+' . RE_IPV6_WORD . '/', '$1$2', $ip_oct ); |
203 | 227 | return $ip_oct; |
204 | 228 | } |
205 | | - |
| 229 | + |
206 | 230 | /** |
207 | 231 | * Converts a hexadecimal number to an IPv4 address in octet notation |
208 | 232 | * @param $ip string Hex IP |
209 | 233 | * @return string |
210 | | - */ |
| 234 | + */ |
211 | 235 | public static function hexToQuad( $ip ) { |
212 | 236 | // Converts a hexadecimal IP to nnn.nnn.nnn.nnn format |
213 | 237 | $s = ''; |
— | — | @@ -277,12 +301,14 @@ |
278 | 302 | # Convert to hex |
279 | 303 | $end = wfBaseConvert( $end, 2, 16, 32, false ); |
280 | 304 | # see toHex() comment |
281 | | - $start = "v6-$start"; $end = "v6-$end"; |
| 305 | + $start = "v6-$start"; |
| 306 | + $end = "v6-$end"; |
282 | 307 | } |
283 | 308 | } elseif ( strpos( $range, '-' ) !== false ) { |
284 | 309 | # Explicit range |
285 | 310 | list( $start, $end ) = array_map( 'trim', explode( '-', $range, 2 ) ); |
286 | | - $start = self::toUnsigned6( $start ); $end = self::toUnsigned6( $end ); |
| 311 | + $start = self::toUnsigned6( $start ); |
| 312 | + $end = self::toUnsigned6( $end ); |
287 | 313 | if ( $start > $end ) { |
288 | 314 | $start = $end = false; |
289 | 315 | } else { |
— | — | @@ -290,7 +316,8 @@ |
291 | 317 | $end = wfBaseConvert( $end, 10, 16, 32, false ); |
292 | 318 | } |
293 | 319 | # see toHex() comment |
294 | | - $start = "v6-$start"; $end = "v6-$end"; |
| 320 | + $start = "v6-$start"; |
| 321 | + $end = "v6-$end"; |
295 | 322 | } else { |
296 | 323 | # Single IP |
297 | 324 | $start = $end = self::toHex( $range ); |
— | — | @@ -307,7 +334,7 @@ |
308 | 335 | * @return boolean True if it is valid. |
309 | 336 | */ |
310 | 337 | public static function isValid( $ip ) { |
311 | | - return ( preg_match( '/^' . RE_IP_ADD . '$/', $ip) || preg_match( '/^' . RE_IPV6_ADD . '$/', $ip) ); |
| 338 | + return ( preg_match( '/^' . RE_IP_ADD . '$/', $ip ) || preg_match( '/^' . RE_IPV6_ADD . '$/', $ip ) ); |
312 | 339 | } |
313 | 340 | |
314 | 341 | /** |
— | — | @@ -315,7 +342,7 @@ |
316 | 343 | * @return boolean True if it is valid. |
317 | 344 | */ |
318 | 345 | public static function isValidBlock( $ipblock ) { |
319 | | - return ( count(self::toArray($ipblock)) == 1 + 5 ); |
| 346 | + return ( count( self::toArray( $ipblock ) ) == 1 + 5 ); |
320 | 347 | } |
321 | 348 | |
322 | 349 | /** |
— | — | @@ -365,9 +392,9 @@ |
366 | 393 | */ |
367 | 394 | public static function toArray( $ipblock ) { |
368 | 395 | $matches = array(); |
369 | | - if( preg_match( '/^' . RE_IP_ADD . '(?:\/(?:'.RE_IP_PREFIX.'))?' . '$/', $ipblock, $matches ) ) { |
| 396 | + if( preg_match( '/^' . RE_IP_ADD . '(?:\/(?:' . RE_IP_PREFIX . '))?' . '$/', $ipblock, $matches ) ) { |
370 | 397 | return $matches; |
371 | | - } else if ( preg_match( '/^' . RE_IPV6_ADD . '(?:\/(?:'.RE_IPV6_PREFIX.'))?' . '$/', $ipblock, $matches ) ) { |
| 398 | + } elseif ( preg_match( '/^' . RE_IPV6_ADD . '(?:\/(?:' . RE_IPV6_PREFIX . '))?' . '$/', $ipblock, $matches ) ) { |
372 | 399 | return $matches; |
373 | 400 | } else { |
374 | 401 | return false; |
— | — | @@ -388,7 +415,7 @@ |
389 | 416 | public static function toHex( $ip ) { |
390 | 417 | $n = self::toUnsigned( $ip ); |
391 | 418 | if ( $n !== false ) { |
392 | | - $n = self::isIPv6($ip) ? "v6-" . wfBaseConvert( $n, 10, 16, 32, false ) : wfBaseConvert( $n, 10, 16, 8, false ); |
| 419 | + $n = self::isIPv6( $ip ) ? 'v6-' . wfBaseConvert( $n, 10, 16, 32, false ) : wfBaseConvert( $n, 10, 16, 8, false ); |
393 | 420 | } |
394 | 421 | return $n; |
395 | 422 | } |
— | — | @@ -450,7 +477,7 @@ |
451 | 478 | if ( $bits == 0 ) { |
452 | 479 | $network = 0; |
453 | 480 | } else { |
454 | | - $network &= ~((1 << (32 - $bits)) - 1); |
| 481 | + $network &= ~( ( 1 << ( 32 - $bits ) ) - 1); |
455 | 482 | } |
456 | 483 | # Convert to unsigned |
457 | 484 | if ( $network < 0 ) { |
— | — | @@ -489,13 +516,14 @@ |
490 | 517 | $start = $end = false; |
491 | 518 | } else { |
492 | 519 | $start = sprintf( '%08X', $network ); |
493 | | - $end = sprintf( '%08X', $network + pow( 2, (32 - $bits) ) - 1 ); |
| 520 | + $end = sprintf( '%08X', $network + pow( 2, ( 32 - $bits ) ) - 1 ); |
494 | 521 | } |
495 | 522 | } elseif ( strpos( $range, '-' ) !== false ) { |
496 | 523 | # Explicit range |
497 | 524 | list( $start, $end ) = array_map( 'trim', explode( '-', $range, 2 ) ); |
498 | 525 | if( self::isIPAddress( $start ) && self::isIPAddress( $end ) ) { |
499 | | - $start = self::toUnsigned( $start ); $end = self::toUnsigned( $end ); |
| 526 | + $start = self::toUnsigned( $start ); |
| 527 | + $end = self::toUnsigned( $end ); |
500 | 528 | if ( $start > $end ) { |
501 | 529 | $start = $end = false; |
502 | 530 | } else { |
— | — | @@ -526,8 +554,8 @@ |
527 | 555 | // Convert to IPv6 if needed |
528 | 556 | $hexIP = self::toHex( $addr ); |
529 | 557 | list( $start, $end ) = self::parseRange( $range ); |
530 | | - return (strcmp($hexIP, $start) >= 0 && |
531 | | - strcmp($hexIP, $end) <= 0); |
| 558 | + return ( strcmp( $hexIP, $start ) >= 0 && |
| 559 | + strcmp( $hexIP, $end ) <= 0 ); |
532 | 560 | } |
533 | 561 | |
534 | 562 | /** |
— | — | @@ -541,25 +569,31 @@ |
542 | 570 | * @return valid dotted quad IPv4 address or null |
543 | 571 | */ |
544 | 572 | public static function canonicalize( $addr ) { |
545 | | - if ( self::isValid( $addr ) ) |
| 573 | + if ( self::isValid( $addr ) ) { |
546 | 574 | return $addr; |
| 575 | + } |
547 | 576 | |
548 | 577 | // Turn mapped addresses from ::ce:ffff:1.2.3.4 to 1.2.3.4 |
549 | | - if ( strpos($addr,':') !==false && strpos($addr,'.') !==false ) { |
550 | | - $addr = substr( $addr, strrpos($addr,':')+1 ); |
551 | | - if( self::isIPv4($addr) ) return $addr; |
| 578 | + if ( strpos( $addr, ':' ) !== false && strpos( $addr, '.' ) !== false ) { |
| 579 | + $addr = substr( $addr, strrpos( $addr, ':' ) + 1 ); |
| 580 | + if( self::isIPv4( $addr ) ) { |
| 581 | + return $addr; |
| 582 | + } |
552 | 583 | } |
553 | 584 | |
554 | 585 | // IPv6 loopback address |
555 | 586 | $m = array(); |
556 | | - if ( preg_match( '/^0*' . RE_IPV6_GAP . '1$/', $addr, $m ) ) |
| 587 | + if ( preg_match( '/^0*' . RE_IPV6_GAP . '1$/', $addr, $m ) ) { |
557 | 588 | return '127.0.0.1'; |
| 589 | + } |
558 | 590 | |
559 | 591 | // IPv4-mapped and IPv4-compatible IPv6 addresses |
560 | | - if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . '(' . RE_IP_ADD . ')$/i', $addr, $m ) ) |
| 592 | + if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . '(' . RE_IP_ADD . ')$/i', $addr, $m ) ) { |
561 | 593 | return $m[1]; |
562 | | - if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . RE_IPV6_WORD . ':' . RE_IPV6_WORD . '$/i', $addr, $m ) ) |
| 594 | + } |
| 595 | + if ( preg_match( '/^' . RE_IPV6_V4_PREFIX . RE_IPV6_WORD . ':' . RE_IPV6_WORD . '$/i', $addr, $m ) ) { |
563 | 596 | return long2ip( ( hexdec( $m[1] ) << 16 ) + hexdec( $m[2] ) ); |
| 597 | + } |
564 | 598 | |
565 | 599 | return null; // give up |
566 | 600 | } |