/
Validator.class.php
201 lines (167 loc) · 7 KB
/
Validator.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
<?php
/**
* PandraValidator
*
* Validates an input against an array of defined data types, populating an error
* message and logging to debug loggers
*
* @author Michael Pearson <pandra-support@phpgrease.net>
* @copyright 2010 phpgrease.net
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
* @version 0.2.1
* @package pandra
*/
class PandraValidator {
// primitives for which there is self::check() logic
static public $primitive = array(
'notempty',
'isempty', // honeypot
'int',
'float',
'numeric',
'string',
'bool', // PHP bool types or strings 'true', 'false', 't', 'f', '1', '0', 'y', 'n'
'maxlength', // =[length]
'minlength', // =[length]
'enum', // =[comma,delimitered,enumerates]
'email',
'url',
'uuid'
);
/**
* Complex types are aggregates of the predefined primitive type definitions. Similarly,
* the type definitions can also be aggregated to build even more complex types (try not to get crazy with the stack yo).
* In cases where there appears to be collision between types (aggregate types with different maxlength options for example)
* the final type will be viewed as authoritive.
*/
static public $complex = array(
'stringregular' => array('string', 'notempty'),
'string20' => array('stringregular', 'maxlength=20'),
);
/**
* Type definition is defined
* @param string $typeDef check type is available
* @return bool type exists
*/
static public function exists($typeDef) {
if (stripos($typeDef, '=') != 0) {
list($type, $args) = explode('=', $typeDef);
} else {
$type = $typeDef;
}
return (in_array($type, self::$primitive) || array_key_exists($type, self::$complex));
}
/**
* given a typedef array, detects complex types and expands to primitives
* @param array &$typeDefs validating type definitions
*/
static private function typeExpander(&$typeDefs) {
$isComplex = FALSE;
foreach ($typeDefs as $idx => $typeDef) {
// check if type is complex
if (array_key_exists($typeDef, self::$complex)) {
// drop this complex type from our typeDefs, ready to expand
unset($typeDefs[$idx]);
// merge against complex type def
$typeDefs = array_merge($typeDefs, self::$complex[$typeDef]);
// if it looks like this type has expanded to another complex type, then flag for recursion
foreach ($typeDefs as $xType) {
if (array_key_exists($xType, self::$complex)) {
$isComplex = TRUE;
}
}
}
}
// recurse, expand out new complex type
if ($isComplex) self::typeExpander($typeDefs);
}
/**
* Validates a field
* @param string $errorMsg custom error message for field validation error
* @return bool field validated correctly
*/
static public function check($value, $label, $typeDefs, &$errors) {
if (empty($typeDefs)) return TRUE;
if (!is_array($typeDefs)) $typeDefs = array($typeDefs);
// normalise to real type defs if complex types found
self::typeExpander($typeDefs);
$error = FALSE;
$errorMsg = array();
foreach ($typeDefs as $type) {
if (preg_match('/=/', $type)) {
list($type, $args) = explode("=", $type);
}
if (!in_array($type, self::$primitive)) {
throw new RuntimeException("undefined type definition ($type)");
}
// check for basic validator types
switch ($type) {
case 'notempty' :
$error = empty($value);
if ($error) $errorMsg[] = "Field cannot be empty";
break;
case 'isempty' :
// NULL is never allowed, just empty strings
$error = ($value != '');
if ($error) $errorMsg[] = "Field must be empty";
break;
case 'email' :
$error = !filter_var($value, FILTER_VALIDATE_EMAIL);
if ($error) $errorMsg[] = "Invalid email address";
break;
case 'url' :
$error = !filter_var($value, FILTER_VALIDATE_URL);
if ($error) $errorMsg[] = "Invalid URL";
break;
case 'float' :
$error = !is_float($value);
if ($error) $errorMsg[] = "Field error, expected ".$type;
break;
case 'int' :
case 'numeric' :
$error = !is_numeric($value);
if ($error) $errorMsg[] = "Field error, expected ".$type;
break;
case 'string' :
$error = !is_string($value);
if ($error) $errorMsg[] = "Field error, expected ".$type;
break;
case 'bool' :
$val = strtolower($value);
$boolVals = array('true', 'false', 't', 'f', '1', '0', 'y', 'n');
$error = !is_bool($value) && !(in_array($val, $boolVals));
if ($error) $errorMsg[] = "Field error, expected ".$type;
break;
case 'maxlength' :
if (empty($args)) throw new RuntimeException("type $type requires argument");
$error = (strlen($value) > $args);
if ($error) $errorMsg[] = "Maximum length $args exceeded";
break;
case 'minlength' :
if (empty($args)) throw new RuntimeException("type $type requires argument");
$error = (strlen($value) < $args);
if ($error) $errorMsg[] = "Minimum length $args unmet";
break;
case 'enum' :
if (empty($args)) throw new RuntimeException("type $type requires argument");
$enums = explode(",", $args);
$error = (!in_array($value, $enums));
if ($error) $errorMsg[] = "Invalid Argument";
break;
case 'uuid' :
$error = (!UUID::validUUID($value));
if ($error) $errorMsg[] = "Invalid UUID (UUID String expected)";
break;
default :
throw new RuntimeException("Unhandled type definition ($type)");
break;
}
}
if (!empty($errorMsg)) {
$errors[] = array($label => $errorMsg);
PandraLog::debug(array($label => $errorMsg));
}
return empty($errorMsg);
}
}
?>