示例#1
0
文件: CIDR.php 项目: 0151n/vichan
 /**
  * Return the maximum prefix length that would fit the IP address given.
  *
  * This is useful to determine how my bit would be needed to store the IP
  * address when you don't already have a prefix for the IP.
  *
  * @example 216.240.32.0 would return 27
  *
  * @param string $ip IP address without prefix
  * @param integer $bits Maximum bits to check; defaults to 32 for IPv4 and 128 for IPv6
  */
 public static function max_prefix($ip, $bits = null)
 {
     static $mask = array();
     $ver = false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? 6 : 4;
     $max = $ver == 6 ? 128 : 32;
     if ($bits === null) {
         $bits = $max;
     }
     $int = IP::inet_ptod($ip);
     while ($bits > 0) {
         // micro-optimization; calculate mask once ...
         if (!isset($mask[$ver][$bits - 1])) {
             // 2^$max - 2^($max - $bits);
             if ($ver == 4) {
                 $mask[$ver][$bits - 1] = pow(2, $max) - pow(2, $max - ($bits - 1));
             } else {
                 $mask[$ver][$bits - 1] = bcsub(bcpow(2, $max), bcpow(2, $max - ($bits - 1)));
             }
         }
         $m = $mask[$ver][$bits - 1];
         //printf("%s/%d: %s & %s == %s\n", $ip, $bits-1, BC::bcdecbin($m, 32), BC::bcdecbin($int, 32), BC::bcdecbin(BC::bcand($int, $m)));
         //echo "$ip/", $bits-1, ": ", IP::inet_dtop($m), " ($m) & $int == ", BC::bcand($int, $m), "\n";
         if (bccomp(BC::bcand($int, $m), $int) != 0) {
             return $bits;
         }
         $bits--;
     }
     return $bits;
 }