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 | /* |
||
4 | * This file is part of the webmozart/console package. |
||
5 | * |
||
6 | * (c) Bernhard Schussek <[email protected]> |
||
7 | * |
||
8 | * For the full copyright and license information, please view the LICENSE |
||
9 | * file that was distributed with this source code. |
||
10 | */ |
||
11 | |||
12 | namespace Webmozart\Console\Api\Command; |
||
13 | |||
14 | use Exception; |
||
15 | use LogicException; |
||
16 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
17 | use Webmozart\Console\Api\Application\Application; |
||
18 | use Webmozart\Console\Api\Args\Args; |
||
19 | use Webmozart\Console\Api\Args\CannotParseArgsException; |
||
20 | use Webmozart\Console\Api\Args\Format\ArgsFormat; |
||
21 | use Webmozart\Console\Api\Args\RawArgs; |
||
22 | use Webmozart\Console\Api\Config\CommandConfig; |
||
23 | use Webmozart\Console\Api\Config\OptionCommandConfig; |
||
24 | use Webmozart\Console\Api\Config\SubCommandConfig; |
||
25 | use Webmozart\Console\Api\Event\ConsoleEvents; |
||
26 | use Webmozart\Console\Api\Event\PreHandleEvent; |
||
27 | use Webmozart\Console\Api\IO\IO; |
||
28 | use Webmozart\Console\Util\ProcessTitle; |
||
29 | |||
30 | /** |
||
31 | * A console command. |
||
32 | * |
||
33 | * A `Command` object contains all the information that is necessary to describe |
||
34 | * and run a console command. Use the {@link CommandConfig} class to configure |
||
35 | * a command: |
||
36 | * |
||
37 | * ```php |
||
38 | * $config = CommandConfig::create() |
||
39 | * ->setDescription('List and manage servers') |
||
40 | * |
||
41 | * ->beginSubCommand('add') |
||
42 | * ->setDescription('Add a new server') |
||
43 | * ->addArgument('host', InputArgument::REQUIRED) |
||
44 | * ->addOption('port', 'p', InputOption::VALUE_OPTIONAL, null, 80) |
||
45 | * ->end() |
||
46 | * ; |
||
47 | * |
||
48 | * $command = new Command($config); |
||
49 | * ``` |
||
50 | * |
||
51 | * @since 1.0 |
||
52 | * |
||
53 | * @author Bernhard Schussek <[email protected]> |
||
54 | */ |
||
55 | class Command |
||
56 | { |
||
57 | /** |
||
58 | * @var string |
||
59 | */ |
||
60 | private $name; |
||
61 | |||
62 | /** |
||
63 | * @var string |
||
64 | */ |
||
65 | private $shortName; |
||
66 | |||
67 | /** |
||
68 | * @var string[] |
||
69 | */ |
||
70 | private $aliases = array(); |
||
71 | |||
72 | /** |
||
73 | * @var CommandConfig |
||
74 | */ |
||
75 | private $config; |
||
76 | |||
77 | /** |
||
78 | * @var ArgsFormat |
||
79 | */ |
||
80 | private $argsFormat; |
||
81 | |||
82 | /** |
||
83 | * @var Application |
||
84 | */ |
||
85 | private $application; |
||
86 | |||
87 | /** |
||
88 | * @var Command |
||
89 | */ |
||
90 | private $parentCommand; |
||
91 | |||
92 | /** |
||
93 | * @var CommandCollection |
||
94 | */ |
||
95 | private $subCommands; |
||
96 | |||
97 | /** |
||
98 | * @var CommandCollection |
||
99 | */ |
||
100 | private $namedSubCommands; |
||
101 | |||
102 | /** |
||
103 | * @var CommandCollection |
||
104 | */ |
||
105 | private $defaultSubCommands; |
||
106 | |||
107 | /** |
||
108 | * @var EventDispatcherInterface |
||
109 | */ |
||
110 | private $dispatcher; |
||
111 | |||
112 | /** |
||
113 | * Creates a new command. |
||
114 | * |
||
115 | * @param CommandConfig $config The command configuration. |
||
116 | * @param Application $application The console application. |
||
0 ignored issues
–
show
|
|||
117 | * @param Command $parentCommand The parent command. |
||
0 ignored issues
–
show
Should the type for parameter
$parentCommand not be null|Command ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
118 | * |
||
119 | * @throws LogicException If the name of the command configuration is not set. |
||
120 | */ |
||
121 | 230 | public function __construct(CommandConfig $config, Application $application = null, Command $parentCommand = null) |
|
122 | { |
||
123 | 230 | if (!$config->getName()) { |
|
124 | 1 | throw new LogicException('The name of the command config must be set.'); |
|
125 | } |
||
126 | |||
127 | 229 | $this->name = $config->getName(); |
|
128 | 229 | $this->shortName = $config instanceof OptionCommandConfig ? $config->getShortName() : null; |
|
129 | 229 | $this->aliases = $config->getAliases(); |
|
130 | 229 | $this->config = $config; |
|
131 | 229 | $this->application = $application; |
|
132 | 229 | $this->parentCommand = $parentCommand; |
|
133 | 229 | $this->subCommands = new CommandCollection(); |
|
134 | 229 | $this->namedSubCommands = new CommandCollection(); |
|
135 | 229 | $this->defaultSubCommands = new CommandCollection(); |
|
136 | 229 | $this->argsFormat = $config->buildArgsFormat($this->getBaseFormat()); |
|
137 | 229 | $this->dispatcher = $application ? $application->getConfig()->getEventDispatcher() : null; |
|
138 | |||
139 | 229 | foreach ($config->getSubCommandConfigs() as $subConfig) { |
|
140 | 32 | $this->addSubCommand($subConfig); |
|
141 | } |
||
142 | 226 | } |
|
143 | |||
144 | /** |
||
145 | * Returns the name of the command. |
||
146 | * |
||
147 | * @return string The name of the command. |
||
148 | */ |
||
149 | 360 | public function getName() |
|
150 | { |
||
151 | 360 | return $this->name; |
|
152 | } |
||
153 | |||
154 | /** |
||
155 | * Returns the short name of the command. |
||
156 | * |
||
157 | * This method only returns a value if an {@link OptionCommandConfig} was |
||
158 | * passed to the constructor. Otherwise this method returns `null`. |
||
159 | * |
||
160 | * @return string|null The short name or `null` if the command is not an |
||
161 | * option command. |
||
162 | */ |
||
163 | 177 | public function getShortName() |
|
164 | { |
||
165 | 177 | return $this->shortName; |
|
166 | } |
||
167 | |||
168 | /** |
||
169 | * Returns the alias names of the command. |
||
170 | * |
||
171 | * @return string[] An array of alias names of the command. |
||
172 | */ |
||
173 | 179 | public function getAliases() |
|
174 | { |
||
175 | 179 | return $this->aliases; |
|
176 | } |
||
177 | |||
178 | /** |
||
179 | * Returns whether the command has aliases. |
||
180 | * |
||
181 | * @return bool Returns `true` if the command has aliases and `false` |
||
182 | * otherwise. |
||
183 | */ |
||
184 | 27 | public function hasAliases() |
|
185 | { |
||
186 | 27 | return count($this->aliases) > 0; |
|
187 | } |
||
188 | |||
189 | /** |
||
190 | * Returns the configuration of the command. |
||
191 | * |
||
192 | * @return CommandConfig The command configuration. |
||
193 | */ |
||
194 | 253 | public function getConfig() |
|
195 | { |
||
196 | 253 | return $this->config; |
|
197 | } |
||
198 | |||
199 | /** |
||
200 | * Returns the arguments format of the command. |
||
201 | * |
||
202 | * @return ArgsFormat The input definition. |
||
203 | */ |
||
204 | 71 | public function getArgsFormat() |
|
205 | { |
||
206 | 71 | return $this->argsFormat; |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * Returns the console application. |
||
211 | * |
||
212 | * @return Application The console application. |
||
213 | */ |
||
214 | 79 | public function getApplication() |
|
215 | { |
||
216 | 79 | return $this->application; |
|
217 | } |
||
218 | |||
219 | /** |
||
220 | * Returns the parent command. |
||
221 | * |
||
222 | * @return Command The parent command. |
||
223 | */ |
||
224 | 1 | public function getParentCommand() |
|
225 | { |
||
226 | 1 | return $this->parentCommand; |
|
227 | } |
||
228 | |||
229 | /** |
||
230 | * Returns all sub-commands of the command. |
||
231 | * |
||
232 | * @return CommandCollection The sub-commands. |
||
233 | */ |
||
234 | 29 | public function getSubCommands() |
|
235 | { |
||
236 | 29 | return $this->subCommands; |
|
237 | } |
||
238 | |||
239 | /** |
||
240 | * Returns the sub-command with a specific name. |
||
241 | * |
||
242 | * @param string $name The name of the sub-command. |
||
243 | * |
||
244 | * @return Command The sub-command. |
||
245 | * |
||
246 | * @throws NoSuchCommandException If the sub-command with the given name |
||
247 | * does not exist. |
||
248 | */ |
||
249 | 3 | public function getSubCommand($name) |
|
250 | { |
||
251 | 3 | return $this->subCommands->get($name); |
|
252 | } |
||
253 | |||
254 | /** |
||
255 | * Returns whether a sub-command with the given name exists. |
||
256 | * |
||
257 | * @param string $name The name of the sub-command. |
||
258 | * |
||
259 | * @return bool Returns `true` if a sub-command with that name exists and |
||
260 | * `false` otherwise. |
||
261 | */ |
||
262 | 1 | public function hasSubCommand($name) |
|
263 | { |
||
264 | 1 | return $this->subCommands->contains($name); |
|
265 | } |
||
266 | |||
267 | /** |
||
268 | * Returns whether the command has any sub-commands. |
||
269 | * |
||
270 | * @return bool Returns `true` if the command has sub-commands and `false` |
||
271 | * otherwise. |
||
272 | */ |
||
273 | 2 | public function hasSubCommands() |
|
274 | { |
||
275 | 2 | return !$this->subCommands->isEmpty(); |
|
276 | } |
||
277 | |||
278 | /** |
||
279 | * Returns all sub-commands that are not anonymous. |
||
280 | * |
||
281 | * @return CommandCollection The named commands. |
||
282 | */ |
||
283 | 226 | public function getNamedSubCommands() |
|
284 | { |
||
285 | 226 | return $this->namedSubCommands; |
|
286 | } |
||
287 | |||
288 | /** |
||
289 | * Returns whether the command has any commands that are not anonymous. |
||
290 | * |
||
291 | * @return bool Returns `true` if the command has named commands and |
||
292 | * `false` otherwise. |
||
293 | * |
||
294 | * @see getNamedSubCommands() |
||
295 | */ |
||
296 | 2 | public function hasNamedSubCommands() |
|
297 | { |
||
298 | 2 | return count($this->namedSubCommands) > 0; |
|
299 | } |
||
300 | |||
301 | /** |
||
302 | * Returns the commands that should be executed if no explicit command is |
||
303 | * passed. |
||
304 | * |
||
305 | * @return CommandCollection The default commands. |
||
306 | */ |
||
307 | 204 | public function getDefaultSubCommands() |
|
308 | { |
||
309 | 204 | return $this->defaultSubCommands; |
|
310 | } |
||
311 | |||
312 | /** |
||
313 | * Returns whether the command has any default commands. |
||
314 | * |
||
315 | * @return bool Returns `true` if the command has default commands and |
||
316 | * `false` otherwise. |
||
317 | * |
||
318 | * @see getDefaultSubCommands() |
||
319 | */ |
||
320 | 29 | public function hasDefaultSubCommands() |
|
321 | { |
||
322 | 29 | return count($this->defaultSubCommands) > 0; |
|
323 | } |
||
324 | |||
325 | /** |
||
326 | * Parses the raw console arguments and returns the parsed arguments. |
||
327 | * |
||
328 | * @param RawArgs $args The raw console arguments. |
||
329 | * @param bool $lenient Whether the parser should ignore parse errors. |
||
0 ignored issues
–
show
Should the type for parameter
$lenient not be boolean|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
330 | * If `true`, the parser will not throw any |
||
331 | * exceptions when parse errors occur. |
||
332 | * |
||
333 | * @return Args The parsed console arguments. |
||
334 | * |
||
335 | * @throws CannotParseArgsException If the arguments cannot be parsed. |
||
336 | */ |
||
337 | 268 | public function parseArgs(RawArgs $args, $lenient = null) |
|
338 | { |
||
339 | 268 | if (null === $lenient) { |
|
340 | 260 | $lenient = $this->config->isLenientArgsParsingEnabled(); |
|
341 | } |
||
342 | |||
343 | 268 | return $this->config->getArgsParser()->parseArgs($args, $this->argsFormat, $lenient); |
|
344 | } |
||
345 | |||
346 | /** |
||
347 | * Executes the command for the given unparsed arguments. |
||
348 | * |
||
349 | * @param RawArgs $args The unparsed console arguments. |
||
350 | * @param IO $io The I/O. |
||
351 | * |
||
352 | * @return int Returns 0 on success and any other integer on error. |
||
353 | */ |
||
354 | 2 | public function run(RawArgs $args, IO $io) |
|
355 | { |
||
356 | 2 | return $this->handle($this->parseArgs($args), $io); |
|
357 | } |
||
358 | |||
359 | /** |
||
360 | * Executes the command for the given parsed arguments. |
||
361 | * |
||
362 | * @param Args $args The parsed console arguments. |
||
363 | * @param IO $io The I/O. |
||
364 | * |
||
365 | * @return int Returns 0 on success and any other integer on error. |
||
366 | * |
||
367 | * @throws Exception |
||
368 | */ |
||
369 | 50 | public function handle(Args $args, IO $io) |
|
370 | { |
||
371 | 50 | $processTitle = $this->config->getProcessTitle(); |
|
372 | |||
373 | 50 | $this->warnIfProcessTitleNotSupported($processTitle, $io); |
|
374 | |||
375 | 50 | if ($processTitle && ProcessTitle::isSupported()) { |
|
0 ignored issues
–
show
The expression
$processTitle of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
![]() |
|||
376 | ProcessTitle::setProcessTitle($processTitle); |
||
377 | |||
378 | try { |
||
379 | $statusCode = $this->doHandle($args, $io); |
||
380 | } catch (Exception $e) { |
||
381 | ProcessTitle::resetProcessTitle(); |
||
382 | |||
383 | throw $e; |
||
384 | } |
||
385 | |||
386 | ProcessTitle::resetProcessTitle(); |
||
387 | } else { |
||
388 | 50 | $statusCode = $this->doHandle($args, $io); |
|
389 | } |
||
390 | |||
391 | // Any empty value is considered a success |
||
392 | 46 | if (!$statusCode) { |
|
393 | 16 | return 0; |
|
394 | } |
||
395 | |||
396 | // Anything else is normalized to a valid error status code |
||
397 | // (i.e. one of [1, 255]) |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
39% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. ![]() |
|||
398 | 30 | return min(max((int) $statusCode, 1), 255); |
|
399 | } |
||
400 | |||
401 | /** |
||
402 | * Returns the inherited arguments format of the command. |
||
403 | * |
||
404 | * @return ArgsFormat The inherited format. |
||
0 ignored issues
–
show
|
|||
405 | * |
||
406 | * @see CommandConfig::buildArgsFormat() |
||
407 | */ |
||
408 | 229 | private function getBaseFormat() |
|
409 | { |
||
410 | 229 | if ($this->parentCommand) { |
|
411 | 31 | return $this->parentCommand->getArgsFormat(); |
|
412 | } |
||
413 | |||
414 | 229 | if ($this->application) { |
|
415 | 130 | return $this->application->getGlobalArgsFormat(); |
|
416 | } |
||
417 | |||
418 | 99 | return null; |
|
419 | } |
||
420 | |||
421 | /** |
||
422 | * Adds a sub-command. |
||
423 | * |
||
424 | * @param SubCommandConfig $config The sub-command configuration. |
||
425 | * |
||
426 | * @throws CannotAddCommandException If the command cannot be added. |
||
427 | */ |
||
428 | 32 | private function addSubCommand(SubCommandConfig $config) |
|
429 | { |
||
430 | 32 | if (!$config->isEnabled()) { |
|
431 | 1 | return; |
|
432 | } |
||
433 | |||
434 | 32 | $this->validateSubCommandName($config); |
|
435 | |||
436 | 29 | $command = new self($config, $this->application, $this); |
|
437 | |||
438 | 29 | $this->subCommands->add($command); |
|
439 | |||
440 | 29 | if ($config->isDefault()) { |
|
441 | 10 | $this->defaultSubCommands->add($command); |
|
442 | } |
||
443 | |||
444 | 29 | if (!$config->isAnonymous()) { |
|
445 | 28 | $this->namedSubCommands->add($command); |
|
446 | } |
||
447 | 29 | } |
|
448 | |||
449 | 50 | private function warnIfProcessTitleNotSupported($processTitle, IO $io) |
|
450 | { |
||
451 | 50 | if ($processTitle && !ProcessTitle::isSupported()) { |
|
452 | $io->errorLine( |
||
453 | '<warn>Notice: Install the proctitle PECL to be able to change the process title.</warn>', |
||
454 | IO::VERY_VERBOSE |
||
455 | ); |
||
456 | } |
||
457 | 50 | } |
|
458 | |||
459 | 32 | private function validateSubCommandName(SubCommandConfig $config) |
|
460 | { |
||
461 | 32 | $name = $config->getName(); |
|
462 | |||
463 | 32 | if (!$name) { |
|
464 | 1 | throw CannotAddCommandException::nameEmpty(); |
|
465 | } |
||
466 | |||
467 | 31 | if ($this->subCommands->contains($name)) { |
|
468 | 4 | throw CannotAddCommandException::nameExists($name); |
|
469 | } |
||
470 | |||
471 | 31 | if ($config instanceof OptionCommandConfig) { |
|
472 | 14 | if ($this->argsFormat->hasOption($name)) { |
|
473 | 1 | throw CannotAddCommandException::optionExists($name); |
|
474 | } |
||
475 | |||
476 | 13 | if ($shortName = $config->getShortName()) { |
|
477 | 10 | if ($this->subCommands->contains($shortName)) { |
|
478 | 1 | throw CannotAddCommandException::nameExists($name); |
|
479 | } |
||
480 | |||
481 | 10 | if ($this->argsFormat->hasOption($shortName)) { |
|
482 | 1 | throw CannotAddCommandException::optionExists($shortName); |
|
483 | } |
||
484 | } |
||
485 | } |
||
486 | 29 | } |
|
487 | |||
488 | 50 | private function doHandle(Args $args, IO $io) |
|
0 ignored issues
–
show
The return type could not be reliably inferred; please add a
@return annotation.
Our type inference engine in quite powerful, but sometimes the code does not
provide enough clues to go by. In these cases we request you to add a ![]() |
|||
489 | { |
||
490 | 50 | View Code Duplication | if ($this->dispatcher && $this->dispatcher->hasListeners(ConsoleEvents::PRE_HANDLE)) { |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
491 | 32 | $event = new PreHandleEvent($args, $io, $this); |
|
492 | 32 | $this->dispatcher->dispatch(ConsoleEvents::PRE_HANDLE, $event); |
|
493 | |||
494 | 32 | if ($event->isHandled()) { |
|
495 | 5 | return $event->getStatusCode(); |
|
496 | } |
||
497 | } |
||
498 | |||
499 | 45 | $commandHandler = $this->config->getHandler(); |
|
500 | 45 | $handlerMethod = $this->config->getHandlerMethod(); |
|
501 | |||
502 | 45 | return $commandHandler->$handlerMethod($args, $io, $this); |
|
503 | } |
||
504 | } |
||
505 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.