265 |
266 | | Rule |
267 | Parameter |
268 | Description |
269 | Example |
270 |
271 |
272 | | required |
273 | No |
274 | Returns FALSE if the input is empty |
275 | |
276 |
277 |
278 | | numeric |
279 | No |
280 | Returns FALSE if the input is not numeric |
281 | |
282 |
283 |
284 | | email |
285 | No |
286 | Returns FALSE if the input is not a valid email address |
287 | |
288 |
289 |
290 | | integer |
291 | No |
292 | Returns FALSE if the input is not an integer value |
293 | |
294 |
295 |
296 | | float |
297 | No |
298 | Returns FALSE if the input is not a float value |
299 | |
300 |
301 |
302 | | alpha |
303 | No |
304 | Returns FALSE if the input contains non-alphabetical characters |
305 | |
306 |
307 |
308 | | alpha_numeric |
309 | No |
310 | Returns FALSE if the input contains non-alphabetical and numeric characters |
311 | |
312 |
313 |
314 | | ip |
315 | No |
316 | Returns FALSE if the input is not a valid IP (IPv6 supported) |
317 | |
318 |
319 |
320 | | url |
321 | No |
322 | Returns FALSE if the input is not a valid URL |
323 | |
324 |
325 |
326 | | max_length |
327 | Yes |
328 | Returns FALSE if the input is longer than the parameter |
329 | max_length(10) |
330 |
331 |
332 | | min_length |
333 | Yes |
334 | Returns FALSE if the input is shorter than the parameter |
335 | min_length(10) |
336 |
337 |
338 | | exact_length |
339 | Yes |
340 | Returns FALSE if the input is not exactly parameter value long |
341 | exact_length(10) |
342 |
343 |
344 | | equals |
345 | Yes |
346 | Returns FALSE if the input is not same as the parameter |
347 | equals(:password_verify) or equals(foo) |
348 |
349 |
350 |
--------------------------------------------------------------------------------
/src/SimpleValidator/Validator.php:
--------------------------------------------------------------------------------
1 |
8 | * @copyright (c) 2013, Can Geliş
9 | * @license https://github.com/cangelis/simple-validator/blob/master/licence.txt MIT Licence
10 | * @link https://github.com/cangelis/simple-validator
11 | */
12 |
13 | /**
14 | * TODO: Exception handling for rules with parameters
15 | * TODO: unit tests for numeric, float, alpha_numeric, max_length, min_length, exact_length
16 | * TODO: add protection filters for several input vulnerabilities.
17 | */
18 | class Validator {
19 |
20 | protected $errors = array();
21 | protected $namings = array();
22 | protected $customErrorsWithInputName = array();
23 | protected $customErrors = array();
24 |
25 | /**
26 | * Constructor is not allowed because SimpleValidator uses its own
27 | * static method to instantiate the validaton
28 | */
29 | private function __construct($errors, $namings) {
30 | $this->errors = (array) $errors;
31 | $this->namings = (array) $namings;
32 | }
33 |
34 | /**
35 | *
36 | * @return boolean
37 | */
38 | public function isSuccess() {
39 | return (empty($this->errors) == true);
40 | }
41 |
42 | /**
43 | *
44 | * @param Array $errors_array
45 | */
46 | public function customErrors($errors_array) {
47 | foreach ($errors_array as $key => $value) {
48 | // handle input.rule eg (name.required)
49 | if (preg_match("#^(.+?)\.(.+?)$#", $key, $matches)) {
50 | // $this->customErrorsWithInputName[name][required] = error message
51 | $this->customErrorsWithInputName[(string) $matches[1]][(string) $matches[2]] = $value;
52 | } else {
53 | $this->customErrors[(string) $key] = $value;
54 | }
55 | }
56 | }
57 |
58 | protected function getDefaultLang() {
59 | return "en";
60 | }
61 |
62 | protected function getErrorFilePath($lang) {
63 | return null;
64 | }
65 |
66 | protected function getDefaultErrorTexts($lang = null) {
67 | /* handle default error text file */
68 | $default_error_texts = array();
69 | if (file_exists(__DIR__ . "/../../errors/" . $lang . ".php")) {
70 | $default_error_texts = include(__DIR__ . "/../../errors/" . $lang . ".php");
71 | }
72 | return $default_error_texts;
73 | }
74 |
75 | protected function getCustomErrorTexts($lang = null) {
76 | /* handle error text file for custom validators */
77 | $custom_error_texts = array();
78 | if (file_exists($this->getErrorFilePath($lang)))
79 | $custom_error_texts = include($this->getErrorFilePath($lang));
80 | return $custom_error_texts;
81 | }
82 |
83 | protected function handleNaming($input_name) {
84 | if (isset($this->namings[(string) $input_name])) {
85 | $named_input = $this->namings[(string) $input_name];
86 | } else {
87 | $named_input = $input_name;
88 | }
89 | return $named_input;
90 | }
91 |
92 | protected function handleParameterNaming($params) {
93 | foreach ($params as $key => $param) {
94 | if (preg_match("#^:([a-zA-Z0-9_]+)$#", $param, $param_type)) {
95 | if (isset($this->namings[(string) $param_type[1]]))
96 | $params[$key] = $this->namings[(string) $param_type[1]];
97 | else
98 | $params[$key] = $param_type[1];
99 | }
100 | }
101 | return $params;
102 | }
103 |
104 | /**
105 | *
106 | * @param string $error_file
107 | * @return array
108 | * @throws SimpleValidatorException
109 | */
110 | public function getErrors($lang = null) {
111 | if ($lang == null)
112 | $lang = $this->getDefaultLang();
113 |
114 | $error_results = array();
115 | $default_error_texts = $this->getDefaultErrorTexts($lang);
116 | $custom_error_texts = $this->getCustomErrorTexts($lang);
117 | foreach ($this->errors as $input_name => $results) {
118 | foreach ($results as $rule => $result) {
119 | $named_input = $this->handleNaming($input_name);
120 | /**
121 | * if parameters are input name they should be named as well
122 | */
123 | $result['params'] = $this->handleParameterNaming($result['params']);
124 | // if there is a custom message with input name, apply it
125 | if (isset($this->customErrorsWithInputName[(string) $input_name][(string) $rule])) {
126 | $error_message = $this->customErrorsWithInputName[(string) $input_name][(string) $rule];
127 | }
128 | // if there is a custom message for the rule, apply it
129 | else if (isset($this->customErrors[(string) $rule])) {
130 | $error_message = $this->customErrors[(string) $rule];
131 | }
132 | // if there is a custom validator try to fetch from its error file
133 | else if (isset($custom_error_texts[(string) $rule])) {
134 | $error_message = $custom_error_texts[(string) $rule];
135 | }
136 | // if none try to fetch from default error file
137 | else if (isset($default_error_texts[(string) $rule])) {
138 | $error_message = $default_error_texts[(string) $rule];
139 | } else {
140 | throw new SimpleValidatorException(SimpleValidatorException::NO_ERROR_TEXT, $rule);
141 | }
142 | /**
143 | * handle :params(..)
144 | */
145 | if (preg_match_all("#:params\((.+?)\)#", $error_message, $param_indexes))
146 | foreach ($param_indexes[1] as $param_index) {
147 | $error_message = str_replace(":params(" . $param_index . ")", $result['params'][$param_index], $error_message);
148 | }
149 | $error_results[] = str_replace(":attribute", $named_input, $error_message);
150 | }
151 | }
152 | return $error_results;
153 | }
154 |
155 | /**
156 | *
157 | * @return boolean
158 | */
159 | public function has($input_name, $rule_name = null) {
160 | if ($rule_name != null)
161 | return isset($this->errors[$input_name][$rule_name]);
162 | return isset($this->errors[$input_name]);
163 | }
164 |
165 | final public function getResults() {
166 | return $this->errors;
167 | }
168 |
169 | /**
170 | * Gets the parameter names of a rule
171 | * @param type $rule
172 | * @return mixed
173 | */
174 | private static function getParams($rule) {
175 | if (preg_match("#^([a-zA-Z0-9_]+)\((.+?)\)$#", $rule, $matches)) {
176 | return array(
177 | 'rule' => $matches[1],
178 | 'params' => explode(",", $matches[2])
179 | );
180 | }
181 | return array(
182 | 'rule' => $rule,
183 | 'params' => array()
184 | );
185 | }
186 |
187 | /**
188 | * Handle parameter with input name
189 | * eg: equals(:name)
190 | * @param mixed $params
191 | * @return mixed
192 | */
193 | private static function getParamValues($params, $inputs) {
194 | foreach ($params as $key => $param) {
195 | if (preg_match("#^:([\[\]a-zA-Z0-9_]+)$#", $param, $param_type)) {
196 | $params[$key] = @$inputs[(string) $param_type[1]];
197 | }
198 | }
199 | return $params;
200 | }
201 |
202 | /**
203 | *
204 | * @param Array $inputs
205 | * @param Array $rules
206 | * @param Array $naming
207 | * @return Validator
208 | * @throws SimpleValidatorException
209 | */
210 | public static function validate($inputs, $rules, $naming = null) {
211 | $errors = null;
212 | foreach ($rules as $input => $input_rules) {
213 | if (is_array($input_rules)) {
214 | foreach ($input_rules as $rule => $closure) {
215 | if (!isset($inputs[(string) $input]))
216 | $input_value = null;
217 | else
218 | $input_value = $inputs[(string) $input];
219 | /**
220 | * if the key of the $input_rules is numeric that means
221 | * it's neither an anonymous nor an user function.
222 | */
223 | if (is_numeric($rule)) {
224 | $rule = $closure;
225 | }
226 | $rule_and_params = static::getParams($rule);
227 | $params = $real_params = $rule_and_params['params'];
228 | $rule = $rule_and_params['rule'];
229 | $params = static::getParamValues($params, $inputs);
230 | array_unshift($params, $input_value);
231 | /**
232 | * Handle anonymous functions
233 | */
234 | if(is_object($closure) && get_class($closure) == 'Closure') {
235 | $refl_func = new \ReflectionFunction($closure);
236 | $validation = $refl_func->invokeArgs($params);
237 | }/**
238 | * handle class methods
239 | */ else if (@method_exists(get_called_class(), $rule)) {
240 | $refl = new \ReflectionMethod(get_called_class(), $rule);
241 | if ($refl->isStatic()) {
242 | $refl->setAccessible(true);
243 | $validation = $refl->invokeArgs(null, $params);
244 | } else {
245 | throw new SimpleValidatorException(SimpleValidatorException::STATIC_METHOD, $rule);
246 | }
247 | } else {
248 | throw new SimpleValidatorException(SimpleValidatorException::UNKNOWN_RULE, $rule);
249 | }
250 | if ($validation == false) {
251 | $errors[(string) $input][(string) $rule]['result'] = false;
252 | $errors[(string) $input][(string) $rule]['params'] = $real_params;
253 | }
254 | }
255 | } else {
256 | throw new SimpleValidatorException(SimpleValidatorException::ARRAY_EXPECTED, $input);
257 | }
258 | }
259 | return new static($errors, $naming);
260 | }
261 |
262 | protected static function required($input = null) {
263 | return (!is_null($input) && (trim($input) != ''));
264 | }
265 |
266 | protected static function numeric($input) {
267 | return is_numeric($input);
268 | }
269 |
270 | protected static function email($input) {
271 | return filter_var($input, FILTER_VALIDATE_EMAIL);
272 | }
273 |
274 | protected static function integer($input) {
275 | return is_int($input) || ($input == (string) (int) $input);
276 | }
277 |
278 | protected static function float($input) {
279 | return is_float($input) || ($input == (string) (float) $input);
280 | }
281 |
282 | protected static function alpha($input) {
283 | return (preg_match("#^[a-zA-ZÀ-ÿ]+$#", $input) == 1);
284 | }
285 |
286 | protected static function alpha_numeric($input) {
287 | return (preg_match("#^[a-zA-ZÀ-ÿ0-9]+$#", $input) == 1);
288 | }
289 |
290 | protected static function ip($input) {
291 | return filter_var($input, FILTER_VALIDATE_IP);
292 | }
293 |
294 | /*
295 | * TODO: need improvements for tel and urn urls.
296 | * check out url.test.php for the test result
297 | * urn syntax: http://www.faqs.org/rfcs/rfc2141.html
298 | *
299 | */
300 |
301 | protected static function url($input) {
302 | return filter_var($input, FILTER_VALIDATE_URL);
303 | }
304 |
305 | protected static function max_length($input, $length) {
306 | return (strlen($input) <= $length);
307 | }
308 |
309 | protected static function min_length($input, $length) {
310 | return (strlen($input) >= $length);
311 | }
312 |
313 | protected static function exact_length($input, $length) {
314 | return (strlen($input) == $length);
315 | }
316 |
317 | protected static function equals($input, $param) {
318 | return ($input == $param);
319 | }
320 |
321 | }
322 |
--------------------------------------------------------------------------------