Completed
Push — 4-cactus ( 59c50f...21a27c )
by Alberto
02:40
created

BEdita/Core/src/Model/Validation/Validation.php (4 issues)

Labels
Severity
1
<?php
2
/**
3
 * BEdita, API-first content management framework
4
 * Copyright 2017 ChannelWeb Srl, Chialab Srl
5
 *
6
 * This file is part of BEdita: you can redistribute it and/or modify
7
 * it under the terms of the GNU Lesser General Public License as published
8
 * by the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * See LICENSE.LGPL or <http://gnu.org/licenses/lgpl-3.0.html> for more details.
12
 */
13
14
namespace BEdita\Core\Model\Validation;
15
16
use Cake\Core\Configure;
17
use Cake\Core\Configure\Engine\PhpConfig;
18
use Cake\Utility\Hash;
19
use Cake\Validation\Validation as CakeValidation;
20
use DateTimeInterface;
21
use League\JsonGuard\Validator as JsonSchemaValidator;
0 ignored issues
show
The type League\JsonGuard\Validator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use League\JsonReference\Dereferencer as JsonSchemaDereferencer;
0 ignored issues
show
The type League\JsonReference\Dereferencer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use League\JsonReference\Loader\ArrayLoader;
0 ignored issues
show
The type League\JsonReference\Loader\ArrayLoader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use League\JsonReference\Loader\ChainedLoader;
0 ignored issues
show
The type League\JsonReference\Loader\ChainedLoader was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
26
/**
27
 * Class to provide reusable validation rules.
28
 * Used for object types and properties.
29
 *
30
 * @since 4.0.0
31
 */
32
class Validation
33
{
34
    /**
35
     * The list of reserved names
36
     *
37
     * @var string[]|null
38
     */
39
    protected static $reserved = null;
40
41
    /**
42
     * Clear reserved names list
43
     *
44
     * @return void
45
     */
46
    public static function clear()
47
    {
48
        static::$reserved = null;
49
    }
50
51
    /**
52
     * Load list of reserved names in `$reserved`
53
     *
54
     * @return string[]
55
     */
56
    protected static function reservedWords()
57
    {
58
        if (static::$reserved === null) {
59
            static::$reserved = (new PhpConfig())->read('BEdita/Core.reserved');
60
        }
61
62
        return static::$reserved;
63
    }
64
65
    /**
66
     * Check if a value is not reserved
67
     *
68
     * @param mixed $value Value to check
69
     * @return bool
70
     */
71
    public static function notReserved($value)
72
    {
73
        if ($value && in_array($value, static::reservedWords())) {
74
            return false;
75
        }
76
77
        return true;
78
    }
79
80
    /**
81
     * Checks that a value is a valid URL or custom url as myapp://
82
     *
83
     * @param string $value The url to check
84
     * @return bool
85
     */
86
    public static function url($value)
87
    {
88
        // check for a valid scheme (https://, myapp://,...)
89
        $regex = '/(?<scheme>^[a-z][a-z0-9+\-.]*:\/\/).*/';
90
        if (!preg_match($regex, $value, $matches)) {
91
            return false;
92
        }
93
94
        // if scheme is not an URL protocol then it's a custom url (myapp://) => ok
95
        if (!preg_match('/^(https?|ftps?|sftp|file|news|gopher:\/\/)/', $matches['scheme'])) {
96
            return true;
97
        }
98
99
        return CakeValidation::url($value, true);
100
    }
101
102
    /**
103
     * Validate using JSON Schema.
104
     *
105
     * @param mixed $value Value being validated.
106
     * @param mixed $schema Schema to validate against.
107
     * @return true|string
108
     */
109
    public static function jsonSchema($value, $schema)
110
    {
111
        if (is_string($schema)) {
112
            $cacheLoader = new ArrayLoader([
113
                'json-schema.org/draft-06/schema' => json_decode(file_get_contents(__DIR__ . DS . 'schemas' . DS . 'draft-06.json')),
114
            ]);
115
116
            $dereferencer = JsonSchemaDereferencer::draft6();
117
            $loaderManager = $dereferencer->getLoaderManager();
118
            $loaderManager->registerLoader('http', new ChainedLoader(
119
                $cacheLoader,
120
                $loaderManager->getLoader('http')
121
            ));
122
            $loaderManager->registerLoader('https', new ChainedLoader(
123
                $cacheLoader,
124
                $loaderManager->getLoader('https')
125
            ));
126
127
            $schema = $dereferencer->dereference($schema);
128
        }
129
        if (empty($schema)) {
130
            return true;
131
        }
132
133
        $value = json_decode(json_encode($value));
134
        $schema = json_decode(json_encode($schema));
135
        $validator = new JsonSchemaValidator($value, $schema);
136
137
        if ($validator->fails()) {
138
            $errors = $validator->errors();
139
            $error = reset($errors);
140
141
            return sprintf('%s (in: %s)', $error->getMessage(), $error->getDataPath());
142
        }
143
144
        return true;
145
    }
146
147
    /**
148
     * Validate language tag using `I18n` configuration.
149
     *
150
     * @param string $tag Language tag
151
     * @return true|string
152
     */
153
    public static function languageTag($tag)
154
    {
155
        $languages = Hash::normalize((array)Configure::read('I18n.languages'));
156
        if (!empty($languages)) {
157
            if (!array_key_exists($tag, $languages)) {
158
                return __d('bedita', 'Invalid language tag "{0}"', $tag);
159
            }
160
        }
161
162
        return true;
163
    }
164
165
    /**
166
     * Validate input date and datetime.
167
     * Accepetd input formats:
168
     *  - string date format
169
     *  - integer timestamps
170
     *  - DateTime objects
171
     *
172
     * Accepted date time string formats are
173
     *  - 2017-01-01                    YYYY-MM-DD
174
     *  - 2017-01-01 11:22              YYYY-MM-DD hh:mm
175
     *  - 2017-01-01T11:22:33           YYYY-MM-DDThh:mm:ss
176
     *  - 2017-01-01T11:22:33Z          YYYY-MM-DDThh:mm:ssZ
177
     *  - 2017-01-01T19:20+01:00        YYYY-MM-DDThh:mmTZD
178
     *  - 2017-01-01T11:22:33+01:00     YYYY-MM-DDThh:mm:ssTZD
179
     *  - 2017-01-01T19:20:30.45+01:00  YYYY-MM-DDThh:mm:ss.sTZD
180
     *
181
     * See ISO 8601 subset as defined here https://www.w3.org/TR/NOTE-datetime:
182
     *
183
     * Also timestamp as integer are accepted.
184
     *
185
     * @param mixed $value Date or datetime value
186
     * @return true|string
187
     */
188
    public static function dateTime($value)
189
    {
190
        if ($value instanceof DateTimeInterface) {
191
            return true;
192
        }
193
194
        if (is_string($value) && preg_match('/^\d{4}(-\d\d(-\d\d([T ]\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i', $value)) {
195
            return true;
196
        }
197
198
        if (filter_var($value, FILTER_VALIDATE_INT)) {
199
            return true;
200
        }
201
202
        return __d('bedita', 'Invalid date or datetime "{0}"', print_r($value, true));
203
    }
204
}
205