Exemple #1
0
 /**
  * Determines the intersection between an IP (with optional prefix) and a
  * CIDR block.
  *
  * The IP will be checked against the CIDR block given and will either be
  * inside or outside the CIDR completely, or partially.
  *
  * NOTE: The caller should explicitly check against the INTERSECT_*
  * constants because this method will return a value > 1 even for partial
  * matches.
  *
  * @param mixed $ip The IP/cidr to match
  * @param mixed $cidr The CIDR block to match within
  * @return integer Returns an INTERSECT_* constant
  * @throws \InvalidArgumentException if either $ip or $cidr is invalid
  */
 public static function cidr_intersect($ip, $cidr)
 {
     // use fixed length HEX strings so we can easily do STRING comparisons
     // instead of using slower bccomp() math.
     list($lo, $hi) = array_map(function ($v) {
         return sprintf("%032s", IP::inet_ptoh($v));
     }, CIDR::cidr_to_range($ip));
     list($min, $max) = array_map(function ($v) {
         return sprintf("%032s", IP::inet_ptoh($v));
     }, CIDR::cidr_to_range($cidr));
     /** visualization of logic used below
            lo-hi   = $ip to check
            min-max = $cidr block being checked against
            --- --- --- lo  --- --- hi  --- --- --- --- --- IP/prefix to check
            --- min --- --- max --- --- --- --- --- --- --- Partial "LOW" match
            --- --- --- --- --- min --- --- max --- --- --- Partial "HIGH" match
            --- --- --- --- min max --- --- --- --- --- --- No match "NO"
            --- --- --- --- --- --- --- --- min --- max --- No match "NO"
            min --- max --- --- --- --- --- --- --- --- --- No match "NO"
            --- --- min --- --- --- --- max --- --- --- --- Full match "YES"
         */
     // IP is exact match or completely inside the CIDR block
     if ($lo >= $min and $hi <= $max) {
         return self::INTERSECT_YES;
     }
     // IP is completely outside the CIDR block
     if ($max < $lo or $min > $hi) {
         return self::INTERSECT_NO;
     }
     // @todo is it useful to return LOW/HIGH partial matches?
     // IP matches the lower end
     if ($max <= $hi and $min <= $lo) {
         return self::INTERSECT_LOW;
     }
     // IP matches the higher end
     if ($min >= $lo and $max >= $hi) {
         return self::INTERSECT_HIGH;
     }
     return self::INTERSECT_NO;
 }