includes/functions.php
changeset 766 d6690840e331
parent 756 e8cf18383425
child 770 62fed244fa1c
equal deleted inserted replaced
765:51f64b1c9413 766:d6690840e331
  3440  * @return string
  3440  * @return string
  3441  */
  3441  */
  3442 
  3442 
  3443 function parse_ip_range_regex($range)
  3443 function parse_ip_range_regex($range)
  3444 {
  3444 {
       
  3445   if ( strstr($range, ':') )
       
  3446   {
       
  3447     return parse_ipv6_range_regex($range);
       
  3448   }
       
  3449   else
       
  3450   {
       
  3451     return parse_ipv4_range_regex($range);
       
  3452   }
       
  3453 }
       
  3454 
       
  3455 /**
       
  3456  * Parses a valid IPv4 address range into a regular expression.
       
  3457  * @param string IP range string
       
  3458  * @return string
       
  3459  */
       
  3460 
       
  3461 function parse_ipv4_range_regex($range)
       
  3462 {
  3445   // Regular expression to test the range string for validity
  3463   // Regular expression to test the range string for validity
  3446   $regex = '/^(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.'
  3464   $regex = '/^(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.'
  3447            . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.'
  3465            . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.'
  3448            . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.'
  3466            . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)\.'
  3449            . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)$/';
  3467            . '(([0-9]+(-[0-9]+)?)(\|([0-9]+(-[0-9]+)?))*)$/';
  3496     $return .= $alts . '\.';
  3514     $return .= $alts . '\.';
  3497   }
  3515   }
  3498   $return = substr($return, 0, -2);
  3516   $return = substr($return, 0, -2);
  3499   $return .= '$';
  3517   $return .= '$';
  3500   return $return;
  3518   return $return;
       
  3519 }
       
  3520 
       
  3521 /**
       
  3522  * Parses a valid IPv6 address range into a regular expression.
       
  3523  * @param string IP range string
       
  3524  * @return string
       
  3525  */
       
  3526 
       
  3527 function parse_ipv6_range_regex($range)
       
  3528 {
       
  3529   $range = strtolower(trim($range));
       
  3530   $valid = '/^';
       
  3531   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}):';
       
  3532   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}):';
       
  3533   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?';
       
  3534   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?';
       
  3535   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?';
       
  3536   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?';
       
  3537   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4}:|:)?';
       
  3538   $valid .= '(?:[0-9a-f]{0,4}|[0-9a-f]{1,4}-[0-9a-f]{1,4})$/';
       
  3539   if ( !preg_match($valid, $range) )
       
  3540     return false;
       
  3541   
       
  3542   // expand address range.
       
  3543   // this takes short ranges like:
       
  3544   //   2001:470-471:054-b02b::5-bb
       
  3545   // up to:
       
  3546   //   2001:0470-0471:0054-b02b:0000:0000:0000:0005-00bb
       
  3547   $range = explode(':', $range);
       
  3548   $expanded = '';
       
  3549   $size = count($range);
       
  3550   foreach ( $range as $byteset )
       
  3551   {
       
  3552     if ( empty($byteset) )
       
  3553     {
       
  3554       // ::
       
  3555       while ( $size < 9 )
       
  3556       {
       
  3557         $expanded .= '0000:';
       
  3558         $size++;
       
  3559       }
       
  3560     }
       
  3561     else
       
  3562     {
       
  3563       if ( strstr($byteset, '-') ) 
       
  3564       {
       
  3565         // this is a range
       
  3566         $sides = explode('-', $byteset);
       
  3567         foreach ( $sides as &$bytepair )
       
  3568         {
       
  3569           while ( strlen($bytepair) < 4 )
       
  3570           {
       
  3571             $bytepair = "0$bytepair";
       
  3572           }
       
  3573         }
       
  3574         $byteset = implode('-', $sides);
       
  3575       }
       
  3576       else
       
  3577       {
       
  3578         while ( strlen($byteset) < 4 )
       
  3579         {
       
  3580           $byteset = "0$byteset";
       
  3581         }
       
  3582       }
       
  3583       $expanded .= "$byteset:";
       
  3584     }
       
  3585   }
       
  3586   $expanded = explode(':', rtrim($expanded, ':'));
       
  3587   
       
  3588   // ready to dive in and start generating range regexes.
       
  3589   // this has to be pretty optimized... we want to end up with regexes like:
       
  3590   // range: 54-b12b
       
  3591   /*
       
  3592   /005[4-9a-f]|
       
  3593   00[6-9a-f][0-9a-f]|
       
  3594   0[1-9a-f][0-9a-f][0-9a-f]|
       
  3595   [1-9a][0-9a-f][0-9a-f][0-9a-f]|
       
  3596   b[0-0][0-1][0-9a-f]|
       
  3597   b0[0-1][0-9a-f]|
       
  3598   b02[0-9a-b]/x
       
  3599   */
       
  3600   foreach ( $expanded as &$word )
       
  3601   {
       
  3602     if ( strstr($word, '-') )
       
  3603     {
       
  3604       // oh... damn.
       
  3605       $word = '(?:' . generate_hex_numeral_range($word) . ')';
       
  3606     }
       
  3607   }
       
  3608 
       
  3609   // return print_r($expanded, true);  
       
  3610   return '^' . implode(':', $expanded) . '$';
       
  3611 }
       
  3612 
       
  3613 /**
       
  3614  * Take a hex numeral range and parse it in to a PCRE.
       
  3615  * @param string
       
  3616  * @return string
       
  3617  * @access private
       
  3618  */
       
  3619 
       
  3620 function generate_hex_numeral_range($word)
       
  3621 {
       
  3622   list($low, $high) = explode('-', $word);
       
  3623   
       
  3624   if ( hexdec($low) > hexdec($high) )
       
  3625   {
       
  3626     $_ = $low;
       
  3627     $low = $high;
       
  3628     $high = $_;
       
  3629     unset($_);
       
  3630   }
       
  3631   
       
  3632   while ( strlen($low) < strlen($high) )
       
  3633   {
       
  3634     $low = "0$low";
       
  3635   }
       
  3636   
       
  3637   // trim off everything that's the same
       
  3638   $trimmed = '';
       
  3639   $len = strlen($low);
       
  3640   for ( $i = 0; $i < $len; $i++ )
       
  3641   {
       
  3642     if ( $low{0} === $high{0} )
       
  3643     {
       
  3644       $trimmed .= $low{0};
       
  3645       $low = substr($low, 1);
       
  3646       $high = substr($high, 1);
       
  3647     }
       
  3648     else
       
  3649     {
       
  3650       break;
       
  3651     }
       
  3652   }
       
  3653   
       
  3654   $len = strlen($high);
       
  3655   if ( $len == 1 )
       
  3656   {
       
  3657     // this does happen sometimes, so we can save a bit of CPU power here.
       
  3658     return $trimmed . __hexdigitrange($low, $high);
       
  3659   }
       
  3660     
       
  3661   $return = '';
       
  3662   // lower half
       
  3663   for ( $i = $len - 1; $i > 0; $i-- )
       
  3664   {
       
  3665     if ( $low{$i} == 'f' )
       
  3666       continue;
       
  3667     $return .= $trimmed;
       
  3668     for ( $j = 0; $j < $len; $j++ )
       
  3669     {
       
  3670       if ( $j < $i )
       
  3671       {
       
  3672         $return .= $low{$j};
       
  3673       }
       
  3674       else if ( $j == $i && ( $i == $len - 1 || $low{$j} == 'f' ) )
       
  3675       {
       
  3676         $return .= __hexdigitrange($low{$j}, 'f');
       
  3677       }
       
  3678       else if ( $j == $i && $i != $len - 1 )
       
  3679       {
       
  3680         $return .= __hexdigitrange(dechex(hexdec($low{$j}) + 1), 'f');
       
  3681       }
       
  3682       else
       
  3683       {
       
  3684         $return .= __hexdigitrange('0', 'f');
       
  3685       }
       
  3686     }
       
  3687     $return .= '|';
       
  3688   }
       
  3689   // middle block
       
  3690   if ( hexdec($low{0}) + 1 < hexdec($high{0}) )
       
  3691   {
       
  3692     if ( hexdec($low{0}) + 1 < hexdec($high{0}) - 1 )
       
  3693       $return .= $trimmed . __hexdigitrange(dechex(hexdec($low{0}) + 1), dechex(hexdec($high{0}) - 1));
       
  3694     else
       
  3695       $return .= $trimmed . __hexdigitrange($low{0}, $high{0});
       
  3696     if ( $len - 1 > 0 )
       
  3697       $return .= '[0-9a-f]{' . ( $len - 1 ) . '}|';
       
  3698   }
       
  3699   // higher half
       
  3700   for ( $i = 1; $i < $len; $i++ )
       
  3701   {
       
  3702     if ( $high{$i} == '0' )
       
  3703       continue;
       
  3704     $return .= $trimmed;
       
  3705     for ( $j = 0; $j < $len; $j++ )
       
  3706     {
       
  3707       if ( $j < $i )
       
  3708       {
       
  3709         $return .= $high{$j};
       
  3710       }
       
  3711       else if ( $j == $i && ( $i == $len - 1 || $high{$j} == '0' ) )
       
  3712       {
       
  3713         $return .= __hexdigitrange('0', $high{$j});
       
  3714       }
       
  3715       else if ( $j == $i && $i != $len - 1 )
       
  3716       {
       
  3717         $return .= __hexdigitrange('0', dechex(hexdec($high{$j}) - 1));
       
  3718       }
       
  3719       else if ( $j > $i )
       
  3720       {
       
  3721         $return .= __hexdigitrange('0', 'f');
       
  3722       }
       
  3723       else
       
  3724       {
       
  3725         die("I don't know what to do! i $i j $j");
       
  3726       }
       
  3727     }
       
  3728     $return .= '|';
       
  3729   }
       
  3730   
       
  3731   return rtrim($return, '|');
       
  3732 }
       
  3733 
       
  3734 function __hexdigitrange($low, $high)
       
  3735 {
       
  3736   if ( $low == $high )
       
  3737     return $low;
       
  3738   if ( empty($low) )
       
  3739     $low = '0';
       
  3740   
       
  3741   $low_type = ( preg_match('/[0-9]/', $low) ) ? 'num' : 'alph';
       
  3742   $high_type = ( preg_match('/[0-9]/', $high) ) ? 'num' : 'alph';
       
  3743   if ( ( $low_type == 'num' && $high_type == 'num') || ( $low_type == 'alph' && $high_type == 'alph' ) )
       
  3744   {
       
  3745     return "[$low-$high]";
       
  3746   }
       
  3747   else if ( $low_type == 'num' && $high_type == 'alph' )
       
  3748   {
       
  3749     $ret = '[';
       
  3750     
       
  3751     if ( $low == '9' )
       
  3752       $ret .= '9';
       
  3753     else
       
  3754       $ret .= "$low-9";
       
  3755     if ( $high == 'a' )
       
  3756       $ret .= 'a';
       
  3757     else
       
  3758       $ret .= "a-$high";
       
  3759       
       
  3760     $ret .= "]";
       
  3761     return $ret;
       
  3762   }
       
  3763   else if ( $low_type == 'alph' && $high_type == 'num' )
       
  3764   {
       
  3765     // ???? this should never happen
       
  3766     return __hexdigitrange($high, $low); 
       
  3767   }
  3501 }
  3768 }
  3502 
  3769 
  3503 /**
  3770 /**
  3504  * Validates an e-mail address. Uses a compacted version of the regular expression generated by the scripts at <http://examples.oreilly.com/regex/>.
  3771  * Validates an e-mail address. Uses a compacted version of the regular expression generated by the scripts at <http://examples.oreilly.com/regex/>.
  3505  * @param string E-mail address
  3772  * @param string E-mail address