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