Completed
Push — master ( 906e59...08ade2 )
by AJ
02:01
created

Validation::validateIP()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 2
dl 0
loc 7
ccs 4
cts 4
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 *       __  ___      ____  _     ___                           _                    __
4
 *      /  |/  /_  __/ / /_(_)___/ (_)___ ___  ___  ____  _____(_)___  ____   ____ _/ /
5
 *     / /|_/ / / / / / __/ / __  / / __ `__ \/ _ \/ __ \/ ___/ / __ \/ __ \ / __ `/ /
6
 *    / /  / / /_/ / / /_/ / /_/ / / / / / / /  __/ / / (__  ) / /_/ / / / // /_/ / /
7
 *   /_/  /_/\__,_/_/\__/_/\__,_/_/_/ /_/ /_/\___/_/ /_/____/_/\____/_/ /_(_)__,_/_/
8
 *
9
 *  Array Validation Library
10
 *  Copyright (c) Multidimension.al (http://multidimension.al)
11
 *  Github : https://github.com/multidimension-al/array-validation
12
 *
13
 *  Licensed under The MIT License
14
 *  For full copyright and license information, please see the LICENSE file
15
 *  Redistributions of files must retain the above copyright notice.
16
 *
17
 *  @copyright  Copyright © 2017-2019 Multidimension.al (http://multidimension.al)
18
 *  @link       https://github.com/multidimension-al/array-validation Github
19
 *  @license    http://www.opensource.org/licenses/mit-license.php MIT License
20
 */
21
22
namespace Multidimensional\ArrayValidation;
23
24
use Exception;
25
26
class Validation
27
{
28
    /**
29
     * @param array $array
30
     * @param array $rules
31
     * @return true
32
     * @throws Exception
33
     */
34 54
    public static function validate($array, $rules)
35
    {
36 54
        if (is_array($array) && is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
37 52
            self::checkRequired($array, $rules);
38 48
            foreach ($array as $key => $value) {
39 46
                if (!isset($rules[$key]) && !array_key_exists($key, $rules)) {
40 2
                    throw new Exception(sprintf('Unexpected key "%s" found in array.', $key));
41
                }
42
43 46
                if (is_array($value) && isset($rules[$key]['type']) && strtolower($rules[$key]['type']) == 'array' && isset($rules[$key]['fields'])) {
44 6
                    self::validate($value, $rules[$key]['fields']);
45 46
                } elseif (in_array($key, array_keys($rules))) {
46 48
                    self::validateField($value, $rules[$key], $key);
47
                }
48
            }
49 2
        } elseif (!is_array($array)) {
50 2
            throw new Exception('Validation array not found.');
51 2
        } elseif (!is_array($rules)) {
52 2
            throw new Exception('Validation rules array not found.');
53
        }
54
55 42
        return true;
56
    }
57
58
    /**
59
     * Main required check function. Must be fed with two variables, both of type array.
60
     * Returns void if all checks pass without a Exception being thrown. Only
61
     * performs checkRequired operation on values that are not set in the main $array.
62
     *
63
     * @param array $array Validation Array comprised of key / value pairs to be checked.
64
     * @param array $rules Rules Array comprised of properly formatted keys with rules.
65
     * @return void
66
     * @throws Exception
67
     */
68 52
    protected static function checkRequired($array, $rules)
69
    {
70 52
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
71 52
            foreach ($rules as $key => $value) {
72 50
                if (self::requiredNull($array, $key)) {
73 18
                    if (isset($value['required'])) {
74 10
                        if (is_array($value['required']) && !self::requiredOne($array, $value['required'])) {
75
                            //
76 10
                        } elseif (($value['required'] == 'true' || $value['required'] === true) && isset($array[$key])) {
77
                            //
78
                        } else {
79 50
                            throw new Exception(sprintf('Required value not found for key: %s.', $key));
80
                        }
81
                    }
82
                }
83
            }
84
        }
85
86 48
        return;
87
    }
88
89
    /**
90
     * Returns true when $key value is null, returns false when it is not.
91
     *
92
     * @param array $array
93
     * @param string $key
94
     * @return true|false
95
     */
96 50
    protected static function requiredNull($array, $key)
97
    {
98 50
        if ((!isset($array[$key]) && !array_key_exists($key, $array))
99 48
            || ((isset($array[$key]) || array_key_exists($key, $array))
100 50
                && ($array[$key] === null || $array[$key] === 'null'))
101
        ) {
102 18
            return true;
103
        }
104
105 44
        return false;
106
    }
107
108
    /**
109
     * Returns true if one of the conditions comes back as requiring the key being tested
110
     * to be required. Returns false if all the conditions find that checks do not require
111
     * the key value to be present.
112
     *
113
     * @param array $array
114
     * @param array $rules
115
     * @return true|false
116
     */
117 6
    protected static function requiredOne($array, $rules)
118
    {
119 6
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
120 6
            foreach ($rules as $key => $value) {
121 6
                if ((is_array($value) && self::requiredAll($array, $value)) || self::requiredTest($array, $value, $key)) {
122 6
                    return true;
123
                }
124
            }
125
        }
126 4
        return false;
127
    }
128
129
    /**
130
     * Checks an array of $rules and returns false if any one of the rules fails.
131
     * If all rule tests pass, then the method returns true.
132
     *
133
     * @param array $array
134
     * @param array $rules
135
     * @return true|false
136
     */
137 2
    protected static function requiredAll($array, $rules)
138
    {
139 2
        if (is_array($rules)) {
0 ignored issues
show
introduced by
The condition is_array($rules) is always true.
Loading history...
140 2
            foreach ($rules as $key => $value) {
141 2
                if (!self::requiredTest($array, $value, $key)) {
142 2
                    return false;
143
                }
144
            }
145
        }
146
147 2
        return true;
148
    }
149
150
    /**
151
     * Returns output of testing functions. Will return true if $key is required
152
     * false if the $key is not required.
153
     *
154
     * @param $array
155
     * @param $value
156
     * @param $key
157
     * @return true|false
158
     */
159 6
    protected static function requiredTest($array, $value, $key)
160
    {
161 6
        if (is_null($value) || $value == 'null') {
162 4
            return self::requiredNull($array, $key);
163 2
        } elseif (isset($array[$key]) && $array[$key] == $value) {
164 2
            return true;
165
        }
166
167 2
        return false;
168
    }
169
170
    /**
171
     * @param string $value
172
     * @param array $rules
173
     * @param string $key
174
     * @return true
175
     * @throws Exception
176
     */
177 46
    public static function validateField($value, $rules, $key)
178
    {
179 46
        if (is_array($value) && isset($rules['type']) && strtolower($rules['type']) == 'group' && isset($rules['fields'])) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
180 6
            foreach ($value as $k => $v) {
181 6
                if (is_array($v) && !isset($rules['fields'][$k])) {
182 6
                    self::validate($v, $rules['fields']);
183 2
                } elseif (isset($rules['fields'][$k])) {
184 6
                    self::validateField($v, $rules['fields'][$k], $k);
185
                }
186
            }
187 46
        } elseif (is_array($value)) {
0 ignored issues
show
introduced by
The condition is_array($value) is always false.
Loading history...
188 4
            throw new Exception(sprintf('Unexpected array found for key: %s.', $key));
189
        }
190
191 44
        if (isset($value) && $value !== null && $value != 'null') {
192 40
            if (isset($rules['type'])) {
193 40
                if ($rules['type'] === 'integer') {
194 6
                    self::validateInteger($value, $key);
0 ignored issues
show
Bug introduced by
$value of type string is incompatible with the type integer expected by parameter $value of Multidimensional\ArrayVa...tion::validateInteger(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

194
                    self::validateInteger(/** @scrutinizer ignore-type */ $value, $key);
Loading history...
195 38
                } elseif ($rules['type'] === 'decimal') {
196 6
                    self::validateDecimal($value, $key);
0 ignored issues
show
Bug introduced by
$value of type string is incompatible with the type double expected by parameter $value of Multidimensional\ArrayVa...tion::validateDecimal(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

196
                    self::validateDecimal(/** @scrutinizer ignore-type */ $value, $key);
Loading history...
197 36
                } elseif ($rules['type'] === 'string') {
198 34
                    self::validateString($value, $key);
199 10
                } elseif ($rules['type'] === 'boolean') {
200 2
                    self::validateBoolean($value, $key);
0 ignored issues
show
Bug introduced by
$value of type string is incompatible with the type boolean expected by parameter $value of Multidimensional\ArrayVa...tion::validateBoolean(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

200
                    self::validateBoolean(/** @scrutinizer ignore-type */ $value, $key);
Loading history...
201
                }
202
            }
203
204 40
            if (isset($rules['values'])) {
205 10
                self::validateValues($value, $rules['values'], $key);
206
            }
207
208 38
            if (isset($rules['pattern'])) {
209 14
                if (strtoupper($rules['pattern']) == 'ISO 8601' || strtoupper($rules['pattern']) == 'ISO8601') {
210 2
                    self::validateISO8601($value, $key);
211 14
                } else if (strtoupper($rules['pattern']) == 'URL') {
212 2
                    self::validateURL($value, $key);
213 12
                } else if (strtoupper($rules['pattern']) == 'EMAIL') {
214 2
                    self::validateEmail($value, $key);
215 10
                } else if (strtoupper($rules['pattern']) == 'IP') {
216 2
                    self::validateIP($value, $key);
217 8
                } else if (strtoupper($rules['pattern']) == 'MAC') {
218 2
                    self::validateMAC($value, $key);
219
                } else {
220 6
                    self::validatePattern($value, $rules['pattern'], $key);
221
                }
222
            }
223
        }
224
225 42
        return true;
226
    }
227
228
    /**
229
     * @param int $value
230
     * @param string|null $key
231
     * @return true|false
232
     * @throws Exception
233
     */
234 6
    protected static function validateInteger($value, $key)
235
    {
236 6
        if (!is_int($value)) {
0 ignored issues
show
introduced by
The condition is_int($value) is always true.
Loading history...
237 2
            throw new Exception(sprintf('Invalid integer "%s" for key: %s.', $value, $key));
238
        }
239
240 6
        return true;
241
    }
242
243
    /**
244
     * @param float $value
245
     * @param string|null $key
246
     * @return true|false
247
     * @throws Exception
248
     */
249 6
    protected static function validateDecimal($value, $key)
250
    {
251 6
        if (!is_float($value)) {
0 ignored issues
show
introduced by
The condition is_float($value) is always true.
Loading history...
252 2
            throw new Exception(sprintf('Invalid decimal "%s" for key: %s.', $value, $key));
253
        }
254
255 6
        return true;
256
    }
257
258
    /**
259
     * @param string $value
260
     * @param string|null $key
261
     * @return true|false
262
     * @throws Exception
263
     */
264 34
    protected static function validateString($value, $key)
265
    {
266 34
        if (!is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
267 2
            throw new Exception(sprintf('Invalid string "%s" for key: %s.', $value, $key));
268
        }
269
270 34
        return true;
271
    }
272
273
    /**
274
     * @param bool $value
275
     * @param string|null $key
276
     * @return true
277
     * @throws Exception
278
     */
279 2
    protected static function validateBoolean($value, $key)
280
    {
281 2
        if (!is_bool($value)) {
0 ignored issues
show
introduced by
The condition is_bool($value) is always true.
Loading history...
282 2
            throw new Exception(sprintf('Invalid boolean "%s" for key: %s.', $value, $key));
283
        }
284
285 2
        return true;
286
    }
287
288
    /**
289
     * @param string $value
290
     * @param array|string $array
291
     * @param string|null $key
292
     * @return bool
293
     * @throws Exception
294
     */
295 10
    protected static function validateValues($value, $array, $key)
296
    {
297 10
        $compareArray = [];
298 10
        if (is_array($array)) {
299 8
            foreach ($array as $compareKey) {
300 8
                $compareScore = levenshtein($value, $compareKey);
301 8
                $compareArray[$compareKey] = $compareScore;
302 8
                if ($compareScore === 0) {
303 8
                    return true;
304
                }
305
            }
306 2
        } elseif (strcasecmp($value, $array) === 0) {
307 2
            return true;
308
        }
309
310 2
        $errorMessage = sprintf('Invalid value "%s" for key: %s.', $value, $key);
311
312 1
        array_walk($compareArray, function (&$item) {
313 2
            $item = abs($item);
314 2
        });
315 2
        asort($compareArray);
316 2
        $compareArray = array_keys($compareArray);
317 2
        if (count($compareArray)) {
318 2
            $errorMessage .= sprintf(' Did you mean "%s"?', array_shift($compareArray));
319
        }
320
321 2
        throw new Exception($errorMessage);
322
    }
323
324
    /**
325
     * @param string $value
326
     * @param string $key
327
     * @return bool
328
     * @throws Exception
329
     */
330 2
    protected static function validateISO8601($value, $key)
331
    {
332 2
        $pattern = '(?:[1-9]\d{3}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1\d|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[1-9]\d(?:0[48]|[2468][048]|[13579][26])|(?:[2468][048]|[13579][26])00)-02-29)T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:Z|[+-][01]\d:[0-5]\d)';
333 2
        if (!preg_match('/^' . $pattern . '$/', $value)) {
334 2
            throw new Exception(sprintf('Invalid value "%s" does not match ISO 8601 pattern for key: %s.', $value, $key));
335
        }
336
337 2
        return true;
338
    }
339
340
    /**
341
     * @param string $value
342
     * @param string $key
343
     * @return bool
344
     * @throws Exception
345
     */
346 2
    protected static function validateURL($value, $key)
347
    {
348 2
        if(!filter_var($value, FILTER_VALIDATE_URL)){
349 2
            throw new Exception(sprintf('Invalid value "%s" does not match URL pattern for key: %s.', $value, $key));
350
        }
351
352 2
        return true;
353
    }
354
355
    /**
356
     * @param string $value
357
     * @param string $key
358
     * @return bool
359
     * @throws Exception
360
     */
361 2
    protected static function validateEmail($value, $key)
362
    {
363 2
        if(!filter_var($value, FILTER_VALIDATE_EMAIL)){
364 2
            throw new Exception(sprintf('Invalid value "%s" does not match email pattern for key: %s.', $value, $key));
365
        }
366
367 2
        return true;
368
    }
369
370
    /**
371
     * @param string $value
372
     * @param string $key
373
     * @return bool
374
     * @throws Exception
375
     */
376 2
    protected static function validateIP($value, $key)
377
    {
378 2
        if(!filter_var($value, FILTER_VALIDATE_IP)){
379 2
            throw new Exception(sprintf('Invalid value "%s" does not match IP address pattern for key: %s.', $value, $key));
380
        }
381
382 2
        return true;
383
    }
384
385
    /**
386
     * @param string $value
387
     * @param string $key
388
     * @return bool
389
     * @throws Exception
390
     */
391 2
    protected static function validateMAC($value, $key)
392
    {
393 2
        if(!filter_var($value, FILTER_VALIDATE_MAC)){
394 2
            throw new Exception(sprintf('Invalid value "%s" does not match MAC address pattern for key: %s.', $value, $key));
395
        }
396
397 2
        return true;
398
    }
399
400
401
    /**
402
     * @param string $value
403
     * @param string $pattern
404
     * @param string $key
405
     * @return bool
406
     * @throws Exception
407
     */
408 6
    protected static function validatePattern($value, $pattern, $key)
409
    {
410 6
        if (!preg_match('/^' . $pattern . '$/', $value)) {
411 2
            throw new Exception(sprintf('Invalid value "%s" does not match pattern "%s" for key: %s.', $value, $pattern, $key));
412
        }
413
414 6
        return true;
415
    }
416
}
417