01 <?php
02 # Function(1) - Bad Example -
03 
04     function ip2cidr($ip_start, $ip_end) {
05         $cidr = $ip_start . "/" . (int)(32 - log((ip2long($ip_end) + 1 - ip2long($ip_start)), 2));
06 
07         return $cidr;
08     }
09 
10 # Function(2) - Bad Example -
11 
12     function ip2cidr($ip_start, $ip_end) {
13          if(long2ip(ip2long($ip_start)) != $ip_start || long2ip(ip2long($ip_end)) != $ip_end) {
14              return NULL;
15          }
16  
17          $ipl_start = (int)ip2long($ip_start);
18          $ipl_end = (int)ip2long($ip_end);
19  
20          if($ipl_start > 0 && $ipl_end < 0) {
21             $delta = ($ipl_end + 4294967296) - $ipl_start;
22          } else {
23              $delta = $ipl_end - $ipl_start;
24          }
25  
26          $netmask = str_pad(decbin($delta), 32, "0", "STR_PAD_LEFT");
27  
28          if(ip2long($ip_start) == 0 && substr_count($netmask, "1") == 32) {
29              return "0.0.0.0/0";
30          }
31          if($delta < 0 || ($delta > 0 && $delta % 2 == 0)) {
32              return NULL;
33          }
34  
35          for($mask = 0; $mask < 32; $mask++) {
36              if($netmask[$mask] == 1) {
37                  break;
38              }
39          }
40  
41          if(substr_count($netmask, "0") != $mask) {
42              return NULL;
43          }
44  
45          return "$ip_start/$mask";
46      }
47 
48 # Function(3) - Good Example (Bug Fixed) -
49 
50     function imask($this) {
51         // use base_convert not dechex because dechex is broken and returns 0x80000000 instead of 0xffffffff
52         return base_convert((pow(2, 32) - pow(2, (32 - $this))), 10, 16);
53     }
54 
55     function imaxblock($ibase, $tbit) {
56         while($tbit > 0) {
57             $im = hexdec(imask($tbit - 1));
58             $imand = $ibase & $im;
59             if ($imand != $ibase) {
60                 break;
61             }
62             $tbit--;
63         }
64         return $tbit;
65     }
66 
67     function range2cidrlist($istart, $iend) {
68         // this function returns an array of cidr lists that map the range given
69         $s = explode(".", $istart);
70         // PHP ip2long does not handle leading zeros on IP addresses! 172.016 comes back as 172.14, seems to be treated as octal!
71         $start = "";
72         $dot = "";
73         while(list($key, $val) = each($s)) {
74             $start = sprintf("%s%s%d", $start, $dot, $val);
75             $dot = ".";
76         }
77         $end = "";
78         $dot = "";
79         $e = explode(".", $iend);
80         while(list($key, $val) = each($e)) {
81             $end = sprintf("%s%s%d", $end, $dot, $val);
82             $dot = ".";
83         }
84         $start = ip2long($start);
85         $end = ip2long($end);
86         $result = array();
87         while($end >= $start) {
88             $maxsize = imaxblock($start, 32);
89             $x = log($end - $start + 1) / log(2);
90             $maxdiff = floor(32 - floor($x));
91             $ip = long2ip($start);
92             if($maxsize < $maxdiff) {
93                 $maxsize = $maxdiff;
94             }
95             array_push($result, "$ip/$maxsize");
96             $start += pow(2, (32 - $maxsize));
97         }
98         return $result;
99     }
100 ?>