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