PageRenderTime 149ms CodeModel.GetById 75ms app.highlight 65ms RepoModel.GetById 1ms app.codeStats 0ms

/dooframework/helper/DooValidator.php

https://bitbucket.org/cidious/vault_doo
PHP | 1236 lines | 544 code | 93 blank | 599 comment | 212 complexity | ef1e3c1010569d491e2e534a89a2d32d MD5 | raw file
   1<?php
   2/**
   3 * DooValidator class file.
   4 *
   5 * @author Leng Sheng Hong <darkredz@gmail.com>
   6 * @link http://www.doophp.com/
   7 * @copyright Copyright &copy; 2009 Leng Sheng Hong
   8 * @license http://www.doophp.com/license
   9 */
  10
  11/**
  12 * A helper class that helps validating data.
  13 *
  14 * <p>DooValidator can be used for form and Model data validation before saving/inserting/deleting a data.</p>
  15 *
  16 * <p>To use DooValidator, you have to create an instance of it and defined the validation rules.
  17 * All the methods start with 'test' can be used as a rule for validating data. Rule names are case insensitive.</p>
  18 *
  19 * <p>You can pass in custom error message along with the rules. By default all fields in the rules are <b>required</b></p>
  20 * <code>
  21 * $rules = array(
  22 *              'creattime'=>array(
  23 *                    array('datetime'),
  24 *                    array('email'),
  25 *                    array('optional')   //Optional field
  26 *              ),
  27 *              'username'=>array(
  28 *                    array('username',6,16),
  29 *                    //Custom error message will be used
  30 *                    array('lowercase', 'Username must only be lowercase.')
  31 *               ),
  32 *
  33 *               //Only one rule
  34 *               'pwd'=>array('password'),
  35 *               'email'=>array('email'),
  36 *               'age'=>array('between',13,200),
  37 *               'today'=>array('date','mm/dd/yy'),
  38 *
  39 *               //Custom rules, static method required
  40 *               'a'=>array('custom', 'MainController::isA'),
  41 *
  42 *               //Custom Required field message.
  43 *               'content'=>array('required', 'Content is required!')
  44 *        );
  45 * </code>
  46 *
  47 * <p>Rules are defined based on the validation method's parameters. For example:</p>
  48 * <code>
  49 * //Validation method
  50 * testBetween($value, $min, $max, $msg=null)
  51 *
  52 * $rule = array(
  53 *     'field'=>array('between', 0, 20)
  54 *     'field2'=>array('between', 0, 20, 'Custom Err Msg!')
  55 * );
  56 * </code>
  57 *
  58 * <p>You can get the list of available validation rules by calling DooValidator::getAvailableRules()</p>
  59 *
  60 * <p>To validate the data, create an instance of DooValidator and call validate() in your Controller/Model.</p>
  61 * <code>
  62 * $v = new DooValidator();
  63 *
  64 * # There are 3 different validation Mode.
  65 * //$v->checkMode = DooValidator::CHECK_SKIP;
  66 * //$v->checkMode = DooValidator::CHECK_ALL_ONE;
  67 * //$v->checkMode = DooValidator::CHECK_ALL;
  68 *
  69 * //The $_POST or data pass in need to be an assoc array
  70 * //$data = array('username'=>'doophp', 'pwd'=>'12345');
  71 * if($error = $v->validate($_POST, $rules)){
  72 *      print_r($error);
  73 * }
  74 * </code>
  75 *
  76 * <p>You can pass in a string to load predefined Rules which located at SITE_PATH/protected/config/forms/</p>
  77 * <code>
  78 * <?php
  79 * //in protected/config/forms/example.php
  80 * return array(
  81 *      'username'=>array(
  82 *                      array('username',4,5,'username invalid'),
  83 *                      array('maxlength',6,'This is too long'),
  84 *                      array('minlength',6)
  85 *                  ),
  86 *      'pwd'=>array('password',3,5),
  87 *      'email'=>array('email')
  88 *  );
  89 * ?>
  90 *
  91 * //in your Controller/Model
  92 * $error = $v->validate($data, 'example');
  93 * </code>
  94 *
  95 * <p>If nothing is returned from the validate() call, it means that all the data passed the validation rules.</p>
  96 *
  97 * <p>The Model validation rules are automatically generated when you used the framework's model generator feature.
  98 * If your Models are extending DooModel or DooSmartModel, you can validate the data by calling DooModel::validate()</p>
  99 * <code>
 100 * $f = new Food;
 101 * $f->name = 'My Food name for validation';
 102 * $error = $f->validate();
 103 *
 104 * //Or...
 105 * $error = Food::_validate($f);
 106 * </code>
 107 *
 108 * @author Leng Sheng Hong <darkredz@gmail.com>
 109 * @version $Id: DooValidator.php 1000 2009-08-30 11:37:22
 110 * @package doo.helper
 111 * @since 1.2
 112 */
 113class DooValidator {
 114    /**
 115     * Checks All and returns All errors
 116     */
 117    const CHECK_ALL = 'all';
 118
 119    /**
 120     * Checks All and returns one error for each data field
 121     */
 122    const CHECK_ALL_ONE = 'all_one';
 123
 124    /**
 125     * Returns one error once the first is detected
 126     */
 127    const CHECK_SKIP = 'skip';
 128
 129	/**
 130	 * Use PHP empty method to test for required (or optional)
 131	 */
 132	const REQ_MODE_NULL_EMPTY = 'nullempty';
 133
 134	/**
 135	 * Only ensure required fields are non null / accept not null on required
 136	 */
 137	const REQ_MODE_NULL_ONLY = 'null';
 138
 139    /**
 140     * Default require message to display field name "first_name is required."
 141     */
 142    const REQ_MSG_FIELDNAME = 'fieldname';
 143
 144    /**
 145     * Default require message to display "This is required."
 146     */
 147    const REQ_MSG_THIS = 'this';
 148
 149    /**
 150     * Default require message to convert field name with underscore to words. eg(field = first_name). "First name is required."
 151     */
 152    const REQ_MSG_UNDERSCORE_TO_SPACE = 'underscore';
 153
 154    /**
 155     * Default require message to convert field name with camelcase to words. eg(field = firstName). "First name is required."
 156     */
 157    const REQ_MSG_CAMELCASE_TO_SPACE = 'camelcase';
 158
 159    /**
 160     * Validation mode
 161     * @var string all/all_one/skip
 162     */
 163    public $checkMode = 'all';
 164
 165	/**
 166	 * How should required fields be tested (or be considered left out on optional)
 167	 * @var string empty/null
 168	 */
 169	public $requireMode = 'nullempty';
 170
 171    /**
 172     * Default method to generate error message for a required field.
 173     * @var string
 174     */
 175    public $requiredMsgDefaultMethod = 'underscore';
 176
 177    /**
 178     * Default error message suffix for a required field.
 179     * @var string
 180     */
 181    public $requiredMsgDefaultSuffix = ' field is required';
 182
 183    /**
 184     * Trim the data fields. The data will be modified.
 185     * @param array $data assoc array to be trimmed
 186	 * @param int $maxDepth Maximum number of recursive calls. Defaults to a max nesting depth of 5.
 187     */
 188    public function trimValues(&$data, $maxDepth = 5) {
 189		foreach($data as $k=>&$v) {
 190			if (is_array($v)) {
 191				if ($maxDepth > 0) {
 192					$this->trimValues($v, $maxDepth - 1);
 193				}
 194			} else {
 195				$v = trim($v);
 196			}
 197		}
 198	}
 199
 200    /**
 201     * Get a list of available rules
 202     * @return array
 203     */
 204    public static function getAvailableRules(){
 205        return array('alpha', 'alphaNumeric', 'between', 'betweenInclusive', 'ccAmericanExpress', 'ccDinersClub', 'ccDiscover', 'ccMasterCard',
 206                    'ccVisa', 'colorHex', 'creditCard', 'custom', 'date', 'dateBetween', 'datetime', 'digit', 'email', 'equal', 'equalAs', 'float',
 207                    'greaterThan', 'greaterThanOrEqual', 'hostname', 'ip', 'integer', 'lessThan', 'lessThanOrEqual', 'lowercase', 'max',
 208                    'maxlength', 'min', 'minlength', 'notEmpty', 'notEqual', 'notNull', 'password', 'passwordComplex', 'price', 'regex',
 209                    'uppercase', 'url', 'username','dbExist','dbNotExist','alphaSpace','notInList','inList'
 210                );
 211    }
 212
 213    /**
 214     * Get appropriate rules for a certain DB data type
 215     * @param string $dataType
 216     * @return string Rule name for the data type
 217     */
 218    public static function dbDataTypeToRules($type){
 219        $dataType = array(
 220                        //integers
 221                        'tinyint'=>'integer',
 222                        'smallint'=>'integer',
 223                        'mediumint'=>'integer',
 224                        'int'=>'integer',
 225                        'bigint'=>'integer',
 226
 227                        //float
 228                        'float'=>'float',
 229                        'double'=>'float',
 230                        'decimal'=>'float',
 231
 232                        //datetime
 233                        'date'=>'date',
 234                        'datetime'=>'datetime',
 235                        'timestamp'=>'datetime',
 236                        'time'=>'datetime'
 237                    );
 238        if(isset($dataType[$type]))
 239            return $dataType[$type];
 240    }
 241
 242    /**
 243     * Validate the data with the defined rules.
 244     *
 245     * @param array $data Data to be validate. One dimension assoc array, eg. array('user'=>'leng', 'email'=>'abc@abc.com')
 246     * @param string|array $rules Validation rule. Pass in a string to load the predefined rules in SITE_PATH/protected/config/forms
 247     * @return array Returns an array of errors if errors exist.
 248     */
 249    public function validate($data=null, $rules=null){
 250        //$data = array('username'=>'leng s', 'pwd'=>'234231dfasd', 'email'=>'asdb12@#asd.com.my');
 251        //$rules = array('username'=>array('username'), 'pwd'=>array('password',6,32), 'email'=>array('email'));
 252        if(is_string($rules)){
 253            $rules = include(Doo::conf()->SITE_PATH .  Doo::conf()->PROTECTED_FOLDER . 'config/forms/'.$rules.'.php');
 254        }
 255
 256        $optErrorRemove = array();
 257
 258        foreach($data as $dk=>$dv){
 259            if($this->requireMode == DooValidator::REQ_MODE_NULL_EMPTY && ($dv === null || $dv === '') ||
 260			   $this->requireMode == DooValidator::REQ_MODE_NULL_ONLY  && $dv === null){
 261                unset($data[$dk]);
 262			}
 263        }
 264
 265        if($missingKey = array_diff_key($rules, $data) ){
 266                $fieldnames = array_keys($missingKey);
 267                $customRequireMsg = null;
 268
 269                foreach($fieldnames as $fieldname){
 270                    if(isset($missingKey[$fieldname])){
 271                        if( in_array('required', $missingKey[$fieldname]) ){
 272                            $customRequireMsg = $missingKey[$fieldname][1];
 273                        }
 274                        else if(is_array($missingKey[$fieldname][0])){
 275                            foreach($missingKey[$fieldname] as $f)
 276                                if($f[0]=='required'){
 277                                    if(isset($f[1]))
 278                                        $customRequireMsg = $f[1];
 279                                    break;
 280                                }
 281                        }
 282                    }
 283
 284                    //remove optional fields from error
 285                    if(is_array($missingKey[$fieldname][0])){
 286                       foreach($missingKey[$fieldname] as $innerArrayRules){
 287                           if($innerArrayRules[0]=='optional'){
 288                               //echo $fieldname.' - 1 this is not set and optional, should be removed from error';
 289                               $optErrorRemove[] = $fieldname;
 290                               break;
 291                           }
 292                       }
 293                    }
 294
 295                    if($this->checkMode==DooValidator::CHECK_ALL){
 296                        if($customRequireMsg!==null)
 297                            $errors[$fieldname] = $customRequireMsg;
 298                        else
 299                            $errors[$fieldname] = $this->getRequiredFieldDefaultMsg($fieldname);
 300                    }else if($this->checkMode==DooValidator::CHECK_SKIP){
 301                        if(in_array($fieldname, $optErrorRemove))
 302                            continue;
 303                        if($customRequireMsg!==null)
 304                            return $customRequireMsg;
 305                        return $this->getRequiredFieldDefaultMsg($fieldname);
 306                    }else if($this->checkMode==DooValidator::CHECK_ALL_ONE){
 307                        if($customRequireMsg!==null)
 308                            $errors[$fieldname] = $customRequireMsg;
 309                        else
 310                            $errors[$fieldname] = $this->getRequiredFieldDefaultMsg($fieldname);
 311                    }
 312                }
 313        }
 314
 315        foreach($data as $k=>$v){
 316            if(!isset($rules[$k])) continue;
 317            $cRule = $rules[$k];
 318            foreach($cRule as $v2){
 319                if(is_array($v2)){
 320                    //print_r(array_slice($v2, 1));
 321                    $vv = array_merge(array($v),array_slice($v2, 1));
 322
 323					$vIsEmpty = ($this->requireMode == DooValidator::REQ_MODE_NULL_EMPTY && ($v === null || $v === '') ||
 324								 $this->requireMode == DooValidator::REQ_MODE_NULL_ONLY  && $v === null) ? true : false;
 325
 326                    //call func
 327                    if($vIsEmpty && $v2[0]=='optional'){
 328                        //echo $k.' - this is not set and optional, should be removed from error';
 329                        $optErrorRemove[] = $k;
 330                    }
 331                    if($err = call_user_func_array(array(&$this, 'test'.$v2[0]), $vv) ){
 332                        if($this->checkMode==DooValidator::CHECK_ALL)
 333                            $errors[$k][$v2[0]] = $err;
 334                        else if($this->checkMode==DooValidator::CHECK_SKIP && !$vIsEmpty && $v2[0]!='optional'){
 335                            return $err;
 336                        }else if($this->checkMode==DooValidator::CHECK_ALL_ONE)
 337                            $errors[$k] = $err;
 338                    }
 339                }
 340                else if(is_string($cRule[0])){
 341                    if(sizeof($cRule)>1){
 342                        //print_r(array_slice($cRule, 1));
 343                        $vv = array_merge(array($v),array_slice($cRule, 1));
 344
 345                        if($err = call_user_func_array(array(&$this, 'test'.$cRule[0]), $vv) ){
 346                            if($this->checkMode==DooValidator::CHECK_ALL || $this->checkMode==DooValidator::CHECK_ALL_ONE)
 347                                $errors[$k] = $err;
 348                            else if($this->checkMode==DooValidator::CHECK_SKIP){
 349                                return $err;
 350                            }
 351                        }
 352                    }else{
 353                        if($err = $this->{'test'.$cRule[0]}($v) ){
 354                            if($this->checkMode==DooValidator::CHECK_ALL || $this->checkMode==DooValidator::CHECK_ALL_ONE)
 355                                $errors[$k] = $err;
 356                            else if($this->checkMode==DooValidator::CHECK_SKIP){
 357                                return $err;
 358                            }
 359                        }
 360                    }
 361                    continue 2;
 362                }
 363            }
 364        }
 365        if(isset($errors)){
 366            if(sizeof($optErrorRemove)>0){
 367                foreach($errors as $ek=>$ev){
 368                    if(in_array($ek, $optErrorRemove)){
 369                        //echo '<h3>Removing error '.$ek.'</h3>';
 370                        unset($errors[$ek]);
 371                    }
 372                }
 373            }
 374            return $errors;
 375        }
 376    }
 377
 378    /**
 379     * Set default settings to display the default error message for required fields
 380     * @param type $displayMethod Default error message display method. use: DooValidator::REQ_MSG_UNDERSCORE_TO_SPACE, DooValidator::REQ_MSG_CAMELCASE_TO_SPACE, DooValidator::REQ_MSG_THIS, DooValidator::REQ_MSG_FIELDNAME
 381     * @param type $suffix suffix for the error message. Default is ' field is required'
 382     */
 383    public function setRequiredFieldDefaults( $displayMethod = DooValidator::REQ_MSG_UNDERSCORE_TO_SPACE, $suffix = ' field is required'){
 384        $this->requiredMsgDefaultMethod = $displayMethod;
 385        $this->requiredMsgDefaultSuffix = $suffix;
 386    }
 387
 388    /**
 389     * Get the default error message for required field
 390     * @param string $fieldname Name of the field
 391     * @return string Error message
 392     */
 393    public function getRequiredFieldDefaultMsg($fieldname){
 394        if($this->requiredMsgDefaultMethod==DooValidator::REQ_MSG_UNDERSCORE_TO_SPACE)
 395            return ucfirst(str_replace('_', ' ', $fieldname)) . $this->requiredMsgDefaultSuffix;
 396
 397        if($this->requiredMsgDefaultMethod==DooValidator::REQ_MSG_THIS)
 398            return 'This ' . $this->requiredMsgDefaultSuffix;
 399
 400        if($this->requiredMsgDefaultMethod==DooValidator::REQ_MSG_CAMELCASE_TO_SPACE)
 401            return ucfirst(strtolower(preg_replace('/([A-Z])/', ' $1', $fieldname))) . $this->requiredMsgDefaultSuffix;
 402
 403        if($this->requiredMsgDefaultMethod==DooValidator::REQ_MSG_FIELDNAME)
 404            return $fieldname . $this->requiredMsgDefaultSuffix;
 405    }
 406
 407    public function testOptional($value){}
 408    public function testRequired($value, $msg){
 409		if ($this->requireMode == DooValidator::REQ_MODE_NULL_EMPTY && ($value === null || $value === '') ||
 410			$this->requireMode == DooValidator::REQ_MODE_NULL_ONLY  && $value === null) {
 411
 412            if($msg!==null) return $msg;
 413            return 'This field is required!';
 414        }
 415    }
 416
 417    /**
 418     * Validate data with your own custom rules.
 419     *
 420     * Usage in Controller:
 421     * <code>
 422     * public static function isA($value){
 423     *      if($value!='a'){
 424     *          return 'Value must be A';
 425     *      }
 426     * }
 427     *
 428     * public function test(){
 429     *     $rules = array(
 430     *          'email'=>array('custom', 'TestController::isA')
 431     *     );
 432     *
 433     *     $v = new DooValidator();
 434     *     if($error = $v->validate($_POST, $rules)){
 435     *          //display error
 436     *     }
 437     * }
 438     * </code>
 439     *
 440     * @param string $value Value of data to be validated
 441     * @param string $function Name of the custom function
 442     * @param string $msg Custom error message
 443     * @return string
 444     */
 445    public function testCustom($value, $function, $options=null ,$msg=null){
 446        if($options==null){
 447            if($err = call_user_func($function, $value)){
 448                if($err!==true){
 449                    if($msg!==null) return $msg;
 450                    return $err;
 451                }
 452            }
 453        }else{
 454            //if array, additional parameters
 455            if($err = call_user_func_array($function, array_merge(array($value), $options)) ){
 456                if($err!==true){
 457                    if($msg!==null) return $msg;
 458                    return $err;
 459                }
 460            }
 461        }
 462    }
 463
 464    /**
 465     * Validate against a Regex rule
 466     *
 467     * @param string $value Value of data to be validated
 468     * @param string $regex Regex rule to be tested against
 469     * @param string $msg Custom error message
 470     * @return string
 471     */
 472    public function testRegex($value, $regex, $msg=null){
 473        if(!preg_match($regex, $value) ){
 474            if($msg!==null) return $msg;
 475            return 'Error in field.';
 476        }
 477    }
 478
 479    /**
 480     * Validate username format.
 481     *
 482     * @param string $value Value of data to be validated
 483     * @param int $minLength Minimum length
 484     * @param int $maxLength Maximum length
 485     * @param string $msg Custom error message
 486     * @return string
 487     */
 488    public function testUsername($value, $minLength=4, $maxLength=12, $msg=null){
 489        if(!preg_match('/^[a-zA-Z][a-zA-Z.0-9_-]{'. ($minLength-1) .','.$maxLength.'}$/i', $value)){
 490            if($msg!==null) return $msg;
 491            return "User name must be $minLength-$maxLength characters. Only characters, dots, digits, underscore & hyphen are allowed.";
 492        }
 493        else if(strpos($value, '..')!==False){
 494            if($msg!==null) return $msg;
 495            return "User name cannot consist of 2 continuous dots.";
 496        }
 497        else if(strpos($value, '__')!==False){
 498            if($msg!==null) return $msg;
 499            return "User name cannot consist of 2 continuous underscore.";
 500        }
 501        else if(strpos($value, '--')!==False){
 502            if($msg!==null) return $msg;
 503            return "User name cannot consist of 2 continuous dash.";
 504        }
 505        else if(strpos($value, '.-')!==False || strpos($value, '-.')!==False ||
 506                strpos($value, '._')!==False || strpos($value, '_.')!==False ||
 507                strpos($value, '_-')!==False || strpos($value, '-_')!==False){
 508            if($msg!==null) return $msg;
 509            return "User name cannot consist of 2 continuous punctuation.";
 510        }
 511        else if(ctype_punct($value[0])){
 512            if($msg!==null) return $msg;
 513            return "User name cannot start with a punctuation.";
 514        }
 515        else if(ctype_punct( substr($value, strlen($value)-1) )){
 516            if($msg!==null) return $msg;
 517            return "User name cannot end with a punctuation.";
 518        }
 519    }
 520
 521    /**
 522     * Validate password format
 523     *
 524     * @param string $value Value of data to be validated
 525     * @param int $minLength Minimum length
 526     * @param int $maxLength Maximum length
 527     * @param string $msg Custom error message
 528     * @return string
 529     */
 530    public function testPassword($value, $minLength=6, $maxLength=32, $msg=null){
 531        if(!preg_match('/^[a-zA-Z.0-9_-]{'.$minLength.','.$maxLength.'}$/i', $value)){
 532            if($msg!==null) return $msg;
 533            return "Only characters, dots, digits, underscore & hyphen are allowed. Password must be at least $minLength characters long.";
 534        }
 535    }
 536
 537    /**
 538     * Validate against a complex password format
 539     *
 540     * @param string $value Value of data to be validated
 541     * @param string $msg Custom error message
 542     * @return string
 543     */
 544    public function testPasswordComplex($value, $msg=null){
 545        if(!preg_match('/\A(?=[-_a-zA-Z0-9]*?[A-Z])(?=[-_a-zA-Z0-9]*?[a-z])(?=[-_a-zA-Z0-9]*?[0-9])[-_a-zA-Z0-9]{6,32}\Z/', $value)){
 546            if($msg!==null) return $msg;
 547            return 'Password must contain at least one upper case letter, one lower case letter and one digit. It must consists of 6 or more letters, digits, underscores and hyphens.';
 548        }
 549    }
 550
 551    /**
 552     * Validate email address
 553     *
 554     * @param string $value Value of data to be validated
 555     * @param string $msg Custom error message
 556     * @return string
 557     */
 558    public function testEmail($value, $msg=null){
 559		// Regex based on best solution from here: http://fightingforalostcause.net/misc/2006/compare-email-regex.php
 560        if(!preg_match('/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~\_]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i', $value) ||
 561            strpos($value, '--')!==False || strpos($value, '-.')!==False
 562        ){
 563            if($msg!==null) return $msg;
 564            return 'Invalid email format!';
 565        }
 566    }
 567
 568    /**
 569     * Validate a URL
 570     *
 571     * @param string $value Value of data to be validated
 572     * @param string $msg Custom error message
 573     * @return string
 574     */
 575    public function testUrl($value, $msg=null){
 576        if(!preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $value)){
 577            if($msg!==null) return $msg;
 578            return 'Invalid URL!';
 579        }
 580    }
 581
 582    /**
 583     * Validate an IP address (198.168.1.101)
 584     *
 585     * @param string $value Value of data to be validated
 586     * @param string $msg Custom error message
 587     * @return string
 588     */
 589    public function testIP($value, $msg=null){
 590        //198.168.1.101
 591        if (!preg_match('/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/',$value)) {
 592            if($msg!==null) return $msg;
 593            return 'Invalid IP address!';
 594        }
 595    }
 596
 597    /**
 598     * Validate a hostname as per RFC 952.
 599     *
 600     * @param string $value Value of data to be validated
 601     * @param string $msg Custom error message
 602     * @return string
 603     */
 604    public function testHostname($value, $msg=null){
 605        //198.168.1.101
 606        if (!preg_match('/^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)(([a-zA-Z0-9])([a-zA-Z0-9\-])*\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$/',$value)) {
 607            if($msg!==null) return $msg;
 608            return 'Invalid hostname!';
 609        }
 610    }
 611
 612    /**
 613     * Validate a credit card number
 614     *
 615     * @param string $value Value of data to be validated
 616     * @param string $msg Custom error message
 617     * @return string
 618     */
 619    public function testCreditCard($value, $msg=null){
 620        //568282246310632
 621        if (!preg_match('/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})$/', $value)) {
 622            if($msg!==null) return $msg;
 623            return 'Invalid credit card number!';
 624        }
 625    }
 626
 627    /**
 628     * Validate an American Express credit card number
 629     *
 630     * @param string $value Value of data to be validated
 631     * @param string $msg Custom error message
 632     * @return string
 633     */
 634    public function testCcAmericanExpress($value, $msg=null){
 635        if (!preg_match('/^3[47][0-9]{13}$/', $value)) {
 636            if($msg!==null) return $msg;
 637            return 'Invalid American Express credit card number!';
 638        }
 639    }
 640
 641    /**
 642     * Validate an Discover credit card number
 643     *
 644     * @param string $value Value of data to be validated
 645     * @param string $msg Custom error message
 646     * @return string
 647     */
 648    public function testCcDiscover($value, $msg=null){
 649        if (!preg_match('/^6011[0-9]{12}$/', $value)) {
 650            if($msg!==null) return $msg;
 651            return 'Invalid Discover credit card number!';
 652        }
 653    }
 654
 655    /**
 656     * Validate an Diners Club credit card number
 657     *
 658     * @param string $value Value of data to be validated
 659     * @param string $msg Custom error message
 660     * @return string
 661     */
 662    public function testCcDinersClub($value, $msg=null){
 663        if (!preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/', $value)) {
 664            if($msg!==null) return $msg;
 665            return 'Invalid Diners Club credit card number!';
 666        }
 667    }
 668
 669    /**
 670     * Validate an Master Card number
 671     *
 672     * @param string $value Value of data to be validated
 673     * @param string $msg Custom error message
 674     * @return string
 675     */
 676    public function testCcMasterCard($value, $msg=null){
 677        if (!preg_match('/^5[1-5][0-9]{14}$/', $value)) {
 678            if($msg!==null) return $msg;
 679            return 'Invalid Master Card number!';
 680        }
 681    }
 682
 683    /**
 684     * Validate an Visa Card number
 685     *
 686     * @param string $value Value of data to be validated
 687     * @param string $msg Custom error message
 688     * @return string
 689     */
 690    public function testCcVisa($value, $msg=null){
 691        if (!preg_match('/^4[0-9]{12}(?:[0-9]{3})?$/', $value)) {
 692            if($msg!==null) return $msg;
 693            return 'Invalid Visa card number!';
 694        }
 695    }
 696
 697    /**
 698     * Validate Color hex #ff0000
 699     *
 700     * @param string $value Value of data to be validated
 701     * @param string $msg Custom error message
 702     * @return string
 703     */
 704    public function testColorHex($value, $msg=null){
 705        //#ff0000
 706        if (!preg_match('/^#([0-9a-f]{1,2}){3}$/i', $value)) {
 707            if($msg!==null) return $msg;
 708            return 'Invalid color code!';
 709        }
 710    }
 711
 712    //------------------- Common data validation ---------------------
 713
 714    /**
 715     * Validate Date Time
 716     *
 717     * @param string $value Value of data to be validated
 718     * @param string $msg Custom error message
 719     * @return string
 720     */
 721    public function testDateTime($value, $msg=null){
 722        $rs = strtotime($value);
 723
 724        if ($rs===false || $rs===-1){
 725            if($msg!==null) return $msg;
 726            return 'Invalid date time format!';
 727        }
 728    }
 729
 730    /**
 731     * Validate Date format. Default yyyy/mm/dd.
 732     *
 733     * <p>Date format: yyyy-mm-dd, yyyy/mm/dd, yyyy.mm.dd
 734     * Date valid from 1900-01-01 through 2099-12-31</p>
 735     *
 736     * @param string $value Value of data to be validated
 737     * @param string $dateFormat Date format
 738     * @param string $msg Custom error message
 739     * @return string
 740     */
 741    public function testDate($value, $format='yyyy/mm/dd', $msg=null, $forceYearLength=false){
 742        //Date yyyy-mm-dd, yyyy/mm/dd, yyyy.mm.dd
 743        //1900-01-01 through 2099-12-31
 744
 745		$yearFormat = "(19|20)?[0-9]{2}";
 746		if ($forceYearLength == true) {
 747			if (strpos($format, 'yyyy') !== false) {
 748				$yearFormat = "(19|20)[0-9]{2}";
 749			} else {
 750				$yearFormat = "[0-9]{2}";
 751			}
 752		}
 753
 754        switch($format){
 755            case 'dd/mm/yy':
 756                $format = "/^\b(0?[1-9]|[12][0-9]|3[01])[- \/.](0?[1-9]|1[012])[- \/.]{$yearFormat}\b$/";
 757                break;
 758            case 'mm/dd/yy':
 759                $format = "/^\b(0?[1-9]|1[012])[- \/.](0?[1-9]|[12][0-9]|3[01])[- \/.]{$yearFormat}\b$/";
 760                break;
 761            case 'mm/dd/yyyy':
 762                $format = "/^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]{$yearFormat}$/";
 763                break;
 764            case 'dd/mm/yyyy':
 765                $format = "/^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]{$yearFormat}$/";
 766                break;
 767            case 'yy/mm/dd':
 768                $format = "/^\b{$yearFormat}[- \/.](0?[1-9]|1[012])[- \/.](0?[1-9]|[12][0-9]|3[01])\b$/";
 769                break;
 770            case 'yyyy/mm/dd':
 771            default:
 772                $format = "/^\b{$yearFormat}[- \/.](0?[1-9]|1[012])[- \/.](0?[1-9]|[12][0-9]|3[01])\b$/";
 773        }
 774
 775        if (!preg_match($format, $value)) {
 776            if($msg!==null) return $msg;
 777            return 'Invalid date format!';
 778        }
 779    }
 780
 781    /**
 782     * Validate if given date is between 2 dates.
 783     *
 784     * @param string $value Value of data to be validated
 785     * @param string $dateStart Starting date
 786     * @param string $dateEnd Ending date
 787     * @param string $msg Custom error message
 788     * @return string
 789     */
 790    public function testDateBetween($value, $dateStart, $dateEnd, $msg=null){
 791		$value = strtotime($value);
 792        if(!( $value > strtotime($dateStart) && $value < strtotime($dateEnd) ) ) {
 793            if($msg!==null) return $msg;
 794            return "Date must be between $dateStart and $dateEnd";
 795        }
 796    }
 797
 798    /**
 799     * Validate integer
 800     *
 801     * @param string $value Value of data to be validated
 802     * @param string $msg Custom error message
 803     * @return string
 804     */
 805    public function testInteger($value, $msg=null){
 806        if(intval($value)!=$value || strlen(intval($value))!=strlen($value)){
 807            if($msg!==null) return $msg;
 808            return 'Input is not an integer.';
 809        }
 810    }
 811
 812    /**
 813     * Validate price. 2 decimal points only
 814     *
 815     * @param string $value Value of data to be validated
 816     * @param string $msg Custom error message
 817     * @return string
 818     */
 819    public function testPrice($value, $msg=null){
 820        // 2 decimal
 821        if (!preg_match('/^[0-9]*\\.?[0-9]{0,2}$/', $value)){
 822            if($msg!==null) return $msg;
 823            return 'Input is not a valid price amount.';
 824        }
 825    }
 826
 827    /**
 828     * Validate float value.
 829     *
 830     * @param string $value Value of data to be validated
 831     * @param int $decimal Number of Decimal points
 832     * @param string $msg Custom error message
 833     * @return string
 834     */
 835    public function testFloat($value, $decimal='', $msg=null){
 836        // any amount of decimal
 837        if (!preg_match('/^[-]?[0-9]*\\.?[0-9]{0,'.$decimal.'}$/', $value)){
 838            if($msg!==null) return $msg;
 839            return 'Input is not a valid float value.';
 840        }
 841    }
 842
 843    /**
 844     * Validate digits.
 845     *
 846     * @param string $value Value of data to be validated
 847     * @param string $msg Custom error message
 848     * @return string
 849     */
 850    public function testDigit($value, $msg=null){
 851        if(!ctype_digit($value)){
 852            if($msg!==null) return $msg;
 853            return 'Input is not a digit.';
 854        }
 855    }
 856
 857    /**
 858     * Validate Alpha numeric values.
 859     *
 860     * Input string can only consist of only Letters or Digits.
 861     *
 862     * @param string $value Value of data to be validated
 863     * @param string $msg Custom error message
 864     * @return string
 865     */
 866    public function testAlphaNumeric($value, $msg=null){
 867        if(!ctype_alnum($value)){
 868            if($msg!==null) return $msg;
 869            return 'Input can only consist of letters or digits.';
 870        }
 871    }
 872
 873    /**
 874     * Validate Alpha values.
 875     *
 876     * Input string can only consist of only Letters.
 877     *
 878     * @param string $value Value of data to be validated
 879     * @param string $msg Custom error message
 880     * @return string
 881     */
 882    public function testAlpha($value, $msg=null){
 883        if(!ctype_alpha($value)){
 884            if($msg!==null) return $msg;
 885            return 'Input can only consist of letters.';
 886        }
 887    }
 888
 889    /**
 890     * Validate if string only consist of letters and spaces
 891     *
 892     * Input string can only consist of only Letters and spaces.
 893     *
 894     * @param string $value Value of data to be validated
 895     * @param string $msg Custom error message
 896     * @return string
 897     */
 898    public function testAlphaSpace($value, $msg=null){
 899        if(!ctype_alpha(str_replace(' ','',$value))){
 900            if($msg!==null) return $msg;
 901            return 'Input can only consist of letters and spaces.';
 902        }
 903    }
 904
 905
 906    /**
 907     * Validate lowercase string.
 908     *
 909     * Input string can only be lowercase letters.
 910     *
 911     * @param string $value Value of data to be validated
 912     * @param string $msg Custom error message
 913     * @return string
 914     */
 915    public function testLowercase($value, $msg=null){
 916        if(!ctype_lower($value)){
 917            if($msg!==null) return $msg;
 918            return 'Input can only consists of lowercase letters.';
 919        }
 920    }
 921
 922    /**
 923     * Validate uppercase string.
 924     *
 925     * Input string can only be uppercase letters.
 926     *
 927     * @param string $value Value of data to be validated
 928     * @param string $msg Custom error message
 929     * @return string
 930     */
 931    public function testUppercase($value, $msg=null){
 932        if(!ctype_upper($value)){
 933            if($msg!==null) return $msg;
 934            return 'Input can only consists of uppercase letters.';
 935        }
 936    }
 937
 938    /**
 939     * Validate Not Empty. Input cannot be empty.
 940     *
 941     * @param string $value Value of data to be validated
 942     * @param string $msg Custom error message
 943     * @return string
 944     */
 945    public function testNotEmpty($value, $msg=null){
 946        if(empty($value)){
 947            if($msg!==null) return $msg;
 948            return 'Value cannot be empty!';
 949        }
 950    }
 951
 952    /**
 953     * Validate Max length of a string.
 954     *
 955     * @param string $value Value of data to be validated
 956     * @param int $length Maximum length of the string
 957     * @param string $msg Custom error message
 958     * @return string
 959     */
 960    public function testMaxLength($value, $length=0, $msg=null){
 961        if(mb_strlen($value) > $length){
 962            if($msg!==null) return $msg;
 963            return "Input cannot be longer than $length characters.";
 964        }
 965    }
 966
 967    /**
 968     * Validate Minimum length of a string.
 969     *
 970     * @param string $value Value of data to be validated
 971     * @param int $length Minimum length of the string
 972     * @param string $msg Custom error message
 973     * @return string
 974     */
 975    public function testMinLength($value, $length=0, $msg=null){
 976        if(strlen($value) < $length){
 977            if($msg!==null) return $msg;
 978            return "Input cannot be shorter than $length characters.";
 979        }
 980    }
 981
 982    /**
 983     * Validate Not Null. Value cannot be null.
 984     *
 985     * @param string $value Value of data to be validated
 986     * @param string $msg Custom error message
 987     * @return string
 988     */
 989    public function testNotNull($value, $msg=null){
 990        if(is_null($value)){
 991            if($msg!==null) return $msg;
 992            return 'Value cannot be null.';
 993        }
 994    }
 995
 996    /**
 997     * Validate Minimum value of a number.
 998     *
 999     * @param string $value Value of data to be validated
1000     * @param int $min Minimum value
1001     * @param string $msg Custom error message
1002     * @return string
1003     */
1004    public function testMin($value, $min, $msg=null){
1005        if( $value < $min){
1006            if($msg!==null) return $msg;
1007            return "Value cannot be less than $min";
1008        }
1009    }
1010
1011    /**
1012     * Validate Maximum value of a number.
1013     *
1014     * @param string $value Value of data to be validated
1015     * @param int $max Maximum value
1016     * @param string $msg Custom error message
1017     * @return string
1018     */
1019    public function testMax($value, $max, $msg=null){
1020        if( $value > $max){
1021            if($msg!==null) return $msg;
1022            return "Value cannot be more than $max";
1023        }
1024    }
1025
1026    /**
1027     * Validate if a value is Between 2 values (inclusive)
1028     *
1029     * @param string $value Value of data to be validated
1030     * @param int $min Minimum value
1031     * @param int $max Maximum value
1032     * @param string $msg Custom error message
1033     * @return string
1034     */
1035    public function testBetweenInclusive($value, $min, $max, $msg=null){
1036        if( $value < $min || $value > $max ){
1037            if($msg!==null) return $msg;
1038            return "Value must be between $min and $max inclusively.";
1039        }
1040    }
1041
1042    /**
1043     * Validate if a value is Between 2 values
1044     *
1045     * @param string $value Value of data to be validated
1046     * @param int $min Minimum value
1047     * @param int $max Maximum value
1048     * @param string $msg Custom error message
1049     * @return string
1050     */
1051    public function testBetween($value, $min, $max, $msg=null){
1052        if( $value < $min+1 || $value > $max-1 ){
1053            if($msg!==null) return $msg;
1054            return "Value must be between $min and $max.";
1055        }
1056    }
1057
1058    /**
1059     * Validate if a value is greater than a number
1060     *
1061     * @param string $value Value of data to be validated
1062     * @param int $number Number to be compared
1063     * @param string $msg Custom error message
1064     * @return string
1065     */
1066    public function testGreaterThan($value, $number, $msg=null){
1067        if( !($value > $number)){
1068            if($msg!==null) return $msg;
1069            return "Value must be greater than $number.";
1070        }
1071    }
1072
1073    /**
1074     * Validate if a value is greater than or equal to a number
1075     *
1076     * @param string $value Value of data to be validated
1077     * @param int $number Number to be compared
1078     * @param string $msg Custom error message
1079     * @return string
1080     */
1081    public function testGreaterThanOrEqual($value, $number, $msg=null){
1082        if( !($value >= $number)){
1083            if($msg!==null) return $msg;
1084            return "Value must be greater than or equal to $number.";
1085        }
1086    }
1087
1088    /**
1089     * Validate if a value is less than a number
1090     *
1091     * @param string $value Value of data to be validated
1092     * @param int $number Number to be compared
1093     * @param string $msg Custom error message
1094     * @return string
1095     */
1096    public function testLessThan($value, $number, $msg=null){
1097        if( !($value < $number)){
1098            if($msg!==null) return $msg;
1099            return "Value must be less than $number.";
1100        }
1101    }
1102
1103    /**
1104     * Validate if a value is less than or equal to a number
1105     *
1106     * @param string $value Value of data to be validated
1107     * @param int $number Number to be compared
1108     * @param string $msg Custom error message
1109     * @return string
1110     */
1111    public function testLessThanOrEqual($value, $number, $msg=null){
1112        if( !($value <= $number)){
1113            if($msg!==null) return $msg;
1114            return "Value must be less than $number.";
1115        }
1116    }
1117
1118    /**
1119     * Validate if a value is equal to a number
1120     *
1121     * @param string $value Value of data to be validated
1122     * @param int $equalValue Number to be compared
1123     * @param string $msg Custom error message
1124     * @return string
1125     */
1126    public function testEqual($value, $equalValue, $msg=null){
1127        if(!($value==$equalValue && strlen($value)==strlen($equalValue))){
1128            if($msg!==null) return $msg;
1129            return 'Both values must be the same.';
1130        }
1131    }
1132
1133    /**
1134     * Validate if a value is Not equal to a number
1135     *
1136     * @param string $value Value of data to be validated
1137     * @param int $equalValue Number to be compared
1138     * @param string $msg Custom error message
1139     * @return string
1140     */
1141    public function testNotEqual($value, $equalValue, $msg=null){
1142        if( $value==$equalValue && strlen($value)==strlen($equalValue) ){
1143            if($msg!==null) return $msg;
1144            return 'Both values must be different.';
1145        }
1146    }
1147
1148   /**
1149    * Validate if value Exists in database
1150    *
1151    * @param string $value Value of data to be validated
1152    * @param string $table Name of the table in DB
1153    * @param string $field Name of field you want to check
1154    * @return string
1155    */
1156    public function testDbExist($value, $table, $field, $msg=null) {
1157        $result = Doo::db()->fetchRow("SELECT COUNT($field) AS count FROM " . $table . ' WHERE '.$field.' = ? LIMIT 1', array($value));
1158        if ((!isset($result['count'])) || ($result['count'] < 1)) {
1159            if($msg!==null) return $msg;
1160            return 'Value does not exist in database.';
1161        }
1162    }
1163
1164   /**
1165    * Validate if value does Not Exist in database
1166    *
1167    * @param string $value Value of data to be validated
1168    * @param string $table Name of the table in DB
1169    * @param string $field Name of field you want to check
1170    * @return string
1171    */
1172    public function testDbNotExist($value, $table, $field, $msg=null) {
1173        $result = Doo::db()->fetchRow("SELECT COUNT($field) AS count FROM " . $table . ' WHERE '.$field.' = ? LIMIT 1', array($value));
1174        if ((isset($result['count'])) && ($result['count'] > 0)) {
1175            if($msg!==null) return $msg;
1176            return 'Same value exists in database.';
1177        }
1178    }
1179
1180
1181
1182    /**
1183     * Validate if a value is in a list of values
1184     *
1185     * @param string $value Value of data to be validated
1186     * @param int $equalValue List of values to be checked
1187     * @param string $msg Custom error message
1188     * @return string
1189     */
1190    public function testInList($value, $valueList, $msg=null){
1191        if(!(in_array($value, $valueList))){
1192            if($msg!==null) return $msg;
1193            return 'Unmatched value.';
1194        }
1195    }
1196
1197    /**
1198     * Validate if a value is NOT in a list of values
1199     *
1200     * @param string $value Value of data to be validated
1201     * @param int $equalValue List of values to be checked
1202     * @param string $msg Custom error message
1203     * @return string
1204     */
1205    public function testNotInList($value, $valueList, $msg=null){
1206        if(in_array($value, $valueList)){
1207            if($msg!==null) return $msg;
1208            return 'Unmatched value.';
1209        }
1210    }
1211
1212	/**
1213	* Validate field if it is equal with some other field from $_GET or $_POST method
1214	* This method is used for validating form
1215	*
1216	* @param string $value Value of data to be validated
1217	* @param string $method Method (get or post), default $_POST
1218	* @param string $field Name of field that you want to check
1219	* @return string
1220	*/
1221
1222	public function testEqualAs($value, $method, $field, $msg=null) {
1223		if ($method == "get") {
1224		  $method = $_GET;
1225		} else if ($method == "post") {
1226		  $method = $_POST;
1227		} else {
1228		  $method = $_POST;
1229		}
1230		if (!isset($method[$field]) || $value != $method[$field]) {
1231		    if($msg!==null) return $msg;
1232            return 'Value '.$value.' is not equal with "'.$field.'".';
1233		}
1234	}
1235
1236}