1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Utils;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17:
18: class Validators extends Nette\Object
19: {
20: protected static $validators = array(
21: 'bool' => 'is_bool',
22: 'boolean' => 'is_bool',
23: 'int' => 'is_int',
24: 'integer' => 'is_int',
25: 'float' => 'is_float',
26: 'number' => NULL,
27: 'numeric' => array(__CLASS__, 'isNumeric'),
28: 'numericint' => array(__CLASS__, 'isNumericInt'),
29: 'string' => 'is_string',
30: 'unicode' => array(__CLASS__, 'isUnicode'),
31: 'array' => 'is_array',
32: 'list' => array('Nette\Utils\Arrays', 'isList'),
33: 'object' => 'is_object',
34: 'resource' => 'is_resource',
35: 'scalar' => 'is_scalar',
36: 'callable' => array(__CLASS__, 'isCallable'),
37: 'null' => 'is_null',
38: 'email' => array(__CLASS__, 'isEmail'),
39: 'url' => array(__CLASS__, 'isUrl'),
40: 'uri' => array(__CLASS__, 'isUri'),
41: 'none' => array(__CLASS__, 'isNone'),
42: 'type' => array(__CLASS__, 'isType'),
43: 'identifier' => array(__CLASS__, 'isPhpIdentifier'),
44: 'pattern' => NULL,
45: 'alnum' => 'ctype_alnum',
46: 'alpha' => 'ctype_alpha',
47: 'digit' => 'ctype_digit',
48: 'lower' => 'ctype_lower',
49: 'upper' => 'ctype_upper',
50: 'space' => 'ctype_space',
51: 'xdigit' => 'ctype_xdigit',
52: );
53:
54: protected static $counters = array(
55: 'string' => 'strlen',
56: 'unicode' => array('Nette\Utils\Strings', 'length'),
57: 'array' => 'count',
58: 'list' => 'count',
59: 'alnum' => 'strlen',
60: 'alpha' => 'strlen',
61: 'digit' => 'strlen',
62: 'lower' => 'strlen',
63: 'space' => 'strlen',
64: 'upper' => 'strlen',
65: 'xdigit' => 'strlen',
66: );
67:
68:
69: 70: 71: 72: 73: 74: 75:
76: public static function assert($value, $expected, $label = 'variable')
77: {
78: if (!static::is($value, $expected)) {
79: $expected = str_replace(array('|', ':'), array(' or ', ' in range '), $expected);
80: if (is_array($value)) {
81: $type = 'array(' . count($value) . ')';
82: } elseif (is_object($value)) {
83: $type = 'object ' . get_class($value);
84: } elseif (is_string($value) && strlen($value) < 40) {
85: $type = "string '$value'";
86: } else {
87: $type = gettype($value);
88: }
89: throw new AssertionException("The $label expects to be $expected, $type given.");
90: }
91: }
92:
93:
94: 95: 96: 97: 98: 99: 100: 101:
102: public static function assertField($arr, $field, $expected = NULL, $label = "item '%' in array")
103: {
104: self::assert($arr, 'array', 'first argument');
105: if (!array_key_exists($field, $arr)) {
106: throw new AssertionException('Missing ' . str_replace('%', $field, $label) . '.');
107:
108: } elseif ($expected) {
109: static::assert($arr[$field], $expected, str_replace('%', $field, $label));
110: }
111: }
112:
113:
114: 115: 116: 117: 118: 119:
120: public static function is($value, $expected)
121: {
122: foreach (explode('|', $expected) as $item) {
123: list($type) = $item = explode(':', $item, 2);
124: if (isset(static::$validators[$type])) {
125: if (!call_user_func(static::$validators[$type], $value)) {
126: continue;
127: }
128: } elseif ($type === 'number') {
129: if (!is_int($value) && !is_float($value)) {
130: continue;
131: }
132: } elseif ($type === 'pattern') {
133: if (preg_match('|^' . (isset($item[1]) ? $item[1] : '') . '\z|', $value)) {
134: return TRUE;
135: }
136: continue;
137: } elseif (!$value instanceof $type) {
138: continue;
139: }
140:
141: if (isset($item[1])) {
142: $length = $value;
143: if (isset(static::$counters[$type])) {
144: $length = call_user_func(static::$counters[$type], $value);
145: }
146: $range = explode('..', $item[1]);
147: if (!isset($range[1])) {
148: $range[1] = $range[0];
149: }
150: if (($range[0] !== '' && $length < $range[0]) || ($range[1] !== '' && $length > $range[1])) {
151: continue;
152: }
153: }
154: return TRUE;
155: }
156: return FALSE;
157: }
158:
159:
160: 161: 162: 163:
164: public static function isNumericInt($value)
165: {
166: return is_int($value) || is_string($value) && preg_match('#^-?[0-9]+\z#', $value);
167: }
168:
169:
170: 171: 172: 173:
174: public static function isNumeric($value)
175: {
176: return is_float($value) || is_int($value) || is_string($value) && preg_match('#^-?[0-9]*[.]?[0-9]+\z#', $value);
177: }
178:
179:
180: 181: 182: 183:
184: public static function isCallable($value)
185: {
186: return $value && is_callable($value, TRUE);
187: }
188:
189:
190: 191: 192: 193: 194:
195: public static function isUnicode($value)
196: {
197: return is_string($value) && preg_match('##u', $value);
198: }
199:
200:
201: 202: 203: 204:
205: public static function isNone($value)
206: {
207: return $value == NULL;
208: }
209:
210:
211: 212: 213: 214: 215:
216: public static function isList($value)
217: {
218: return Arrays::isList($value);
219: }
220:
221:
222: 223: 224: 225: 226: 227:
228: public static function isInRange($value, $range)
229: {
230: return (!isset($range[0]) || $range[0] === '' || $value >= $range[0])
231: && (!isset($range[1]) || $range[1] === '' || $value <= $range[1]);
232: }
233:
234:
235: 236: 237: 238: 239:
240: public static function isEmail($value)
241: {
242: $atom = "[-a-z0-9!#$%&'*+/=?^_`{|}~]";
243: $alpha = "a-z\x80-\xFF";
244: return (bool) preg_match("(^
245: (\"([ !#-[\\]-~]*|\\\\[ -~])+\"|$atom+(\\.$atom+)*) # quoted or unquoted
246: @
247: ([0-9$alpha]([-0-9$alpha]{0,61}[0-9$alpha])?\\.)+ # domain - RFC 1034
248: [$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain
249: \\z)ix", $value);
250: }
251:
252:
253: 254: 255: 256: 257:
258: public static function isUrl($value)
259: {
260: $alpha = "a-z\x80-\xFF";
261: return (bool) preg_match("(^
262: https?://(
263: (([-_0-9$alpha]+\\.)* # subdomain
264: [0-9$alpha]([-0-9$alpha]{0,61}[0-9$alpha])?\\.)? # domain
265: [$alpha]([-0-9$alpha]{0,17}[$alpha])? # top domain
266: |\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3} # IPv4
267: |\[[0-9a-f:]{3,39}\] # IPv6
268: )(:\\d{1,5})? # port
269: (/\\S*)? # path
270: \\z)ix", $value);
271: }
272:
273:
274: 275: 276: 277: 278:
279: public static function isUri($value)
280: {
281: return (bool) preg_match('#^[a-z\d+\.-]+:\S+\z#i', $value);
282: }
283:
284:
285: 286: 287: 288: 289:
290: public static function isType($type)
291: {
292: return class_exists($type) || interface_exists($type) || (PHP_VERSION_ID >= 50400 && trait_exists($type));
293: }
294:
295:
296: 297: 298: 299:
300: public static function isPhpIdentifier($value)
301: {
302: return is_string($value) && preg_match('#^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*\z#', $value);
303: }
304:
305: }
306:
307:
308: 309: 310:
311: class AssertionException extends \Exception
312: {
313: }
314: