Completed
Push — master ( 500912...f85444 )
by Jared
02:28
created

Validator::email()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
c 1
b 1
f 1
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 2
1
<?php
2
3
/**
4
 * @author Jared King <[email protected]>
5
 *
6
 * @link http://jaredtking.com
7
 *
8
 * @copyright 2015 Jared King
9
 * @license MIT
10
 */
11
namespace Pulsar;
12
13
use Infuse\Utility;
14
15
class Validator
16
{
17
    /**
18
     * @staticvar array
19
     */
20
    private static $config = [
21
        'salt' => '',
22
    ];
23
24
    /**
25
     * @var array
26
     */
27
    private $requirements;
28
29
    /**
30
     * @var Errors
31
     */
32
    private $errors;
33
34
    /**
35
     * @var bool
36
     */
37
    private $skipRemaining;
38
39
    /**
40
     * Changes settings for the validator.
41
     *
42
     * @param array $config
43
     */
44
    public static function configure($config)
45
    {
46
        self::$config = array_replace(self::$config, (array) $config);
47
    }
48
49
    /**
50
     * @var array
51
     * @var Errors
52
     */
53
    public function __construct(array $requirements, Errors $errors = null)
54
    {
55
        // parse requirement strings if used
56
        foreach ($requirements as &$requirements2) {
57
            if (!is_array($requirements2)) {
58
                $requirements2 = $this->buildRequirementsFromStr($requirements2);
59
            }
60
        }
61
62
        $this->requirements = $requirements;
63
        $this->errors = $errors;
64
    }
65
66
    /**
67
     * Validates whether an input matches the requirements.
68
     *
69
     * @param array $data
70
     *
71
     * @return bool
72
     */
73
    public function validate(array &$data)
74
    {
75
        $validated = true;
76
        foreach ($this->requirements as $name => $requirements) {
77
            if (!array_key_exists($name, $data)) {
78
                $data[$name] = null;
79
            }
80
81
            $this->skipRemaining = false;
82
83
            foreach ($requirements as $requirement) {
84
                list($filter, $parameters) = $requirement;
85
86
                $valid = self::$filter($data[$name], $parameters);
87
                $validated = $validated && $valid;
88
89
                if (!$valid && $this->errors) {
90
                    $this->errors->add($name, "pulsar.validation.$filter");
91
                }
92
93
                if ($this->skipRemaining) {
94
                    break;
95
                }
96
            }
97
        }
98
99
        return $validated;
100
    }
101
102
    /**
103
     * Parses a string into a list of requirements.
104
     * Requirement strings have the form "numeric|range:10,30" where
105
     * '|' separates filters and ':' allows a comma-separated list
106
     * of parameters to be specified. This example would generate 
107
     * [['numeric', []], ['range', [10, 30]]].
108
     *
109
     * @param string $requirements
0 ignored issues
show
Bug introduced by
There is no parameter named $requirements. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
110
     *
111
     * @return array
112
     */
113
    private function buildRequirementsFromStr($str)
114
    {
115
        $requirements = [];
116
117
        // explodes the string into a a list of strings
118
        // containing filters and parameters
119
        $pieces = explode('|', $str);
120
        foreach ($pieces as $piece) {
121
            $exp = explode(':', $piece);
122
            // [0] = filter method
123
            $method = $exp[0];
0 ignored issues
show
Unused Code introduced by
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
124
            // [1] = optional method parameters
125
            $parameters = isset($exp[1]) ? explode(',', $exp[1]) : [];
126
127
            $requirements[] = [$exp[0], $parameters];
128
        }
129
130
        return $requirements;
131
    }
132
133
    /**
134
     * Skips remaining requirements.
135
     *
136
     * @return self
137
     */
138
    private function skipRemaining()
139
    {
140
        $this->skipRemaining = true;
141
142
        return $this;
143
    }
144
145
    ////////////////////////////////
146
    // FILTERS
147
    ////////////////////////////////
148
149
    /**
150
     * Validates an alpha string.
151
     * OPTIONAL alpha:5 can specify minimum length.
152
     *
153
     * @param mixed $value
154
     * @param array $parameters
155
     *
156
     * @return bool
157
     */
158
    private function alpha($value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
159
    {
160
        return preg_match('/^[A-Za-z]*$/', $value) && strlen($value) >= array_value($parameters, 0);
161
    }
162
163
    /**
164
     * Validates an alpha-numeric string
165
     * OPTIONAL alpha_numeric:6 can specify minimum length.
166
     *
167
     * @param mixed $value
168
     * @param array $parameters
169
     *
170
     * @return bool
171
     */
172
    private function alpha_numeric($value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
173
    {
174
        return preg_match('/^[A-Za-z0-9]*$/', $value) && strlen($value) >= array_value($parameters, 0);
175
    }
176
177
    /**
178
     * Validates an alpha-numeric string with dashes and underscores
179
     * OPTIONAL alpha_dash:7 can specify minimum length.
180
     *
181
     * @param mixed $value
182
     * @param array $parameters
183
     *
184
     * @return bool
185
     */
186
    private function alpha_dash($value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
187
    {
188
        return preg_match('/^[A-Za-z0-9_-]*$/', $value) && strlen($value) >= array_value($parameters, 0);
189
    }
190
191
    /**
192
     * Validates a boolean value.
193
     *
194
     * @param mixed $value
195
     *
196
     * @return bool
197
     */
198
    private function boolean(&$value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
199
    {
200
        $value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
201
202
        return true;
203
    }
204
205
    /**
206
     * Validates by calling a given function.
207
     *
208
     * @param mixed $value
209
     * @param array $parameters
210
     *
211
     * @return bool
212
     */
213
    private function custom(&$value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
214
    {
215
        $method = $parameters[0];
216
        $parameters2 = (array) array_slice($parameters, 1);
217
218
        return $method($value, $parameters2);
219
    }
220
221
    /**
222
     * Validates an e-mail address.
223
     *
224
     * @param string $email      e-mail address
0 ignored issues
show
Bug introduced by
There is no parameter named $email. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
225
     * @param array  $parameters parameters for validation
226
     *
227
     * @return bool success
228
     */
229
    private function email(&$value, array $parameters)
0 ignored issues
show
Unused Code introduced by
The parameter $parameters is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
230
    {
231
        $value = trim(strtolower($value));
232
233
        return filter_var($value, FILTER_VALIDATE_EMAIL);
234
    }
235
236
    /**
237
     * Validates a value exists in an array. i.e. enum:blue,red,green,yellow.
238
     *
239
     * @param mixed $value
240
     * @param array $parameters
241
     *
242
     * @return bool
243
     */
244
    private function enum($value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
245
    {
246
        return in_array($value, $parameters);
247
    }
248
249
    /**
250
     * Validates a date string.
251
     *
252
     * @param mixed $value
253
     *
254
     * @return bool
255
     */
256
    private function date($value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
257
    {
258
        return strtotime($value);
259
    }
260
261
    /**
262
     * Validates an IP address.
263
     *
264
     * @param mixed $value
265
     *
266
     * @return bool
267
     */
268
    private function ip($value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
269
    {
270
        return filter_var($value, FILTER_VALIDATE_IP);
271
    }
272
273
    /**
274
     * Validates that an array of values matches. The array will
275
     * be flattened to a single value if it matches.
276
     *
277
     * @param mixed $value
278
     *
279
     * @return bool
280
     */
281
    private function matching(&$value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
282
    {
283
        if (!is_array($value)) {
284
            return true;
285
        }
286
287
        $matches = true;
288
        $cur = reset($value);
289
        foreach ($value as $v) {
290
            $matches = ($v == $cur) && $matches;
291
            $cur = $v;
292
        }
293
294
        if ($matches) {
295
            $value = $cur;
296
        }
297
298
        return $matches;
299
    }
300
301
    /**
302
     * Validates a number.
303
     * OPTIONAL numeric:int specifies a type.
304
     *
305
     * @param mixed $value
306
     * @param array $parameters
307
     *
308
     * @return bool
309
     */
310
    private function numeric($value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
311
    {
312
        $check = 'is_'.array_value($parameters, 0);
313
314
        return (!isset($parameters[0])) ? is_numeric($value) : $check($value);
315
    }
316
317
    /**
318
     * Validates a password and hashes the value.
319
     * OPTIONAL password:10 sets the minimum length.
320
     *
321
     * @param mixed $value
322
     * @param array $parameters
323
     *
324
     * @return bool
325
     */
326
    private function password(&$value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
327
    {
328
        $minimumPasswordLength = (isset($parameters[0])) ? $parameters[0] : 8;
329
330
        if (strlen($value) < $minimumPasswordLength) {
331
            return false;
332
        }
333
334
        $value = Utility::encryptPassword($value, self::$config['salt']);
335
336
        return true;
337
    }
338
339
    /**
340
     * Validates that a number falls within a range.
341
     *
342
     * @param mixed $value
343
     * @param array $parameters
344
     *
345
     * @return bool
346
     */
347
    private function range($value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
348
    {
349
        // check min
350
        if (isset($parameters[0]) && $value < $parameters[0]) {
351
            return false;
352
        }
353
354
        // check max
355
        if (isset($parameters[1]) && $value > $parameters[1]) {
356
            return false;
357
        }
358
359
        return true;
360
    }
361
362
    /**
363
     * Makes sure that a variable is not empty.
364
     *
365
     * @param mixed $value
366
     *
367
     * @return bool
368
     */
369
    private function required($value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
370
    {
371
        return !empty($value);
372
    }
373
374
    /**
375
     * Skips any remaining requirements for a field if the
376
     * value is empty.
377
     *
378
     * @param mixed $value
379
     *
380
     * @return bool
381
     */
382
    public function skip_empty(&$value)
383
    {
384
        if (empty($value)) {
385
            $value = null;
386
            $this->skipRemaining();
387
        }
388
389
        return true;
390
    }
391
392
    /**
393
     * Validates a string.
394
     * OPTIONAL string:5 supplies a minimum length
395
     *          string:1:5 supplies a minimum and maximum length.
396
     *
397
     * @param mixed $value
398
     * @param array $parameters
399
     *
400
     * @return bool
401
     */
402
    private function string($value, array $parameters)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
403
    {
404
        if (!is_string($value)) {
405
            return false;
406
        }
407
408
        $len = strlen($value);
409
        $min = array_value($parameters, 0);
410
        $max = array_value($parameters, 1);
411
412
        return $len >= $min && (!$max || $len <= $max);
413
    }
414
415
    /**
416
     * Validates a PHP time zone identifier.
417
     *
418
     * @param mixed $value
419
     *
420
     * @return bool
421
     */
422
    private function time_zone($value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
423
    {
424
        // thanks to http://stackoverflow.com/questions/5816960/how-to-check-is-timezone-identifier-valid-from-code
425
        $valid = [];
426
        $tza = timezone_abbreviations_list();
427
        foreach ($tza as $zone) {
428
            foreach ($zone as $item) {
429
                $valid[$item['timezone_id']] = true;
430
            }
431
        }
432
        unset($valid['']);
433
434
        return !!array_value($valid, $value);
435
    }
436
437
    /**
438
     * Validates a Unix timestamp. If the value is not a timestamp it will be
439
     * converted to one with strtotime().
440
     *
441
     * @param mixed $value
442
     *
443
     * @return bool
444
     */
445
    private function timestamp(&$value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
446
    {
447
        if (ctype_digit((string) $value)) {
448
            return true;
449
        }
450
451
        $value = strtotime($value);
452
453
        return !!$value;
454
    }
455
456
    /**
457
     * Converts a Unix timestamp into a format compatible with database
458
     * timestamp types.
459
     *
460
     * @param mixed $value
461
     *
462
     * @return bool
463
     */
464
    private function db_timestamp(&$value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
465
    {
466
        if (is_integer($value)) {
467
            $value = Utility::unixToDb($value);
468
469
            return true;
470
        }
471
472
        return false;
473
    }
474
475
    /**
476
     * Validates a URL.
477
     *
478
     * @param mixed $value
479
     *
480
     * @return bool
481
     */
482
    private function url($value)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
483
    {
484
        return filter_var($value, FILTER_VALIDATE_URL);
485
    }
486
}
487