From b4adbbd0b8bdc11363015789be9911ba38d6f02a Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 23 Jun 2020 14:31:34 +0200 Subject: [PATCH 1/6] Fixed typo in test name --- Tests/Helper/QuestionHelperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Helper/QuestionHelperTest.php b/Tests/Helper/QuestionHelperTest.php index 93b762c26..f1a7676a0 100644 --- a/Tests/Helper/QuestionHelperTest.php +++ b/Tests/Helper/QuestionHelperTest.php @@ -1014,7 +1014,7 @@ public function testTraversableAutocomplete() $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } - public function testDisableSttby() + public function testDisableStty() { if (!Terminal::hasSttyAvailable()) { $this->markTestSkipped('`stty` is required to test autocomplete functionality'); From cbbaa74b947a76fdc5ef0fc4dff17f22c10e1ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 30 Jun 2020 14:50:28 +0200 Subject: [PATCH 2/6] Removed comments and requirements relative to php <5.5 (not supported anymore) --- Command/Command.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/Command/Command.php b/Command/Command.php index 311fdb6a1..e39cc3ba4 100644 --- a/Command/Command.php +++ b/Command/Command.php @@ -437,8 +437,6 @@ public function setName($name) * This feature should be used only when creating a long process command, * like a daemon. * - * PHP 5.5+ or the proctitle PECL library is required - * * @param string $title The process title * * @return $this From fc323759f84afa467e0f34d88e57e40cd23dc9ac Mon Sep 17 00:00:00 2001 From: YaFou <33806646+YaFou@users.noreply.github.com> Date: Wed, 1 Jul 2020 09:43:16 +0200 Subject: [PATCH 3/6] [Console] Fixes question input encoding on Windows --- Helper/QuestionHelper.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index 80f6048b8..ee6d4b664 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -158,6 +158,11 @@ private function doAsk(OutputInterface $output, Question $question) $inputStream = $this->inputStream ?: STDIN; $autocomplete = $question->getAutocompleterValues(); + if (\function_exists('sapi_windows_cp_set')) { + // Codepage used by cmd.exe on Windows to allow special characters (éàüñ). + sapi_windows_cp_set(1252); + } + if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { $ret = false; if ($question->isHidden()) { From 426b401f5504b4e52b4b3fd9f133c2cbf412b378 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 1 Jul 2020 14:09:20 +0200 Subject: [PATCH 4/6] [Console] always use stty when possible to ask hidden questions --- Helper/QuestionHelper.php | 83 +++++++++++++-------------------------- 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index 1b60786c9..6efec5b5b 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -34,6 +34,7 @@ class QuestionHelper extends Helper private $inputStream; private static $shell; private static $stty = true; + private static $stdinIsInteractive; /** * Asks a question to the user. @@ -419,33 +420,26 @@ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $ if (self::$stty && Terminal::hasSttyAvailable()) { $sttyMode = shell_exec('stty -g'); - shell_exec('stty -echo'); - $value = fgets($inputStream, 4096); - shell_exec(sprintf('stty %s', $sttyMode)); + } elseif ($this->isInteractiveInput($inputStream)) { + throw new RuntimeException('Unable to hide the response.'); + } - if (false === $value) { - throw new MissingInputException('Aborted.'); - } - if ($trimmable) { - $value = trim($value); - } - $output->writeln(''); + $value = fgets($inputStream, 4096); - return $value; + if (self::$stty && Terminal::hasSttyAvailable()) { + shell_exec(sprintf('stty %s', $sttyMode)); } - if (false !== $shell = $this->getShell()) { - $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword'; - $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword' 2> /dev/null", $shell, $readCmd); - $sCommand = shell_exec($command); - $value = $trimmable ? rtrim($sCommand) : $sCommand; - $output->writeln(''); - - return $value; + if (false === $value) { + throw new MissingInputException('Aborted.'); + } + if ($trimmable) { + $value = trim($value); } + $output->writeln(''); - throw new RuntimeException('Unable to hide the response.'); + return $value; } /** @@ -473,56 +467,35 @@ private function validateAttempts(callable $interviewer, OutputInterface $output throw $e; } catch (\Exception $error) { } - - $attempts = $attempts ?? -(int) $this->askForever(); } throw $error; } - /** - * Returns a valid unix shell. - * - * @return string|bool The valid shell name, false in case no valid shell is found - */ - private function getShell() + private function isInteractiveInput($inputStream): bool { - if (null !== self::$shell) { - return self::$shell; + if ('php://stdin' !== (stream_get_meta_data($inputStream)['uri'] ?? null)) { + return false; } - self::$shell = false; - - if (file_exists('/usr/bin/env')) { - // handle other OSs with bash/zsh/ksh/csh if available to hide the answer - $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null"; - foreach (['bash', 'zsh', 'ksh', 'csh'] as $sh) { - if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) { - self::$shell = $sh; - break; - } - } - } - - return self::$shell; - } - - private function askForever(): bool - { - $inputStream = $this->inputStream ?: fopen('php://stdin', 'r'); - - if ('php://stdin' !== (stream_get_meta_data($inputStream)['url'] ?? null)) { - return true; + if (null !== self::$stdinIsInteractive) { + return self::$stdinIsInteractive; } if (\function_exists('stream_isatty')) { - return stream_isatty($inputStream); + return self::$stdinIsInteractive = stream_isatty(fopen('php://stdin', 'r')); } if (\function_exists('posix_isatty')) { - return posix_isatty($inputStream); + return self::$stdinIsInteractive = posix_isatty(fopen('php://stdin', 'r')); } - return true; + if (!\function_exists('exec')) { + return self::$stdinIsInteractive = true; + } + + exec('stty 2> /dev/null', $output, $status); + + return self::$stdinIsInteractive = 1 !== $status; } } From 5e980f99034c73c00b06959345728dc0dc29d512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Wed, 1 Jul 2020 12:07:23 +0200 Subject: [PATCH 5/6] [Console] Do not check for "stty" using "exec" if that function is disabled --- Terminal.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Terminal.php b/Terminal.php index 43a318262..774c5f76b 100644 --- a/Terminal.php +++ b/Terminal.php @@ -66,6 +66,11 @@ public static function hasSttyAvailable() return self::$stty; } + // skip check if exec function is disabled + if (!\function_exists('exec')) { + return false; + } + exec('stty 2>&1', $output, $exitcode); return self::$stty = 0 === $exitcode; From 9f9ab1ef18b733b948783c43e4f40ea70c5d8d95 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 4 Jul 2020 11:30:27 +0200 Subject: [PATCH 6/6] [Console] fix reading from STDIN --- Helper/QuestionHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index 6efec5b5b..72c270e22 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -105,7 +105,7 @@ private function doAsk(OutputInterface $output, Question $question) { $this->writePrompt($output, $question); - $inputStream = $this->inputStream ?: fopen('php://stdin', 'r'); + $inputStream = $this->inputStream ?: STDIN; $autocomplete = $question->getAutocompleterCallback(); if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) {