Skip to content
Newer
Older
100644 632 lines (595 sloc) 28.2 KB
e7f3c31 @gwoo going lithium
gwoo authored Oct 12, 2009
1 <?php
2 /**
3 * Lithium: the most rad php framework
4 *
4f1a9c0 @nateabele Updating copyright year.
nateabele authored Mar 28, 2011
5 * @copyright Copyright 2011, Union of RAD (http://union-of-rad.org)
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
6 * @license http://opensource.org/licenses/bsd-license.php The BSD License
7 */
8
9 namespace lithium\util;
10
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
11 use lithium\util\Set;
12 use InvalidArgumentException;
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
13
e4bc392 Adding Validator docs.
psychic authored Feb 11, 2010
14 /**
a0930f4 @phishy fixed spelling errors
phishy authored Jun 11, 2011
15 * The `Validator` class provides static access to commonly used data validation logic. These common
bc7d5d7 @nateabele Fixing formatting and adding clarifying detail to documentation in `\…
nateabele authored Mar 7, 2010
16 * routines cover HTML form input data such as phone and credit card numbers, dates and postal
17 * codes, but also include general checks for regular expressions and booleans and numericality.
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 21, 2010
18 *
bc7d5d7 @nateabele Fixing formatting and adding clarifying detail to documentation in `\…
nateabele authored Mar 7, 2010
19 * General data checking is done by using `Validator` statically. Rules can be specified as a
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
20 * parameter to the `rule()` method or accessed directly via the `is[RuleName]()` method name
e4bc392 Adding Validator docs.
psychic authored Feb 11, 2010
21 * convention:
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
22 *
e4bc392 Adding Validator docs.
psychic authored Feb 11, 2010
23 * {{{
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
24 * use lithium\util\Validator;
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
25 *
1a4a9d0 @nateabele Moving class constructor from `\data\collection\Document` to `\data\C…
nateabele authored May 14, 2010
26 * // The following are equivalent:
27 * Validator::rule('email', 'foo@example.com'); // true
28 * Validator::isEmail('foo-at-example.com'); // false
e4bc392 Adding Validator docs.
psychic authored Feb 11, 2010
29 * }}}
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
30 *
fbda39a @nateabele Updating `Validator` docs and replacing code snippets with unit test …
nateabele authored Apr 16, 2010
31 * Data can also be validated against multiple rules, each having their own associated error
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
32 * message. The rule structure is array-based and hierarchical based on rule names and
a0930f4 @phishy fixed spelling errors
phishy authored Jun 11, 2011
33 * messages. Responses match the keys present in the `$data` parameter of `check()` up with an array
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
34 * of rules which they violate.
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
35 *
fbda39a @nateabele Updating `Validator` docs and replacing code snippets with unit test …
nateabele authored Apr 16, 2010
36 * {{{ embed:lithium\tests\cases\util\ValidatorTest::testCheckMultipleHasFirstError(1-15) }}}
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
37 *
fbda39a @nateabele Updating `Validator` docs and replacing code snippets with unit test …
nateabele authored Apr 16, 2010
38 * See the `check()` method for more information an multi-value datasets. Custom validation rules
39 * can also be added to `Validator` at runtime. These can either take the form of regular expression
40 * strings or functions supplied to the `add()` method.
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
41 *
42 * ### Rules
43 *
44 * The `Validator` class includes a series of commonly-used rules by default, any of which may be
45 * used in calls to `rule()` or `check()`, or called directly as a method. Additionally, many rules
46 * have a variety of different _formats_ in which they may be specified. The following is the list
47 * of the built-in rules, but keep in mind that none of them are hard-coded. Any rule may be
48 * overridden by adding a new rule of the same name using the `add()` method.
49 *
50 * - `notEmpty`: Checks that a string contains at least one non-whitespace character.
51 *
52 * - `alphaNumeric`: Checks that a string contains only integer or letters.
53 *
54 * - `lengthBetween`: Checks that a string length is within a specified range. Spaces are included
55 * in the character count. The available options are `'min'` and `'max'`, which designate the
56 * minimum and maximum length of the string.
57 *
58 * - `blank`: Checks that a field is left blank **OR** only whitespace characters are present in its
59 * value. Whitespace characters include spaces, tabs, carriage returns and newlines.
60 *
61 * - `creditCard`: Checks that a value is a valid credit card number. This rule is divided into a
62 * series of formats: `'amex'`, `'bankcard'`, `'diners'`, `'disc'`, `'electron'`, `'enroute'`,
63 * `'jcb'`, `'maestro'`, `'mc'`, `'solo'`, `'switch'`, `'visa'`, `'voyager'`, `'fast'`. If no
64 * format value is specified, the value defaults to `'any'`, which will validate the value if
65 * _any_ of the available formats match. You can also use the `'fast'` format, which does a
66 * high-speed, low-fidelity check to ensure that the value looks like a real credit card number.
67 * This rule includes one option, `'deep'`, which (if set to `true`) validates the value using the
68 * [Luhn algorithm](http://en.wikipedia.org/wiki/Luhn_algorithm) if the format validation is
69 * successful. See the `luhn` validator below for more details.
70 *
71 * - `date`: Checks that a value is a valid date that complies with one or more formats. Also
72 * validates leap years. Possible formats are `'dmy'` (27-12-2010 or 27-12-10 separators can be a
73 * space, period, dash, forward slash), `'mdy'` (12-27-2010 or 12-27-10 separators can be a space,
74 * period, dash, forward slash), `'ymd'` (2010-12-27 or 10-12-27 separators can be a space,
75 * period, dash, forward slash), `'dMy'` (27 December 2010 or 27 Dec 2010), `'Mdy'` (December 27,
76 * 2010 or Dec 27, 2010 comma is optional), `'My'` (December 2010 or Dec 2010) or `'my'` (12/2010
77 * separators can be a space, period, dash, forward slash).
78 *
79 * - `time`: Checks that a value is a valid time. Validates time as 24hr (HH:MM) or am/pm
80 * ([ H]H:MM[a|p]m). Does not allow / validate seconds.
81 *
82 * - `boolean`: Checks that a value is a boolean integer or `true` or `false`.
83 *
84 * - `decimal`: Checks that a value is a valid decimal. Takes one option, `'precision'`, which is
85 * an optional integer value defining the level of precision the decimal number must match.
86 *
87 * - `email`: Checks that a value is (probably) a valid email address. The subject of validating
88 * an actual email address is complicated and problematic. A regular expression that correctly
89 * validates addresses against [RFC 5322](http://tools.ietf.org/html/rfc5322) would be several
90 * pages long, with the drawback of being unable to keep up as new top-level domains are added.
91 * Instead, this validator uses PHP's internal input filtering API to check the format, and
92 * provides an option, `'deep'` ( _boolean_) which, if set to `true`, will validate that the email
93 * address' domain contains a valid MX record. Keep in mind, this is just one of the many ways to
94 * validate an email address in the overall context of an application. For other ideas or
95 * examples, [ask Sean](http://seancoates.com/).
96 *
97 * - `ip`: Validates a string as a valid IPv4 or IPv6 address.
98 *
99 * - `money`: Checks that a value is a valid monetary amount. This rule has two formats, `'right'`
100 * and `'left'`, which indicates which side the monetary symbol (i.e. $) appears on.
101 *
102 * - `numeric`: Checks that a value is numeric.
103 *
104 * - `phone`: Check that a value is a valid phone number, non-locale-specific phone number.
105 *
106 * - `postalCode`: Checks that a given value is a valid US postal code.
107 *
108 * - `inRange`: Checks that a numeric value is within a specified range. This value has two options,
109 * `'upper'` and `'lower'`, which specify the boundary of the value.
110 *
111 * - `url`: Checks that a value is a valid URL according to
112 * [RFC 2395](http://www.faqs.org/rfcs/rfc2396.html). Uses PHP's filter API, and accepts any
113 * options accepted for
114 * [the validation URL filter](http://www.php.net/manual/en/filter.filters.validate.php).
115 *
116 * - `luhn`: Checks that a value is a valid credit card number according to the
117 * [Luhn algorithm](http://en.wikipedia.org/wiki/Luhn_algorithm). (See also: the `creditCard`
118 * validator).
119 *
120 * - `inList`: Checks that a value is in a pre-defined list of values. This validator accepts one
121 * option, `'list'`, which is an array containing acceptable values.
122 *
c8d7278 @nateabele Implementing alternative regular expression delimiters for validation…
nateabele authored May 16, 2011
123 * - `regex`: Checks that a value appears to be a valid regular expression, possibly
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
124 * containing PCRE-compatible options flags.
125 *
126 * - `uuid`: Checks that a value is a valid UUID.
e4bc392 Adding Validator docs.
psychic authored Feb 11, 2010
127 */
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
128 class Validator extends \lithium\core\StaticObject {
129
130 /**
131 * An array of validation rules. May contain a single regular expression, an array of regular
132 * expressions (where the array keys define various possible 'formats' of the same rule), or a
133 * closure which accepts a value to be validated, and an array of options, and returns a
134 * boolean value, indicating whether the validation succeeded or failed.
135 *
136 * @var array
137 * @see lithium\util\Validator::add()
138 * @see lithium\util\Validator::rule()
139 */
140 protected static $_rules = array();
141
0c12c78 @jperras Adding missing doc block for util\Validator::.
jperras authored Feb 27, 2010
142 /**
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
143 * Default options used when defining a new validator rule. Each key contains method-specific
144 * options that should always be applied, or options that should be applied to all rules in the
145 * `'defaults'` key.
0c12c78 @jperras Adding missing doc block for util\Validator::.
jperras authored Feb 27, 2010
146 *
147 * @see lithium\util\Validator::add()
148 * @see lithium\util\Validator::rule()
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
149 * @var array
0c12c78 @jperras Adding missing doc block for util\Validator::.
jperras authored Feb 27, 2010
150 */
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
151 protected static $_options = array(
152 'defaults' => array('contains' => true)
153 );
154
155 /**
156 * Initializes the list of default validation rules.
157 *
158 * @return void
159 */
160 public static function __init() {
161 $alnum = '[A-Fa-f0-9]';
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 11, 2010
162 $class = get_called_class();
163 static::$_methodFilters[$class] = array();
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
164
165 static::$_rules = array(
166 'alphaNumeric' => '/^[\p{Ll}\p{Lm}\p{Lo}\p{Lt}\p{Lu}\p{Nd}]+$/mu',
167 'blank' => '/[^\\s]/',
168 'creditCard' => array(
169 'amex' => '/^3[4|7]\\d{13}$/',
170 'bankcard' => '/^56(10\\d\\d|022[1-5])\\d{10}$/',
171 'diners' => '/^(?:3(0[0-5]|[68]\\d)\\d{11})|(?:5[1-5]\\d{14})$/',
172 'disc' => '/^(?:6011|650\\d)\\d{12}$/',
173 'electron' => '/^(?:417500|4917\\d{2}|4913\\d{2})\\d{10}$/',
174 'enroute' => '/^2(?:014|149)\\d{11}$/',
175 'jcb' => '/^(3\\d{4}|2100|1800)\\d{11}$/',
176 'maestro' => '/^(?:5020|6\\d{3})\\d{12}$/',
177 'mc' => '/^5[1-5]\\d{14}$/',
178 'solo' => '/^(6334[5-9][0-9]|6767[0-9]{2})\\d{10}(\\d{2,3})?$/',
179 'switch' => '/^(?:49(03(0[2-9]|3[5-9])|11(0[1-2]|7[4-9]|8[1-2])|36[0-9]{2})' .
180 '\\d{10}(\\d{2,3})?)|(?:564182\\d{10}(\\d{2,3})?)|(6(3(33[0-4]' .
181 '[0-9])|759[0-9]{2})\\d{10}(\\d{2,3})?)$/',
182 'visa' => '/^4\\d{12}(\\d{3})?$/',
183 'voyager' => '/^8699[0-9]{11}$/',
184 'fast' => '/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3' .
860cffb @Howard3 Closes #370 & #371
Howard3 authored Jun 3, 2011
185 '(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})$/'
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
186 ),
187 'date' => array(
188 'dmy' => '%^(?:(?:31(\\/|-|\\.|\\x20)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)' .
189 '(\\/|-|\\.|\\x20)(?:0?[1,3-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?' .
190 '\\d{2})$|^(?:29(\\/|-|\\.|\\x20)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?' .
191 '(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])' .
192 '00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.|\\x20)(?:(?:0?[1-9])|' .
193 '(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%',
194 'mdy' => '%^(?:(?:(?:0?[13578]|1[02])(\\/|-|\\.|\\x20)31)\\1|(?:(?:0?[13-9]|' .
195 '1[0-2])(\\/|-|\\.|\\x20)(?:29|30)\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d' .
196 '{2})$|^(?:0?2(\\/|-|\\.|\\x20)29\\3(?:(?:(?:1[6-9]|[2-9]\\d)?' .
197 '(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])' .
198 '00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(\\/|-|\\.|\\x20)(?:0?[1-9]|1' .
199 '\\d|2[0-8])\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$%',
200 'ymd' => '%^(?:(?:(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579]' .
201 '[26])|(?:(?:16|[2468][048]|[3579][26])00)))(\\/|-|\\.|\\x20)' .
202 '(?:0?2\\1(?:29)))|(?:(?:(?:1[6-9]|[2-9]\\d)?\\d{2})(\\/|-|\\.|' .
203 '\\x20)(?:(?:(?:0?[13578]|1[02])\\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])' .
204 '\\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\\2(?:0?[1-9]|1\\d|2[0-8]' .
205 '))))$%',
206 'dMy' => '/^((31(?!\\ (Feb(ruary)?|Apr(il)?|June?|(Sep(?=\\b|t)t?|Nov)' .
207 '(ember)?)))|((30|29)(?!\\ Feb(ruary)?))|(29(?=\\ Feb(ruary)?\\ ' .
208 '(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468]' .
209 '[048]|[3579][26])00)))))|(0?[1-9])|1\\d|2[0-8])\\ (Jan(uary)?|' .
210 'Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|Aug(ust)?|' .
211 'Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)\\ ((1[6-9]|[2-9]' .
212 '\\d)\\d{2})$/',
213 'Mdy' => '/^(?:(((Jan(uary)?|Ma(r(ch)?|y)|Jul(y)?|Aug(ust)?|Oct(ober)?' .
214 '|Dec(ember)?)\\ 31)|((Jan(uary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)' .
215 '|(ne?))|Aug(ust)?|Oct(ober)?|(Sept|Nov|Dec)(ember)?)\\ (0?[1-9]' .
216 '|([12]\\d)|30))|(Feb(ruary)?\\ (0?[1-9]|1\\d|2[0-8]|(29(?=,?\\ ' .
217 '((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468]' .
218 '[048]|[3579][26])00)))))))\\,?\\ ((1[6-9]|[2-9]\\d)\\d{2}))$/',
219 'My' => '%^(Jan(uary)?|Feb(ruary)?|Ma(r(ch)?|y)|Apr(il)?|Ju((ly?)|(ne?))|' .
220 'Aug(ust)?|Oct(ober)?|(Sep(?=\\b|t)t?|Nov|Dec)(ember)?)[ /]((1[6-9]' .
221 '|[2-9]\\d)\\d{2})$%',
222 'my' => '%^(((0[123456789]|10|11|12)([- /.])(([1][9][0-9][0-9])|([2][0-9]' .
223 '[0-9][0-9]))))$%'
224 ),
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
225 'ip' => function($value, $format = null, array $options = array()) {
226 $options += array('flags' => array());
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
227 return (boolean) filter_var($value, FILTER_VALIDATE_IP, $options);
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
228 },
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
229 'money' => array(
230 'right' => '/^(?!0,?\d)(?:\d{1,3}(?:([, .])\d{3})?(?:\1\d{3})*|(?:\d+))' .
231 '((?!\1)[,.]\d{2})?(?<!\x{00a2})\p{Sc}?$/u',
232 'left' => '/^(?!\x{00a2})\p{Sc}?(?!0,?\d)(?:\d{1,3}(?:([, .])\d{3})?' .
860cffb @Howard3 Closes #370 & #371
Howard3 authored Jun 3, 2011
233 '(?:\1\d{3})*|(?:\d+))((?!\1)[,.]\d{2})?$/u'
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
234 ),
235 'notEmpty' => '/[^\s]+/m',
338196b @davidpersson Moving locale dependent validation rules to g11n resources.
davidpersson authored Jan 7, 2010
236 'phone' => '/^\+?[0-9\(\)\-]{10,20}$/',
237 'postalCode' => '/(^|\A\b)[A-Z0-9\s\-]{5,}($|\b\z)/i',
c8d7278 @nateabele Implementing alternative regular expression delimiters for validation…
nateabele authored May 16, 2011
238 'regex' => '/^(?:([^[:alpha:]\\\\{<\[\(])(.+)(?:\1))|(?:{(.+)})|(?:<(.+)>)|' .
239 '(?:\[(.+)\])|(?:\((.+)\))[gimsxu]*$/',
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
240 'time' => '%^((0?[1-9]|1[012])(:[0-5]\d){0,2}([AP]M|[ap]m))$|^([01]\d|2[0-3])' .
241 '(:[0-5]\d){0,2}$%',
c8d7278 @nateabele Implementing alternative regular expression delimiters for validation…
nateabele authored May 16, 2011
242 'boolean' => function($value) {
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
243 $bool = is_bool($value);
0c12c78 @jperras Adding missing doc block for util\Validator::.
jperras authored Feb 27, 2010
244 $filter = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
245 return ($bool || $filter !== null);
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
246 },
f80098d @nateabele Adding type hinting to constructor `$config` arrays and all applicabl…
nateabele authored Feb 16, 2010
247 'decimal' => function($value, $format = null, array $options = array()) {
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
248 if (isset($options['precision'])) {
249 $precision = strlen($value) - strrpos($value, '.') - 1;
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
250
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
251 if ($precision !== (int) $options['precision']) {
252 return false;
253 }
254 }
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
255 return (filter_var($value, FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE) !== null);
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
256 },
257 'inList' => function($value, $format, $options) {
258 $options += array('list' => array());
259 return in_array($value, $options['list']);
260 },
261 'lengthBetween' => function($value, $format, $options) {
262 $length = strlen($value);
263 $options += array('min' => 1, 'max' => 255);
264 return ($length >= $options['min'] && $length <= $options['max']);
265 },
266 'luhn' => function($value) {
267 if (empty($value) || !is_string($value)) {
268 return false;
269 }
270 $sum = 0;
271 $length = strlen($value);
272
273 for ($position = 1 - ($length % 2); $position < $length; $position += 2) {
274 $sum += $value[$position];
275 }
276 for ($position = ($length % 2); $position < $length; $position += 2) {
277 $number = $value[$position] * 2;
278 $sum += ($number < 10) ? $number : $number - 9;
279 }
280 return ($sum % 10 == 0);
281 },
282 'numeric' => function($value) {
283 return is_numeric($value);
284 },
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
285 'inRange' => function($value, $format, $options) {
286 $defaults = array('upper' => null, 'lower' => null);
287 $options += $defaults;
288
289 if (!is_numeric($value)) {
290 return false;
291 }
292 switch (true) {
293 case (!is_null($options['upper']) && !is_null($options['lower'])):
294 return ($value > $options['lower'] && $value < $options['upper']);
295 case (!is_null($options['upper'])):
296 return ($value < $options['upper']);
297 case (!is_null($options['lower'])):
298 return ($value > $options['lower']);
299 }
300 return is_finite($value);
301 },
8c8279c @ddebernardy fix insufficiently robust uuid validator
ddebernardy authored Aug 24, 2010
302 'uuid' => "/^{$alnum}{8}-{$alnum}{4}-{$alnum}{4}-{$alnum}{4}-{$alnum}{12}$/",
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
303 'email' => function($value) {
304 return filter_var($value, FILTER_VALIDATE_EMAIL);
305 },
306 'url' => function($value, $format = null, array $options = array()) {
307 $options += array('flags' => array());
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
308 return (boolean) filter_var($value, FILTER_VALIDATE_URL, $options);
5fba2fb @jperras Modifying util\Validator to use filter_var() where possible.
jperras authored Feb 22, 2010
309 }
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
310 );
311
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
312 $isEmpty = function($self, $params, $chain) {
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
313 extract($params);
314 return (empty($value) && $value != '0') ? false : $chain->next($self, $params, $chain);
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
315 };
316
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
317 static::$_methodFilters[$class]['alphaNumeric'] = array($isEmpty);
318 static::$_methodFilters[$class]['notEmpty'] = array($isEmpty);
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
319
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
320 static::$_methodFilters[$class]['creditCard'] = array(function($self, $params, $chain) {
321 extract($params);
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
322 $options += array('deep' => false);
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
323
324 if (strlen($value = str_replace(array('-', ' '), '', $value)) < 13) {
325 return false;
326 }
327 if (!$chain->next($self, compact('value') + $params, $chain)) {
328 return false;
329 }
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
330 return $options['deep'] ? Validator::isLuhn($value) : true;
331 });
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
332
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
333 static::$_methodFilters[$class]['email'] = array(function($self, $params, $chain) {
334 extract($params);
335 $defaults = array('deep' => false);
336 $options += $defaults;
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
337
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
338 if (!$chain->next($self, $params, $chain)) {
d87fbbe @gwoo changing deep email validator to use getmxrr
gwoo authored Nov 16, 2009
339 return false;
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
340 }
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
341 if (!$options['deep']) {
342 return true;
343 }
344 list($prefix, $host) = explode('@', $params['value']);
345
346 if (getmxrr($host, $mxhosts)) {
347 return is_array($mxhosts);
348 }
349 return false;
350 });
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
351 }
352
353 /**
354 * Maps method calls to validation rule names. For example, a validation rule that would
355 * normally be called as `Validator::rule('email', 'foo@bar.com')` can also be called as
356 * `Validator::isEmail('foo@bar.com')`.
357 *
358 * @param string $method The name of the method called, i.e. `'isEmail'` or `'isCreditCard'`.
64f6039 @jperras Replacing various instances of array_key_exists with isset().
jperras authored Nov 16, 2009
359 * @param array $args
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
360 * @return boolean
361 */
362 public static function __callStatic($method, $args = array()) {
363 if (!isset($args[0])) {
364 return false;
365 }
366 $args += array(1 => 'any', 2 => array());
367 $rule = preg_replace("/^is([A-Z][A-Za-z0-9]+)$/", '$1', $method);
368 $rule[0] = strtolower($rule[0]);
369 return static::rule($rule, $args[0], $args[1], $args[2]);
370 }
371
372 /**
fbda39a @nateabele Updating `Validator` docs and replacing code snippets with unit test …
nateabele authored Apr 16, 2010
373 * Checks a set of values against a specified rules list. This method may be used to validate
374 * any arbitrary array of data against a set of validation rules.
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
375 *
fbda39a @nateabele Updating `Validator` docs and replacing code snippets with unit test …
nateabele authored Apr 16, 2010
376 * @param array $values An array of key/value pairs, where the values are to be checked.
377 * @param array $rules An array of rules to check the values in `$values` against. Each key in
378 * `$rules` should match a key contained in `$values`, and each value should be a
5089955 @nateabele Updating documentation for `\util\Validator`, adding tests to prove f…
nateabele authored Apr 17, 2010
379 * validation rule in one of the allowable formats. For example, if you are
1ec455e @nateabele Updating example used in docblock of `\util\Validator::check()`. Fixe…
nateabele authored May 5, 2010
380 * validating a data set containing a `'credit_card'` key, possible values for
5089955 @nateabele Updating documentation for `\util\Validator`, adding tests to prove f…
nateabele authored Apr 17, 2010
381 * `$rules` would be as follows:
1ec455e @nateabele Updating example used in docblock of `\util\Validator::check()`. Fixe…
nateabele authored May 5, 2010
382 * - `array('credit_card' => 'You must include a credit card number')`: This is the
383 * simplest form of validation rule, in which the value is simply a message to
384 * display if the rule fails. Using this format, all other validation settings
385 * inherit from the defaults, including the validation rule itself, which only
386 * checks to see that the corresponding key in `$values` is present and contains
387 * a value that is not empty. _Please note when globalizing validation messages:_
388 * When specifying messages, it may be preferable to use a code string (i.e.
389 * `'ERR_NO_TITLE'`) instead of the full text of the validation error. These code
390 * strings may then be translated by the appropriate tools in the templating
391 * layer.
392 * - `array('credit_card' => array('creditCard', 'message' => 'Invalid CC #'))`:
393 * In the second format, the validation rule (in this case `creditCard`) and
394 * associated configuration are specified as an array, where the rule to use is
395 * the first value in the array (no key), and additional settings are specified
396 * as other keys in the array. Please see the list below for more information on
397 * allowed keys.
5089955 @nateabele Updating documentation for `\util\Validator`, adding tests to prove f…
nateabele authored Apr 17, 2010
398 * - The final format allows you to apply multiple validation rules to a single
399 * value, and it is specified as follows:
400 *
1ec455e @nateabele Updating example used in docblock of `\util\Validator::check()`. Fixe…
nateabele authored May 5, 2010
401 * `array('credit_card' => array(
402 * array('notEmpty', 'message' => 'You must include credit card number'),
403 * array('creditCard', 'message' => 'Your credit card number must be valid')
5089955 @nateabele Updating documentation for `\util\Validator`, adding tests to prove f…
nateabele authored Apr 17, 2010
404 * ));`
470d76e @jperras Fixing coding standards violations in `util\Validator`.
jperras authored Jun 2, 2010
405 * @param array $options Validator-specific options.
5089955 @nateabele Updating documentation for `\util\Validator`, adding tests to prove f…
nateabele authored Apr 17, 2010
406 *
407 * Each rule defined as an array can contain any of the following settings (in addition to the
408 * first value, which represents the rule to be used):
409 * - `'message'` _string_: The error message to be returned if the validation rule fails. See
410 * the note above regarding globalization of error messages.
411 * - `'required`' _boolean_: Represents whether the value is required to be present in
412 * `$values`. If `'required'` is set to `false`, the validation rule will be skipped if the
413 * corresponding key is not present. Defaults to `true`.
414 * - `'skipEmpty'` _boolean_: Similar to `'required'`, this setting (if `true`) will cause the
415 * validation rule to be skipped if the corresponding value is empty (an empty string or
416 * `null`). Defaults to `false`.
417 * - `'format'` _string_: If the validation rule has multiple format definitions (see the
418 * `add()` or `__init()` methods), the name of the format to be used can be specified here.
419 * Additionally, two special values can be used: either `'any'`, which means that all formats
420 * will be checked and the rule will pass if any format passes, or `'all'`, which requires
421 * all formats to pass in order for the rule check to succeed.
fbda39a @nateabele Updating `Validator` docs and replacing code snippets with unit test …
nateabele authored Apr 16, 2010
422 * @return array Returns an array containing all validation failures for data in `$values`,
423 * where each key matches a key in `$values`, and each value is an array of that
424 * element's validation errors.
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
425 */
fbda39a @nateabele Updating `Validator` docs and replacing code snippets with unit test …
nateabele authored Apr 16, 2010
426 public static function check(array $values, array $rules, array $options = array()) {
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
427 $defaults = array(
428 'notEmpty',
429 'message' => null,
430 'required' => true,
431 'skipEmpty' => false,
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
432 'format' => 'any',
afe30c7 @vesln Adding support for "last" rule in `Validator::check` method
vesln authored Aug 7, 2011
433 'on' => null,
434 'last' => false
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
435 );
436 $errors = array();
e86fd73 @nateabele Implementing validator events, to enable conditional validation. To u…
nateabele authored Dec 15, 2010
437 $events = (array) (isset($options['events']) ? $options['events'] : null);
5b1f99e @nateabele Enabling validation rules on nested keys using dot syntax.
nateabele authored May 24, 2011
438 $values = Set::flatten($values);
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
439
440 foreach ($rules as $field => $rules) {
441 $rules = is_string($rules) ? array('message' => $rules) : $rules;
442 $rules = is_array(current($rules)) ? $rules : array($rules);
443 $errors[$field] = array();
3f75cd7 @alkemann Implement and test for Field name passed as option to validation rule…
alkemann authored Jul 2, 2010
444 $options['field'] = $field;
e86fd73 @nateabele Implementing validator events, to enable conditional validation. To u…
nateabele authored Dec 15, 2010
445
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
446 foreach ($rules as $key => $rule) {
c0a3feb @nateabele Allowing `$options` from `Model::validates()` to `Validator::check()`.
nateabele authored Mar 25, 2010
447 $rule += $defaults + compact('values');
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
448 list($name) = $rule;
449
e86fd73 @nateabele Implementing validator events, to enable conditional validation. To u…
nateabele authored Dec 15, 2010
450 if ($events && $rule['on'] && !array_intersect($events, (array) $rule['on'])) {
451 continue;
452 }
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
453 if (!isset($values[$field])) {
454 if ($rule['required']) {
455 $errors[$field][] = $rule['message'] ?: $key;
4fceb8b @gwoo refactoring Model::validates. adding Record::errors
gwoo authored Nov 24, 2009
456 }
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
457 continue;
4fceb8b @gwoo refactoring Model::validates. adding Record::errors
gwoo authored Nov 25, 2009
458 }
dc191c8 @gwoo fixing typo in Validator
gwoo authored Dec 8, 2009
459 if (empty($values[$field]) && $rule['skipEmpty']) {
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
460 continue;
4fceb8b @gwoo refactoring Model::validates. adding Record::errors
gwoo authored Nov 25, 2009
461 }
c0a3feb @nateabele Allowing `$options` from `Model::validates()` to `Validator::check()`.
nateabele authored Mar 26, 2010
462 if (!static::rule($name, $values[$field], $rule['format'], $rule + $options)) {
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
463 $errors[$field][] = $rule['message'] ?: $key;
afe30c7 @vesln Adding support for "last" rule in `Validator::check` method
vesln authored Aug 7, 2011
464
465 if ($rule['last']) {
466 break;
467 }
4fceb8b @gwoo refactoring Model::validates. adding Record::errors
gwoo authored Nov 25, 2009
468 }
469 }
470 }
471 return array_filter($errors);
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
472 }
473
474 /**
475 * Adds to or replaces built-in validation rules specified in `Validator::$_rules`. Any new
476 * validation rules created are automatically callable as validation methods.
64f6039 @jperras Replacing various instances of array_key_exists with isset().
jperras authored Nov 16, 2009
477 *
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
478 * For example:
479 * {{{
480 * Validator::add('zeroToNine', '/^[0-9]$/');
481 * $isValid = Validator::isZeroToNine("5"); // true
482 * $isValid = Validator::isZeroToNine("20"); // false
483 * }}}
64f6039 @jperras Replacing various instances of array_key_exists with isset().
jperras authored Nov 16, 2009
484 *
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
485 * Alternatively, the first parameter may be an array of rules expressed as key/value pairs,
486 * as in the following:
487 * {{{
488 * Validator::add(array(
489 * 'zeroToNine' => '/^[0-9]$/',
490 * 'tenToNineteen' => '/^1[0-9]$/',
491 * ));
492 * }}}
64f6039 @jperras Replacing various instances of array_key_exists with isset().
jperras authored Nov 16, 2009
493 *
bc7d5d7 @nateabele Fixing formatting and adding clarifying detail to documentation in `\…
nateabele authored Mar 7, 2010
494 * In addition to regular expressions, validation rules can also be defined as full anonymous
495 * functions:
496 * {{{
497 * use app\models\Account;
498 *
499 * Validator::add('accountActive', function($value) {
500 * $value = is_int($value) ? Account::find($value) : $value;
501 * return (boolean) $value->is_active;
502 * });
503 *
504 * $testAccount = Account::create(array('is_active' => false));
505 * Validator::isAccountActive($testAccount); // returns false
506 * }}}
507 *
508 * These functions can take up to 3 parameters:
509 * - `$value` _mixed_: This is the actual value to be validated (as in the above example).
510 * - `$format` _string_: Often, validation rules come in multiple "formats", for example:
511 * postal codes, which vary by country or region. Defining multiple formats allows you to
470d76e @jperras Fixing coding standards violations in `util\Validator`.
jperras authored Jun 2, 2010
512 * retian flexibility in how you validate data. In cases where a user's country of origin
513 * is known, the appropriate validation rule may be selected. In cases where it is not
514 * known, the value of `$format` may be `'any'`, which should pass if any format matches.
515 * In cases where validation rule formats are not mutually exclusive, the value may be
516 * `'all'`, in which case all must match.
517 * - `$options` _array_: This parameter allows a validation rule to implement custom
518 * options.
bc7d5d7 @nateabele Fixing formatting and adding clarifying detail to documentation in `\…
nateabele authored Mar 7, 2010
519 *
520 * @see lithium\util\Validator::$_rules
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
521 * @param mixed $name The name of the validation rule (string), or an array of key/value pairs
522 * of names and rules.
523 * @param string $rule If $name is a string, this should be a string regular expression, or a
524 * closure that returns a boolean indicating success. Should be left blank if
525 * `$name` is an array.
526 * @param array $options The default options for validating this rule. An option which applies
527 * to all regular expression rules is `'contains'` which, if set to true, allows
528 * validated values to simply _contain_ a match to a rule, rather than exactly
529 * matching it in whole.
530 * @return void
531 */
f80098d @nateabele Adding type hinting to constructor `$config` arrays and all applicabl…
nateabele authored Feb 17, 2010
532 public static function add($name, $rule = null, array $options = array()) {
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
533 if (!is_array($name)) {
534 $name = array($name => $rule);
535 }
536 static::$_rules = Set::merge(static::$_rules, $name);
537
538 if (!empty($options)) {
539 $options = array_combine(array_keys($name), array_fill(0, count($name), $options));
540 static::$_options = Set::merge(static::$_options, $options);
541 }
542 }
543
544 /**
545 * Checks a single value against a single validation rule in one or more formats.
546 *
64f6039 @jperras Replacing various instances of array_key_exists with isset().
jperras authored Nov 16, 2009
547 * @param string $rule
548 * @param mixed $value
549 * @param string $format
97c5e7c @Howard3 Doing a general QA and Docblock
Howard3 authored Jun 12, 2011
550 * @param array $options
b6a2d05 @nateabele Cleaning up `\util\Validator`, and adding documentation on various va…
nateabele authored Oct 30, 2010
551 * @return boolean Returns `true` or `false` indicating whether the validation rule check
552 * succeeded or failed.
59cb735 @nateabele Ensuring `@filter` tags are present in docblocks that support filteri…
nateabele authored May 24, 2011
553 * @filter
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
554 */
f80098d @nateabele Adding type hinting to constructor `$config` arrays and all applicabl…
nateabele authored Feb 17, 2010
555 public static function rule($rule, $value, $format = 'any', array $options = array()) {
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
556 if (!isset(static::$_rules[$rule])) {
5c0ba72 @davidpersson Appending period to error and exception messages where missing.
davidpersson authored Feb 15, 2011
557 throw new InvalidArgumentException("Rule `{$rule}` is not a validation rule.");
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
558 }
559 $defaults = isset(static::$_options[$rule]) ? static::$_options[$rule] : array();
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
560 $options = (array) $options + $defaults + static::$_options['defaults'];
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
561
562 $ruleCheck = static::$_rules[$rule];
563 $ruleCheck = is_array($ruleCheck) ? $ruleCheck : array($ruleCheck);
564
565 if (!$options['contains'] && !empty($ruleCheck)) {
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
566 foreach ($ruleCheck as $key => $item) {
567 $ruleCheck[$key] = is_string($item) ? "/^{$item}$/" : $item;
568 }
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
569 }
570
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
571 $params = compact('value', 'format', 'options');
572 return static::_filter($rule, $params, static::_checkFormats($ruleCheck));
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
573 }
574
575 /**
904be25 @nateabele Refactoring `Validator::check()`, implementing updated rules syntax. …
nateabele authored Dec 8, 2009
576 * Returns a list of available validation rules, or the configuration details of a single rule.
577 *
578 * @param string $name Optional name of a rule to get the details of. If not specified, an array
579 * of all available rule names is returned. Otherwise, returns the details of a
580 * single rule. This can be a regular expression string, a closure object, or an
581 * array of available rule formats made up of string regular expressions,
582 * closures, or both.
583 * @return mixed Returns either an single array of rule names, or the details of a single rule.
584 */
585 public static function rules($name = null) {
586 if (!$name) {
587 return array_keys(static::$_rules);
588 }
589 return isset(static::$_rules[$name]) ? static::$_rules[$name] : null;
590 }
591
592 /**
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
593 * Perform validation checks against a value using an array of all possible formats for a rule,
594 * and an array specifying which formats within the rule to use.
595 *
596 * @param array $rules All available rules.
536efae @svemir Update comments to specify when a method is returning a Closure
svemir authored Jan 10, 2011
597 * @return closure Function returning boolean `true` if validation succeeded, `false` otherwise.
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
598 */
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
599 protected static function _checkFormats($rules) {
600 return function($self, $params, $chain) use ($rules) {
601 extract($params);
602 $defaults = array('all' => true);
603 $options += $defaults;
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
604
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
605 $formats = (array) $format;
606
860cffb @Howard3 Closes #370 & #371
Howard3 authored Jun 3, 2011
607 $ruleIndexes = array_keys($rules);
608 $options['all'] = ($format == 'all');
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
609
860cffb @Howard3 Closes #370 & #371
Howard3 authored Jun 3, 2011
610 foreach ($ruleIndexes as $index) {
611 if (!isset($rules[$index])) {
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
612 continue;
613 }
860cffb @Howard3 Closes #370 & #371
Howard3 authored Jun 3, 2011
614 $check = $rules[$index];
615 $format = isset($formats[$index]) ? $formats[$index] : null;
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
616
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
617 $regexPassed = (is_string($check) && preg_match($check, $value));
860cffb @Howard3 Closes #370 & #371
Howard3 authored Jun 3, 2011
618 $closurePassed = (is_object($check) && $check($value, $format, $options));
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
619
620 if (!$options['all'] && ($regexPassed || $closurePassed)) {
621 return true;
622 }
623 if ($options['all'] && (!$regexPassed && !$closurePassed)) {
624 return false;
625 }
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
626 }
f7a9ba6 @nateabele Removing unused validators in `util\Validator`, refactoring `Validato…
nateabele authored Feb 12, 2010
627 return $options['all'];
628 };
e7f3c31 @gwoo going lithium
gwoo authored Oct 13, 2009
629 }
630 }
631
632 ?>
Something went wrong with that request. Please try again.