Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ff4b1d4

Browse files
committed
bug #30277 [Console] Prevent ArgvInput::getFirstArgument() from returning an option value (chalasr)
This PR was merged into the 3.4 branch. Discussion ---------- [Console] Prevent ArgvInput::getFirstArgument() from returning an option value | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #23343 | License | MIT | Doc PR | n/a Fixes the case where the passed input string contains no command name but one or more global (i.e. application-defined) options accepting values. Commits ------- 46461e9 [Console] Prevent ArgvInput::getFirstArgument() from returning an option value
2 parents 68d5597 + 46461e9 commit ff4b1d4

File tree

5 files changed

+51
-2
lines changed

5 files changed

+51
-2
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@ public function doRun(InputInterface $input, OutputInterface $output)
202202
return 0;
203203
}
204204

205+
try {
206+
// Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument.
207+
$input->bind($this->getDefinition());
208+
} catch (ExceptionInterface $e) {
209+
// Errors must be ignored, full binding/validation happens later when the command is known.
210+
}
211+
205212
$name = $this->getCommandName($input);
206213
if (true === $input->hasParameterOption(['--help', '-h'], true)) {
207214
if (!$name) {

src/Symfony/Component/Console/Input/ArgvInput.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,27 @@ private function addLongOption($name, $value)
262262
*/
263263
public function getFirstArgument()
264264
{
265-
foreach ($this->tokens as $token) {
265+
$isOption = false;
266+
foreach ($this->tokens as $i => $token) {
266267
if ($token && '-' === $token[0]) {
268+
if (false !== strpos($token, '=') || !isset($this->tokens[$i + 1])) {
269+
continue;
270+
}
271+
272+
// If it's a long option, consider that everything after "--" is the option name.
273+
// Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator)
274+
$name = '-' === $token[1] ? substr($token, 2) : substr($token, -1);
275+
if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) {
276+
// noop
277+
} elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) {
278+
$isOption = true;
279+
}
280+
281+
continue;
282+
}
283+
284+
if ($isOption) {
285+
$isOption = false;
267286
continue;
268287
}
269288

src/Symfony/Component/Console/Input/InputDefinition.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,10 @@ public function getOptionDefaults()
338338
* @return string The InputOption name
339339
*
340340
* @throws InvalidArgumentException When option given does not exist
341+
*
342+
* @internal
341343
*/
342-
private function shortcutToName($shortcut)
344+
public function shortcutToName($shortcut)
343345
{
344346
if (!isset($this->shortcuts[$shortcut])) {
345347
throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut));

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,19 @@ public function testRun()
884884
$this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed');
885885
}
886886

887+
public function testRunWithGlobalOptionAndNoCommand()
888+
{
889+
$application = new Application();
890+
$application->setAutoExit(false);
891+
$application->setCatchExceptions(false);
892+
$application->getDefinition()->addOption(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL));
893+
894+
$output = new StreamOutput(fopen('php://memory', 'w', false));
895+
$input = new ArgvInput(['cli.php', '--foo', 'bar']);
896+
897+
$this->assertSame(0, $application->run($input, $output));
898+
}
899+
887900
/**
888901
* Issue #9285.
889902
*

src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,14 @@ public function testGetFirstArgument()
312312

313313
$input = new ArgvInput(['cli.php', '-fbbar', 'foo']);
314314
$this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input');
315+
316+
$input = new ArgvInput(['cli.php', '--foo', 'fooval', 'bar']);
317+
$input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')]));
318+
$this->assertSame('bar', $input->getFirstArgument());
319+
320+
$input = new ArgvInput(['cli.php', '-bf', 'fooval', 'argval']);
321+
$input->bind(new InputDefinition([new InputOption('bar', 'b', InputOption::VALUE_NONE), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')]));
322+
$this->assertSame('argval', $input->getFirstArgument());
315323
}
316324

317325
public function testHasParameterOption()

0 commit comments

Comments
 (0)