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\PackagePrivate; |
||
4 | |||
5 | use DataValues\DataValue; |
||
6 | use Exception; |
||
7 | use ParamProcessor\IParam; |
||
8 | use ParamProcessor\IParamDefinition; |
||
9 | use ParamProcessor\Options; |
||
10 | use ParamProcessor\ParamDefinition; |
||
11 | use ParamProcessor\ParamDefinitionFactory; |
||
12 | use ParamProcessor\ProcessingError; |
||
13 | use ValueParsers\NullParser; |
||
14 | use ValueParsers\ParseException; |
||
15 | use ValueParsers\ValueParser; |
||
16 | |||
17 | /** |
||
18 | * Package private! |
||
19 | * |
||
20 | * Parameter class, representing the "instance" of a parameter. |
||
21 | * Holds a ParamDefinition, user provided input (name & value) and processing state. |
||
22 | * |
||
23 | * @licence GNU GPL v2+ |
||
24 | * @author Jeroen De Dauw < [email protected] > |
||
25 | */ |
||
26 | class Param implements IParam { |
||
0 ignored issues
–
show
|
|||
27 | |||
28 | /** |
||
29 | * Indicates whether parameters not found in the criteria list |
||
30 | * should be stored in case they are not accepted. The default is false. |
||
31 | * |
||
32 | * @deprecated since 1.7 |
||
33 | */ |
||
34 | public static $accumulateParameterErrors = false; |
||
35 | |||
36 | /** |
||
37 | * The original parameter name as provided by the user. This can be the |
||
38 | * main name or an alias. |
||
39 | * @var string |
||
40 | */ |
||
41 | protected $originalName; |
||
42 | |||
43 | /** |
||
44 | * The original value as provided by the user. This is mainly retained for |
||
45 | * usage in error messages when the parameter turns out to be invalid. |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $originalValue; |
||
49 | |||
50 | /** |
||
51 | * @var mixed |
||
52 | */ |
||
53 | protected $value; |
||
54 | |||
55 | /** |
||
56 | * Keeps track of how many times the parameter has been set by the user. |
||
57 | * This is used to detect overrides and for figuring out a parameter is missing. |
||
58 | * @var integer |
||
59 | */ |
||
60 | protected $setCount = 0; |
||
61 | |||
62 | /** |
||
63 | * @var ProcessingError[] |
||
64 | */ |
||
65 | protected $errors = []; |
||
66 | |||
67 | /** |
||
68 | * Indicates if the parameter was set to it's default. |
||
69 | * @var boolean |
||
70 | */ |
||
71 | protected $defaulted = false; |
||
72 | |||
73 | /** |
||
74 | * @var ParamDefinition |
||
75 | */ |
||
76 | protected $definition; |
||
77 | |||
78 | 107 | public function __construct( IParamDefinition $definition ) { |
|
79 | 107 | $this->definition = $definition; |
|
0 ignored issues
–
show
$definition is of type object<ParamProcessor\IParamDefinition> , but the property $definition was declared to be of type object<ParamProcessor\ParamDefinition> . Are you sure that you always receive this specific sub-class here, or does it make sense to add an instanceof check?
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 given class or a super-class is assigned to a property that is type hinted more strictly. Either this assignment is in error or an instanceof check should be added for that assignment. class Alien {}
class Dalek extends Alien {}
class Plot
{
/** @var Dalek */
public $villain;
}
$alien = new Alien();
$plot = new Plot();
if ($alien instanceof Dalek) {
$plot->villain = $alien;
}
Loading history...
|
|||
80 | 107 | } |
|
81 | |||
82 | /** |
||
83 | * Sets and cleans the original value and name. |
||
84 | */ |
||
85 | 105 | public function setUserValue( string $paramName, $paramValue, Options $options ): bool { |
|
86 | 105 | if ( $this->setCount > 0 && !$options->acceptOverriding() ) { |
|
87 | // TODO |
||
88 | return false; |
||
89 | } |
||
90 | |||
91 | 105 | $this->originalName = $paramName; |
|
92 | 105 | $this->originalValue = $paramValue; |
|
93 | |||
94 | 105 | $this->cleanValue( $options ); |
|
95 | |||
96 | 105 | $this->setCount++; |
|
97 | |||
98 | 105 | return true; |
|
99 | } |
||
100 | |||
101 | /** |
||
102 | * @param mixed $value |
||
103 | */ |
||
104 | 93 | public function setValue( $value ) { |
|
105 | 93 | $this->value = $value; |
|
106 | 93 | } |
|
107 | |||
108 | /** |
||
109 | * Sets the $value to a cleaned value of $originalValue. |
||
110 | */ |
||
111 | 105 | protected function cleanValue( Options $options ) { |
|
112 | 105 | if ( $this->definition->isList() ) { |
|
113 | $this->value = explode( $this->definition->getDelimiter(), $this->originalValue ); |
||
114 | } |
||
115 | else { |
||
116 | 105 | $this->value = $this->originalValue; |
|
117 | } |
||
118 | |||
119 | 105 | if ( $this->shouldTrim( $options ) ) { |
|
120 | 105 | $this->trimValue(); |
|
121 | } |
||
122 | |||
123 | 105 | if ( $this->shouldLowercase( $options ) ) { |
|
124 | $this->lowercaseValue(); |
||
125 | } |
||
126 | 105 | } |
|
127 | |||
128 | 105 | private function shouldTrim( Options $options ): bool { |
|
129 | 105 | $trim = $this->definition->trimDuringClean(); |
|
130 | |||
131 | 105 | if ( $trim === true ) { |
|
132 | return true; |
||
133 | } |
||
134 | |||
135 | 105 | return is_null( $trim ) && $options->trimValues(); |
|
136 | } |
||
137 | |||
138 | 105 | private function trimValue() { |
|
139 | 105 | if ( is_string( $this->value ) ) { |
|
140 | 99 | $this->value = trim( $this->value ); |
|
141 | } |
||
142 | 58 | elseif ( $this->definition->isList() ) { |
|
143 | foreach ( $this->value as &$element ) { |
||
0 ignored issues
–
show
The expression
$this->value of type object|integer|double|null|array|boolean is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
Loading history...
|
|||
144 | if ( is_string( $element ) ) { |
||
145 | $element = trim( $element ); |
||
146 | } |
||
147 | } |
||
148 | } |
||
149 | 105 | } |
|
150 | |||
151 | 105 | private function shouldLowercase( Options $options ): bool { |
|
152 | 105 | if ( $options->lowercaseValues() ) { |
|
153 | return true; |
||
154 | } |
||
155 | |||
156 | 105 | $definitionOptions = $this->definition->getOptions(); |
|
157 | |||
158 | 105 | return array_key_exists( 'tolower', $definitionOptions ) && $definitionOptions['tolower']; |
|
159 | } |
||
160 | |||
161 | private function lowercaseValue() { |
||
162 | if ( $this->definition->isList() ) { |
||
163 | foreach ( $this->value as &$element ) { |
||
164 | if ( is_string( $element ) ) { |
||
165 | $element = strtolower( $element ); |
||
166 | } |
||
167 | } |
||
168 | } |
||
169 | elseif ( is_string( $this->value ) ) { |
||
170 | $this->value = strtolower( $this->value ); |
||
171 | } |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Parameter processing entry point. |
||
176 | * Processes the parameter. This includes parsing, validation and additional formatting. |
||
177 | * |
||
178 | * @param ParamDefinition[] $definitions |
||
179 | * @param Param[] $params |
||
180 | * @param Options $options |
||
181 | * |
||
182 | * @throws Exception |
||
183 | */ |
||
184 | 105 | public function process( array &$definitions, array $params, Options $options ) { |
|
185 | 105 | if ( $this->setCount == 0 ) { |
|
186 | 1 | if ( $this->definition->isRequired() ) { |
|
187 | // This should not occur, so throw an exception. |
||
188 | throw new Exception( 'Attempted to validate a required parameter without first setting a value.' ); |
||
189 | } |
||
190 | else { |
||
191 | 1 | $this->setToDefault(); |
|
192 | } |
||
193 | } |
||
194 | else { |
||
195 | 104 | $this->parseAndValidate( $options ); |
|
196 | } |
||
197 | |||
198 | 105 | if ( !$this->hasFatalError() && ( $this->definition->shouldManipulateDefault() || !$this->wasSetToDefault() ) ) { |
|
199 | 93 | $this->definition->format( $this, $definitions, $params ); |
|
0 ignored issues
–
show
|
|||
200 | } |
||
201 | 105 | } |
|
202 | |||
203 | 104 | public function getValueParser( Options $options ): ValueParser { |
|
204 | 104 | $parser = $this->definition->getValueParser(); |
|
205 | |||
206 | 104 | if ( !( $parser instanceof NullParser ) ) { |
|
207 | return $parser; |
||
208 | } |
||
209 | |||
210 | // TODO: inject factory |
||
211 | 104 | $type = ParamDefinitionFactory::singleton()->getType( $this->definition->getType() ); |
|
0 ignored issues
–
show
The method
ParamProcessor\ParamDefinitionFactory::singleton() has been deprecated with message: since 1.0
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...
|
|||
212 | |||
213 | 104 | $parserClass = $options->isStringlyTyped() ? $type->getStringParserClass() : $type->getTypedParserClass(); |
|
0 ignored issues
–
show
The method
ParamProcessor\Options::isStringlyTyped() has been deprecated with message: since 1.7
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...
|
|||
214 | |||
215 | 104 | return new $parserClass( new \ValueParsers\ParserOptions( $this->definition->getOptions() ) ); |
|
216 | } |
||
217 | |||
218 | 104 | protected function parseAndValidate( Options $options ) { |
|
219 | 104 | $parser = $this->getValueParser( $options ); |
|
220 | |||
221 | 104 | if ( $this->definition->isList() ) { |
|
222 | $values = []; |
||
223 | |||
224 | foreach ( $this->getValue() as $value ) { |
||
225 | $parsedValue = $this->parseAndValidateValue( $parser, $value ); |
||
226 | |||
227 | if ( is_array( $parsedValue ) ) { |
||
228 | $values[] = $parsedValue[0]; |
||
229 | } |
||
230 | } |
||
231 | |||
232 | $this->value = $values; |
||
233 | } |
||
234 | else { |
||
235 | 104 | $parsedValue = $this->parseAndValidateValue( $parser, $this->getValue() ); |
|
236 | |||
237 | 104 | if ( is_array( $parsedValue ) ) { |
|
238 | 99 | $this->value = $parsedValue[0]; |
|
239 | } |
||
240 | } |
||
241 | |||
242 | 104 | $this->setToDefaultIfNeeded(); |
|
243 | 104 | } |
|
244 | |||
245 | /** |
||
246 | * Parses and validates the provided with with specified parser. |
||
247 | * The result is returned in an array on success. On fail, false is returned. |
||
248 | * The result is wrapped in an array since we need to be able to distinguish |
||
249 | * between the method returning false and the value being false. |
||
250 | * |
||
251 | * Parsing and validation errors get added to $this->errors. |
||
252 | * |
||
253 | * @since 1.0 |
||
254 | * |
||
255 | * @param ValueParser $parser |
||
256 | * @param mixed $value |
||
257 | * |
||
258 | * @return array|bool |
||
259 | */ |
||
260 | 104 | protected function parseAndValidateValue( ValueParser $parser, $value ) { |
|
261 | try { |
||
262 | 104 | $value = $parser->parse( $value ); |
|
263 | } |
||
264 | 13 | catch ( ParseException $parseException ) { |
|
265 | 13 | $this->registerProcessingError( $parseException->getMessage() ); |
|
266 | 13 | return false; |
|
267 | } |
||
268 | |||
269 | 99 | if ( $value instanceof DataValue ) { |
|
270 | 58 | $value = $value->getValue(); |
|
271 | } |
||
272 | |||
273 | 99 | $this->validateValue( $value ); |
|
274 | |||
275 | 99 | return [ $value ]; |
|
276 | } |
||
277 | |||
278 | 35 | protected function registerProcessingError( string $message ) { |
|
279 | 35 | $this->errors[] = $this->newProcessingError( $message ); |
|
280 | 35 | } |
|
281 | |||
282 | 35 | protected function newProcessingError( string $message ): ProcessingError { |
|
283 | 35 | $severity = $this->isRequired() ? ProcessingError::SEVERITY_FATAL : ProcessingError::SEVERITY_NORMAL; |
|
284 | 35 | return new ProcessingError( $message, $severity ); |
|
285 | } |
||
286 | |||
287 | /** |
||
288 | * @param mixed $value |
||
289 | */ |
||
290 | 99 | protected function validateValue( $value ) { |
|
291 | 99 | $validationCallback = $this->definition->getValidationCallback(); |
|
292 | |||
293 | 99 | if ( $validationCallback !== null && $validationCallback( $value ) !== true ) { |
|
294 | 7 | $this->registerProcessingError( 'Validation callback failed' ); |
|
295 | } |
||
296 | else { |
||
297 | 99 | $validator = $this->definition->getValueValidator(); |
|
298 | 99 | if ( method_exists( $validator, 'setOptions' ) ) { |
|
299 | 99 | $validator->setOptions( $this->definition->getOptions() ); |
|
300 | } |
||
301 | 99 | $validationResult = $validator->validate( $value ); |
|
302 | |||
303 | 99 | if ( !$validationResult->isValid() ) { |
|
304 | 24 | foreach ( $validationResult->getErrors() as $error ) { |
|
305 | 24 | $this->registerProcessingError( $error->getText() ); |
|
306 | } |
||
307 | } |
||
308 | } |
||
309 | 99 | } |
|
310 | |||
311 | /** |
||
312 | * Sets the parameter value to the default if needed. |
||
313 | */ |
||
314 | 104 | protected function setToDefaultIfNeeded() { |
|
315 | 104 | if ( $this->shouldSetToDefault() ) { |
|
316 | 15 | $this->setToDefault(); |
|
317 | } |
||
318 | 104 | } |
|
319 | |||
320 | 104 | private function shouldSetToDefault(): bool { |
|
321 | 104 | if ( $this->hasFatalError() ) { |
|
322 | 20 | return false; |
|
323 | } |
||
324 | |||
325 | 92 | if ( $this->definition->isList() ) { |
|
326 | return $this->errors !== [] && $this->value === []; |
||
327 | } |
||
328 | |||
329 | 92 | return $this->errors !== []; |
|
330 | } |
||
331 | |||
332 | /** |
||
333 | * Returns the original use-provided name. |
||
334 | * |
||
335 | * @throws Exception |
||
336 | * @return string |
||
337 | */ |
||
338 | 36 | public function getOriginalName(): string { |
|
339 | 36 | if ( $this->setCount == 0 ) { |
|
340 | throw new Exception( 'No user input set to the parameter yet, so the original name does not exist' ); |
||
341 | } |
||
342 | 36 | return $this->originalName; |
|
343 | } |
||
344 | |||
345 | /** |
||
346 | * Returns the original use-provided value. |
||
347 | * |
||
348 | * @throws Exception |
||
349 | * @return mixed |
||
350 | */ |
||
351 | 36 | public function getOriginalValue() { |
|
352 | 36 | if ( $this->setCount == 0 ) { |
|
353 | throw new Exception( 'No user input set to the parameter yet, so the original value does not exist' ); |
||
354 | } |
||
355 | 36 | return $this->originalValue; |
|
356 | } |
||
357 | |||
358 | /** |
||
359 | * Returns all validation errors that occurred so far. |
||
360 | * |
||
361 | * @return ProcessingError[] |
||
362 | */ |
||
363 | 95 | public function getErrors(): array { |
|
364 | 95 | return $this->errors; |
|
365 | } |
||
366 | |||
367 | /** |
||
368 | * Sets the parameter value to the default. |
||
369 | */ |
||
370 | 16 | protected function setToDefault() { |
|
371 | 16 | $this->defaulted = true; |
|
372 | 16 | $this->value = $this->definition->getDefault(); |
|
373 | 16 | } |
|
374 | |||
375 | 49 | public function wasSetToDefault(): bool { |
|
376 | 49 | return $this->defaulted; |
|
377 | } |
||
378 | |||
379 | 105 | public function hasFatalError(): bool { |
|
380 | 105 | foreach ( $this->errors as $error ) { |
|
381 | 35 | if ( $error->isFatal() ) { |
|
382 | 20 | return true; |
|
383 | } |
||
384 | } |
||
385 | |||
386 | 93 | return false; |
|
387 | } |
||
388 | |||
389 | /** |
||
390 | * Returns the ParamDefinition this Param was constructed from. |
||
391 | */ |
||
392 | public function getDefinition(): ParamDefinition { |
||
393 | return $this->definition; |
||
394 | } |
||
395 | |||
396 | /** |
||
397 | * @return mixed |
||
398 | */ |
||
399 | 105 | public function &getValue() { |
|
400 | 105 | return $this->value; |
|
401 | } |
||
402 | |||
403 | 36 | public function isRequired(): bool { |
|
404 | 36 | return $this->definition->isRequired(); |
|
405 | } |
||
406 | |||
407 | 49 | public function getName(): string { |
|
408 | 49 | return $this->definition->getName(); |
|
409 | } |
||
410 | |||
411 | /** |
||
412 | * @return string[] |
||
413 | */ |
||
414 | public function getAliases(): array { |
||
415 | return $this->definition->getAliases(); |
||
416 | } |
||
417 | |||
418 | } |
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.