Validate
[ class tree: Validate ] [ index: Validate ] [ all elements ]

Source for file Validate.php

Documentation is available at Validate.php

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | Copyright (c) 1997-2005 Pierre-Alain Joye,Tomas V.V.Cox              |
  5. // +----------------------------------------------------------------------+
  6. // | This source file is subject to the New BSD license, That is bundled  |
  7. // | with this package in the file LICENSE, and is available through      |
  8. // | the world-wide-web at                                                |
  9. // | http://www.opensource.org/licenses/bsd-license.php                   |
  10. // | If you did not receive a copy of the new BSDlicense and are unable   |
  11. // | to obtain it through the world-wide-web, please send a note to       |
  12. // | pajoye@php.net so we can mail you a copy immediately.                |
  13. // +----------------------------------------------------------------------+
  14. // | Author: Tomas V.V.Cox  <cox@idecnet.com>                             |
  15. // |         Pierre-Alain Joye <pajoye@php.net>                           |
  16. // +----------------------------------------------------------------------+
  17. //
  18. /**
  19.  * Validation class
  20.  *
  21.  * Package to validate various datas. It includes :
  22.  *   - numbers (min/max, decimal or not)
  23.  *   - email (syntax, domain check)
  24.  *   - string (predifined type alpha upper and/or lowercase, numeric,...)
  25.  *   - date (min, max)
  26.  *   - uri (RFC2396)
  27.  *   - possibility valid multiple data with a single method call (::multiple)
  28.  *
  29.  * @category   Validate
  30.  * @package    Validate
  31.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  32.  * @author     Pierre-Alain Joye <pajoye@php.net>
  33.  * @copyright  1997-2005 Pierre-Alain Joye,Tomas V.V.Cox
  34.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  35.  * @version    CVS: $Id: Validate.php,v 1.99 2006/10/05 05:51:00 amir Exp $
  36.  * @link       http://pear.php.net/package/Validate
  37.  */
  38.  
  39. /**
  40.  * Methods for common data validations
  41.  */
  42. define('VALIDATE_NUM',          '0-9');
  43. define('VALIDATE_SPACE',        '\s');
  44. define('VALIDATE_ALPHA_LOWER',  'a-z');
  45. define('VALIDATE_ALPHA_UPPER',  'A-Z');
  46. define('VALIDATE_ALPHA',        VALIDATE_ALPHA_LOWER . VALIDATE_ALPHA_UPPER);
  47. define('VALIDATE_EALPHA_LOWER'VALIDATE_ALPHA_LOWER . 'áéíóúàèìòùäëïöüâêîôûñçþæðå');
  48. define('VALIDATE_EALPHA_UPPER'VALIDATE_ALPHA_UPPER . 'ÁÉÍÓÚÀÈÌÒÙÄËÏÖÜÂÊÎÔÛÑÇÞÆÐÅ');
  49. define('VALIDATE_EALPHA',       VALIDATE_EALPHA_LOWER . VALIDATE_EALPHA_UPPER);
  50. define('VALIDATE_PUNCTUATION',  VALIDATE_SPACE . '\.,;\:&"\'\?\!\(\)');
  51. define('VALIDATE_NAME',         VALIDATE_EALPHA . VALIDATE_SPACE . "'");
  52. define('VALIDATE_STREET',       VALIDATE_NAME . "/\\ºª\.");
  53.  
  54. /**
  55.  * Validation class
  56.  *
  57.  * Package to validate various datas. It includes :
  58.  *   - numbers (min/max, decimal or not)
  59.  *   - email (syntax, domain check)
  60.  *   - string (predifined type alpha upper and/or lowercase, numeric,...)
  61.  *   - date (min, max)
  62.  *   - uri (RFC2396)
  63.  *   - possibility valid multiple data with a single method call (::multiple)
  64.  *
  65.  * @category   Validate
  66.  * @package    Validate
  67.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  68.  * @author     Pierre-Alain Joye <pajoye@php.net>
  69.  * @copyright  1997-2005 Pierre-Alain Joye,Tomas V.V.Cox
  70.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  71.  * @version    Release: @package_version@
  72.  * @link       http://pear.php.net/package/Validate
  73.  */
  74. class Validate
  75. {
  76.     /**
  77.      * Validate a number
  78.      *
  79.      * @param string    $number     Number to validate
  80.      * @param array     $options    array where:
  81.      *                               'decimal'   is the decimal char or false when decimal not allowed
  82.      *                                           i.e. ',.' to allow both ',' and '.'
  83.      *                               'dec_prec'  Number of allowed decimals
  84.      *                               'min'       minimum value
  85.      *                               'max'       maximum value
  86.      *
  87.      * @return boolean true if valid number, false if not
  88.      *
  89.      * @access public
  90.      */
  91.     function number($number$options = array())
  92.     {
  93.         $decimal $dec_prec $min $max = null;
  94.         if (is_array($options)) {
  95.             extract($options);
  96.         }
  97.  
  98.         $dec_prec   $dec_prec ? "{1,$dec_prec}" : '+';
  99.         $dec_regex  $decimal  ? "[$decimal][0-9]$dec_prec" : '';
  100.  
  101.         if (!preg_match("|^[-+]?\s*[0-9]+($dec_regex)?\$|"$number)) {
  102.             return false;
  103.         }
  104.  
  105.         if ($decimal != '.'{
  106.             $number strtr($number$decimal'.');
  107.         }
  108.  
  109.         $number = (float)str_replace(' '''$number);
  110.         if ($min !== null && $min $number{
  111.             return false;
  112.         }
  113.  
  114.         if ($max !== null && $max $number{
  115.             return false;
  116.         }
  117.         return true;
  118.     }
  119.     
  120.     /**
  121.      * Converting a string to UTF-7 (RFC 2152)
  122.      *
  123.      * @param   $string     string to be converted
  124.      *
  125.      * @return  string  converted string
  126.      *
  127.      * @access  private
  128.      */
  129.     function __stringToUtf7($string{
  130.         $return '';
  131.         $utf7 = array(
  132.                         'A''B''C''D''E''F''G''H''I''J''K',
  133.                         'L''M''N''O''P''Q''R''S''T''U''V',
  134.                         'W''X''Y''Z''a''b''c''d''e''f''g',
  135.                         'h''i''j''k''l''m''n''o''p''q''r',
  136.                         's''t''u''v''w''x''y''z''0''1''2',
  137.                         '3''4''5''6''7''8''9''+'','
  138.                     );
  139.  
  140.         $state = 0;
  141.         if (!empty($string)) {
  142.             $i = 0;
  143.             while ($i <= strlen($string)) {
  144.                 $char substr($string$i1);
  145.                 if ($state == 0{
  146.                     if ((ord($char>= 0x7F|| (ord($char<= 0x1F)) {
  147.                         if ($char{
  148.                             $return .= '&';
  149.                         }
  150.                         $state = 1;
  151.                     elseif ($char == '&'{
  152.                         $return .= '&-';
  153.                     else {
  154.                         $return .= $char;
  155.                     }
  156.                 elseif (($i == strlen($string|| 
  157.                             !((ord($char>= 0x7F)) || (ord($char<= 0x1F))) {
  158.                     if ($state != 1{
  159.                         if (ord($char> 64{
  160.                             $return .= '';
  161.                         else {
  162.                             $return .= $utf7[ord($char)];
  163.                         }
  164.                     }
  165.                     $return .= '-';
  166.                     $state = 0;
  167.                 else {
  168.                     switch($state{
  169.                         case 1:
  170.                             $return .= $utf7[ord($char>> 2];
  171.                             $residue (ord($char0x03<< 4;
  172.                             $state = 2;
  173.                             break;
  174.                         case 2:
  175.                             $return .= $utf7[$residue (ord($char>> 4)];
  176.                             $residue (ord($char0x0F<< 2;
  177.                             $state = 3;
  178.                             break;
  179.                         case 3:
  180.                             $return .= $utf7[$residue (ord($char>> 6)];
  181.                             $return .= $utf7[ord($char0x3F];
  182.                             $state = 1;
  183.                             break;
  184.                     }
  185.                 }
  186.                 $i++;
  187.             }
  188.             return $return;
  189.         }
  190.         return '';
  191.     }
  192.  
  193.     /**
  194.      * Validate an email according to full RFC822 (inclusive human readable part)
  195.      *
  196.      * @param string $email email to validate,
  197.      *                       will return the address for optional dns validation
  198.      * @param array $options email() options
  199.      *
  200.      * @return boolean true if valid email, false if not
  201.      *
  202.      * @access private
  203.      */
  204.     function __emailRFC822(&$email&$options)
  205.     {
  206.         if (Validate::__stringToUtf7($email!= $email{
  207.             return false;
  208.         }
  209.         static $address = null;
  210.         static $uncomment = null;
  211.         if (!$address{
  212.             // atom        =  1*<any CHAR except specials, SPACE and CTLs>
  213.                         $atom '[^][()<>@,;:\\".\s\000-\037\177-\377]+\s*';
  214.             // qtext       =  <any CHAR excepting <">,     ; => may be folded
  215.             //         "\" & CR, and including linear-white-space>
  216.                         $qtext '[^"\\\\\r]';
  217.             // quoted-pair =  "\" CHAR                     ; may quote any char
  218.                         $quoted_pair '\\\\.';
  219.             // quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
  220.             //                                             ;   quoted chars.
  221.                         $quoted_string '"(?:' $qtext '|' $quoted_pair ')*"\s*';
  222.             // word        =  atom / quoted-string
  223.                         $word '(?:' $atom '|' $quoted_string ')';
  224.             // local-part  =  word *("." word)             ; uninterpreted
  225.             //                                             ; case-preserved
  226.                         $local_part $word '(?:\.\s*' $word ')*';
  227.             // dtext       =  <any CHAR excluding "[",     ; => may be folded
  228.             //         "]", "\" & CR, & including linear-white-space>
  229.                         $dtext '[^][\\\\\r]';
  230.             // domain-literal =  "[" *(dtext / quoted-pair) "]"
  231.                         $domain_literal '\[(?:' $dtext '|' $quoted_pair ')*\]\s*';
  232.             // sub-domain  =  domain-ref / domain-literal
  233.             // domain-ref  =  atom                         ; symbolic reference
  234.                         $sub_domain '(?:' $atom '|' $domain_literal ')';
  235.             // domain      =  sub-domain *("." sub-domain)
  236.                         $domain $sub_domain '(?:\.\s*' $sub_domain ')*';
  237.             // addr-spec   =  local-part "@" domain        ; global address
  238.                         $addr_spec $local_part '@\s*' $domain;
  239.             // route       =  1#("@" domain) ":"           ; path-relative
  240.                         $route '@' $domain '(?:,@\s*' $domain ')*:\s*';
  241.             // route-addr  =  "<" [route] addr-spec ">"
  242.                         $route_addr '<\s*(?:' $route ')?' $addr_spec '>\s*';
  243.             // phrase      =  1*word                       ; Sequence of words
  244.                         $phrase $word  '+';
  245.             // mailbox     =  addr-spec                    ; simple address
  246.             //             /  phrase route-addr            ; name & addr-spec
  247.                         $mailbox '(?:' $addr_spec '|' $phrase $route_addr ')';
  248.             // group       =  phrase ":" [#mailbox] ";"
  249.                         $group $phrase ':\s*(?:' $mailbox '(?:,\s*' $mailbox ')*)?;\s*';
  250.             //     address     =  mailbox                      ; one addressee
  251.             //                 /  group                        ; named list
  252.                         $address '/^\s*(?:' $mailbox '|' $group ')$/';
  253.             $uncomment =
  254.             '/((?:(?:\\\\"|[^("])*(?:' $quoted_string .
  255.                                              ')?)*)((?<!\\\\)\((?:(?2)|.)*?(?<!\\\\)\))/';
  256.         }
  257.         // strip comments
  258.                 $email = preg_replace($uncomment'$1 '$email);
  259.         return preg_match($address$email);
  260.     }
  261.  
  262.     /**
  263.      * Validate an email
  264.      *
  265.      * @param string $email email to validate
  266.      * @param mixed boolean (BC) $check_domain   Check or not if the domain exists
  267.      *               array $options associative array of options
  268.      *               'check_domain' boolean Check or not if the domain exists
  269.      *               'use_rfc822' boolean Apply the full RFC822 grammar
  270.      *
  271.      * @return boolean true if valid email, false if not
  272.      *
  273.      * @access public
  274.      */
  275.     function email($email$options = null)
  276.     {
  277.         $check_domain = false;
  278.         $use_rfc822 = false;
  279.         if (is_bool($options)) {
  280.             $check_domain $options;
  281.         elseif (is_array($options)) {
  282.             extract($options);
  283.         }
  284.  
  285.         // the base regexp for address
  286.         $regex '&^(?:                                               # recipient:
  287.          ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")|                          #1 quoted name
  288.          ([-\w!\#\$%\&\'*+~/^`|{}]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}]+)*)) #2 OR dot-atom
  289.          @(((\[)?                     #3 domain, 4 as IPv4, 5 optionally bracketed
  290.          (?:(?:(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:[0-1]?[0-9]?[0-9]))\.){3}
  291.                (?:(?:25[0-5])|(?:2[0-4][0-9])|(?:[0-1]?[0-9]?[0-9]))))(?(5)\])|
  292.          ((?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*[a-z0-9](?:[-a-z0-9]*[a-z0-9])?)  #6 domain as hostname
  293.          \.((?:([^- ])[-a-z]*[-a-z])?)) #7 TLD 
  294.          $&xi';
  295.  
  296.         if ($use_rfc822Validate::__emailRFC822($email$options:
  297.             preg_match($regex$email)) {
  298.             if ($check_domain && function_exists('checkdnsrr')) {
  299.                 list ($domain)  explode('@'$email);
  300.                 if (checkdnsrr($domain'MX'|| checkdnsrr($domain'A')) {
  301.                     return true;
  302.                 }
  303.                 return false;
  304.             }
  305.             return true;
  306.         }
  307.         return false;
  308.     }
  309.  
  310.     /**
  311.      * Validate a string using the given format 'format'
  312.      *
  313.      * @param string    $string     String to validate
  314.      * @param array     $options    Options array where:
  315.      *                               'format' is the format of the string
  316.      *                                   Ex: VALIDATE_NUM . VALIDATE_ALPHA (see constants)
  317.      *                               'min_length' minimum length
  318.      *                               'max_length' maximum length
  319.      *
  320.      * @return boolean true if valid string, false if not
  321.      *
  322.      * @access public
  323.      */
  324.     function string($string$options)
  325.     {
  326.         $format = null;
  327.         $min_length $max_length = 0;
  328.         if (is_array($options)) {
  329.             extract($options);
  330.         }
  331.         if ($format && !preg_match("|^[$format]*\$|s"$string)) {
  332.             return false;
  333.         }
  334.         if ($min_length && strlen($string$min_length{
  335.             return false;
  336.         }
  337.         if ($max_length && strlen($string$max_length{
  338.             return false;
  339.         }
  340.         return true;
  341.     }
  342.  
  343.     /**
  344.      * Validate an URI (RFC2396)
  345.      * This function will validate 'foobarstring' by default, to get it to validate
  346.      * only http, https, ftp and such you have to pass it in the allowed_schemes
  347.      * option, like this:
  348.      * <code>
  349.      * $options = array('allowed_schemes' => array('http', 'https', 'ftp'))
  350.      * var_dump(Validate::uri('http://www.example.org'), $options);
  351.      * </code>
  352.      *
  353.      * NOTE 1: The rfc2396 normally allows middle '-' in the top domain
  354.      *         e.g. http://example.co-m should be valid
  355.      *         However, as '-' is not used in any known TLD, it is invalid
  356.      * NOTE 2: As double shlashes // are allowed in the path part, only full URIs
  357.      *         including an authority can be valid, no relative URIs
  358.      *         the // are mandatory (optionally preceeded by the 'sheme:' )
  359.      * NOTE 3: the full complience to rfc2396 is not achieved by default
  360.      *         the characters ';/?:@$,' will not be accepted in the query part
  361.      *         if not urlencoded, refer to the option "strict'"
  362.      *
  363.      * @param string    $url        URI to validate
  364.      * @param array     $options    Options used by the validation method.
  365.      *                               key => type
  366.      *                               'domain_check' => boolean
  367.      *                                   Whether to check the DNS entry or not
  368.      *                               'allowed_schemes' => array, list of protocols
  369.      *                                   List of allowed schemes ('http',
  370.      *                                   'ssh+svn', 'mms')
  371.      *                               'strict' => string the refused chars
  372.      *                                    in query and fragment parts
  373.      *                                    default: ';/?:@$,'
  374.      *                                    empty: accept all rfc2396 foreseen chars
  375.      *
  376.      * @return boolean true if valid uri, false if not
  377.      *
  378.      * @access public
  379.      */
  380.     function uri($url$options = null)
  381.     {
  382.         $strict ';/?:@$,';
  383.         $domain_check = false;
  384.         $allowed_schemes = null;
  385.         if (is_array($options)) {
  386.             extract($options);
  387.         }
  388.         if (preg_match(
  389.              '&^(?:([a-z][-+.a-z0-9]*):)?                             # 1. scheme
  390.               (?://                                                   # authority start
  391.               (?:((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();:\&=+$,])*)@)?    # 2. authority-userinfo
  392.               (?:((?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*[a-z](?:[a-z0-9]+)?\.?)  # 3. authority-hostname OR
  393.               |([0-9]{1,3}(?:\.[0-9]{1,3}){3}))                       # 4. authority-ipv4
  394.               (?::([0-9]*))?)                                        # 5. authority-port
  395.               ((?:/(?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'():@\&=+$,;])*)*/?)? # 6. path
  396.               (?:\?([^#]*))?                                          # 7. query
  397.               (?:\#((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();/?:@\&=+$,])*))? # 8. fragment
  398.               $&xi'$url$matches)) {
  399.             $scheme = isset($matches[1]$matches[1'';
  400.             $authority = isset($matches[3]$matches[3'' ;
  401.             if (is_array($allowed_schemes&&
  402.                 !in_array($scheme,$allowed_schemes)
  403.             {
  404.                 return false;
  405.             }
  406.             if (!empty($matches[4])) {
  407.                 $parts explode('.'$matches[4]);
  408.                 foreach ($parts as $part{
  409.                     if ($part > 255{
  410.                         return false;
  411.                     }
  412.                 }
  413.             elseif ($domain_check && function_exists('checkdnsrr')) {
  414.                 if (!checkdnsrr($authority'A')) {
  415.                     return false;
  416.                 }
  417.             }
  418.             if ($strict{
  419.                 $strict '#[' preg_quote($strict'#'']#';
  420.                 if ((!empty($matches[7]&& preg_match($strict$matches[7]))
  421.                  || (!empty($matches[8]&& preg_match($strict$matches[8]))) {
  422.                     return false;
  423.                 }
  424.             }
  425.             return true;
  426.         }
  427.         return false;
  428.     }
  429.  
  430.     /**
  431.      * Validate date and times. Note that this method need the Date_Calc class
  432.      *
  433.      * @param string    $date   Date to validate
  434.      * @param array     $options array options where :
  435.      *                           'format' The format of the date (%d-%m-%Y)
  436.      *                           'min' The date has to be greater
  437.      *                                 than this array($day, $month, $year)
  438.      *                                 or PEAR::Date object
  439.      *                           'max' The date has to be smaller than
  440.      *                                 this array($day, $month, $year)
  441.      *                                 or PEAR::Date object
  442.      *
  443.      * @return boolean true if valid date/time, false if not
  444.      *
  445.      * @access public
  446.      */
  447.     function date($date$options)
  448.     {
  449.         $max $min = false;
  450.         $format '';
  451.         if (is_array($options)) {
  452.             extract($options);
  453.         }
  454.  
  455.         $date_len strlen($format);
  456.         for ($i = 0; $i $date_len$i++{
  457.             $c $format{$i};
  458.             if ($c == '%'{
  459.                 $next $format{$i + 1};
  460.                 switch ($next{
  461.                     case 'j':
  462.                     case 'd':
  463.                         if ($next == 'j'{
  464.                             $day = (int)Validate::_substr($date12);
  465.                         else {
  466.                             $day = (int)Validate::_substr($date2);
  467.                         }
  468.                         if ($day < 1 || $day > 31{
  469.                             return false;
  470.                         }
  471.                         break;
  472.                     case 'm':
  473.                     case 'n':
  474.                         if ($next == 'm'{
  475.                             $month = (int)Validate::_substr($date2);
  476.                         else {
  477.                             $month = (int)Validate::_substr($date12);
  478.                         }
  479.                         if ($month < 1 || $month > 12{
  480.                             return false;
  481.                         }
  482.                         break;
  483.                     case 'Y':
  484.                     case 'y':
  485.                         if ($next == 'Y'{
  486.                             $year Validate::_substr($date4);
  487.                             $year = (int)$year?$year:'';
  488.                         else {
  489.                             $year = (int)(substr(date('Y')02.
  490.                                           Validate::_substr($date2));
  491.                         }
  492.                         if (strlen($year!= 4 || $year < 0 || $year > 9999{
  493.                             return false;
  494.                         }
  495.                         break;
  496.                     case 'g':
  497.                     case 'h':
  498.                         if ($next == 'g'{
  499.                             $hour Validate::_substr($date12);
  500.                         else {
  501.                             $hour Validate::_substr($date2);
  502.                         }
  503.                         if (!preg_match('/^\d+$/'$hour|| $hour < 0 || $hour > 12{
  504.                             return false;
  505.                         }
  506.                         break;
  507.                     case 'G':
  508.                     case 'H':
  509.                         if ($next == 'G'{
  510.                             $hour Validate::_substr($date12);
  511.                         else {
  512.                             $hour Validate::_substr($date2);
  513.                         }
  514.                         if (!preg_match('/^\d+$/'$hour|| $hour < 0 || $hour > 24{
  515.                             return false;
  516.                         }
  517.                         break;
  518.                     case 's':
  519.                     case 'i':
  520.                         $t Validate::_substr($date2);
  521.                         if (!preg_match('/^\d+$/'$t|| $t < 0 || $t > 59{
  522.                             return false;
  523.                         }
  524.                         break;
  525.                     default:
  526.                         trigger_error("Not supported char `$next' after % in offset " . ($i+2)E_USER_WARNING);
  527.                 }
  528.                 $i++;
  529.             else {
  530.                 //literal
  531.                 if (Validate::_substr($date1!= $c{
  532.                     return false;
  533.                 }
  534.             }
  535.         }
  536.         // there is remaing data, we don't want it
  537.         if (strlen($date)) {
  538.             return false;
  539.         }
  540.  
  541.         if (isset($day&& isset($month&& isset($year)) {
  542.             if (!checkdate($month$day$year)) {
  543.                 return false;
  544.             }
  545.  
  546.             if ($min{
  547.                 include_once 'Date/Calc.php';
  548.                 if (is_a($min'Date'&&
  549.                     (Date_Calc::compareDates($day$month$year,
  550.                                              $min->getDay()$min->getMonth()$min->getYear()) < 0))
  551.                 {
  552.                     return false;
  553.                 elseif (is_array($min&&
  554.                         (Date_Calc::compareDates($day$month$year,
  555.                                              $min[0]$min[1]$min[2]< 0))
  556.                 {
  557.                     return false;
  558.                 }
  559.             }
  560.  
  561.             if ($max{
  562.                 include_once 'Date/Calc.php';
  563.                 if (is_a($max'Date'&&
  564.                     (Date_Calc::compareDates($day$month$year,
  565.                                              $max->getDay()$max->getMonth()$max->getYear()) > 0))
  566.                 {
  567.                     return false;
  568.                 elseif (is_array($max&&
  569.                         (Date_Calc::compareDates($day$month$year,
  570.                                                  $max[0]$max[1]$max[2]> 0))
  571.                 {
  572.                     return false;
  573.                 }
  574.             }
  575.         }
  576.  
  577.         return true;
  578.     }
  579.  
  580.     function _substr(&$date$num$opt = false)
  581.     {
  582.         if ($opt && strlen($date>= $opt && preg_match('/^[0-9]{'.$opt.'}/'$date$m)) {
  583.             $ret $m[0];
  584.         else {
  585.             $ret substr($date0$num);
  586.         }
  587.         $date substr($datestrlen($ret));
  588.         return $ret;
  589.     }
  590.  
  591.     function _modf($val$div{
  592.         if (function_exists('bcmod')) {
  593.             return bcmod($val$div);
  594.         elseif (function_exists('fmod')) {
  595.             return fmod($val$div);
  596.         }
  597.         $r $val $div;
  598.         $i intval($r);
  599.         return intval($val $i $div + .1);
  600.     }
  601.  
  602.     /**
  603.      * Calculates sum of product of number digits with weights
  604.      *
  605.      * @param string $number number string
  606.      * @param array $weights reference to array of weights
  607.      *
  608.      * @returns int returns product of number digits with weights
  609.      *
  610.      * @access protected
  611.      */
  612.     function _multWeights($number&$weights{
  613.         if (!is_array($weights)) {
  614.             return -1;
  615.         }
  616.         $sum = 0;
  617.  
  618.         $count min(count($weights)strlen($number));
  619.         if ($count == 0)  // empty string or weights array
  620.             return -1;
  621.         }
  622.         for ($i = 0; $i $count; ++$i{
  623.             $sum += intval(substr($number$i1)) $weights[$i];
  624.         }
  625.  
  626.         return $sum;
  627.     }
  628.  
  629.     /**
  630.      * Calculates control digit for a given number
  631.      *
  632.      * @param string $number number string
  633.      * @param array $weights reference to array of weights
  634.      * @param int $modulo (optionsl) number
  635.      * @param int $subtract (optional) number
  636.      * @param bool $allow_high (optional) true if function can return number higher than 10
  637.      *
  638.      * @returns int -1 calculated control number is returned
  639.      *
  640.      * @access protected
  641.      */
  642.     function _getControlNumber($number&$weights$modulo = 10$subtract = 0$allow_high = false{
  643.         // calc sum
  644.         $sum Validate::_multWeights($number$weights);
  645.         if ($sum == -1{
  646.             return -1;
  647.         }
  648.         $mod Validate::_modf($sum$modulo);  // calculate control digit
  649.  
  650.         if ($subtract $mod && $mod > 0{
  651.             $mod $subtract $mod;
  652.         }
  653.         if ($allow_high === false{
  654.             $mod %= 10;           // change 10 to zero
  655.         }
  656.         return $mod;
  657.     }
  658.  
  659.     /**
  660.      * Validates a number
  661.      *
  662.      * @param string $number number to validate
  663.      * @param array $weights reference to array of weights
  664.      * @param int $modulo (optionsl) number
  665.      * @param int $subtract (optional) numbier
  666.      *
  667.      * @returns bool true if valid, false if not
  668.      *
  669.      * @access protected
  670.      */
  671.     function _checkControlNumber($number&$weights$modulo = 10$subtract = 0{
  672.         if (strlen($numbercount($weights)) {
  673.             return false;
  674.         }
  675.         $target_digit  substr($numbercount($weights)1);
  676.         $control_digit Validate::_getControlNumber($number$weights$modulo$subtract$target_digit === 'X');
  677.  
  678.         if ($control_digit == -1{
  679.             return false;
  680.         }
  681.         if ($target_digit === 'X' && $control_digit == 10{
  682.             return true;
  683.         }
  684.         if ($control_digit != $target_digit{
  685.             return false;
  686.         }
  687.         return true;
  688.     }
  689.  
  690.     /**
  691.      * Bulk data validation for data introduced in the form of an
  692.      * assoc array in the form $var_name => $value.
  693.      * Can be used on any of Validate subpackages
  694.      *
  695.      * @param  array   $data     Ex: array('name' => 'toto', 'email' => 'toto@thing.info');
  696.      * @param  array   $val_type Contains the validation type and all parameters used in.
  697.      *                            'val_type' is not optional
  698.      *                            others validations properties must have the same name as the function
  699.      *                            parameters.
  700.      *                            Ex: array('toto'=>array('type'=>'string','format'='toto@thing.info','min_length'=>5));
  701.      * @param  boolean $remove if set, the elements not listed in data will be removed
  702.      *
  703.      * @return array   value name => true|false    the value name comes from the data key
  704.      *
  705.      * @access public
  706.      */
  707.     function multiple(&$data&$val_type$remove = false)
  708.     {
  709.         $keys array_keys($data);
  710.         $valid = array();
  711.         foreach ($keys as $var_name{
  712.             if (!isset($val_type[$var_name])) {
  713.                 if ($remove{
  714.                     unset($data[$var_name]);
  715.                 }
  716.                 continue;
  717.             }
  718.             $opt $val_type[$var_name];
  719.             $methods get_class_methods('Validate');
  720.             $val2check $data[$var_name];
  721.             // core validation method
  722.             if (in_array(strtolower($opt['type'])$methods)) {
  723.                 //$opt[$opt['type']] = $data[$var_name];
  724.                 $method $opt['type'];
  725.                 unset($opt['type']);
  726.  
  727.                 if (sizeof($opt== 1{
  728.                     $opt array_pop($opt);
  729.                 }
  730.                 $valid[$var_namecall_user_func(array('Validate'$method)$val2check$opt);
  731.  
  732.             /**
  733.              * external validation method in the form:
  734.              * "<class name><underscore><method name>"
  735.              * Ex: us_ssn will include class Validate/US.php and call method ssn()
  736.              */
  737.             elseif (strpos($opt['type']'_'!== false{
  738.                 $validateType explode('_'$opt['type']);
  739.                 $method       array_pop($validateType);
  740.                 $class        implode('_'$validateType);
  741.                 $classPath    str_replace('_'DIRECTORY_SEPARATOR$class);
  742.                 $class        'Validate_' $class;
  743.                 if (!@include_once "Validate/$classPath.php"{
  744.                     trigger_error("$class isn't installed or you may have some permissoin issues"E_USER_ERROR);
  745.                 }
  746.  
  747.                 $ce substr(phpversion()01> 4 ? class_exists($classfalseclass_exists($class);
  748.                 if (!$ce ||
  749.                     !in_array($methodget_class_methods($class)))
  750.                 {
  751.                     trigger_error("Invalid validation type $class::$method"E_USER_WARNING);
  752.                     continue;
  753.                 }
  754.                 unset($opt['type']);
  755.                 if (sizeof($opt== 1{
  756.                     $opt array_pop($opt);
  757.                 }
  758.                 $valid[$var_namecall_user_func(array($class$method)$data[$var_name]$opt);
  759.             else {
  760.                 trigger_error("Invalid validation type {$opt['type']}"E_USER_WARNING);
  761.             }
  762.         }
  763.         return $valid;
  764.     }
  765. }
  766.  
  767. ?>

Documentation generated on Sat, 14 Oct 2006 08:32:10 -0400 by phpDocumentor 1.3.0. PEAR Logo Copyright © PHP Group 2004.