Login | ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/vgwhois/trunk/shared/php_includes/ipv6_functions.inc.php
Revision: 45
Committed: Sat Mar 28 23:50:01 2020 UTC (3 months, 1 week ago) by daniel-marschall
File size: 18559 byte(s)
Log Message:
TLD ".ve" update

File Contents

# Content
1 <?php
2
3 /*
4 * IPv6 functions for PHP
5 * Copyright 2012-2020 Daniel Marschall, ViaThinkSoft
6 * Version 2020-02-28
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21 # This library requires either the GMP extension (or BCMath if gmp_supplement.inc.php is present)
22
23 // TODO: oop, exceptions?
24 // TODO: variant without gmp ?
25 // TODO: IPv6 auflösung 'ffff::192.168.69.1' -> 'ffff:0000:0000:0000:0000:0000:c0a8:4501' geht nicht!!!
26
27 if (file_exists(__DIR__ . '/gmp_supplement.inc.php')) include_once __DIR__ . '/gmp_supplement.inc.php';
28
29 define('GMP_ONE', gmp_init('1'));
30
31 // Very small self-test:
32 /*
33 function ipv6_selftest() {
34 $iv_b = 'c0ff:ee00::';
35 $iv_m = 32;
36 $r = ipv6_cidr2range($iv_b, $iv_m);
37 echo "$iv_b/$iv_m => $r[0] - $r[1]\n";
38
39 $rev = ipv6_range2cidr($r[0], $r[1]);
40 $rev = implode("\n", $rev);
41 echo "$r[0] - $r[1] => $rev [";
42 $ok = $rev == "$iv_b/$iv_m";
43 echo $ok ? 'OK' : 'Mismatch';
44 echo "]\n";
45 echo "In-CIDR-Test: ";
46 echo ipv6_in_cidr("$iv_b/$iv_m", "$iv_b/$iv_m") ? 'OK' : 'Fail';
47 echo "\n";
48 }
49 ipv6_selftest();
50 */
51
52 $cache_ipv6_cidr2range = array();
53 function ipv6_cidr2range($baseip_or_cidr, $subnet='') {
54 # (C) 2012 ViaThinkSoft
55 # Version 1.1
56 # This function converts an CIDR notation <baseip>/<subnet> into an IPv6 address block array($low_ip, $high_ip)
57
58 global $cache_ipv6_cidr2range;
59 $vvv = $baseip_or_cidr.'|'.$subnet;
60 if (isset($cache_ipv6_cidr2range[$vvv])) return $cache_ipv6_cidr2range[$vvv];
61
62 if (strpos($baseip_or_cidr, '/') !== false) {
63 $tmp = explode('/', $baseip_or_cidr, 2);
64 $baseip_or_cidr = $tmp[0];
65 $subnet = $tmp[1];
66 unset($tmp);
67 }
68
69 if (($subnet < 0) || ($subnet > 128)) {
70 $cache_ipv6_cidr2range[$vvv] = false;
71 return false;
72 }
73
74 $maxint128 = gmp_sub(gmp_pow('2', 128), GMP_ONE); # TODO: GMP_TWO ?
75 $netmask = gmp_shiftl($maxint128, 128-$subnet);
76 $netmask = gmp_and($netmask, $maxint128); // crop to 128 bit
77 $wildcard = gmp_xor($maxint128, $netmask);
78
79 $x = gmp_and(ip2long6($baseip_or_cidr), $netmask);
80 $nums = $wildcard;
81 $low = long2ip6($x);
82 $high = long2ip6(gmp_add($x, $nums));
83
84 $out = array($low, $high);
85 $cache_ipv6_cidr2range[$vvv] = $out;
86 return $out;
87 }
88
89 $cache_ipv6_range2cidr = array();
90 function ipv6_range2cidr($baseip, $topip) {
91 # (C) 2012 ViaThinkSoft
92 # Version 1.0
93 # This function converts an IPv6 address block into valid CIDR blocks (There may be multiple blocks!)
94
95 global $cache_ipv6_range2cidr;
96 $vvv = $baseip.'|'.$topip;
97 if (isset($cache_ipv6_range2cidr[$vvv])) return $cache_ipv6_range2cidr[$vvv];
98
99 $out = array();
100 if (ipv6_cmp($baseip, $topip) > 0) {
101 $cache_ipv6_range2cidr[$vvv] = false;
102 return false;
103 }
104 while (gmp_cmp(gmp_sub(ip2long6($baseip), GMP_ONE), ip2long6($topip)) != 0) {
105 $i = -1;
106 do {
107 $i++;
108 $range = ipv6_cidr2range($baseip, $i);
109 $l = $range[0];
110 $t = $range[1];
111 } while ((ipv6_cmp($l, $baseip) != 0) || (ipv6_cmp($t, $topip) > 0));
112
113 $out[] = "$baseip/$i";
114 $baseip = ipv6_add($t, GMP_ONE);
115 }
116
117 $cache_ipv6_range2cidr[$vvv] = $out;
118 return $out;
119 }
120
121 function ipv6_add($baseip, $num) {
122 # (C) 2012 ViaThinkSoft
123 # Version 1.0
124
125 return long2ip6(gmp_add(ip2long6($baseip), $num));
126 }
127
128 function ipv6_sub($baseip, $num) {
129 # (C) 2012 ViaThinkSoft
130 # Version 1.0
131
132 return long2ip6(gmp_sub(ip2long6($baseip), $num));
133 }
134
135 function ipv6_cmp($a, $b) {
136 # (C) 2012 ViaThinkSoft
137 # Version 1.0
138
139 return gmp_cmp(ip2long6($a), ip2long6($b));
140 }
141
142 $cache_ipv6_in_cidr = array();
143 function ipv6_in_cidr($haystack, $needle) {
144 # (C) 2012 ViaThinkSoft
145 # Version 1.1
146
147 global $cache_ipv6_in_cidr;
148 $vvv = $haystack.'|'.$needle;
149 if (isset($cache_ipv6_in_cidr[$vvv])) return $cache_ipv6_in_cidr[$vvv];
150
151 $x = explode('/', $haystack);
152 $ha = ipv6_cidr2range($x[0], $x[1]);
153
154 $x = explode('/', $needle);
155 if (!isset($x[1])) $x[1] = 128; // single IP
156 $ne = ipv6_cidr2range($x[0], $x[1]);
157
158 $ha_low = ip2long6($ha[0]);
159 $ha_hig = ip2long6($ha[1]);
160 $ne_low = ip2long6($ne[0]);
161 $ne_hig = ip2long6($ne[1]);
162
163 # HA: low[ ]high
164 # NE: low[ ]high
165
166 $out = (gmp_cmp($ne_low, $ha_low) >= 0) && (gmp_cmp($ne_hig, $ha_hig) <= 0);
167 $cache_ipv6_in_cidr[$vvv] = $out;
168 return $out;
169 }
170
171 // IMPORTANT! $cmp_ary[x]=y MUST HAVE x<=y !
172 function ipv6_merge_address_blocks($data, $debug = false) {
173 # (C) 2012-2013 ViaThinkSoft
174 # Version 2.2
175
176 if ($debug !== false) $STARTZEIT = time();
177
178 // 1. Convert IPs to numbers
179
180 $cmp_ary = array();
181 foreach ($data as $a => &$b) {
182 $a = ip2long6($a);
183 $b = ip2long6($b);
184
185 $cmp_ary[gmp_strval($a)] = gmp_strval($b);
186 unset($a);
187 unset($b);
188 }
189
190 // 2. Sort array
191
192 ksort($cmp_ary);
193
194 // 3. Merge the blocks in an intelligent way (and remove redundant blocks)
195
196 # Merge overlapping blocks
197 # [ ]
198 # [ ] -> [ ]
199
200 # Merge neighbor blocks
201 # [ ][ ] -> [ ]
202
203 # Remove redundant blocks
204 # [ ] -> [ ]
205 # [ ]
206
207 $merge_count = 0;
208 $redundant_deleted_count = 0;
209 $round_count = 0;
210 do {
211 if ($debug !== false) {
212 $LAUFZEIT = time() - $STARTZEIT;
213 echo $debug."Merging... $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\r";
214 }
215
216 $round_count++;
217
218 $clean = true;
219
220 foreach ($cmp_ary as $a => &$b) {
221 foreach ($cmp_ary as $x => &$y) {
222 // x in range [a+1..b+1] ?
223 if (gmp_cmp(gmp_init($x), gmp_init($a)) <= 0) continue;
224 if (gmp_cmp(gmp_init($x), gmp_add(gmp_init($b), GMP_ONE)) > 0) break;
225
226 // Merge
227 $clean = false;
228 if (gmp_cmp(gmp_init($y), gmp_init($b)) > 0) {
229 $merge_count++;
230 $b = $y;
231 unset($cmp_ary[$x]);
232 } else {
233 $redundant_deleted_count++;
234 unset($cmp_ary[$x]);
235 }
236 }
237 }
238 } while (!$clean);
239
240 if ($debug !== false) {
241 $LAUFZEIT = time() - $STARTZEIT;
242 echo $debug."Merge completed. $round_count rounds; merged $merge_count blocks; deleted $redundant_deleted_count redundant blocks; time: $LAUFZEIT seconds\n";
243 }
244
245 // 4. Convert back to IPs
246
247 $out_ary = array();
248 foreach ($cmp_ary as $a => &$b) {
249 $a = long2ip6(gmp_init($a));
250 $b = long2ip6(gmp_init($b));
251 $out_ary[$a] = $b;
252 }
253
254 return $out_ary;
255 }
256
257 function ipv6_merge_arrays($data_a, $data_b) {
258 # (C) 2012 ViaThinkSoft
259 # Version 1.2
260
261 $normalized_data_a = array();
262 foreach ($data_a as $from => &$to) {
263 $normalized_data_a[ipv6_normalize($from)] = ipv6_normalize($to);
264 }
265
266 $normalized_data_b = array();
267 foreach ($data_b as $from => &$to) {
268 $normalized_data_b[ipv6_normalize($from)] = ipv6_normalize($to);
269 }
270
271 $data = array();
272
273 foreach ($normalized_data_a as $from => &$to) {
274 if (isset($normalized_data_b[$from])) {
275 $data[$from] = ipv6_max($to, $normalized_data_b[$from]);
276 } else {
277 $data[$from] = $to;
278 }
279 }
280
281 foreach ($normalized_data_b as $from => &$to) {
282 if (!isset($normalized_data_a[$from])) {
283 $data[$from] = $to;
284 }
285 }
286
287 return $data;
288 }
289
290 function ipv6_valid($ip) {
291 # (C) 2012 ViaThinkSoft
292 # Version 1.0
293
294 return ip2long6($ip) !== false;
295 }
296
297 function ipv6_normalize($ip) {
298 # (C) 2012 ViaThinkSoft
299 # Version 1.0
300
301 # Example:
302 # 2001:0000:0000::1 -> 2001::1
303
304 $long = ip2long6($ip);
305 if ($long == -1 || $long === FALSE) return false;
306 return long2ip6($long);
307 }
308
309 function ipv6_expand($ip) {
310 # (C) 2012 ViaThinkSoft
311 # Version 1.0
312
313 # Example:
314 # 2001::1 -> 2001:0000:0000:0000:0000:0000:0000:0000
315
316 $long = ip2long6($ip);
317 if ($long == -1 || $long === FALSE) return false;
318 return long2ip6($long, false);
319 }
320
321 function ipv6_min($ip_a, $ip_b) {
322 # (C) 2012 ViaThinkSoft
323 # Version 1.0
324
325 if (ipv6_cmp($ip_a, $ip_b) == -1) {
326 return $ip_a;
327 } else {
328 return $ip_b;
329 }
330 }
331
332 function ipv6_max($ip_a, $ip_b) {
333 # (C) 2012 ViaThinkSoft
334 # Version 1.0
335
336 if (ipv6_cmp($ip_a, $ip_b) == 1) {
337 return $ip_a;
338 } else {
339 return $ip_b;
340 }
341 }
342
343 function ipv6_ipcount($data) {
344 # (C) 2012 ViaThinkSoft
345 # Version 1.0
346
347 $cnt = gmp_init('0');
348
349 foreach ($data as $from => &$to) {
350 $cnt = gmp_add($cnt, gmp_sub(ip2long6($to), ip2long6($from)));
351 }
352
353 return gmp_strval($cnt, 10);
354 }
355
356 function ipv6_read_file($file) {
357 # (C) 2012 ViaThinkSoft
358 # Version 1.0
359
360 $data = array();
361
362 $lines = file($file);
363 foreach ($lines as &$line) {
364 $rng = ipv6_line2range($line);
365 $data[$rng[0]] = $rng[1];
366 }
367
368 return $data;
369 }
370
371 function ipv6_line2range($line) {
372 # (C) 2012 ViaThinkSoft
373 # Version 1.0
374
375 $line = trim($line);
376
377 if (strpos($line, '/') !== false) {
378 $rng = ipv6_cidr2range($line);
379 } else {
380 $rng = explode('-', $line);
381 $rng[0] = trim($rng[0]);
382 $rng[1] = trim($rng[1]);
383 $rng[0] = ipv6_normalize($rng[0]);
384 if (!isset($rng[1])) $rng[1] = $rng[0];
385 $rng[1] = ipv6_normalize($rng[1]);
386 }
387
388 return $rng;
389 }
390
391 # ---
392
393 if (!function_exists('gmp_shiftl')) {
394 function gmp_shiftl($x, $n) { // shift left
395 // http://www.php.net/manual/en/ref.gmp.php#99788
396 return gmp_mul($x, gmp_pow('2', $n));
397 }
398 }
399
400 if (!function_exists('gmp_shiftr')) {
401 function gmp_shiftr($x, $n) { // shift right
402 // http://www.php.net/manual/en/ref.gmp.php#99788
403 return gmp_div($x, gmp_pow('2', $n));
404 }
405 }
406
407 $cache_ip2long6 = array();
408 function ip2long6($ipv6) {
409 // Source:
410 // http://www.netz-guru.de/2009/11/07/php-ipv6-ip2long-und-long2ip-funktionen/
411 // Slightly modified
412
413 global $cache_ip2long6;
414 if (isset($cache_ip2long6[$ipv6])) return $cache_ip2long6[$ipv6];
415
416 if ($ipv6 == '') $ipv6 = '::';
417
418 if (filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
419 $cache_ip2long6[$ipv6] = false;
420 return false;
421 }
422
423 $ip_n = @inet_pton($ipv6);
424 if ($ip_n === false) {
425 $cache_ip2long6[$ipv6] = false;
426 return false; // modified
427 }
428 $bytes = 16; // 16 bytes x 8 bit/byte = 128bit
429 $ipv6long = '';
430
431 while ($bytes > 0) {
432 $bin = sprintf('%08b',(ord($ip_n[$bytes-1])));
433 $ipv6long = $bin.$ipv6long;
434 $bytes--;
435 }
436
437 // $out = gmp_strval(gmp_init($ipv6long, 2), 10);
438 $out = gmp_init($ipv6long, 2);
439 $cache_ip2long6[$ipv6] = $out;
440 return $out;
441 }
442
443 $cache_long2ip6 = array();
444 function long2ip6($ipv6long, $compress=true) {
445 // Source:
446 // http://www.netz-guru.de/2009/11/07/php-ipv6-ip2long-und-long2ip-funktionen/
447 // Slightly modified
448
449 global $cache_long2ip6;
450 $vvv = ($compress ? 'T' : 'F').$ipv6long;
451 if (isset($cache_long2ip6[$vvv])) return $cache_long2ip6[$vvv];
452
453 // $bin = gmp_strval(gmp_init($ipv6long, 10), 2);
454 $bin = gmp_strval($ipv6long, 2);
455 if (strlen($bin) < 128) {
456 $pad = 128 - strlen($bin);
457 for ($i = 1; $i <= $pad; $i++) {
458 $bin = '0'.$bin;
459 }
460 }
461
462 $bytes = 0;
463 $ipv6 = '';
464 while ($bytes < 8) { // 16 bytes x 8 bit/byte = 128bit
465 $bin_part = substr($bin,($bytes*16),16);
466 $part = dechex(bindec($bin_part));
467 if (!$compress) {
468 $part = str_pad($part, 4, '0', STR_PAD_LEFT);
469 }
470 $ipv6 .= $part.':';
471 $bytes++;
472 }
473
474 if ($compress) {
475 $out = inet_ntop(inet_pton(substr($ipv6, 0, -1)));
476 } else {
477 $out = substr($ipv6, 0, strlen($ipv6)-1);
478 }
479 $cache_long2ip6[$vvv] = $out;
480 return $out;
481 }
482
483 # --- New 16,12,12
484
485 define('IPV6_BITS', 128);
486
487 $global_ipv6_distance = array();
488 function ipv6_distance($ipOrCIDR_Searchterm, $ipOrCIDR_Candidate) {
489 global $global_ipv6_distance;
490 $vvv = $ipOrCIDR_Searchterm.'|'.$ipOrCIDR_Candidate;
491 if (isset($global_ipv6_distance[$vvv])) return $global_ipv6_distance[$vvv];
492
493 $ary = ipv6_cidr_split($ipOrCIDR_Searchterm);
494 $ip = $ary[0];
495
496 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
497 $global_ipv6_distance[$vvv] = false;
498 return false;
499 }
500
501 $ary = ipv6_cidr_split($ipOrCIDR_Candidate);
502 $ip = $ary[0];
503 $cidr_bits = $ary[1];
504 if ($cidr_bits > IPV6_BITS) {
505 $global_ipv6_distance[$vvv] = false;
506 return false; // throw new Exception('CIDR bits > '.IPV6_BITS);
507 }
508 if (!is_numeric($cidr_bits)) return false;
509
510 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
511 $global_ipv6_distance[$vvv] = false;
512 return false;
513 }
514
515 $x = ipv6_trackdown($ipOrCIDR_Searchterm);
516
517 if (ipv6_in_cidr($x[0], $ip.'/'.$cidr_bits)) {
518 $ary = ipv6_cidr_split($x[0]);
519 $cidr_bits2 = $ary[1];
520 if ($cidr_bits2 > IPV6_BITS) {
521 $global_ipv6_distance[$vvv] = false;
522 return false; // throw new Exception('CIDR bits > '.IPV6_BITS);
523 }
524 $out = $cidr_bits2-$cidr_bits;
525 $global_ipv6_distance[$vvv] = $out;
526 return $out;
527 }
528
529 $i = 0;
530 $max = false;
531 foreach ($x as &$y) {
532 if (ipv6_in_cidr($ip.'/'.$cidr_bits, $y)) {
533 $max = $i;
534 }
535 $i++;
536 }
537
538 $global_ipv6_distance[$vvv] = $max;
539 return $max;
540 }
541
542 function ipv6_cidr_split($ipOrCIDR) {
543 $ary = explode('/', $ipOrCIDR, 2);
544 $cidr_bits = isset($ary[1]) ? $ary[1] : IPV6_BITS;
545 if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS);
546 if (!is_numeric($cidr_bits)) return false;
547 $ip = $ary[0];
548 return array($ip, $cidr_bits);
549 }
550
551 function ipv6_equals($ipOrCIDRA, $ipOrCIDRB) {
552 return ipv6_normalize_range($ipOrCIDRA) == ipv6_normalize_range($ipOrCIDRB);
553 }
554
555 function ipv6_cidr_min_ip($ipOrCIDR) {
556 $ary = ipv6_cidr_split($ipOrCIDR);
557 $ipOrCIDR = $ary[0];
558 $cidr_bits = $ary[1];
559 if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS);
560 if (!is_numeric($cidr_bits)) return false;
561
562 $m = ip2bin($ipOrCIDR);
563 $m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV6_BITS-$cidr_bits);
564
565 return bin2ip($m);
566 }
567
568 function ipv6_cidr_max_ip($ipOrCIDR) {
569 $ary = ipv6_cidr_split($ipOrCIDR);
570 $ipOrCIDR = $ary[0];
571 $cidr_bits = $ary[1];
572 if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS);
573 if (!is_numeric($cidr_bits)) return false;
574
575 $m = ip2bin($ipOrCIDR);
576 $m = substr($m, 0, $cidr_bits) . str_repeat('1', IPV6_BITS-$cidr_bits);
577
578 return bin2ip($m);
579 }
580
581 function ipv6_normalize_range($ipOrCIDR) {
582 # 2001:1800::1/21
583 # --> 2001:1800::/21
584
585 # 2001:1af8:4100:a061:0001::1337
586 # --> 2001:1af8:4100:a061:1::1337/128
587
588 $ary = ipv6_cidr_split($ipOrCIDR);
589 $ipOrCIDR = $ary[0];
590 $cidr_bits = $ary[1];
591 if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS);
592 if (!is_numeric($cidr_bits)) return false;
593
594 $m = ip2bin($ipOrCIDR);
595 $m = substr($m, 0, $cidr_bits) . str_repeat('0', IPV6_BITS-$cidr_bits);
596
597 return bin2ip($m) . '/' . $cidr_bits;
598 }
599
600 function ipv6_trackdown($ipOrCIDR) {
601 $ary = ipv6_cidr_split($ipOrCIDR);
602 $ipOrCIDR = $ary[0];
603 $cidr_bits = $ary[1];
604 if ($cidr_bits > IPV6_BITS) return false; // throw new Exception('CIDR bits > '.IPV6_BITS);
605 if (!is_numeric($cidr_bits)) return false;
606
607 $out = array();
608 $m = ip2bin($ipOrCIDR);
609 for ($i=$cidr_bits; $i>=0; $i--) {
610 $m = substr($m, 0, $i) . str_repeat('0', IPV6_BITS-$i);
611 $out[] = bin2ip($m) . '/' . $i;
612 }
613
614 return $out;
615 }
616
617 function ipv6_sort($ary) {
618 $f = array();
619 foreach ($ary as $c) {
620 $a = explode('/', $c);
621 $ip = $a[0];
622 $bits = isset($a[1]) ? $a[1] : 128;
623
624 $d = ip2bin($ip);
625
626 # ord('*') must be smaller than ord('0')
627 $d = substr($d, 0, $bits).str_repeat('*', 128-$bits);
628
629 $f[$d] = $c;
630 }
631
632 return $f;
633 }
634
635 function ipv6_make_tree($ary) {
636 $ary = ipv6_sort($ary);
637
638 if (count($ary) == 0) return array();
639
640 $sub_begin = '';
641 $sub_begin_ip = '';
642 foreach ($ary as $n => $d) {
643 $sub_begin = substr($n, 0, strpos($n, '*'));
644 $sub_begin_ip = $d;
645 unset($ary[$n]);
646 break;
647 }
648
649 $sub = array();
650 $nonsub = array();
651 foreach ($ary as $n => $d) {
652 if (substr($n, 0, strlen($sub_begin)) == $sub_begin) {
653 $sub[$n] = $d;
654 } else {
655 $nonsub[$n] = $d;
656 }
657 }
658
659 $out = array();
660 $out[$sub_begin_ip] = ipv6_make_tree($sub);
661
662 $a = ipv6_make_tree($nonsub);
663
664 $out = array_merge($out, $a);
665
666 return $out;
667 }
668
669 # ---
670
671 if (!function_exists('ip2bin')) {
672 $cache_ip2bin = array();
673 function ip2bin($ip) {
674 # Source: http://php.net/manual/en/function.ip2long.php#104163
675 # modified by VTS
676
677 global $cache_ip2bin;
678 if (isset($cache_ip2bin[$ip])) return $cache_ip2bin[$ip];
679
680 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false) {
681 $out = base_convert(ip2long($ip), 10, 2);
682 $cache_ip2bin[$ip] = $out;
683 return $out;
684 }
685 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
686 $cache_ip2bin[$ip] = false;
687 return false;
688 }
689 if (($ip_n = inet_pton($ip)) === false) {
690 $cache_ip2bin[$ip] = false;
691 return false;
692 }
693 $bits = 15; // 16 x 8 bit = 128bit (ipv6)
694 $ipbin = ''; # added by vts to avoid warning
695 while ($bits >= 0) {
696 $bin = sprintf('%08b', (ord($ip_n[$bits])));
697 $ipbin = $bin.$ipbin;
698 $bits--;
699 }
700
701 $cache_ip2bin[$ip] = $ipbin;
702 return $ipbin;
703 }
704 }
705
706 if (!function_exists('bin2ip')) {
707 $cache_bin2ip = array();
708 function bin2ip($bin) {
709 # Source: http://php.net/manual/en/function.ip2long.php#104163
710 # modified by VTS
711
712 global $cache_bin2ip;
713 if (isset($cache_bin2ip[$bin])) return $cache_bin2ip[$bin];
714
715 if (strlen($bin) <= 32) { // 32bits (ipv4)
716 $out = long2ip(base_convert($bin, 2, 10));
717 $cache_bin2ip[$bin] = $out;
718 return $out;
719 }
720 if (strlen($bin) != 128) {
721 $cache_bin2ip[$bin] = false;
722 return false;
723 }
724 $pad = 128 - strlen($bin);
725 for ($i = 1; $i <= $pad; $i++) {
726 $bin = '0'.$bin;
727 }
728 $bits = 0;
729 $ipv6 = ''; # added by vts to avoid warning
730 while ($bits <= 7) {
731 $bin_part = substr($bin,($bits*16),16);
732 $ipv6 .= dechex(bindec($bin_part)) . ':';
733 $bits++;
734 }
735
736 $out = inet_ntop(inet_pton(substr($ipv6, 0, -1)));
737 $cache_bin2ip[$bin] = $out;
738 return $out;
739 }
740 }
741
742 # --- TEST
743
744 /*
745 assert(ipv6_normalize('2001:0000:0000::1') == '2001::1');
746
747 assert(ipv6_distance('2001:1ae0::/27', '2001:1af8::/29') == -2);
748 assert(ipv6_distance('2001:1af0::/28', '2001:1af8::/29') == -1);
749 assert(ipv6_distance('2001:1af8::/29', '2001:1af8::/29') == 0);
750 assert(ipv6_distance('2001:1af8::/30', '2001:1af8::/29') == 1);
751 assert(ipv6_distance('2001:1af8::/31', '2001:1af8::/29') == 2);
752
753 assert(ipv6_distance('2001:1af8:4100:a061:0001::1336/127', '2001:1af8:4100:a061:0001::1335/127') === false);
754 assert(ipv6_distance('2001:1af8:4100:a061:0001::1336/128', '2001:1af8:4100:a061:0001::1337/128') === false);
755 assert(ipv6_distance('2001:1af8:4100:a061:0001::1336', '2001:1af8:4100:a061:0001::1337') === false);
756 */
757
758 /*
759 $test = '2001:1af8:4100:a061:0001::1337';
760 $x = ipv6_trackdown($test);
761 foreach ($x as &$cidr) {
762 $min = ipv6_cidr_min_ip($cidr);
763 $max = ipv6_cidr_max_ip($cidr);
764 echo "$cidr ($min - $max)\n";
765 }
766 */