├── README.md ├── README.txt ├── Validator.php ├── Validator └── Exception.php └── tests ├── ValidatorTest.php └── phpunit.xml /README.md: -------------------------------------------------------------------------------- 1 | # A PHP 5.3 Class for Easy Form Validation 2 | 3 | This class follows Zend Framework naming conventions for easy drop-in as a substitute to Zend_Validation. 4 | If you opt out of using the bulky Zend_Form on your projects, you might choose to use this for quick and painless 5 | form validation. 6 | 7 | ## A Quick Example 8 | 9 | The example below shows how to throw validation exceptions with the custom 10 | exception. You can then retrieve the error messages from the calling method. 11 | It is not good practice to validate your data in your controller, this should 12 | be handled in your Model. This is just a quick example. 13 | 14 | ```php 15 | _validate($_POST); 31 | 32 | // validation passed because no exception was thrown 33 | // ... to something with the $validData ... 34 | 35 | } catch (Validator_Exception $e) { 36 | // retrieve the overall error message to display 37 | $message = $e->getMessage(); 38 | 39 | // retrieve all of the errors 40 | $errors = $e->getErrors(); 41 | 42 | // the below code is specific to ZF 43 | $this->_helper->FlashMessenger(array('error' => $message)); 44 | $this->_helper->layout->getView()->errors = $errors; 45 | } 46 | } 47 | 48 | /** 49 | * Your user-defined validation handling. The exception section is 50 | * very important and should always be used. 51 | * 52 | * @access private 53 | * @param array $post 54 | * @return mixed 55 | */ 56 | private function _validate(array $post = array()) 57 | { 58 | $validator = new Validator($post); 59 | $validator 60 | ->required('You must supply a name.') 61 | ->validate('name', 'Name'); 62 | $validator 63 | ->required('You must supply an email address.') 64 | ->email('You must supply a valid email address') 65 | ->validate('email', 'Email'); 66 | 67 | // check for errors 68 | if ($validator->hasErrors()) { 69 | throw new Validator_Exception( 70 | 'There were errors in your form.', 71 | $validator->getAllErrors() 72 | ); 73 | } 74 | 75 | return $validator->getValidData(); 76 | } 77 | 78 | } 79 | ``` 80 | 81 | ## Available Validation Methods 82 | 83 | * required($message = null) - The field value is required. 84 | * email($message = null) - The field value must be a valid email address string. 85 | * float($message = null) - The field value must be a float. 86 | * integer($message = null) - The field value must be an integer. 87 | * digits($message = null) - The field value must be a digit (integer with no upper bounds). 88 | * min($limit, $include = TRUE, $message = null) - The field value must be greater than $limit (numeric). $include defines if the value can be equal to the limit. 89 | * max($limit, $include = TRUE, $message = null) - The field value must be less than $limit (numeric). $include defines if the value can be equal to the limit. 90 | * between($min, $max, $include = TRUE, $message = null) - The field value must be between $min and $max (numeric). $include defines if the value can be equal to $min and $max. 91 | * minLength($length, $message = null) - The field value must be greater than or equal to $length characters. 92 | * maxLength($length, $message = null) - The field value must be less than or equal to $length characters. 93 | * length($length, $message = null) - The field must be $length characters long. 94 | * matches($field, $label, $message = null) - One field matches another one (i.e. password matching) 95 | * notMatches($field, $label, $message = null) - The field value must not match the value of $field. 96 | * startsWith($sub, $message = null) - The field must start with $sub as a string. 97 | * notStartsWith($sub, $message = null) - The field must not start with $sub as a string. 98 | * endsWith($sub, $message = null) - THe field must end with $sub as a string. 99 | * notEndsWith($sub, $message = null) - The field must not end with $sub as a string. 100 | * ip($message = null) - The field value is a valid IP, determined using filter_var. 101 | * url($message = null) - The field value is a valid URL, determined using filter_var. 102 | * date($message = null) - The field value is a valid date, can be of any format accepted by DateTime() 103 | * minDate($date, $format, $message = null) - The date must be greater than $date. $format must be of a format on the page http://php.net/manual/en/datetime.createfromformat.php 104 | * maxDate($date, $format, $message = null) - The date must be less than $date. $format must be of a format on the page http://php.net/manual/en/datetime.createfromformat.php 105 | * ccnum($message = null) - The field value must be a valid credit card number. 106 | * oneOf($allowed, $message = null) - The field value must be one of the $allowed values. $allowed can be either an array or a comma-separated list of values. If comma separated, do not include spaces unless intended for matching. 107 | * callback($callback, $message = '', $params = array()) - Define your own custom callback validation function. $callback must pass an is_callable() check. $params can be any value, or an array if multiple parameters must be passed. 108 | 109 | ### Callback Examples 110 | 111 | Callback functions can be passed as strings or closures. 112 | 113 | // numeric example 114 | $validadator 115 | ->callback('is_numeric', 'Field is not numeric.') 116 | ->validate('number_field'); 117 | 118 | // closure example 119 | $validator 120 | ->callback(function($val) { 121 | return $val < -1 || $val > 1; 122 | }, 'Number must be less than -1 or greater than 1.') 123 | ->validate('number_field_2'); 124 | 125 | ## Validating Arrays and Array Indices 126 | 127 | This validation class has been extended to allow for validation of arrays as well as nested indices of a multi-dimensional array. 128 | 129 | ### Validating Specific Indices 130 | 131 | To validate specific indices of an array, use dot notation, i.e. 132 | 133 | ```php 134 | required('The nested field is required.') 141 | ->validate('field.nested'); 142 | 143 | // ensure we have the first two numeric indices of $_POST['links'][] 144 | $validator 145 | ->required('This field is required') 146 | ->validate('links.0'); 147 | $validator 148 | ->required('This field is required') 149 | ->validate('links.1'); 150 | ``` 151 | 152 | # Available Pre-Validation Filtering 153 | 154 | You can apply pre-validation filters to your data (i.e. trim, strip_tags, htmlentities). These filters can also 155 | be custom defined so long as they pass an is_callable() check. 156 | 157 | * filter($callback) 158 | 159 | ### Filter Examples 160 | 161 | ```php 162 | // standard php filter for valid user ids. 163 | $validator 164 | ->filter('intval') 165 | ->min(1) 166 | ->validate('user_id'); 167 | 168 | // custom filter 169 | $validator 170 | ->filter(function($val) { 171 | // bogus formatting of the field 172 | $val = rtrim($val, '/'); 173 | $val .= '_custom_formatted'; 174 | return $val; 175 | }) 176 | ->validate('field_to_be_formatted'); 177 | ``` 178 | 179 | # Credits 180 | 181 | * Modifications by Corey Ballou, Chris Gutierrez, and Robert Fruchtman. 182 | * Forked from Tasos Bekos which was based on the initial work of "Bretticus". 183 | * See http://brettic.us/2010/06/18/form-validation-class-using-php-5-3/ for the original. 184 | 185 | # License 186 | 187 | Copyright (c) 2012 http://github.com/bekos, http://github.com/blackbe.lt 188 | 189 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 190 | 191 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 192 | 193 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 194 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | # A PHP 5.3 Class for Easy Form Validation 2 | 3 | ## Available Pre-Validation Filtering 4 | 5 | You can apply pre-validation filters to your data (i.e. trim, strip_tags, htmlentities). These filters can also 6 | be custom defined so long as they pass an is_callable() check. 7 | 8 | * filter($callback) 9 | 10 | ## Filter Examples 11 | 12 | 13 | // standard php filter for valid user ids. 14 | $validator 15 | ->filter('intval') 16 | ->min(1) 17 | ->validate('user_id'); 18 | 19 | // custom filter 20 | $validator 21 | ->filter(function($val) { 22 | // bogus formatting of the field 23 | $val = rtrim($val, '/'); 24 | $val .= '_custom_formatted'; 25 | return $val; 26 | }) 27 | ->validate('field_to_be_formatted'); 28 | 29 | 30 | ## Available Validation Methods 31 | 32 | * required($message = null) - The field value is required. 33 | * email($message = null) - The field value must be a valid email address string. 34 | * float($message = null) - The field value must be a float. 35 | * integer($message = null) - The field value must be an integer. 36 | * digits($message = null) - The field value must be a digit (integer with no upper bounds). 37 | * min($limit, $include = TRUE, $message = null) - The field value must be greater than $limit (numeric). $include defines if the value can be equal to the limit. 38 | * max($limit, $include = TRUE, $message = null) - The field value must be less than $limit (numeric). $include defines if the value can be equal to the limit. 39 | * between($min, $max, $include = TRUE, $message = null) - The field value must be between $min and $max (numeric). $include defines if the value can be equal to $min and $max. 40 | * minLength($length, $message = null) - The field value must be greater than or equal to $length characters. 41 | * maxLength($length, $message = null) - The field value must be less than or equal to $length characters. 42 | * length($length, $message = null) - The field must be $length characters long. 43 | * matches($field, $label, $message = null) - One field matches another one (i.e. password matching) 44 | * notMatches($field, $label, $message = null) - The field value must not match the value of $field. 45 | * startsWith($sub, $message = null) - The field must start with $sub as a string. 46 | * notStartsWith($sub, $message = null) - The field must not start with $sub as a string. 47 | * endsWith($sub, $message = null) - THe field must end with $sub as a string. 48 | * notEndsWith($sub, $message = null) - The field must not end with $sub as a string. 49 | * ip($message = null) - The field value is a valid IP, determined using filter_var. 50 | * url($message = null) - The field value is a valid URL, determined using filter_var. 51 | * date($message = null) - The field value is a valid date, can be of any format accepted by DateTime() 52 | * minDate($date, $format, $message = null) - The date must be greater than $date. $format must be of a format on the page http://php.net/manual/en/datetime.createfromformat.php 53 | * maxDate($date, $format, $message = null) - The date must be less than $date. $format must be of a format on the page http://php.net/manual/en/datetime.createfromformat.php 54 | * ccnum($message = null) - The field value must be a valid credit card number. 55 | * oneOf($allowed, $message = null) - The field value must be one of the $allowed values. $allowed can be either an array or a comma-separated list of values. If comma separated, do not include spaces unless intended for matching. 56 | * callback($callback, $message = '', $params = null) - Define your own custom callback validation function. $callback must pass an is_callable() check. $params can be any value, or an array if multiple parameters must be passed. 57 | 58 | ### Callback Examples 59 | 60 | Callback functions can be passed as strings or closures. 61 | 62 | 63 | // numeric example 64 | $validadator 65 | ->callback('is_numeric', 'Field is not numeric.') 66 | ->validate('number_field'); 67 | 68 | // closure example 69 | $validator 70 | ->callback(function($val) { 71 | return $val < -1 || $val > 1; 72 | }, 'Number must be less than -1 or greater than 1.') 73 | ->validate('number_field_2'); 74 | 75 | 76 | ## Validating Arrays and Array Indices 77 | 78 | This validation class has been extended to allow for validation of arrays as well as nested indices of a multi-dimensional array. 79 | 80 | ### Validating Specific Indices 81 | 82 | To validate specific indices of an array, use dot notation, i.e. 83 | 84 | 85 | // load the validator 86 | $validator = new Blackbelt_Validator($_POST); 87 | 88 | // ensure $_POST['field']['nested'] exists 89 | $validator 90 | ->required('The nested field is required.') 91 | ->validate('field.nested'); 92 | 93 | // ensure we have the first two numeric indices of $_POST['links'][] 94 | $validator 95 | ->required('This field is required') 96 | ->validate('links.0'); 97 | $validator 98 | ->required('This field is required') 99 | ->validate('links.1'); 100 | 101 | 102 | ## Credits 103 | 104 | * Modifications by Corey Ballou, Chris Gutierrez, and Robert Fruchtman. 105 | * Forked from Tasos Bekos which was based on the initial work of "Bretticus". 106 | * See http://brettic.us/2010/06/18/form-validation-class-using-php-5-3/ for the original. 107 | -------------------------------------------------------------------------------- /Validator.php: -------------------------------------------------------------------------------- 1 | 7 | * @author Chris Gutierrez 8 | * @author Corey Ballou 9 | * @see https://github.com/blackbelt/php-validation 10 | * @see Based on idea: http://brettic.us/2010/06/18/form-validation-class-using-php-5-3/ 11 | */ 12 | class Validator { 13 | 14 | protected $messages = array(); 15 | protected $errors = array(); 16 | protected $rules = array(); 17 | protected $fields = array(); 18 | protected $functions = array(); 19 | protected $arguments = array(); 20 | protected $filters = array(); 21 | protected $data = null; 22 | protected $validData = array(); 23 | 24 | /** 25 | * Constructor. 26 | * Define values to validate. 27 | * 28 | * @param array $data 29 | */ 30 | function __construct(array $data = null) { 31 | if (!empty($data)) $this->setData($data); 32 | } 33 | 34 | /** 35 | * set the data to be validated 36 | * 37 | * @access public 38 | * @param mixed $data 39 | * @return FormValidator 40 | */ 41 | public function setData(array $data) { 42 | $this->data = $data; 43 | return $this; 44 | } 45 | 46 | // ----------------- ADD NEW RULE FUNCTIONS BELOW THIS LINE ---------------- 47 | 48 | /** 49 | * Field, if completed, has to be a valid email address. 50 | * 51 | * @param string $message 52 | * @return FormValidator 53 | */ 54 | public function email($message = null) { 55 | $this->setRule(__FUNCTION__, function($email) { 56 | if (strlen($email) == 0) return true; 57 | $isValid = true; 58 | $atIndex = strrpos($email, '@'); 59 | if (is_bool($atIndex) && !$atIndex) { 60 | $isValid = false; 61 | } else { 62 | $domain = substr($email, $atIndex+1); 63 | $local = substr($email, 0, $atIndex); 64 | $localLen = strlen($local); 65 | $domainLen = strlen($domain); 66 | if ($localLen < 1 || $localLen > 64) { 67 | $isValid = false; 68 | } else if ($domainLen < 1 || $domainLen > 255) { 69 | // domain part length exceeded 70 | $isValid = false; 71 | } else if ($local[0] == '.' || $local[$localLen-1] == '.') { 72 | // local part starts or ends with '.' 73 | $isValid = false; 74 | } else if (preg_match('/\\.\\./', $local)) { 75 | // local part has two consecutive dots 76 | $isValid = false; 77 | } else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) { 78 | // character not valid in domain part 79 | $isValid = false; 80 | } else if (preg_match('/\\.\\./', $domain)) { 81 | // domain part has two consecutive dots 82 | $isValid = false; 83 | } else if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\","",$local))) { 84 | // character not valid in local part unless 85 | // local part is quoted 86 | if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\","",$local))) { 87 | $isValid = false; 88 | } 89 | } 90 | // check DNS 91 | if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A"))) { 92 | $isValid = false; 93 | } 94 | } 95 | return $isValid; 96 | }, $message); 97 | return $this; 98 | } 99 | 100 | /** 101 | * Field must be filled in. 102 | * 103 | * @param string $message 104 | * @return FormValidator 105 | */ 106 | public function required($message = null) { 107 | $this->setRule(__FUNCTION__, function($val) { 108 | if (is_scalar($val)) { 109 | $val = trim($val); 110 | } 111 | return !empty($val); 112 | }, $message); 113 | return $this; 114 | } 115 | 116 | /** 117 | * Field must contain a valid float value. 118 | * 119 | * @param string $message 120 | * @return FormValidator 121 | */ 122 | public function float($message = null) { 123 | $this->setRule(__FUNCTION__, function($val) { 124 | return !(filter_var($val, FILTER_VALIDATE_FLOAT) === FALSE); 125 | }, $message); 126 | return $this; 127 | } 128 | 129 | /** 130 | * Field must contain a valid integer value. 131 | * 132 | * @param string $message 133 | * @return FormValidator 134 | */ 135 | public function integer($message = null) { 136 | $this->setRule(__FUNCTION__, function($val) { 137 | return !(filter_var($val, FILTER_VALIDATE_INT) === FALSE); 138 | }, $message); 139 | return $this; 140 | } 141 | 142 | /** 143 | * Every character in field, if completed, must be a digit. 144 | * This is just like integer(), except there is no upper limit. 145 | * 146 | * @param string $message 147 | * @return FormValidator 148 | */ 149 | public function digits($message = null) { 150 | $this->setRule(__FUNCTION__, function($val) { 151 | return (strlen($val) === 0 || ctype_digit((string) $val)); 152 | }, $message); 153 | return $this; 154 | } 155 | 156 | /** 157 | * Field must be a number greater than [or equal to] X. 158 | * 159 | * @param numeric $limit 160 | * @param bool $include Whether to include limit value. 161 | * @param string $message 162 | * @return FormValidator 163 | */ 164 | public function min($limit, $include = TRUE, $message = null) { 165 | $this->setRule(__FUNCTION__, function($val, $args) { 166 | if (strlen($val) === 0) { 167 | return TRUE; 168 | } 169 | 170 | $val = (float) $val; 171 | $limit = (float) $args[0]; 172 | $inc = (bool) $args[1]; 173 | 174 | return ($val > $limit || ($inc === TRUE && $val === $limit)); 175 | }, $message, array($limit, $include)); 176 | return $this; 177 | } 178 | 179 | /** 180 | * Field must be a number greater than [or equal to] X. 181 | * 182 | * @param numeric $limit 183 | * @param bool $include Whether to include limit value. 184 | * @param string $message 185 | * @return FormValidator 186 | */ 187 | public function max($limit, $include = TRUE, $message = null) { 188 | $this->setRule(__FUNCTION__, function($val, $args) { 189 | if (strlen($val) === 0) { 190 | return TRUE; 191 | } 192 | 193 | $val = (float) $val; 194 | $limit = (float) $args[0]; 195 | $inc = (bool) $args[1]; 196 | 197 | return ($val < $limit || ($inc === TRUE && $val === $limit)); 198 | }, $message, array($limit, $include)); 199 | return $this; 200 | } 201 | 202 | /** 203 | * Field must be a number between X and Y. 204 | * 205 | * @param numeric $min 206 | * @param numeric $max 207 | * @param bool $include Whether to include limit value. 208 | * @param string $message 209 | * @return FormValidator 210 | */ 211 | public function between($min, $max, $include = TRUE, $message = null) { 212 | $message = $this->_getDefaultMessage(__FUNCTION__, array($min, $max, $include)); 213 | 214 | $this->min($min, $include, $message)->max($max, $include, $message); 215 | return $this; 216 | } 217 | 218 | /** 219 | * Field has to be greater than or equal to X characters long. 220 | * 221 | * @param int $len 222 | * @param string $message 223 | * @return FormValidator 224 | */ 225 | public function minlength($len, $message = null) { 226 | $this->setRule(__FUNCTION__, function($val, $args) { 227 | return !(strlen(trim($val)) < $args[0]); 228 | }, $message, array($len)); 229 | return $this; 230 | } 231 | 232 | /** 233 | * Field has to be less than or equal to X characters long. 234 | * 235 | * @param int $len 236 | * @param string $message 237 | * @return FormValidator 238 | */ 239 | public function maxlength($len, $message = null) { 240 | $this->setRule(__FUNCTION__, function($val, $args) { 241 | return !(strlen(trim($val)) > $args[0]); 242 | }, $message, array($len)); 243 | return $this; 244 | } 245 | 246 | /** 247 | * Field has to be between minlength and maxlength characters long. 248 | * 249 | * @param int $minlength 250 | * @param int $maxlength 251 | * @ 252 | */ 253 | public function betweenlength($minlength, $maxlength, $message = null) { 254 | $message = empty($message) ? self::getDefaultMessage(__FUNCTION__, array($minlength, $maxlength)) : NULL; 255 | 256 | $this->minlength($minlength, $message)->max($maxlength, $message); 257 | return $this; 258 | } 259 | 260 | /** 261 | * Field has to be X characters long. 262 | * 263 | * @param int $len 264 | * @param string $message 265 | * @return FormValidator 266 | */ 267 | public function length($len, $message = null) { 268 | $this->setRule(__FUNCTION__, function($val, $args) { 269 | return (strlen(trim($val)) == $args[0]); 270 | }, $message, array($len)); 271 | return $this; 272 | } 273 | 274 | /** 275 | * Field is the same as another one (password comparison etc). 276 | * 277 | * @param string $field 278 | * @param string $label 279 | * @param string $message 280 | * @return FormValidator 281 | */ 282 | public function matches($field, $label, $message = null) { 283 | $this->setRule(__FUNCTION__, function($val, $args) { 284 | return ((string) $args[0] == (string) $val); 285 | }, $message, array($this->_getVal($field), $label)); 286 | return $this; 287 | } 288 | 289 | /** 290 | * Field is different from another one. 291 | * 292 | * @param string $field 293 | * @param string $label 294 | * @param string $message 295 | * @return FormValidator 296 | */ 297 | public function notmatches($field, $label, $message = null) { 298 | $this->setRule(__FUNCTION__, function($val, $args) { 299 | return ((string) $args[0] != (string) $val); 300 | }, $message, array($this->_getVal($field), $label)); 301 | return $this; 302 | } 303 | 304 | /** 305 | * Field must start with a specific substring. 306 | * 307 | * @param string $sub 308 | * @param string $message 309 | * @return FormValidator 310 | */ 311 | public function startsWith($sub, $message = null) { 312 | $this->setRule(__FUNCTION__, function($val, $args) { 313 | $sub = $args[0]; 314 | return (strlen($val) === 0 || substr($val, 0, strlen($sub)) === $sub); 315 | }, $message, array($sub)); 316 | return $this; 317 | } 318 | 319 | /** 320 | * Field must NOT start with a specific substring. 321 | * 322 | * @param string $sub 323 | * @param string $message 324 | * @return FormValidator 325 | */ 326 | public function notstartsWith($sub, $message = null) { 327 | $this->setRule(__FUNCTION__, function($val, $args) { 328 | $sub = $args[0]; 329 | return (strlen($val) === 0 || substr($val, 0, strlen($sub)) !== $sub); 330 | }, $message, array($sub)); 331 | return $this; 332 | } 333 | 334 | /** 335 | * Field must end with a specific substring. 336 | * 337 | * @param string $sub 338 | * @param string $message 339 | * @return FormValidator 340 | */ 341 | public function endsWith($sub, $message = null) { 342 | $this->setRule(__FUNCTION__, function($val, $args) { 343 | $sub = $args[0]; 344 | return (strlen($val) === 0 || substr($val, -strlen($sub)) === $sub); 345 | }, $message, array($sub)); 346 | return $this; 347 | } 348 | 349 | /** 350 | * Field must not end with a specific substring. 351 | * 352 | * @param string $sub 353 | * @param string $message 354 | * @return FormValidator 355 | */ 356 | public function notendsWith($sub, $message = null) { 357 | $this->setRule(__FUNCTION__, function($val, $args) { 358 | $sub = $args[0]; 359 | return (strlen($val) === 0 || substr($val, -strlen($sub)) !== $sub); 360 | }, $message, array($sub)); 361 | return $this; 362 | } 363 | 364 | /** 365 | * Field has to be valid IP address. 366 | * 367 | * @param string $message 368 | * @return FormValidator 369 | */ 370 | public function ip($message = null) { 371 | $this->setRule(__FUNCTION__, function($val) { 372 | return (strlen(trim($val)) === 0 || filter_var($val, FILTER_VALIDATE_IP) !== FALSE); 373 | }, $message); 374 | return $this; 375 | } 376 | 377 | /** 378 | * Field has to be valid internet address. 379 | * 380 | * @param string $message 381 | * @return FormValidator 382 | */ 383 | public function url($message = null) { 384 | $this->setRule(__FUNCTION__, function($val) { 385 | return (strlen(trim($val)) === 0 || filter_var($val, FILTER_VALIDATE_URL) !== FALSE); 386 | }, $message); 387 | return $this; 388 | } 389 | 390 | /** 391 | * Date format. 392 | * 393 | * @return string 394 | */ 395 | protected function _getDefaultDateFormat() { 396 | return 'd/m/Y'; 397 | } 398 | 399 | /** 400 | * Field has to be a valid date. 401 | * 402 | * @param string $message 403 | * @return FormValidator 404 | */ 405 | public function date($message = null) { 406 | $this->setRule(__FUNCTION__, function($val, $args) { 407 | 408 | if (strlen(trim($val)) === 0) { 409 | return TRUE; 410 | } 411 | 412 | try { 413 | $dt = new DateTime($val, new DateTimeZone("UTC")); 414 | return true; 415 | } catch(Exception $e) { 416 | return false; 417 | } 418 | 419 | }, $message, array($format, $separator)); 420 | return $this; 421 | } 422 | 423 | /** 424 | * Field has to be a date later than or equal to X. 425 | * 426 | * @param string|int $date Limit date 427 | * @param string $format Date format 428 | * @param string $message 429 | * @return FormValidator 430 | */ 431 | public function minDate($date = 0, $format = null, $message = null) { 432 | if (empty($format)) { 433 | $format = $this->_getDefaultDateFormat(); 434 | } 435 | if (is_numeric($date)) { 436 | $date = new DateTime($date . ' days'); // Days difference from today 437 | } else { 438 | $fieldValue = $this->_getVal($date); 439 | $date = ($fieldValue == FALSE) ? $date : $fieldValue; 440 | 441 | $date = DateTime::createFromFormat($format, $date); 442 | } 443 | 444 | $this->setRule(__FUNCTION__, function($val, $args) { 445 | $format = $args[1]; 446 | $limitDate = $args[0]; 447 | 448 | return ($limitDate > DateTime::createFromFormat($format, $val)) ? FALSE : TRUE; 449 | }, $message, array($date, $format)); 450 | return $this; 451 | } 452 | 453 | /** 454 | * Field has to be a date later than or equal to X. 455 | * 456 | * @param string|integer $date Limit date. 457 | * @param string $format Date format. 458 | * @param string $message 459 | * @return FormValidator 460 | */ 461 | public function maxDate($date = 0, $format = null, $message = null) { 462 | if (empty($format)) { 463 | $format = $this->_getDefaultDateFormat(); 464 | } 465 | if (is_numeric($date)) { 466 | $date = new DateTime($date . ' days'); // Days difference from today 467 | } else { 468 | $fieldValue = $this->_getVal($date); 469 | $date = ($fieldValue == FALSE) ? $date : $fieldValue; 470 | 471 | $date = DateTime::createFromFormat($format, $date); 472 | } 473 | 474 | $this->setRule(__FUNCTION__, function($val, $args) { 475 | $format = $args[1]; 476 | $limitDate = $args[0]; 477 | 478 | return !($limitDate < DateTime::createFromFormat($format, $val)); 479 | }, $message, array($date, $format)); 480 | return $this; 481 | } 482 | 483 | /** 484 | * Field has to be a valid credit card number format. 485 | * 486 | * @see https://github.com/funkatron/inspekt/blob/master/Inspekt.php 487 | * @param string $message 488 | * @return FormValidator 489 | */ 490 | public function ccnum($message = null) { 491 | $this->setRule(__FUNCTION__, function($value) { 492 | $value = str_replace(' ', '', $value); 493 | $length = strlen($value); 494 | 495 | if ($length < 13 || $length > 19) { 496 | return FALSE; 497 | } 498 | 499 | $sum = 0; 500 | $weight = 2; 501 | 502 | for ($i = $length - 2; $i >= 0; $i--) { 503 | $digit = $weight * $value[$i]; 504 | $sum += floor($digit / 10) + $digit % 10; 505 | $weight = $weight % 2 + 1; 506 | } 507 | 508 | $mod = (10 - $sum % 10) % 10; 509 | 510 | return ($mod == $value[$length - 1]); 511 | }, $message); 512 | return $this; 513 | } 514 | 515 | /** 516 | * Field has to be one of the allowed ones. 517 | * 518 | * @param string|array $allowed Allowed values. 519 | * @param string $message 520 | * @return FormValidator 521 | */ 522 | public function oneOf($allowed, $message = null) { 523 | if (is_string($allowed)) { 524 | $allowed = explode(',', $allowed); 525 | } 526 | 527 | $this->setRule(__FUNCTION__, function($val, $args) { 528 | return in_array($val, $args[0]); 529 | }, $message, array($allowed)); 530 | return $this; 531 | } 532 | 533 | // --------------- END [ADD NEW RULE FUNCTIONS ABOVE THIS LINE] ------------ 534 | 535 | /** 536 | * callback 537 | * @param string $name 538 | * @param mixed $function 539 | * @param string $message 540 | * @param mixed $params 541 | * @return FormValidator 542 | */ 543 | public function callback($callback, $message = '', $params = array()) { 544 | if (is_callable($callback)) { 545 | 546 | // If an array is callable, it is a method 547 | if (is_array($callback)) { 548 | $func = new ReflectionMethod($callback[0], $callback[1]); 549 | } else { 550 | $func = new ReflectionFunction($callback); 551 | } 552 | 553 | if (!empty($func)) { 554 | // needs a unique name to avoild collisions in the rules array 555 | $name = 'callback_' . sha1(uniqid()); 556 | $this->setRule($name, function($value) use ($func, $params, $callback) { 557 | // Creates merged arguments array with validation target as first argument 558 | $args = array_merge(array($value), (is_array($params) ? $params : array($params))); 559 | if (is_array($callback)) { 560 | // If callback is a method, the object must be the first argument 561 | return $func->invokeArgs($callback[0], $args); 562 | } else { 563 | return $func->invokeArgs($args); 564 | } 565 | }, $message, $params); 566 | } 567 | 568 | } else { 569 | throw new Exception(sprintf('%s is not callable.', $function)); 570 | } 571 | 572 | return $this; 573 | } 574 | 575 | // ------------------ PRE VALIDATION FILTERING ------------------- 576 | /** 577 | * add a filter callback for the data 578 | * 579 | * @param mixed $callback 580 | * @return FormValidator 581 | */ 582 | public function filter($callback) { 583 | if(is_callable($callback)) { 584 | $this->filters[] = $callback; 585 | } 586 | 587 | return $this; 588 | } 589 | 590 | /** 591 | * applies filters based on a data key 592 | * 593 | * @access protected 594 | * @param string $key 595 | * @return void 596 | */ 597 | protected function _applyFilters($key) { 598 | $this->_applyFilter($this->data[$key]); 599 | } 600 | 601 | /** 602 | * recursively apply filters to a value 603 | * 604 | * @access protected 605 | * @param mixed $val reference 606 | * @return void 607 | */ 608 | protected function _applyFilter(&$val) { 609 | if (is_array($val)) { 610 | foreach($val as $key => &$item) { 611 | $this->_applyFilter($item); 612 | } 613 | } else { 614 | foreach($this->filters as $filter) { 615 | $val = $filter($val); 616 | } 617 | } 618 | } 619 | 620 | /** 621 | * validate 622 | * @param string $key 623 | * @param string $label 624 | * @return bool 625 | */ 626 | public function validate($key, $recursive = false, $label = '') { 627 | // set up field name for error message 628 | $this->fields[$key] = (empty($label)) ? 'Field with the name of "' . $key . '"' : $label; 629 | 630 | // apply filters to the data 631 | $this->_applyFilters($key); 632 | 633 | $val = $this->_getVal($key); 634 | 635 | // validate the piece of data 636 | $this->_validate($key, $val, $recursive); 637 | 638 | // reset rules 639 | $this->rules = array(); 640 | $this->filters = array(); 641 | return $val; 642 | } 643 | 644 | /** 645 | * recursively validates a value 646 | * 647 | * @access protected 648 | * @param string $key 649 | * @param mixed $val 650 | * @return bool 651 | */ 652 | protected function _validate($key, $val, $recursive = false) 653 | { 654 | if ($recursive && is_array($val)) { 655 | // run validations on each element of the array 656 | foreach($val as $index => $item) { 657 | if (!$this->_validate($key, $item, $recursive)) { 658 | // halt validation for this value. 659 | return FALSE; 660 | } 661 | } 662 | return TRUE; 663 | 664 | } else { 665 | 666 | // try each rule function 667 | foreach ($this->rules as $rule => $is_true) { 668 | if ($is_true) { 669 | $function = $this->functions[$rule]; 670 | $args = $this->arguments[$rule]; // Arguments of rule 671 | 672 | $valid = (empty($args)) ? $function($val) : $function($val, $args); 673 | 674 | if ($valid === FALSE) { 675 | $this->registerError($rule, $key); 676 | 677 | $this->rules = array(); // reset rules 678 | $this->filters = array(); 679 | return FALSE; 680 | } 681 | } 682 | } 683 | 684 | $this->validData[$key] = $val; 685 | return TRUE; 686 | } 687 | } 688 | 689 | /** 690 | * Whether errors have been found. 691 | * 692 | * @return bool 693 | */ 694 | public function hasErrors() { 695 | return (count($this->errors) > 0); 696 | } 697 | 698 | /** 699 | * Get specific error. 700 | * 701 | * @param string $field 702 | * @return string 703 | */ 704 | public function getError($field) { 705 | return $this->errors[$field]; 706 | } 707 | 708 | /** 709 | * Get all errors. 710 | * 711 | * @return array 712 | */ 713 | public function getAllErrors($keys = true) { 714 | return ($keys == true) ? $this->errors : array_values($this->errors); 715 | } 716 | 717 | public function getValidData() 718 | { 719 | return $this->validData; 720 | } 721 | 722 | /** 723 | * _getVal with added support for retrieving values from numeric and 724 | * associative multi-dimensional arrays. When doing so, use DOT notation 725 | * to indicate a break in keys, i.e.: 726 | * 727 | * key = "one.two.three" 728 | * 729 | * would search the array: 730 | * 731 | * array('one' => array( 732 | * 'two' => array( 733 | * 'three' => 'RETURN THIS' 734 | * ) 735 | * ); 736 | * 737 | * @param string $key 738 | * @return mixed 739 | */ 740 | protected function _getVal($key) { 741 | // handle multi-dimensional arrays 742 | if (strpos($key, '.') !== FALSE) { 743 | $arrData = NULL; 744 | $keys = explode('.', $key); 745 | $keyLen = count($keys); 746 | for ($i = 0; $i < $keyLen; ++$i) { 747 | if (trim($keys[$i]) == '') { 748 | return false; 749 | } else { 750 | if (is_null($arrData)) { 751 | if (!isset($this->data[$keys[$i]])) { 752 | return false; 753 | } 754 | $arrData = $this->data[$keys[$i]]; 755 | } else { 756 | if (!isset($arrData[$keys[$i]])) { 757 | return false; 758 | } 759 | $arrData = $arrData[$keys[$i]]; 760 | } 761 | } 762 | } 763 | return $arrData; 764 | } else { 765 | return (isset($this->data[$key])) ? $this->data[$key] : FALSE; 766 | } 767 | } 768 | 769 | /** 770 | * Register error. 771 | * 772 | * @param string $rule 773 | * @param string $key 774 | * @param string $message 775 | */ 776 | protected function registerError($rule, $key, $message = null) { 777 | if (empty($message)) { 778 | $message = $this->messages[$rule]; 779 | } 780 | 781 | $this->errors[$key] = sprintf($message, $this->fields[$key]); 782 | } 783 | 784 | /** 785 | * Set rule. 786 | * 787 | * @param string $rule 788 | * @param closure $function 789 | * @param string $message 790 | * @param array $args 791 | */ 792 | public function setRule($rule, $function, $message = '', $args = array()) { 793 | if (!array_key_exists($rule, $this->rules)) { 794 | $this->rules[$rule] = TRUE; 795 | if (!array_key_exists($rule, $this->functions)) { 796 | if (!is_callable($function)) { 797 | die('Invalid function for rule: ' . $rule); 798 | } 799 | $this->functions[$rule] = $function; 800 | } 801 | $this->arguments[$rule] = $args; // Specific arguments for rule 802 | 803 | $this->messages[$rule] = (empty($message)) ? $this->_getDefaultMessage($rule, $args) : $message; 804 | } 805 | } 806 | 807 | /** 808 | * Get default error message. 809 | * 810 | * @param string $key 811 | * @param array $args 812 | * @return string 813 | */ 814 | protected function _getDefaultMessage($rule, $args = null) { 815 | 816 | switch ($rule) { 817 | case 'email': 818 | $message = '%s is an invalid email address.'; 819 | break; 820 | 821 | case 'ip': 822 | $message = '%s is an invalid IP address.'; 823 | break; 824 | 825 | case 'url': 826 | $message = '%s is an invalid url.'; 827 | break; 828 | 829 | case 'required': 830 | $message = '%s is required.'; 831 | break; 832 | 833 | case 'float': 834 | $message = '%s must consist of numbers only.'; 835 | break; 836 | 837 | case 'integer': 838 | $message = '%s must consist of integer value.'; 839 | break; 840 | 841 | case 'digits': 842 | $message = '%s must consist only of digits.'; 843 | break; 844 | 845 | case 'min': 846 | $message = '%s must be greater than '; 847 | if ($args[1] == TRUE) { 848 | $message .= 'or equal to '; 849 | } 850 | $message .= $args[0] . '.'; 851 | break; 852 | 853 | case 'max': 854 | $message = '%s must be less than '; 855 | if ($args[1] == TRUE) { 856 | $message .= 'or equal to '; 857 | } 858 | $message .= $args[0] . '.'; 859 | break; 860 | 861 | case 'between': 862 | $message = '%s must be between ' . $args[0] . ' and ' . $args[1] . '.'; 863 | if ($args[2] == FALSE) { 864 | $message .= '(Without limits)'; 865 | } 866 | break; 867 | 868 | case 'minlength': 869 | $message = '%s must be at least ' . $args[0] . ' characters or longer.'; 870 | break; 871 | 872 | case 'maxlength': 873 | $message = '%s must be no longer than ' . $args[0] . ' characters.'; 874 | break; 875 | 876 | case 'length': 877 | $message = '%s must be exactly ' . $args[0] . ' characters in length.'; 878 | break; 879 | 880 | case 'matches': 881 | $message = '%s must match ' . $args[1] . '.'; 882 | break; 883 | 884 | case 'notmatches': 885 | $message = '%s must not match ' . $args[1] . '.'; 886 | break; 887 | 888 | case 'startsWith': 889 | $message = '%s must start with "' . $args[0] . '".'; 890 | break; 891 | 892 | case 'notstartsWith': 893 | $message = '%s must not start with "' . $args[0] . '".'; 894 | break; 895 | 896 | case 'endsWith': 897 | $message = '%s must end with "' . $args[0] . '".'; 898 | break; 899 | 900 | case 'notendsWith': 901 | $message = '%s must not end with "' . $args[0] . '".'; 902 | break; 903 | 904 | case 'date': 905 | $message = '%s is not valid date.'; 906 | break; 907 | 908 | case 'mindate': 909 | $message = '%s must be later than ' . $args[0]->format($args[1]) . '.'; 910 | break; 911 | 912 | case 'maxdate': 913 | $message = '%s must be before ' . $args[0]->format($args[1]) . '.'; 914 | break; 915 | 916 | case 'oneof': 917 | $message = '%s must be one of ' . implode(', ', $args[0]) . '.'; 918 | break; 919 | 920 | case 'ccnum': 921 | $message = '%s must be a valid credit card number.'; 922 | break; 923 | 924 | default: 925 | $message = '%s has an error.'; 926 | break; 927 | } 928 | 929 | return $message; 930 | } 931 | 932 | } 933 | -------------------------------------------------------------------------------- /Validator/Exception.php: -------------------------------------------------------------------------------- 1 | _errors = $errors; 9 | } 10 | 11 | public function getErrors() { 12 | return $this->_errors; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tests/ValidatorTest.php: -------------------------------------------------------------------------------- 1 | _validator = new Validator(); 12 | } 13 | 14 | /** 15 | * test filter with string 'trim' as the callbacl 16 | */ 17 | public function testFilterTrimCallback() 18 | { 19 | $validator = $this->_validator; 20 | 21 | $data = array( 22 | 'email' => ' test@emailwithwhitespace.com ', 23 | ); 24 | 25 | $validator->setData($data); 26 | $email = $validator->filter('trim')->validate('email'); 27 | 28 | $this->assertEquals(strlen($email), 28); 29 | } 30 | 31 | /** 32 | * test the FormValidator email rule 33 | */ 34 | public function testValidateEmail() 35 | { 36 | $validator = $this->_validator; 37 | 38 | $data = array( 39 | 'email' => 'test@test.com', 40 | ); 41 | 42 | $validator->email()->validate('email'); 43 | 44 | $this->assertFalse($validator->hasErrors()); 45 | } 46 | 47 | /** 48 | * test the FormValidator email rule on an array of emails 49 | */ 50 | public function testValidateEmailArray() 51 | { 52 | $validator = $this->_validator; 53 | 54 | $data = array( 55 | 'emails' => array( 56 | 'test@test.com', 57 | 'test2@test.com', 58 | 'test3@test.com' 59 | ) 60 | ); 61 | 62 | $validator->setData($data); 63 | $validator->email()->validate('emails', true); 64 | $this->assertFalse($validator->hasErrors()); 65 | } 66 | 67 | /** 68 | * test the Validator 69 | */ 70 | public function testInvalidEmailArray() 71 | { 72 | $validator = $this->_validator; 73 | 74 | $data = array( 75 | 'emails' => array( 76 | 'test@test.com', 77 | 'test2@test.com', 78 | 'testtest.com' 79 | ) 80 | ); 81 | 82 | $validator->setData($data) 83 | ->email() 84 | ->validate('emails', true); 85 | 86 | $this->assertTrue($validator->hasErrors()); 87 | } 88 | 89 | /** 90 | * test the required rule with value present 91 | */ 92 | public function testValidateRequired() 93 | { 94 | $validator = $this->_validator; 95 | 96 | $data = array( 97 | 'name' => 'Test Name' 98 | ); 99 | 100 | $validator->setData($data) 101 | ->required() 102 | ->validate('name'); 103 | 104 | $this->assertFalse($validator->hasErrors()); 105 | } 106 | 107 | /** 108 | * test the required rule without value present 109 | */ 110 | public function testValidateRequiredEmptyVal() 111 | { 112 | $validator = $this->_validator; 113 | 114 | $data = array( 115 | 'name' => '' 116 | ); 117 | 118 | $validator->setData($data) 119 | ->required() 120 | ->validate('name'); 121 | 122 | $this->assertTrue($validator->hasErrors()); 123 | } 124 | 125 | public function testValidateRequiredWithArray() 126 | { 127 | $validator = $this->_validator; 128 | 129 | $data = array( 130 | 'names' => array('Test Name', 'Another Name', 'And Another Name') 131 | ); 132 | 133 | $validator->setData($data) 134 | ->required() 135 | ->validate('names'); 136 | 137 | $this->assertFalse($validator->hasErrors()); 138 | } 139 | 140 | /** 141 | * test the required rule without value present 142 | */ 143 | public function testValidateRequiredWithArrayEmptyElement() 144 | { 145 | $validator = $this->_validator; 146 | 147 | $data = array( 148 | 'names' => array('Test Name', '', 'And Another Name') 149 | ); 150 | 151 | $validator->setData($data) 152 | ->required() 153 | ->validate('names', true); 154 | 155 | $this->assertTrue($validator->hasErrors()); 156 | } 157 | 158 | /** 159 | * test the float rule 160 | */ 161 | public function testValidateFloat() 162 | { 163 | $validator = $this->_validator; 164 | 165 | $data = array( 166 | 'float' => 2.5 167 | ); 168 | 169 | $validator->setData($data) 170 | ->float() 171 | ->validate('float'); 172 | 173 | $this->assertFalse($validator->hasErrors()); 174 | 175 | $data['float'] = 'test'; 176 | 177 | $validator->setData($data) 178 | ->float() 179 | ->validate('float'); 180 | 181 | $this->assertTrue($validator->hasErrors()); 182 | } 183 | 184 | /** 185 | * test the integer rule 186 | */ 187 | public function testValidateInteger() 188 | { 189 | $validator = $this->_validator; 190 | 191 | $data = array( 192 | 'integer' => 20 193 | ); 194 | 195 | $validator->setData($data) 196 | ->integer() 197 | ->validate('integer'); 198 | 199 | $this->assertFalse($validator->hasErrors()); 200 | 201 | $data['integer'] = 'test'; 202 | 203 | $validator->setData($data) 204 | ->integer() 205 | ->validate('integer'); 206 | 207 | $this->assertTrue($validator->hasErrors()); 208 | } 209 | 210 | /** 211 | * test the digits rule 212 | */ 213 | public function testValidateDigits() 214 | { 215 | $validator = $this->_validator; 216 | 217 | $data = array( 218 | 'digits' => 20 219 | ); 220 | 221 | $validator->setData($data) 222 | ->digits() 223 | ->validate('digits'); 224 | 225 | $this->assertFalse($validator->hasErrors()); 226 | 227 | $data['digits'] = 'test'; 228 | 229 | $validator->setData($data) 230 | ->digits() 231 | ->validate('digits'); 232 | 233 | $this->assertTrue($validator->hasErrors()); 234 | } 235 | 236 | /** 237 | * test the min rule 238 | */ 239 | public function testValidateMin() 240 | { 241 | $validator = $this->_validator; 242 | 243 | $data = array( 244 | 'min' => 35 245 | ); 246 | 247 | $validator->setData($data) 248 | ->min(30) 249 | ->validate('min'); 250 | 251 | $this->assertFalse($validator->hasErrors()); 252 | 253 | $validator->setData($data) 254 | ->min(40) 255 | ->validate('min'); 256 | 257 | $this->assertTrue($validator->hasErrors()); 258 | } 259 | 260 | /** 261 | * test the max rule 262 | */ 263 | public function testValidateMax() 264 | { 265 | $validator = $this->_validator; 266 | 267 | $data = array( 268 | 'max' => 29 269 | ); 270 | 271 | $validator->setData($data) 272 | ->max(30) 273 | ->validate('max'); 274 | 275 | $this->assertFalse($validator->hasErrors()); 276 | 277 | $validator->setData($data) 278 | ->max(20) 279 | ->validate('max'); 280 | 281 | $this->assertTrue($validator->hasErrors()); 282 | } 283 | 284 | /** 285 | * test the between rule 286 | */ 287 | public function testValidateBetween() 288 | { 289 | $validator = $this->_validator; 290 | 291 | $data = array( 292 | 'between' => 35 293 | ); 294 | 295 | $validator->setData($data) 296 | ->between(30, 40) 297 | ->validate('between'); 298 | 299 | $this->assertFalse($validator->hasErrors()); 300 | 301 | $validator->setData($data) 302 | ->between(40, 50) 303 | ->validate('between'); 304 | 305 | $this->assertTrue($validator->hasErrors()); 306 | } 307 | 308 | /** 309 | * test the minLength rule 310 | */ 311 | public function testValidateMinLength() 312 | { 313 | $validator = $this->_validator; 314 | 315 | $data = array( 316 | 'minlength' => 'this is a string' 317 | ); 318 | 319 | $validator->setData($data) 320 | ->minlength(10) 321 | ->validate('minlength'); 322 | 323 | $this->assertFalse($validator->hasErrors()); 324 | 325 | $validator->setData($data) 326 | ->minlength(60) 327 | ->validate('minlength'); 328 | 329 | $this->assertTrue($validator->hasErrors()); 330 | } 331 | 332 | /** 333 | * test the minLength rule 334 | */ 335 | public function testValidateMaxLength() 336 | { 337 | $validator = $this->_validator; 338 | 339 | $data = array( 340 | 'maxlength' => 'this is a string' 341 | ); 342 | 343 | $validator->setData($data) 344 | ->maxlength(20) 345 | ->validate('maxlength'); 346 | 347 | $this->assertFalse($validator->hasErrors()); 348 | 349 | $validator->setData($data) 350 | ->maxlength(5) 351 | ->validate('maxlength'); 352 | 353 | $this->assertTrue($validator->hasErrors()); 354 | } 355 | 356 | /** 357 | * test the minLength rule 358 | */ 359 | public function testValidateLength() 360 | { 361 | $validator = $this->_validator; 362 | 363 | $data = array( 364 | 'length' => 'this is a string' 365 | ); 366 | 367 | $validator->setData($data) 368 | ->length(16) 369 | ->validate('length'); 370 | 371 | $this->assertFalse($validator->hasErrors()); 372 | 373 | $validator->setData($data) 374 | ->length(5) 375 | ->validate('length'); 376 | 377 | $this->assertTrue($validator->hasErrors()); 378 | } 379 | 380 | /** 381 | * test the matches rule 382 | */ 383 | public function testValidateMatches() 384 | { 385 | $validator = $this->_validator; 386 | 387 | $data = array( 388 | 'password' => 'testpass', 389 | 'password_confirm' => 'testpass' 390 | ); 391 | 392 | $validator->setData($data) 393 | ->matches('password_confirm', 'Password Confirmation') 394 | ->validate('password'); 395 | 396 | $this->assertFalse($validator->hasErrors()); 397 | 398 | $data['password_confirm'] = 'Oh Noes I forgot what I types!'; 399 | 400 | $validator->setData($data) 401 | ->matches('password_confirmaton', 'Password Confirmation') 402 | ->validate('password'); 403 | 404 | $this->assertTrue($validator->hasErrors()); 405 | } 406 | 407 | /** 408 | * test the notmatches rule 409 | */ 410 | public function testValidateNotMatches() 411 | { 412 | $validator = $this->_validator; 413 | 414 | $data = array( 415 | 'password' => 'test', 416 | 'password_confirm' => 'another test' 417 | ); 418 | 419 | $validator->setData($data) 420 | ->notmatches('password_confirm', 'Password Confirmation') 421 | ->validate('password'); 422 | 423 | $this->assertFalse($validator->hasErrors()); 424 | 425 | $data['password_confirm'] = 'test'; 426 | 427 | $validator->setData($data) 428 | ->notmatches('password_confirm', 'Password Confirmation') 429 | ->validate('password'); 430 | 431 | $this->assertTrue($validator->hasErrors()); 432 | } 433 | 434 | /** 435 | * test the date rule 436 | */ 437 | public function testValidateDate() 438 | { 439 | $validator = $this->_validator; 440 | 441 | $data = array( 442 | 'date' => '10/20/2010', 443 | ); 444 | 445 | $validator->setData($data) 446 | ->date('m/d/Y') 447 | ->validate('date'); 448 | 449 | $this->assertFalse($validator->hasErrors()); 450 | 451 | $data['date'] = 'test'; 452 | 453 | $validator->setData($data) 454 | ->date('m/d/Y') 455 | ->validate('date'); 456 | 457 | $this->assertTrue($validator->hasErrors()); 458 | } 459 | 460 | public function testValidateCallback() 461 | { 462 | $validator = $this->_validator; 463 | 464 | $data = array( 465 | 'test' => 'test' 466 | ); 467 | 468 | $validator 469 | ->setData($data) 470 | ->callback(function($val) { 471 | return true; 472 | }) 473 | ->validate('test'); 474 | } 475 | 476 | public function testValidateFiles() 477 | { 478 | 479 | } 480 | } -------------------------------------------------------------------------------- /tests/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | ./ 4 | 5 | --------------------------------------------------------------------------------