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 ParamProcessor; |
||
4 | |||
5 | use ParamProcessor\PackagePrivate\Param; |
||
6 | |||
7 | /** |
||
8 | * Class for parameter validation of a single parser hook or other parametrized construct. |
||
9 | * |
||
10 | * @since 0.1 |
||
11 | * |
||
12 | * @licence GNU GPL v2+ |
||
13 | * @author Jeroen De Dauw < [email protected] > |
||
14 | * @author Daniel Werner |
||
15 | */ |
||
16 | class Processor { |
||
17 | |||
18 | /** |
||
19 | * Flag for unnamed default parameters used in Processor::setFunctionParams() to determine that |
||
20 | * a parameter should not have a named fallback. |
||
21 | * |
||
22 | * @since 0.4.13 |
||
23 | */ |
||
24 | const PARAM_UNNAMED = 1; |
||
25 | |||
26 | /** |
||
27 | * @var Param[] |
||
28 | */ |
||
29 | private $params; |
||
30 | |||
31 | /** |
||
32 | * Associative array containing parameter names (keys) and their user-provided data (values). |
||
33 | * This list is needed because additional parameter definitions can be added to the $parameters |
||
34 | * field during validation, so we can't determine in advance if a parameter is unknown. |
||
35 | * @var string[] |
||
36 | */ |
||
37 | private $rawParameters = []; |
||
38 | |||
39 | /** |
||
40 | * Array containing the names of the parameters to handle, ordered by priority. |
||
41 | * @var string[] |
||
42 | */ |
||
43 | private $paramsToHandle = []; |
||
44 | |||
45 | /** |
||
46 | * @var ParamDefinition[] |
||
47 | */ |
||
48 | private $paramDefinitions = []; |
||
49 | |||
50 | /** |
||
51 | * @var ProcessingError[] |
||
52 | */ |
||
53 | private $errors = []; |
||
54 | |||
55 | private $options; |
||
56 | |||
57 | 67 | public function __construct( Options $options ) { |
|
58 | 67 | $this->options = $options; |
|
59 | 67 | } |
|
60 | |||
61 | /** |
||
62 | * Constructs and returns a Validator object based on the default options. |
||
63 | */ |
||
64 | 56 | public static function newDefault(): self { |
|
65 | 56 | return new Processor( new Options() ); |
|
66 | } |
||
67 | |||
68 | /** |
||
69 | * Constructs and returns a Validator object based on the provided options. |
||
70 | */ |
||
71 | 11 | public static function newFromOptions( Options $options ): self { |
|
72 | 11 | return new Processor( $options ); |
|
73 | } |
||
74 | |||
75 | /** |
||
76 | * Returns the options used by this Validator object. |
||
77 | */ |
||
78 | 1 | public function getOptions(): Options { |
|
79 | 1 | return $this->options; |
|
80 | } |
||
81 | |||
82 | /** |
||
83 | * Determines the names and values of all parameters. Also takes care of default parameters. |
||
84 | * After that the resulting parameter list is passed to Processor::setParameters |
||
85 | * |
||
86 | * @since 0.4 |
||
87 | * |
||
88 | * @param string[] $rawParams |
||
89 | * @param ParamDefinition[]|array[] $parameterDefinitions DEPRECATED! Use @see setParameterDefinitions instead |
||
90 | * @param array $defaultParams array of strings or array of arrays to define which parameters can be used unnamed. |
||
91 | * The second value in array-form is reserved for flags. Currently, Processor::PARAM_UNNAMED determines that |
||
92 | * the parameter has no name which can be used to set it. Therefore all these parameters must be set before |
||
93 | * any named parameter. The effect is, that '=' within the string won't confuse the parameter anymore like |
||
94 | * it would happen with default parameters that still have a name as well. |
||
95 | */ |
||
96 | 4 | public function setFunctionParams( array $rawParams, array $parameterDefinitions = [], array $defaultParams = [] ) { |
|
97 | 4 | $lastUnnamedDefaultNr = -1; |
|
98 | |||
99 | /* |
||
100 | * Find last parameter with self::PARAM_UNNAMED set. Tread all parameters in front as |
||
101 | * the flag were set for them as well to ensure that there can't be any unnamed params |
||
102 | * after the first named param. Wouldn't be possible to determine which unnamed value |
||
103 | * belongs to which parameter otherwise. |
||
104 | */ |
||
105 | 4 | for( $i = count( $defaultParams ) - 1; $i >= 0; $i-- ) { |
|
106 | $dflt = $defaultParams[$i]; |
||
107 | if( is_array( $dflt ) && !empty( $dflt[1] ) && ( $dflt[1] | self::PARAM_UNNAMED ) ) { |
||
108 | $lastUnnamedDefaultNr = $i; |
||
109 | break; |
||
110 | } |
||
111 | } |
||
112 | |||
113 | 4 | $parameters = []; |
|
114 | 4 | $nr = 0; |
|
115 | 4 | $defaultNr = 0; |
|
116 | |||
117 | 4 | foreach ( $rawParams as $arg ) { |
|
118 | // Only take into account strings. If the value is not a string, |
||
119 | // it is not a raw parameter, and can not be parsed correctly in all cases. |
||
120 | 4 | if ( is_string( $arg ) ) { |
|
121 | 4 | $parts = explode( '=', $arg, ( $nr <= $lastUnnamedDefaultNr ? 1 : 2 ) ); |
|
122 | |||
123 | // If there is only one part, no parameter name is provided, so try default parameter assignment. |
||
124 | // Default parameters having self::PARAM_UNNAMED set for having no name alias go here in any case. |
||
125 | 4 | if ( count( $parts ) == 1 ) { |
|
126 | // Default parameter assignment is only possible when there are default parameters! |
||
127 | if ( count( $defaultParams ) > 0 ) { |
||
128 | $defaultParam = array_shift( $defaultParams ); |
||
129 | if( is_array( $defaultParam ) ) { |
||
130 | $defaultParam = $defaultParam[0]; |
||
131 | } |
||
132 | $defaultParam = strtolower( $defaultParam ); |
||
133 | |||
134 | $parameters[$defaultParam] = [ |
||
135 | 'original-value' => trim( $parts[0] ), |
||
136 | 'default' => $defaultNr, |
||
137 | 'position' => $nr |
||
138 | ]; |
||
139 | $defaultNr++; |
||
140 | } |
||
141 | } else { |
||
142 | 4 | $paramName = trim( strtolower( $parts[0] ) ); |
|
143 | |||
144 | 4 | $parameters[$paramName] = [ |
|
145 | 4 | 'original-value' => trim( $parts[1] ), |
|
146 | 'default' => false, |
||
147 | 4 | 'position' => $nr |
|
148 | ]; |
||
149 | |||
150 | // Let's not be evil, and remove the used parameter name from the default parameter list. |
||
151 | // This code is basically a remove array element by value algorithm. |
||
152 | 4 | $newDefaults = []; |
|
153 | |||
154 | 4 | foreach( $defaultParams as $defaultParam ) { |
|
155 | if ( $defaultParam != $paramName ) { |
||
156 | $newDefaults[] = $defaultParam; |
||
157 | } |
||
158 | } |
||
159 | |||
160 | 4 | $defaultParams = $newDefaults; |
|
161 | } |
||
162 | } |
||
163 | |||
164 | 4 | $nr++; |
|
165 | } |
||
166 | |||
167 | 4 | $this->setParameters( $parameters, $parameterDefinitions ); |
|
168 | 4 | } |
|
169 | |||
170 | /** |
||
171 | * @since 1.6.0 |
||
172 | * @param ParamDefinition[] $paramDefinitions |
||
173 | */ |
||
174 | 50 | public function setParameterDefinitions( array $paramDefinitions ) { |
|
175 | 50 | $this->paramDefinitions = $paramDefinitions; |
|
176 | 50 | } |
|
177 | |||
178 | /** |
||
179 | * Loops through a list of provided parameters, resolves aliasing and stores errors |
||
180 | * for unknown parameters and optionally for parameter overriding. |
||
181 | * |
||
182 | * @param array $parameters Parameter name as key, parameter value as value |
||
183 | * @param ParamDefinition[]|array[] $paramDefinitions DEPRECATED! Use @see setParameterDefinitions instead |
||
184 | */ |
||
185 | 65 | public function setParameters( array $parameters, array $paramDefinitions = [] ) { |
|
186 | 65 | $this->paramDefinitions = ParamDefinition::getCleanDefinitions( $paramDefinitions ); |
|
0 ignored issues
–
show
The method
ParamProcessor\ParamDefi...::getCleanDefinitions() has been deprecated with message: since 1.7 - use ParamDefinitionFactory
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
187 | |||
188 | // Loop through all the user provided parameters, and distinguish between those that are allowed and those that are not. |
||
189 | 65 | foreach ( $parameters as $paramName => $paramData ) { |
|
190 | 63 | if ( $this->options->lowercaseNames() ) { |
|
191 | 61 | $paramName = strtolower( $paramName ); |
|
192 | } |
||
193 | |||
194 | 63 | if ( $this->options->trimNames() ) { |
|
195 | 61 | $paramName = trim( $paramName ); |
|
196 | } |
||
197 | |||
198 | 63 | $paramValue = is_array( $paramData ) ? $paramData['original-value'] : $paramData; |
|
199 | |||
200 | 63 | $this->rawParameters[$paramName] = $paramValue; |
|
201 | } |
||
202 | 65 | } |
|
203 | |||
204 | /** |
||
205 | * @param string $message |
||
206 | * @param string[] $tags |
||
207 | * @param integer $severity |
||
208 | */ |
||
209 | 5 | private function registerNewError( string $message, array $tags = [], int $severity = ProcessingError::SEVERITY_NORMAL ) { |
|
210 | 5 | $this->registerError( |
|
211 | 5 | new ProcessingError( |
|
212 | 5 | $message, |
|
213 | $severity, |
||
214 | 5 | $this->options->getName(), |
|
215 | 5 | (array)$tags |
|
216 | ) |
||
217 | ); |
||
218 | 5 | } |
|
219 | |||
220 | 25 | private function registerError( ProcessingError $error ) { |
|
221 | 25 | $error->element = $this->options->getName(); |
|
222 | 25 | $this->errors[] = $error; |
|
223 | 25 | ProcessingErrorHandler::addError( $error ); |
|
224 | 25 | } |
|
225 | |||
226 | /** |
||
227 | * Validates and formats all the parameters (but aborts when a fatal error occurs). |
||
228 | * |
||
229 | * @since 0.4 |
||
230 | * @deprecated since 1.0, use processParameters |
||
231 | */ |
||
232 | public function validateParameters() { |
||
233 | $this->doParamProcessing(); |
||
234 | } |
||
235 | |||
236 | 61 | public function processParameters(): ProcessingResult { |
|
237 | 61 | $this->doParamProcessing(); |
|
238 | |||
239 | 61 | if ( !$this->hasFatalError() && $this->options->unknownIsInvalid() ) { |
|
0 ignored issues
–
show
The method
ParamProcessor\Processor::hasFatalError() has been deprecated with message: since 1.7 - use processParameters() return value
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
240 | // Loop over the remaining raw parameters. |
||
241 | // These are unrecognized parameters, as they where not used by any parameter definition. |
||
242 | 54 | foreach ( $this->rawParameters as $paramName => $paramValue ) { |
|
243 | 2 | $this->registerNewError( |
|
244 | 2 | $paramName . ' is not a valid parameter', // TODO |
|
245 | 2 | [ $paramName ] |
|
246 | ); |
||
247 | } |
||
248 | } |
||
249 | |||
250 | 61 | return $this->newProcessingResult(); |
|
251 | } |
||
252 | |||
253 | 61 | private function newProcessingResult(): ProcessingResult { |
|
254 | 61 | $parameters = []; |
|
255 | |||
256 | 61 | if ( !is_array( $this->params ) ) { |
|
257 | 3 | $this->params = []; |
|
258 | } |
||
259 | |||
260 | 61 | foreach ( $this->params as $parameter ) { |
|
261 | // TODO |
||
262 | 58 | $processedParam = new ProcessedParam( |
|
263 | 58 | $parameter->getName(), |
|
264 | 58 | $parameter->getValue(), |
|
265 | 58 | $parameter->wasSetToDefault() |
|
266 | ); |
||
267 | |||
268 | // TODO: it is possible these values where set even when the value defaulted, |
||
269 | // so this logic is not correct and could be improved |
||
270 | 58 | if ( !$parameter->wasSetToDefault() ) { |
|
271 | 43 | $processedParam->setOriginalName( $parameter->getOriginalName() ); |
|
272 | 43 | $processedParam->setOriginalValue( $parameter->getOriginalValue() ); |
|
273 | } |
||
274 | |||
275 | 58 | $parameters[$processedParam->getName()] = $processedParam; |
|
276 | } |
||
277 | |||
278 | 61 | return new ProcessingResult( |
|
279 | 61 | $parameters, |
|
280 | 61 | $this->getErrors() |
|
0 ignored issues
–
show
The method
ParamProcessor\Processor::getErrors() has been deprecated with message: since 1.7 - use processParameters() return value
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
281 | ); |
||
282 | } |
||
283 | |||
284 | 61 | private function doParamProcessing() { |
|
285 | 61 | $this->errors = []; |
|
286 | |||
287 | 61 | $this->getParamsToProcess( [], $this->paramDefinitions ); |
|
288 | |||
289 | 61 | while ( $this->paramsToHandle !== [] && !$this->hasFatalError() ) { |
|
0 ignored issues
–
show
The method
ParamProcessor\Processor::hasFatalError() has been deprecated with message: since 1.7 - use processParameters() return value
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
290 | 60 | $this->processOneParam(); |
|
291 | } |
||
292 | 61 | } |
|
293 | |||
294 | 60 | private function processOneParam() { |
|
295 | 60 | $paramName = array_shift( $this->paramsToHandle ); |
|
296 | 60 | $definition = $this->paramDefinitions[$paramName]; |
|
297 | |||
298 | 60 | $param = new Param( $definition ); |
|
299 | |||
300 | 60 | $setUserValue = $this->attemptToSetUserValue( $param ); |
|
301 | |||
302 | // If the parameter is required but not provided, register a fatal error and stop processing. |
||
303 | 60 | if ( !$setUserValue && $param->isRequired() ) { |
|
304 | 3 | $this->registerNewError( |
|
305 | 3 | "Required parameter '$paramName' is missing", // FIXME: i18n validator_error_required_missing |
|
306 | 3 | [ $paramName, 'missing' ], |
|
307 | 3 | ProcessingError::SEVERITY_FATAL |
|
308 | ); |
||
309 | 3 | return; |
|
310 | } |
||
311 | |||
312 | 58 | $this->params[$param->getName()] = $param; |
|
313 | |||
314 | 58 | $initialSet = $this->paramDefinitions; |
|
315 | |||
316 | 58 | $param->process( $this->paramDefinitions, $this->params, $this->options ); |
|
317 | |||
318 | 58 | foreach ( $param->getErrors() as $error ) { |
|
319 | 22 | $this->registerError( $error ); |
|
320 | } |
||
321 | |||
322 | 58 | if ( $param->hasFatalError() ) { |
|
323 | 5 | return; |
|
324 | } |
||
325 | |||
326 | 53 | $this->getParamsToProcess( $initialSet, $this->paramDefinitions ); |
|
327 | 53 | } |
|
328 | |||
329 | /** |
||
330 | * Gets an ordered list of parameters to process. |
||
331 | * @throws \UnexpectedValueException |
||
332 | */ |
||
333 | 61 | private function getParamsToProcess( array $initialParamSet, array $resultingParamSet ) { |
|
334 | 61 | if ( $initialParamSet === [] ) { |
|
335 | 61 | $this->paramsToHandle = array_keys( $resultingParamSet ); |
|
0 ignored issues
–
show
It seems like
array_keys($resultingParamSet) of type array<integer,integer|string> is incompatible with the declared type array<integer,string> of property $paramsToHandle .
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property. Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..
Loading history...
|
|||
336 | } |
||
337 | else { |
||
338 | 53 | if ( !is_array( $this->paramsToHandle ) ) { |
|
339 | $this->paramsToHandle = []; |
||
340 | } |
||
341 | |||
342 | 53 | foreach ( $resultingParamSet as $paramName => $parameter ) { |
|
343 | 53 | if ( !array_key_exists( $paramName, $initialParamSet ) ) { |
|
344 | 1 | $this->paramsToHandle[] = $paramName; |
|
345 | } |
||
346 | } |
||
347 | } |
||
348 | |||
349 | 61 | $this->paramsToHandle = $this->getParameterNamesInEvaluationOrder( $this->paramDefinitions, $this->paramsToHandle ); |
|
350 | 61 | } |
|
351 | |||
352 | /** |
||
353 | * @param ParamDefinition[] $paramDefinitions |
||
354 | * @param string[] $paramsToHandle |
||
355 | * |
||
356 | * @return array |
||
357 | */ |
||
358 | 61 | private function getParameterNamesInEvaluationOrder( array $paramDefinitions, array $paramsToHandle ): array { |
|
359 | 61 | $dependencyList = []; |
|
360 | |||
361 | 61 | foreach ( $paramsToHandle as $paramName ) { |
|
362 | 60 | $dependencies = []; |
|
363 | |||
364 | 60 | if ( !array_key_exists( $paramName, $paramDefinitions ) ) { |
|
365 | throw new \UnexpectedValueException( 'Unexpected parameter name "' . $paramName . '"' ); |
||
366 | } |
||
367 | |||
368 | 60 | if ( !is_object( $paramDefinitions[$paramName] ) || !( $paramDefinitions[$paramName] instanceof ParamDefinition ) ) { |
|
369 | throw new \UnexpectedValueException( 'Parameter "' . $paramName . '" is not a ParamDefinition' ); |
||
370 | } |
||
371 | |||
372 | // Only include dependencies that are in the list of parameters to handle. |
||
373 | 60 | foreach ( $paramDefinitions[$paramName]->getDependencies() as $dependency ) { |
|
0 ignored issues
–
show
The method
ParamProcessor\ParamDefinition::getDependencies() has been deprecated with message: since 1.7Returns a list of dependencies the parameter has, in the form of other parameter names. This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
374 | if ( in_array( $dependency, $paramsToHandle ) ) { |
||
375 | $dependencies[] = $dependency; |
||
376 | } |
||
377 | } |
||
378 | |||
379 | 60 | $dependencyList[$paramName] = $dependencies; |
|
380 | } |
||
381 | |||
382 | 61 | $sorter = new TopologicalSort( $dependencyList, true ); |
|
0 ignored issues
–
show
The class
ParamProcessor\TopologicalSort has been deprecated with message: since 1.7
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.
Loading history...
|
|||
383 | |||
384 | 61 | return $sorter->doSort(); |
|
385 | } |
||
386 | |||
387 | /** |
||
388 | * Tries to find a matching user provided value and, when found, assigns it |
||
389 | * to the parameter, and removes it from the raw values. Returns a boolean |
||
390 | * indicating if there was any user value set or not. |
||
391 | */ |
||
392 | 60 | private function attemptToSetUserValue( Param $param ): bool { |
|
393 | 60 | if ( array_key_exists( $param->getName(), $this->rawParameters ) ) { |
|
394 | 58 | $param->setUserValue( $param->getName(), $this->rawParameters[$param->getName()], $this->options ); |
|
395 | 58 | unset( $this->rawParameters[$param->getName()] ); |
|
396 | 58 | return true; |
|
397 | } |
||
398 | else { |
||
399 | 6 | foreach ( $param->getDefinition()->getAliases() as $alias ) { |
|
400 | if ( array_key_exists( $alias, $this->rawParameters ) ) { |
||
401 | $param->setUserValue( $alias, $this->rawParameters[$alias], $this->options ); |
||
402 | unset( $this->rawParameters[$alias] ); |
||
403 | return true; |
||
404 | } |
||
405 | } |
||
406 | } |
||
407 | |||
408 | 6 | return false; |
|
409 | } |
||
410 | |||
411 | /** |
||
412 | * @deprecated since 1.0 |
||
413 | * @return Param[] |
||
414 | */ |
||
415 | public function getParameters(): array { |
||
416 | return $this->params; |
||
417 | } |
||
418 | |||
419 | /** |
||
420 | * @deprecated since 1.0 |
||
421 | */ |
||
422 | public function getParameter( string $parameterName ): Param { |
||
423 | return $this->params[$parameterName]; |
||
424 | } |
||
425 | |||
426 | /** |
||
427 | * Returns an associative array with the parameter names as key and their |
||
428 | * corresponding values as value. |
||
429 | * @deprecated since 1.7 - use processParameters() return value |
||
430 | */ |
||
431 | public function getParameterValues(): array { |
||
432 | $parameters = []; |
||
433 | |||
434 | foreach ( $this->params as $parameter ) { |
||
435 | $parameters[$parameter->getName()] = $parameter->getValue(); |
||
436 | } |
||
437 | |||
438 | return $parameters; |
||
439 | } |
||
440 | |||
441 | /** |
||
442 | * @deprecated since 1.7 - use processParameters() return value |
||
443 | * @return ProcessingError[] |
||
444 | */ |
||
445 | 61 | public function getErrors(): array { |
|
446 | 61 | return $this->errors; |
|
447 | } |
||
448 | |||
449 | /** |
||
450 | * @deprecated since 1.7 - use processParameters() return value |
||
451 | * @return string[] |
||
452 | */ |
||
453 | public function getErrorMessages(): array { |
||
454 | $errors = []; |
||
455 | |||
456 | foreach ( $this->errors as $error ) { |
||
457 | $errors[] = $error->getMessage(); |
||
458 | } |
||
459 | |||
460 | return $errors; |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * @deprecated since 1.7 - use processParameters() return value |
||
465 | */ |
||
466 | public function hasErrors(): bool { |
||
467 | return !empty( $this->errors ); |
||
468 | } |
||
469 | |||
470 | /** |
||
471 | * @deprecated since 1.7 - use processParameters() return value |
||
472 | * @return ProcessingError|boolean false |
||
473 | */ |
||
474 | 61 | public function hasFatalError() { |
|
475 | 61 | foreach ( $this->errors as $error ) { |
|
476 | 25 | if ( $error->isFatal() ) { |
|
477 | 8 | return $error; |
|
478 | } |
||
479 | } |
||
480 | |||
481 | 61 | return false; |
|
482 | } |
||
483 | |||
484 | } |
||
485 |
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: