This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace League\JsonGuard; |
||
4 | |||
5 | use League\JsonGuard\Exception\MaximumDepthExceededException; |
||
6 | use League\JsonGuard\RuleSet\DraftFour; |
||
7 | use League\JsonReference\Reference; |
||
8 | use Psr\Container\ContainerInterface; |
||
9 | |||
10 | final class Validator |
||
11 | { |
||
12 | /** |
||
13 | * @var array |
||
14 | */ |
||
15 | private $errors = []; |
||
16 | |||
17 | /** |
||
18 | * @var mixed |
||
19 | */ |
||
20 | private $data; |
||
21 | |||
22 | /** |
||
23 | * @var object |
||
24 | */ |
||
25 | private $schema; |
||
26 | |||
27 | /** |
||
28 | * @var string |
||
29 | */ |
||
30 | private $dataPath = '/'; |
||
31 | |||
32 | /** |
||
33 | * @var string |
||
34 | */ |
||
35 | private $baseSchemaPath = '/'; |
||
36 | |||
37 | /** |
||
38 | * The maximum depth the validator should recurse into $data |
||
39 | * before throwing an exception. |
||
40 | * |
||
41 | * @var int |
||
42 | */ |
||
43 | private $maxDepth = 50; |
||
44 | |||
45 | /** |
||
46 | * The depth the validator has reached in the data. |
||
47 | * |
||
48 | * @var int |
||
49 | */ |
||
50 | private $depth = 0; |
||
51 | |||
52 | /** |
||
53 | * @var \Psr\Container\ContainerInterface |
||
54 | */ |
||
55 | private $ruleSet; |
||
56 | |||
57 | /** |
||
58 | * @var bool |
||
59 | */ |
||
60 | private $hasValidated; |
||
61 | |||
62 | /** |
||
63 | * @var string |
||
64 | */ |
||
65 | private $currentKeyword; |
||
66 | |||
67 | /** |
||
68 | * @var mixed |
||
69 | */ |
||
70 | private $currentParameter; |
||
71 | |||
72 | /** |
||
73 | * @param mixed $data |
||
74 | * @param object $schema |
||
75 | * @param ContainerInterface|null $ruleSet |
||
76 | */ |
||
77 | 240 | public function __construct($data, $schema, ContainerInterface $ruleSet = null) |
|
78 | { |
||
79 | 240 | if (!is_object($schema)) { |
|
80 | 2 | throw new \InvalidArgumentException( |
|
81 | 2 | sprintf('The schema should be an object from a json_decode call, got "%s"', gettype($schema)) |
|
82 | ); |
||
83 | } |
||
84 | |||
85 | 238 | while ($schema instanceof Reference) { |
|
86 | 16 | $schema = $schema->resolve(); |
|
87 | } |
||
88 | |||
89 | 238 | $this->data = $data; |
|
90 | 238 | $this->schema = $schema; |
|
91 | 238 | $this->ruleSet = $ruleSet ?: new DraftFour(); |
|
92 | 238 | } |
|
93 | |||
94 | /** |
||
95 | * @return boolean |
||
96 | * |
||
97 | * @throws \League\JsonGuard\Exception\InvalidSchemaException |
||
98 | * @throws \League\JsonGuard\Exception\MaximumDepthExceededException |
||
99 | */ |
||
100 | 82 | public function fails() |
|
101 | { |
||
102 | 82 | return !$this->passes(); |
|
103 | } |
||
104 | |||
105 | /** |
||
106 | * @return boolean |
||
107 | * |
||
108 | * @throws \League\JsonGuard\Exception\InvalidSchemaException |
||
109 | * @throws \League\JsonGuard\Exception\MaximumDepthExceededException |
||
110 | */ |
||
111 | 82 | public function passes() |
|
112 | { |
||
113 | 82 | return empty($this->errors()); |
|
114 | } |
||
115 | |||
116 | /** |
||
117 | * Get a collection of errors. |
||
118 | * |
||
119 | * @return ValidationError[] |
||
120 | * |
||
121 | * @throws \League\JsonGuard\Exception\InvalidSchemaException |
||
122 | * @throws \League\JsonGuard\Exception\MaximumDepthExceededException |
||
123 | */ |
||
124 | 150 | public function errors() |
|
125 | { |
||
126 | 150 | $this->validate(); |
|
127 | |||
128 | 80 | return $this->errors; |
|
129 | } |
||
130 | |||
131 | /** |
||
132 | * Set the maximum allowed depth data will be validated until. |
||
133 | * If the data exceeds the stack depth an exception is thrown. |
||
134 | * |
||
135 | * @param int $maxDepth |
||
136 | * |
||
137 | * @return $this |
||
138 | */ |
||
139 | 4 | public function setMaxDepth($maxDepth) |
|
140 | { |
||
141 | 4 | $this->maxDepth = $maxDepth; |
|
142 | |||
143 | 4 | return $this; |
|
144 | } |
||
145 | |||
146 | /** |
||
147 | * @return \Psr\Container\ContainerInterface |
||
148 | */ |
||
149 | 4 | public function getRuleSet() |
|
150 | { |
||
151 | 4 | return $this->ruleSet; |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * @return string |
||
156 | */ |
||
157 | 100 | public function getDataPath() |
|
158 | { |
||
159 | 100 | return $this->dataPath; |
|
160 | } |
||
161 | |||
162 | /** |
||
163 | * @return mixed |
||
164 | */ |
||
165 | 94 | public function getData() |
|
166 | { |
||
167 | 94 | return $this->data; |
|
168 | } |
||
169 | |||
170 | /** |
||
171 | * @return object |
||
172 | */ |
||
173 | 96 | public function getSchema() |
|
174 | { |
||
175 | 96 | return $this->schema; |
|
176 | } |
||
177 | |||
178 | /** |
||
179 | * @return string |
||
180 | */ |
||
181 | 238 | public function getSchemaPath() |
|
182 | { |
||
183 | 238 | return pointer_push($this->baseSchemaPath, $this->currentKeyword); |
|
184 | } |
||
185 | |||
186 | /** |
||
187 | * @return string |
||
188 | */ |
||
189 | 94 | public function getCurrentKeyword() |
|
190 | { |
||
191 | 94 | return $this->currentKeyword; |
|
192 | } |
||
193 | |||
194 | /** |
||
195 | * @return mixed |
||
196 | */ |
||
197 | 94 | public function getCurrentParameter() |
|
198 | { |
||
199 | 94 | return $this->currentParameter; |
|
200 | } |
||
201 | |||
202 | /** |
||
203 | * Create a new sub-validator. |
||
204 | * |
||
205 | * @param mixed $data |
||
206 | * @param object $schema |
||
207 | * @param string|null $dataPath |
||
208 | * @param string|null $schemaPath |
||
209 | * |
||
210 | * @return Validator |
||
211 | */ |
||
212 | 48 | public function makeSubSchemaValidator($data, $schema, $dataPath = null, $schemaPath = null) |
|
213 | { |
||
214 | 48 | $validator = new Validator($data, $schema, $this->ruleSet); |
|
215 | |||
216 | 48 | $validator->dataPath = $dataPath ?: $this->dataPath; |
|
217 | 48 | $validator->baseSchemaPath = $schemaPath ?: $this->getSchemaPath(); |
|
218 | 48 | $validator->maxDepth = $this->maxDepth; |
|
219 | 48 | $validator->depth = $this->depth + 1; |
|
220 | |||
221 | 48 | return $validator; |
|
222 | } |
||
223 | |||
224 | /** |
||
225 | * Validate the data and collect the errors. |
||
226 | */ |
||
227 | 150 | private function validate() |
|
228 | { |
||
229 | 150 | if ($this->hasValidated) { |
|
230 | 30 | return; |
|
231 | } |
||
232 | |||
233 | 150 | $this->checkDepth(); |
|
234 | |||
235 | 150 | foreach ($this->schema as $rule => $parameter) { |
|
236 | 150 | $this->currentKeyword = $rule; |
|
0 ignored issues
–
show
|
|||
237 | 150 | $this->currentParameter = $parameter; |
|
238 | 150 | $this->mergeErrors($this->validateRule($rule, $parameter)); |
|
239 | 80 | $this->currentKeyword = $this->currentParameter = null; |
|
240 | } |
||
241 | |||
242 | 80 | $this->hasValidated = true; |
|
243 | 80 | } |
|
244 | |||
245 | /** |
||
246 | * Keep track of how many levels deep we have validated. |
||
247 | * This is to prevent a really deeply nested JSON |
||
248 | * structure from causing the validator to continue |
||
249 | * validating for an incredibly long time. |
||
250 | * |
||
251 | * @throws \League\JsonGuard\Exception\MaximumDepthExceededException |
||
252 | */ |
||
253 | 150 | private function checkDepth() |
|
254 | { |
||
255 | 150 | if ($this->depth > $this->maxDepth) { |
|
256 | 2 | throw new MaximumDepthExceededException(); |
|
257 | } |
||
258 | 150 | } |
|
259 | |||
260 | /** |
||
261 | * Validate the data using the given rule and parameter. |
||
262 | * |
||
263 | * @param string $keyword |
||
264 | * @param mixed $parameter |
||
265 | * |
||
266 | * @return null|ValidationError|ValidationError[] |
||
267 | */ |
||
268 | 150 | private function validateRule($keyword, $parameter) |
|
269 | { |
||
270 | 150 | if (!$this->ruleSet->has($keyword)) { |
|
271 | 14 | return null; |
|
272 | } |
||
273 | |||
274 | 150 | return $this->ruleSet->get($keyword)->validate($this->data, $parameter, $this); |
|
275 | } |
||
276 | |||
277 | /** |
||
278 | * Merge the errors with our error collection. |
||
279 | * |
||
280 | * @param ValidationError[]|ValidationError|null $errors |
||
281 | */ |
||
282 | 80 | private function mergeErrors($errors) |
|
283 | { |
||
284 | 80 | if (is_null($errors)) { |
|
285 | 76 | return; |
|
286 | } |
||
287 | |||
288 | 80 | $errors = is_array($errors) ? $errors : [$errors]; |
|
289 | 80 | $this->errors = array_merge($this->errors, $errors); |
|
290 | 80 | } |
|
291 | } |
||
292 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.