Completed
Pull Request — master (#16)
by Viacheslav
05:56
created

Format::dateTimeError()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace Swaggest\JsonSchema\Constraint;
4
5
use Swaggest\JsonSchema\Constraint\Format\IdnHostname;
6
use Swaggest\JsonSchema\Constraint\Format\Iri;
7
use Swaggest\JsonSchema\Constraint\Format\Uri;
8
9
class Format
10
{
11
    const DATE_REGEX_PART = '(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])';
12
    const TIME_REGEX_PART = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))?';
13
    /**
14
     * @see http://stackoverflow.com/a/1420225
15
     */
16
    const HOSTNAME_REGEX = '/^
17
      (?=.{1,255}$)
18
      [0-9a-z]
19
      (([0-9a-z]|-){0,61}[0-9a-z])?
20
      (\.[0-9a-z](?:(?:[0-9a-z]|-){0,61}[0-9a-z])?)*
21
      \.?
22
    $/ix';
23
24
    const JSON_POINTER_REGEX = '_^(?:/|(?:/[^/#]*)*)$_';
25
    const JSON_POINTER_RELATIVE_REGEX = '~^(0|[1-9][0-9]*)((?:/[^/#]*)*)(#?)$~';
26
    const JSON_POINTER_UNESCAPED_TILDE = '/~([^01]|$)/';
27
28
    public static function validationError($format, $data)
29
    {
30
        switch ($format) {
31
            case 'date-time':
32
                return self::dateTimeError($data);
33
            case 'date':
34
                return preg_match('/^' . self::DATE_REGEX_PART . '$/i', $data) ? null : 'Invalid date';
35
            case 'time':
36
                return preg_match('/^' . self::TIME_REGEX_PART . '$/i', $data) ? null : 'Invalid time';
37
            case 'uri':
38
                return Uri::validationError($data, Uri::IS_SCHEME_REQUIRED);
39
            case 'iri':
40
                return Iri::validationError($data);
41
            case 'email':
42
                return filter_var($data, FILTER_VALIDATE_EMAIL) ? null : 'Invalid email';
43
            case 'idn-email':
44
                return count(explode('@', $data, 3)) === 2 ? null : 'Invalid email';
45
            case 'ipv4':
46
                return filter_var($data, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? null : 'Invalid ipv4';
47
            case 'ipv6':
48
                return filter_var($data, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? null : 'Invalid ipv6';
49
            case 'hostname':
50
                return preg_match(self::HOSTNAME_REGEX, $data) ? null : 'Invalid hostname';
51
            case 'idn-hostname':
52
                return IdnHostname::validationError($data);
53
            case 'regex':
54
                return self::regexError($data);
55
            case 'json-pointer':
56
                return self::jsonPointerError($data);
57
            case 'relative-json-pointer':
58
                return self::jsonPointerError($data, true);
59
            case 'uri-reference':
60
                return Uri::validationError($data, Uri::IS_URI_REFERENCE);
61
            case 'iri-reference':
62
                return Iri::validationError($data, Uri::IS_URI_REFERENCE);
63
            case 'uri-template':
64
                return Uri::validationError($data, Uri::IS_URI_TEMPLATE);
65
        }
66
        return null;
67
    }
68
69
    public static function dateTimeError($data)
70
    {
71
        return preg_match('/^' . self::DATE_REGEX_PART . 'T' . self::TIME_REGEX_PART . '$/i', $data)
72
            ? null
73
            : 'Invalid date-time: ' . $data;
74
    }
75
76
    public static function regexError($data)
77
    {
78
        if (substr($data, -2) === '\Z') {
79
            return 'Invalid regex: \Z is not supported';
80
        }
81
        if (substr($data, 0, 2) === '\A') {
82
            return 'Invalid regex: \A is not supported';
83
        }
84
85
86
        $d = null;
87
        foreach (array('/', '_', '~', '#', '!', '%', '`', '=') as $delimiter) {
88
            if (strpos($data, $delimiter) === false) {
89
                $d = $delimiter;
90
                break;
91
            }
92
        }
93
        return @preg_match($d . $data . $d, '') === false ? 'Invalid regex: ' . $data : null;
94
    }
95
96
    public static function jsonPointerError($data, $isRelative = false)
97
    {
98
        if (preg_match(self::JSON_POINTER_UNESCAPED_TILDE, $data)) {
99
            return 'Invalid json-pointer: unescaped ~';
100
        }
101
        if ($isRelative) {
102
            return preg_match(self::JSON_POINTER_RELATIVE_REGEX, $data) ? null : 'Invalid relative json-pointer';
103
        } else {
104
            return preg_match(self::JSON_POINTER_REGEX, $data) ? null : 'Invalid json-pointer';
105
        }
106
    }
107
}