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

Source for file Validate.php

Documentation is available at Validate.php

  1. <?php
  2. /**
  3.  * Validation class
  4.  *
  5.  * Copyright (c) 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox, Amir Saied
  6.  *
  7.  * This source file is subject to the New BSD license, That is bundled
  8.  * with this package in the file LICENSE, and is available through
  9.  * the world-wide-web at
  10.  * http://www.opensource.org/licenses/bsd-license.php
  11.  * If you did not receive a copy of the new BSDlicense and are unable
  12.  * to obtain it through the world-wide-web, please send a note to
  13.  * pajoye@php.net so we can mail you a copy immediately.
  14.  *
  15.  * Author: Tomas V.V.Cox  <cox@idecnet.com>
  16.  *         Pierre-Alain Joye <pajoye@php.net>
  17.  *         Amir Mohammad Saied <amir@php.net>
  18.  *
  19.  *
  20.  * Package to validate various datas. It includes :
  21.  *   - numbers (min/max, decimal or not)
  22.  *   - email (syntax, domain check)
  23.  *   - string (predifined type alpha upper and/or lowercase, numeric,...)
  24.  *   - date (min, max, rfc822 compliant)
  25.  *   - uri (RFC2396)
  26.  *   - possibility valid multiple data with a single method call (::multiple)
  27.  *
  28.  * @category   Validate
  29.  * @package    Validate
  30.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  31.  * @author     Pierre-Alain Joye <pajoye@php.net>
  32.  * @author     Amir Mohammad Saied <amir@php.net>
  33.  * @copyright  1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied
  34.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  35.  * @version    CVS: $Id: Validate.php,v 1.134 2009/01/28 12:27:33 davidc 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_NUM . VALIDATE_NAME . "/\\ºª\.");
  53.  
  54. define('VALIDATE_ITLD_EMAILS',  1);
  55. define('VALIDATE_GTLD_EMAILS',  2);
  56. define('VALIDATE_CCTLD_EMAILS'4);
  57. define('VALIDATE_ALL_EMAILS',   8);
  58.  
  59. /**
  60.  * Validation class
  61.  *
  62.  * Package to validate various datas. It includes :
  63.  *   - numbers (min/max, decimal or not)
  64.  *   - email (syntax, domain check)
  65.  *   - string (predifined type alpha upper and/or lowercase, numeric,...)
  66.  *   - date (min, max)
  67.  *   - uri (RFC2396)
  68.  *   - possibility valid multiple data with a single method call (::multiple)
  69.  *
  70.  * @category  Validate
  71.  * @package   Validate
  72.  * @author    Tomas V.V.Cox <cox@idecnet.com>
  73.  * @author    Pierre-Alain Joye <pajoye@php.net>
  74.  * @author    Amir Mohammad Saied <amir@php.net>
  75.  * @copyright 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied
  76.  * @license   http://www.opensource.org/licenses/bsd-license.php  New BSD License
  77.  * @version   Release: @package_version@
  78.  * @link      http://pear.php.net/package/Validate
  79.  */
  80. class Validate
  81. {
  82.     /**
  83.      * International Top-Level Domain
  84.      *
  85.      * This is an array of the known international
  86.      * top-level domain names.
  87.      *
  88.      * @access protected
  89.      * @var    array     $_iTld (International top-level domains)
  90.      */
  91.     var $_itld = array(
  92.         'arpa',
  93.         'root',
  94.     );
  95.  
  96.     /**
  97.      * Generic top-level domain
  98.      *
  99.      * This is an array of the official
  100.      * generic top-level domains.
  101.      *
  102.      * @access protected
  103.      * @var    array     $_gTld (Generic top-level domains)
  104.      */
  105.     var $_gtld = array(
  106.         'aero',
  107.         'biz',
  108.         'cat',
  109.         'com',
  110.         'coop',
  111.         'edu',
  112.         'gov',
  113.         'info',
  114.         'int',
  115.         'jobs',
  116.         'mil',
  117.         'mobi',
  118.         'museum',
  119.         'name',
  120.         'net',
  121.         'org',
  122.         'pro',
  123.         'travel',
  124.         'asia',
  125.         'post',
  126.         'tel',
  127.         'geo',
  128.     );
  129.  
  130.     /**
  131.      * Country code top-level domains
  132.      *
  133.      * This is an array of the official country
  134.      * codes top-level domains
  135.      *
  136.      * @access protected
  137.      * @var    array     $_ccTld (Country Code Top-Level Domain)
  138.      */
  139.     var $_cctld = array(
  140.         'ac',
  141.         'ad','ae','af','ag',
  142.         'ai','al','am','an',
  143.         'ao','aq','ar','as',
  144.         'at','au','aw','ax',
  145.         'az','ba','bb','bd',
  146.         'be','bf','bg','bh',
  147.         'bi','bj','bm','bn',
  148.         'bo','br','bs','bt',
  149.         'bu','bv','bw','by',
  150.         'bz','ca','cc','cd',
  151.         'cf','cg','ch','ci',
  152.         'ck','cl','cm','cn',
  153.         'co','cr','cs','cu',
  154.         'cv','cx','cy','cz',
  155.         'de','dj','dk','dm',
  156.         'do','dz','ec','ee',
  157.         'eg','eh','er','es',
  158.         'et','eu','fi','fj',
  159.         'fk','fm','fo','fr',
  160.         'ga','gb','gd','ge',
  161.         'gf','gg','gh','gi',
  162.         'gl','gm','gn','gp',
  163.         'gq','gr','gs','gt',
  164.         'gu','gw','gy','hk',
  165.         'hm','hn','hr','ht',
  166.         'hu','id','ie','il',
  167.         'im','in','io','iq',
  168.         'ir','is','it','je',
  169.         'jm','jo','jp','ke',
  170.         'kg','kh','ki','km',
  171.         'kn','kp','kr','kw',
  172.         'ky','kz','la','lb',
  173.         'lc','li','lk','lr',
  174.         'ls','lt','lu','lv',
  175.         'ly','ma','mc','md',
  176.         'me','mg','mh','mk',
  177.         'ml','mm','mn','mo',
  178.         'mp','mq','mr','ms',
  179.         'mt','mu','mv','mw',
  180.         'mx','my','mz','na',
  181.         'nc','ne','nf','ng',
  182.         'ni','nl','no','np',
  183.         'nr','nu','nz','om',
  184.         'pa','pe','pf','pg',
  185.         'ph','pk','pl','pm',
  186.         'pn','pr','ps','pt',
  187.         'pw','py','qa','re',
  188.         'ro','rs','ru','rw',
  189.         'sa','sb','sc','sd',
  190.         'se','sg','sh','si',
  191.         'sj','sk','sl','sm',
  192.         'sn','so','sr','st',
  193.         'su','sv','sy','sz',
  194.         'tc','td','tf','tg',
  195.         'th','tj','tk','tl',
  196.         'tm','tn','to','tp',
  197.         'tr','tt','tv','tw',
  198.         'tz','ua','ug','uk',
  199.         'us','uy','uz','va',
  200.         'vc','ve','vg','vi',
  201.         'vn','vu','wf','ws',
  202.         'ye','yt','yu','za',
  203.         'zm','zw',
  204.     );
  205.  
  206.     /**
  207.      * Validate a tag URI (RFC4151)
  208.      *
  209.      * @param string $uri tag URI to validate
  210.      *
  211.      * @return boolean true if valid tag URI, false if not
  212.      *
  213.      * @access private
  214.      */
  215.     function __uriRFC4151($uri)
  216.     {
  217.         $datevalid = false;
  218.         if (preg_match(
  219.             '/^tag:(?<name>.*),(?<date>\d{4}-?\d{0,2}-?\d{0,2}):(?<specific>.*)(.*:)*$/'$uri$matches)) {
  220.             $date  $matches['date'];
  221.             $date6 strtotime($date);
  222.             if ((strlen($date== 4&& $date <= date('Y')) {
  223.                 $datevalid = true;
  224.             elseif ((strlen($date== 7&& ($date6 strtotime("now"))) {
  225.                 $datevalid = true;
  226.             elseif ((strlen($date== 10&& ($date6 strtotime("now"))) {
  227.                 $datevalid = true;
  228.             }
  229.             if (self::email($matches['name'])) {
  230.                 $namevalid = true;
  231.             else {
  232.                 $namevalid = self::email('info@' $matches['name']);
  233.             }
  234.             return $datevalid && $namevalid;
  235.         else {
  236.             return false;
  237.         }
  238.     }
  239.  
  240.     /**
  241.      * Validate a number
  242.      *
  243.      * @param string $number  Number to validate
  244.      * @param array  $options array where:
  245.      *                           'decimal'  is the decimal char or false when decimal
  246.      *                                      not allowed.
  247.      *                                      i.e. ',.' to allow both ',' and '.'
  248.      *                           'dec_prec' Number of allowed decimals
  249.      *                           'min'      minimum value
  250.      *                           'max'      maximum value
  251.      *
  252.      * @return boolean true if valid number, false if not
  253.      *
  254.      * @access public
  255.      */
  256.     function number($number$options = array())
  257.     {
  258.         $decimal $dec_prec $min $max = null;
  259.         if (is_array($options)) {
  260.             extract($options);
  261.         }
  262.  
  263.         $dec_prec  $dec_prec ? "{1,$dec_prec}" : '+';
  264.         $dec_regex $decimal  ? "[$decimal][0-9]$dec_prec" : '';
  265.  
  266.         if (!preg_match("|^[-+]?\s*[0-9]+($dec_regex)?\$|"$number)) {
  267.             return false;
  268.         }
  269.  
  270.         if ($decimal != '.'{
  271.             $number strtr($number$decimal'.');
  272.         }
  273.  
  274.         $number = (float)str_replace(' '''$number);
  275.         if ($min !== null && $min $number{
  276.             return false;
  277.         }
  278.  
  279.         if ($max !== null && $max $number{
  280.             return false;
  281.         }
  282.         return true;
  283.     }
  284.  
  285.     /**
  286.      * Converting a string to UTF-7 (RFC 2152)
  287.      *
  288.      * @param string $string string to be converted
  289.      *
  290.      * @return  string  converted string
  291.      *
  292.      * @access  private
  293.      */
  294.     function __stringToUtf7($string)
  295.     {
  296.         $return '';
  297.         $utf7   = array(
  298.                         'A''B''C''D''E''F''G''H''I''J''K',
  299.                         'L''M''N''O''P''Q''R''S''T''U''V',
  300.                         'W''X''Y''Z''a''b''c''d''e''f''g',
  301.                         'h''i''j''k''l''m''n''o''p''q''r',
  302.                         's''t''u''v''w''x''y''z''0''1''2',
  303.                         '3''4''5''6''7''8''9''+'','
  304.                     );
  305.  
  306.  
  307.         $state = 0;
  308.  
  309.         if (!empty($string)) {
  310.             $i = 0;
  311.             while ($i <= strlen($string)) {
  312.                 $char substr($string$i1);
  313.                 if ($state == 0{
  314.                     if ((ord($char>= 0x7F|| (ord($char<= 0x1F)) {
  315.                         if ($char{
  316.                             $return .= '&';
  317.                         }
  318.                         $state = 1;
  319.                     elseif ($char == '&'{
  320.                         $return .= '&-';
  321.                     else {
  322.                         $return .= $char;
  323.                     }
  324.                 elseif (($i == strlen($string||
  325.                             !((ord($char>= 0x7F)) || (ord($char<= 0x1F))) {
  326.                     if ($state != 1{
  327.                         if (ord($char> 64{
  328.                             $return .= '';
  329.                         else {
  330.                             $return .= $utf7[ord($char)];
  331.                         }
  332.                     }
  333.                     $return .= '-';
  334.                     $state   = 0;
  335.                 else {
  336.                     switch($state{
  337.                     case 1:
  338.                         $return .= $utf7[ord($char>> 2];
  339.                         $residue (ord($char0x03<< 4;
  340.                         $state   = 2;
  341.                         break;
  342.                     case 2:
  343.                         $return .= $utf7[$residue (ord($char>> 4)];
  344.                         $residue (ord($char0x0F<< 2;
  345.                         $state   = 3;
  346.                         break;
  347.                     case 3:
  348.                         $return .= $utf7[$residue (ord($char>> 6)];
  349.                         $return .= $utf7[ord($char0x3F];
  350.                         $state   = 1;
  351.                         break;
  352.                     }
  353.                 }
  354.                 $i++;
  355.             }
  356.             return $return;
  357.         }
  358.         return '';
  359.     }
  360.  
  361.     /**
  362.      * Validate an email according to full RFC822 (inclusive human readable part)
  363.      *
  364.      * @param string $email   email to validate,
  365.      *                         will return the address for optional dns validation
  366.      * @param array  $options email() options
  367.      *
  368.      * @return boolean true if valid email, false if not
  369.      *
  370.      * @access private
  371.      */
  372.     function __emailRFC822(&$email&$options)
  373.     {
  374.         static $address   = null;
  375.         static $uncomment = null;
  376.         if (!$address{
  377.             // atom        =  1*<any CHAR except specials, SPACE and CTLs>
  378.             $atom '[^][()<>@,;:\\".\s\000-\037\177-\377]+\s*';
  379.             // qtext       =  <any CHAR excepting <">,     ; => may be folded
  380.             //         "\" & CR, and including linear-white-space>
  381.             $qtext '[^"\\\\\r]';
  382.             // quoted-pair =  "\" CHAR                     ; may quote any char
  383.             $quoted_pair '\\\\.';
  384.             // quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
  385.             //                                             ;   quoted chars.
  386.             $quoted_string '"(?:' $qtext '|' $quoted_pair ')*"\s*';
  387.             // word        =  atom / quoted-string
  388.             $word '(?:' $atom '|' $quoted_string ')';
  389.             // local-part  =  word *("." word)             ; uninterpreted
  390.             //                                             ; case-preserved
  391.             $local_part $word '(?:\.\s*' $word ')*';
  392.             // dtext       =  <any CHAR excluding "[",     ; => may be folded
  393.             //         "]", "\" & CR, & including linear-white-space>
  394.             $dtext '[^][\\\\\r]';
  395.             // domain-literal =  "[" *(dtext / quoted-pair) "]"
  396.             $domain_literal '\[(?:' $dtext '|' $quoted_pair ')*\]\s*';
  397.             // sub-domain  =  domain-ref / domain-literal
  398.             // domain-ref  =  atom                         ; symbolic reference
  399.             $sub_domain '(?:' $atom '|' $domain_literal ')';
  400.             // domain      =  sub-domain *("." sub-domain)
  401.             $domain $sub_domain '(?:\.\s*' $sub_domain ')*';
  402.             // addr-spec   =  local-part "@" domain        ; global address
  403.             $addr_spec $local_part '@\s*' $domain;
  404.             // route       =  1#("@" domain) ":"           ; path-relative
  405.             $route '@' $domain '(?:,@\s*' $domain ')*:\s*';
  406.             // route-addr  =  "<" [route] addr-spec ">"
  407.             $route_addr '<\s*(?:' $route ')?' $addr_spec '>\s*';
  408.             // phrase      =  1*word                       ; Sequence of words
  409.             $phrase $word  '+';
  410.             // mailbox     =  addr-spec                    ; simple address
  411.             //             /  phrase route-addr            ; name & addr-spec
  412.             $mailbox '(?:' $addr_spec '|' $phrase $route_addr ')';
  413.             // group       =  phrase ":" [#mailbox] ";"
  414.             $group $phrase ':\s*(?:' $mailbox '(?:,\s*' $mailbox ')*)?;\s*';
  415.             //     address     =  mailbox                      ; one addressee
  416.             //                 /  group                        ; named list
  417.             $address '/^\s*(?:' $mailbox '|' $group ')$/';
  418.  
  419.             $uncomment =
  420.             '/((?:(?:\\\\"|[^("])*(?:' $quoted_string .
  421.                                              ')?)*)((?<!\\\\)\((?:(?2)|.)*?(?<!\\\\)\))/';
  422.         }
  423.         // strip comments
  424.         $email = preg_replace($uncomment'$1 '$email);
  425.         return preg_match($address$email);
  426.     }
  427.  
  428.     /**
  429.      * Full TLD Validation function
  430.      *
  431.      * This function is used to make a much more proficient validation
  432.      * against all types of official domain names.
  433.      *
  434.      * @param string $email   The email address to check.
  435.      * @param array  $options The options for validation
  436.      *
  437.      * @access protected
  438.      *
  439.      * @return bool True if validating succeeds
  440.      */
  441.     function _fullTLDValidation($email$options)
  442.     {
  443.         $validate = array();
  444.         if(!empty($options["VALIDATE_ITLD_EMAILS"])) array_push($validate'itld');
  445.         if(!empty($options["VALIDATE_GTLD_EMAILS"])) array_push($validate'gtld');
  446.         if(!empty($options["VALIDATE_CCTLD_EMAILS"])) array_push($validate'cctld');
  447.  
  448.         $self = new Validate;
  449.  
  450.         $toValidate = array();
  451.  
  452.         foreach ($validate as $valid{
  453.             $tmpVar '_' . (string)$valid;
  454.  
  455.             $toValidate[$valid$self->{$tmpVar};
  456.         }
  457.  
  458.         $e $self->executeFullEmailValidation($email$toValidate);
  459.  
  460.         return $e;
  461.     }
  462.     
  463.     /**
  464.      * Execute the validation
  465.      *
  466.      * This function will execute the full email vs tld
  467.      * validation using an array of tlds passed to it.
  468.      *
  469.      * @param string $email       The email to validate.
  470.      * @param array  $arrayOfTLDs The array of the TLDs to validate
  471.      *
  472.      * @access public
  473.      *
  474.      * @return true or false (Depending on if it validates or if it does not)
  475.      */
  476.     function executeFullEmailValidation($email$arrayOfTLDs)
  477.     {
  478.         $emailEnding explode('.'$email);
  479.         $emailEnding $emailEnding[count($emailEnding)-1];
  480.         foreach ($arrayOfTLDs as $validator => $keys{
  481.             if (in_array($emailEnding$keys)) {
  482.                 return true;
  483.             }
  484.         }
  485.         return false;
  486.     }
  487.  
  488.     /**
  489.      * Validate an email
  490.      *
  491.      * @param string $email  email to validate
  492.      * @param mixed  boolean (BC) $check_domain Check or not if the domain exists
  493.      *               array $options associative array of options
  494.      *               'check_domain' boolean Check or not if the domain exists
  495.      *               'use_rfc822' boolean Apply the full RFC822 grammar
  496.      *
  497.      *  Ex.
  498.      *   $options = array(
  499.      *       'check_domain' => 'true',
  500.      *       'fullTLDValidation' => 'true',
  501.      *       'use_rfc822' => 'true',
  502.      *       'VALIDATE_GTLD_EMAILS' => 'true',
  503.      *       'VALIDATE_CCTLD_EMAILS' => 'true',
  504.      *       'VALIDATE_ITLD_EMAILS' => 'true',
  505.      *       );
  506.      *
  507.      * @return boolean true if valid email, false if not
  508.      *
  509.      * @access public
  510.      */
  511.     function email($email$options = null)
  512.     {
  513.         $check_domain = false;
  514.         $use_rfc822   = false;
  515.         if (is_bool($options)) {
  516.             $check_domain $options;
  517.         elseif (is_array($options)) {
  518.             extract($options);
  519.         }
  520.  
  521.         /**
  522.          * Check for IDN usage so we can encode the domain as Punycode
  523.          * before continuing.
  524.          */
  525.         $hasIDNA = false;
  526.  
  527.         if (@include_once('Net/IDNA.php')) {
  528.             $hasIDNA = true;
  529.         }
  530.  
  531.         if ($hasIDNA === true{
  532.             if (strpos($email'@'!== false{
  533.                 list($name$domainexplode('@'$email2);
  534.  
  535.                 // Check if the domain contains characters > 127 which means 
  536.                 // it's an idn domain name.
  537.                 $chars count_chars($domain1);
  538.                 if (!empty($chars&& max(array_keys($chars)) > 127{
  539.                     $idna   =Net_IDNA::singleton();
  540.                     $domain $idna->encode($domain);
  541.                 }
  542.  
  543.                 $email = "$name@$domain";
  544.             }
  545.         }
  546.         
  547.         /**
  548.          * @todo Fix bug here.. even if it passes this, it won't be passing
  549.          *       The regular expression below
  550.          */
  551.         if (isset($fullTLDValidation)) {
  552.             //$valid = Validate::_fullTLDValidation($email, $fullTLDValidation);
  553.             $valid Validate::_fullTLDValidation($email$options);
  554.  
  555.             if (!$valid{
  556.                 return false;
  557.             }
  558.         }
  559.  
  560.         // the base regexp for address
  561.         $regex '&^(?:                                               # recipient:
  562.          ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")|                          #1 quoted name
  563.          ([-\w!\#\$%\&\'*+~/^`|{}]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}]+)*)) #2 OR dot-atom
  564.          @(((\[)?                     #3 domain, 4 as IPv4, 5 optionally bracketed
  565.          (?:(?:(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:[0-1]?[0-9]?[0-9]))\.){3}
  566.                (?:(?:25[0-5])|(?:2[0-4][0-9])|(?:[0-1]?[0-9]?[0-9]))))(?(5)\])|
  567.          ((?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*[a-z0-9](?:[-a-z0-9]*[a-z0-9])?)  #6 domain as hostname
  568.          \.((?:([^- ])[-a-z]*[-a-z]))) #7 TLD 
  569.          $&xi';
  570.  
  571.         //checks if exists the domain (MX or A)
  572.         if ($use_rfc822Validate::__emailRFC822($email$options:
  573.                 preg_match($regex$email)) {
  574.             if ($check_domain && function_exists('checkdnsrr')) {
  575.                 list ($account$domainexplode('@'$email);
  576.                 if (checkdnsrr($domain'MX'|| checkdnsrr($domain'A')) {
  577.                     return true;
  578.                 }
  579.                 return false;
  580.             }
  581.             return true;
  582.         }
  583.         return false;
  584.     }
  585.  
  586.     /**
  587.      * Validate a string using the given format 'format'
  588.      *
  589.      * @param string $string  String to validate
  590.      * @param array  $options Options array where:
  591.      *                           'format' is the format of the string
  592.      *                               Ex:VALIDATE_NUM . VALIDATE_ALPHA (see constants)
  593.      *                           'min_length' minimum length
  594.      *                           'max_length' maximum length
  595.      *
  596.      * @return boolean true if valid string, false if not
  597.      *
  598.      * @access public
  599.      */
  600.     function string($string$options)
  601.     {
  602.         $format     = null;
  603.         $min_length = 0;
  604.         $max_length = 0;
  605.  
  606.         if (is_array($options)) {
  607.             extract($options);
  608.         }
  609.  
  610.         if ($format && !preg_match("|^[$format]*\$|s"$string)) {
  611.             return false;
  612.         }
  613.  
  614.         if ($min_length && strlen($string$min_length{
  615.             return false;
  616.         }
  617.  
  618.         if ($max_length && strlen($string$max_length{
  619.             return false;
  620.         }
  621.  
  622.         return true;
  623.     }
  624.  
  625.     /**
  626.      * Validate an URI (RFC2396)
  627.      * This function will validate 'foobarstring' by default, to get it to validate
  628.      * only http, https, ftp and such you have to pass it in the allowed_schemes
  629.      * option, like this:
  630.      * <code>
  631.      * $options = array('allowed_schemes' => array('http', 'https', 'ftp'))
  632.      * var_dump(Validate::uri('http://www.example.org', $options));
  633.      * </code>
  634.      *
  635.      * NOTE 1: The rfc2396 normally allows middle '-' in the top domain
  636.      *         e.g. http://example.co-m should be valid
  637.      *         However, as '-' is not used in any known TLD, it is invalid
  638.      * NOTE 2: As double shlashes // are allowed in the path part, only full URIs
  639.      *         including an authority can be valid, no relative URIs
  640.      *         the // are mandatory (optionally preceeded by the 'sheme:' )
  641.      * NOTE 3: the full complience to rfc2396 is not achieved by default
  642.      *         the characters ';/?:@$,' will not be accepted in the query part
  643.      *         if not urlencoded, refer to the option "strict'"
  644.      *
  645.      * @param string $url     URI to validate
  646.      * @param array  $options Options used by the validation method.
  647.      *                           key => type
  648.      *                           'domain_check' => boolean
  649.      *                               Whether to check the DNS entry or not
  650.      *                           'allowed_schemes' => array, list of protocols
  651.      *                               List of allowed schemes ('http',
  652.      *                               'ssh+svn', 'mms')
  653.      *                           'strict' => string the refused chars
  654.      *                               in query and fragment parts
  655.      *                               default: ';/?:@$,'
  656.      *                               empty: accept all rfc2396 foreseen chars
  657.      *
  658.      * @return boolean true if valid uri, false if not
  659.      *
  660.      * @access public
  661.      */
  662.     function uri($url$options = null)
  663.     {
  664.         $strict ';/?:@$,';
  665.         $domain_check = false;
  666.         $allowed_schemes = null;
  667.         if (is_array($options)) {
  668.             extract($options);
  669.         }
  670.         if (is_array($allowed_schemes&&
  671.             in_array("tag"$allowed_schemes)
  672.         {
  673.             if (strpos($url"tag:"=== 0{
  674.                 return self::__uriRFC4151($url);
  675.             }
  676.         }
  677.  
  678.         if (preg_match(
  679.              '&^(?:([a-z][-+.a-z0-9]*):)?                             # 1. scheme
  680.               (?://                                                   # authority start
  681.               (?:((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();:\&=+$,])*)@)?    # 2. authority-userinfo
  682.               (?:((?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)*[a-z](?:[a-z0-9]+)?\.?)  # 3. authority-hostname OR
  683.               |([0-9]{1,3}(?:\.[0-9]{1,3}){3}))                       # 4. authority-ipv4
  684.               (?::([0-9]*))?)                                        # 5. authority-port
  685.               ((?:/(?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'():@\&=+$,;])*)*/?)? # 6. path
  686.               (?:\?([^#]*))?                                          # 7. query
  687.               (?:\#((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();/?:@\&=+$,])*))? # 8. fragment
  688.               $&xi'$url$matches)) {
  689.             $scheme = isset($matches[1]$matches[1'';
  690.             $authority = isset($matches[3]$matches[3'' ;
  691.             if (is_array($allowed_schemes&&
  692.                 !in_array($scheme$allowed_schemes)
  693.             {
  694.                 return false;
  695.             }
  696.             if (!empty($matches[4])) {
  697.                 $parts explode('.'$matches[4]);
  698.                 foreach ($parts as $part{
  699.                     if ($part > 255{
  700.                         return false;
  701.                     }
  702.                 }
  703.             elseif ($domain_check && function_exists('checkdnsrr')) {
  704.                 if (!checkdnsrr($authority'A')) {
  705.                     return false;
  706.                 }
  707.             }
  708.             if ($strict{
  709.                 $strict '#[' preg_quote($strict'#'']#';
  710.                 if ((!empty($matches[7]&& preg_match($strict$matches[7]))
  711.                  || (!empty($matches[8]&& preg_match($strict$matches[8]))) {
  712.                     return false;
  713.                 }
  714.             }
  715.             return true;
  716.         }
  717.         return false;
  718.     }
  719.  
  720.     /**
  721.      * Validate date and times. Note that this method need the Date_Calc class
  722.      *
  723.      * @param string $date    Date to validate
  724.      * @param array  $options array options where :
  725.      *                           'format' The format of the date (%d-%m-%Y)
  726.      *                                    or rfc822_compliant
  727.      *                           'min'    The date has to be greater
  728.      *                                    than this array($day, $month, $year)
  729.      *                                    or PEAR::Date object
  730.      *                           'max'    The date has to be smaller than
  731.      *                                    this array($day, $month, $year)
  732.      *                                    or PEAR::Date object
  733.      *
  734.      * @return boolean true if valid date/time, false if not
  735.      *
  736.      * @access public
  737.      */
  738.     function date($date$options)
  739.     {
  740.         $max    = false;
  741.         $min    = false;
  742.         $format '';
  743.  
  744.         if (is_array($options)) {
  745.             extract($options);
  746.         }
  747.  
  748.         if (strtolower($format== 'rfc822_compliant'{
  749.             $preg '&^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),) \s+
  750.                     (?:(\d{2})?) \s+
  751.                     (?:(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)?) \s+
  752.                     (?:(\d{2}(\d{2})?)?) \s+
  753.                     (?:(\d{2}?)):(?:(\d{2}?))(:(?:(\d{2}?)))? \s+
  754.                     (?:[+-]\d{4}|UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[A-IK-Za-ik-z])$&xi';
  755.  
  756.             if (!preg_match($preg$date$matches)) {
  757.                 return false;
  758.             }
  759.  
  760.             $year    = (int)$matches[4];
  761.             $months  = array('Jan''Feb''Mar''Apr''May''Jun',
  762.                              'Jul''Aug''Sep''Oct''Nov''Dec');
  763.             $month   array_keys($months$matches[3]);
  764.             $month   = (int)$month[0]+1;
  765.             $day     = (int)$matches[2];
  766.             $weekday $matches[1];
  767.             $hour    = (int)$matches[6];
  768.             $minute  = (int)$matches[7];
  769.             isset($matches[9]$second = (int)$matches[9$second = 0;
  770.  
  771.             if ((strlen($year!= 4)        ||
  772.                 ($day    > 31   || $day < 1)||
  773.                 ($hour   > 23)  ||
  774.                 ($minute > 59)  ||
  775.                 ($second > 59)) {
  776.                     return false;
  777.             }
  778.         else {
  779.             $date_len strlen($format);
  780.             for ($i = 0; $i $date_len$i++{
  781.                 $c $format{$i};
  782.                 if ($c == '%'{
  783.                     $next $format{$i + 1};
  784.                     switch ($next{
  785.                     case 'j':
  786.                     case 'd':
  787.                         if ($next == 'j'{
  788.                             $day = (int)Validate::_substr($date12);
  789.                         else {
  790.                             $day = (int)Validate::_substr($date02);
  791.                         }
  792.                         if ($day < 1 || $day > 31{
  793.                             return false;
  794.                         }
  795.                         break;
  796.                     case 'm':
  797.                     case 'n':
  798.                         if ($next == 'm'{
  799.                             $month = (int)Validate::_substr($date02);
  800.                         else {
  801.                             $month = (int)Validate::_substr($date12);
  802.                         }
  803.                         if ($month < 1 || $month > 12{
  804.                             return false;
  805.                         }
  806.                         break;
  807.                     case 'Y':
  808.                     case 'y':
  809.                         if ($next == 'Y'{
  810.                             $year Validate::_substr($date4);
  811.                             $year = (int)$year?$year:'';
  812.                         else {
  813.                             $year = (int)(substr(date('Y')02.
  814.                                               Validate::_substr($date2));
  815.                         }
  816.                         if (strlen($year!= 4 || $year < 0 || $year > 9999{
  817.                             return false;
  818.                         }
  819.                         break;
  820.                     case 'g':
  821.                     case 'h':
  822.                         if ($next == 'g'{
  823.                             $hour Validate::_substr($date12);
  824.                         else {
  825.                             $hour Validate::_substr($date2);
  826.                         }
  827.                         if (!preg_match('/^\d+$/'$hour|| $hour < 0 || $hour > 12{
  828.                             return false;
  829.                         }
  830.                         break;
  831.                     case 'G':
  832.                     case 'H':
  833.                         if ($next == 'G'{
  834.                             $hour Validate::_substr($date12);
  835.                         else {
  836.                             $hour Validate::_substr($date2);
  837.                         }
  838.                         if (!preg_match('/^\d+$/'$hour|| $hour < 0 || $hour > 24{
  839.                             return false;
  840.                         }
  841.                         break;
  842.                     case 's':
  843.                     case 'i':
  844.                         $t Validate::_substr($date2);
  845.                         if (!preg_match('/^\d+$/'$t|| $t < 0 || $t > 59{
  846.                             return false;
  847.                         }
  848.                         break;
  849.                     default:
  850.                         trigger_error("Not supported char `$next' after % in offset " . ($i+2)E_USER_WARNING);
  851.                     }
  852.                     $i++;
  853.                 else {
  854.                     //literal
  855.                     if (Validate::_substr($date1!= $c{
  856.                         return false;
  857.                     }
  858.                 }
  859.             }
  860.         }
  861.         // there is remaing data, we don't want it
  862.         if (strlen($date&& (strtolower($format!= 'rfc822_compliant')) {
  863.             return false;
  864.         }
  865.  
  866.         if (isset($day&& isset($month&& isset($year)) {
  867.             if (!checkdate($month$day$year)) {
  868.                 return false;
  869.             }
  870.  
  871.             if (strtolower($format== 'rfc822_compliant'{
  872.                 if ($weekday != date("D"mktime(000$month$day$year))) {
  873.                     return false;
  874.                 }
  875.             }
  876.  
  877.             if ($min{
  878.                 include_once 'Date/Calc.php';
  879.                 if (is_a($min'Date'&&
  880.                     (Date_Calc::compareDates($day$month$year,
  881.                         $min->getDay()$min->getMonth()$min->getYear()) < 0)
  882.                 {
  883.                     return false;
  884.                 elseif (is_array($min&&
  885.                         (Date_Calc::compareDates($day$month$year,
  886.                             $min[0]$min[1]$min[2]< 0)
  887.                 {
  888.                     return false;
  889.                 }
  890.             }
  891.  
  892.             if ($max{
  893.                 include_once 'Date/Calc.php';
  894.                 if (is_a($max'Date'&&
  895.                     (Date_Calc::compareDates($day$month$year,
  896.                         $max->getDay()$max->getMonth()$max->getYear()) > 0)
  897.                 {
  898.                     return false;
  899.                 elseif (is_array($max&&
  900.                         (Date_Calc::compareDates($day$month$year,
  901.                             $max[0]$max[1]$max[2]> 0)
  902.                 {
  903.                     return false;
  904.                 }
  905.             }
  906.         }
  907.  
  908.         return true;
  909.     }
  910.  
  911.     /**
  912.      * Substr
  913.      *
  914.      * @param string &$date Date
  915.      * @param string $num   Length
  916.      * @param string $opt   Unknown
  917.      *
  918.      * @access private
  919.      * @return string 
  920.      */
  921.     function _substr(&$date$num$opt = false)
  922.     {
  923.         if ($opt && strlen($date>= $opt && preg_match('/^[0-9]{'.$opt.'}/'$date$m)) {
  924.             $ret $m[0];
  925.         else {
  926.             $ret substr($date0$num);
  927.         }
  928.         $date substr($datestrlen($ret));
  929.         return $ret;
  930.     }
  931.  
  932.     function _modf($val$div)
  933.     {
  934.         if (function_exists('bcmod')) {
  935.             return bcmod($val$div);
  936.         elseif (function_exists('fmod')) {
  937.             return fmod($val$div);
  938.         }
  939.         $r $val $div;
  940.         $i intval($r);
  941.         return intval($val $i $div + .1);
  942.     }
  943.  
  944.     /**
  945.      * Calculates sum of product of number digits with weights
  946.      *
  947.      * @param string $number  number string
  948.      * @param array  $weights reference to array of weights
  949.      *
  950.      * @access protected
  951.      *
  952.      * @return int returns product of number digits with weights
  953.      */
  954.     function _multWeights($number&$weights)
  955.     {
  956.         if (!is_array($weights)) {
  957.             return -1;
  958.         }
  959.         $sum = 0;
  960.  
  961.         $count min(count($weights)strlen($number));
  962.         if ($count == 0// empty string or weights array
  963.             return -1;
  964.         }
  965.         for ($i = 0; $i $count; ++$i{
  966.             $sum += intval(substr($number$i1)) $weights[$i];
  967.         }
  968.  
  969.         return $sum;
  970.     }
  971.  
  972.     /**
  973.      * Calculates control digit for a given number
  974.      *
  975.      * @param string $number     number string
  976.      * @param array  $weights    reference to array of weights
  977.      * @param int    $modulo     (optionsl) number
  978.      * @param int    $subtract   (optional) number
  979.      * @param bool   $allow_high (optional) true if function can return number higher than 10
  980.      *
  981.      * @access protected
  982.      *
  983.      * @return  int -1 calculated control number is returned
  984.      */
  985.     function _getControlNumber($number&$weights$modulo = 10$subtract = 0$allow_high = false)
  986.     {
  987.         // calc sum
  988.         $sum Validate::_multWeights($number$weights);
  989.         if ($sum == -1{
  990.             return -1;
  991.         }
  992.         $mod Validate::_modf($sum$modulo);  // calculate control digit
  993.  
  994.         if ($subtract $mod && $mod > 0{
  995.             $mod $subtract $mod;
  996.         }
  997.         if ($allow_high === false{
  998.             $mod %= 10;           // change 10 to zero
  999.         }
  1000.         return $mod;
  1001.     }
  1002.  
  1003.     /**
  1004.      * Validates a number
  1005.      *
  1006.      * @param string $number   number to validate
  1007.      * @param array  $weights  reference to array of weights
  1008.      * @param int    $modulo   (optional) number
  1009.      * @param int    $subtract (optional) number
  1010.      *
  1011.      * @access protected
  1012.      *
  1013.      * @return  bool true if valid, false if not
  1014.      */
  1015.     function _checkControlNumber($number&$weights$modulo = 10$subtract = 0)
  1016.     {
  1017.         if (strlen($numbercount($weights)) {
  1018.             return false;
  1019.         }
  1020.         $target_digit  substr($numbercount($weights)1);
  1021.         $control_digit Validate::_getControlNumber($number$weights$modulo$subtract$modulo > 10);
  1022.  
  1023.         if ($control_digit == -1{
  1024.             return false;
  1025.         }
  1026.         if ($target_digit === 'X' && $control_digit == 10{
  1027.             return true;
  1028.         }
  1029.         if ($control_digit != $target_digit{
  1030.             return false;
  1031.         }
  1032.         return true;
  1033.     }
  1034.  
  1035.     /**
  1036.      * Bulk data validation for data introduced in the form of an
  1037.      * assoc array in the form $var_name => $value.
  1038.      * Can be used on any of Validate subpackages
  1039.      *
  1040.      * @param array   $data     Ex: array('name' => 'toto', 'email' => 'toto@thing.info');
  1041.      * @param array   $val_type Contains the validation type and all parameters used in.
  1042.      *                           'val_type' is not optional
  1043.      *                           others validations properties must have the same name as the function
  1044.      *                           parameters.
  1045.      *                           Ex: array('toto'=>array('type'=>'string','format'='toto@thing.info','min_length'=>5));
  1046.      * @param boolean $remove   if set, the elements not listed in data will be removed
  1047.      *
  1048.      * @return array   value name => true|false    the value name comes from the data key
  1049.      *
  1050.      * @access public
  1051.      */
  1052.     function multiple(&$data&$val_type$remove = false)
  1053.     {
  1054.         $keys  array_keys($data);
  1055.         $valid = array();
  1056.  
  1057.         foreach ($keys as $var_name{
  1058.             if (!isset($val_type[$var_name])) {
  1059.                 if ($remove{
  1060.                     unset($data[$var_name]);
  1061.                 }
  1062.                 continue;
  1063.             }
  1064.             $opt       $val_type[$var_name];
  1065.             $methods   get_class_methods('Validate');
  1066.             $val2check $data[$var_name];
  1067.             // core validation method
  1068.             if (in_array(strtolower($opt['type'])$methods)) {
  1069.                 //$opt[$opt['type']] = $data[$var_name];
  1070.                 $method $opt['type'];
  1071.                 unset($opt['type']);
  1072.  
  1073.                 if (sizeof($opt== 1 && is_array(reset($opt))) {
  1074.                     $opt array_pop($opt);
  1075.                 }
  1076.                 $valid[$var_namecall_user_func(array('Validate'$method)$val2check$opt);
  1077.  
  1078.                 /**
  1079.                  * external validation method in the form:
  1080.                  * "<class name><underscore><method name>"
  1081.                  * Ex: us_ssn will include class Validate/US.php and call method ssn()
  1082.                  */
  1083.             elseif (strpos($opt['type']'_'!== false{
  1084.                 $validateType explode('_'$opt['type']);
  1085.                 $method       array_pop($validateType);
  1086.                 $class        implode('_'$validateType);
  1087.                 $classPath    str_replace('_'DIRECTORY_SEPARATOR$class);
  1088.                 $class        'Validate_' $class;
  1089.                 if (!@include_once "Validate/$classPath.php"{
  1090.                     trigger_error("$class isn't installed or you may have some permissoin issues"E_USER_ERROR);
  1091.                 }
  1092.  
  1093.                 $ce substr(phpversion()01> 4 ?
  1094.                     class_exists($classfalseclass_exists($class);
  1095.                 if (!$ce ||
  1096.                     !in_array($methodget_class_methods($class))
  1097.                 {
  1098.                     trigger_error("Invalid validation type $class::$method",
  1099.                         E_USER_WARNING);
  1100.                     continue;
  1101.                 }
  1102.                 unset($opt['type']);
  1103.                 if (sizeof($opt== 1{
  1104.                     $opt array_pop($opt);
  1105.                 }
  1106.                 $valid[$var_namecall_user_func(array($class$method),
  1107.                     $data[$var_name]$opt);
  1108.             else {
  1109.                 trigger_error("Invalid validation type {$opt['type']}",
  1110.                     E_USER_WARNING);
  1111.             }
  1112.         }
  1113.         return $valid;
  1114.     }
  1115. }

Documentation generated on Fri, 13 Feb 2009 13:00:23 +0000 by phpDocumentor 1.4.2. PEAR Logo Copyright © PHP Group 2004.