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