[ Index ] |
PHP Cross Reference of phpBB-3.2.11-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 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 Symfony\Component\Console\Helper; 13 14 use Symfony\Component\Console\Exception\InvalidArgumentException; 15 use Symfony\Component\Console\Exception\RuntimeException; 16 use Symfony\Component\Console\Formatter\OutputFormatter; 17 use Symfony\Component\Console\Formatter\OutputFormatterStyle; 18 use Symfony\Component\Console\Input\InputInterface; 19 use Symfony\Component\Console\Output\ConsoleOutputInterface; 20 use Symfony\Component\Console\Output\OutputInterface; 21 use Symfony\Component\Console\Question\ChoiceQuestion; 22 use Symfony\Component\Console\Question\Question; 23 24 /** 25 * The QuestionHelper class provides helpers to interact with the user. 26 * 27 * @author Fabien Potencier <fabien@symfony.com> 28 */ 29 class QuestionHelper extends Helper 30 { 31 private $inputStream; 32 private static $shell; 33 private static $stty; 34 35 /** 36 * Asks a question to the user. 37 * 38 * @return mixed The user answer 39 * 40 * @throws RuntimeException If there is no data to read in the input stream 41 */ 42 public function ask(InputInterface $input, OutputInterface $output, Question $question) 43 { 44 if ($output instanceof ConsoleOutputInterface) { 45 $output = $output->getErrorOutput(); 46 } 47 48 if (!$input->isInteractive()) { 49 $default = $question->getDefault(); 50 51 if (null !== $default && $question instanceof ChoiceQuestion) { 52 $choices = $question->getChoices(); 53 54 if (!$question->isMultiselect()) { 55 return isset($choices[$default]) ? $choices[$default] : $default; 56 } 57 58 $default = explode(',', $default); 59 foreach ($default as $k => $v) { 60 $v = trim($v); 61 $default[$k] = isset($choices[$v]) ? $choices[$v] : $v; 62 } 63 } 64 65 return $default; 66 } 67 68 if (!$question->getValidator()) { 69 return $this->doAsk($output, $question); 70 } 71 72 $that = $this; 73 74 $interviewer = function () use ($output, $question, $that) { 75 return $that->doAsk($output, $question); 76 }; 77 78 return $this->validateAttempts($interviewer, $output, $question); 79 } 80 81 /** 82 * Sets the input stream to read from when interacting with the user. 83 * 84 * This is mainly useful for testing purpose. 85 * 86 * @param resource $stream The input stream 87 * 88 * @throws InvalidArgumentException In case the stream is not a resource 89 */ 90 public function setInputStream($stream) 91 { 92 if (!\is_resource($stream)) { 93 throw new InvalidArgumentException('Input stream must be a valid resource.'); 94 } 95 96 $this->inputStream = $stream; 97 } 98 99 /** 100 * Returns the helper's input stream. 101 * 102 * @return resource 103 */ 104 public function getInputStream() 105 { 106 return $this->inputStream; 107 } 108 109 /** 110 * {@inheritdoc} 111 */ 112 public function getName() 113 { 114 return 'question'; 115 } 116 117 /** 118 * Asks the question to the user. 119 * 120 * This method is public for PHP 5.3 compatibility, it should be private. 121 * 122 * @return bool|mixed|string|null 123 * 124 * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden 125 */ 126 public function doAsk(OutputInterface $output, Question $question) 127 { 128 $this->writePrompt($output, $question); 129 130 $inputStream = $this->inputStream ?: STDIN; 131 $autocomplete = $question->getAutocompleterValues(); 132 133 if (null === $autocomplete || !$this->hasSttyAvailable()) { 134 $ret = false; 135 if ($question->isHidden()) { 136 try { 137 $ret = trim($this->getHiddenResponse($output, $inputStream)); 138 } catch (RuntimeException $e) { 139 if (!$question->isHiddenFallback()) { 140 throw $e; 141 } 142 } 143 } 144 145 if (false === $ret) { 146 $ret = fgets($inputStream, 4096); 147 if (false === $ret) { 148 throw new RuntimeException('Aborted'); 149 } 150 $ret = trim($ret); 151 } 152 } else { 153 $ret = trim($this->autocomplete($output, $question, $inputStream, \is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false))); 154 } 155 156 $ret = \strlen($ret) > 0 ? $ret : $question->getDefault(); 157 158 if ($normalizer = $question->getNormalizer()) { 159 return $normalizer($ret); 160 } 161 162 return $ret; 163 } 164 165 /** 166 * Outputs the question prompt. 167 */ 168 protected function writePrompt(OutputInterface $output, Question $question) 169 { 170 $message = $question->getQuestion(); 171 172 if ($question instanceof ChoiceQuestion) { 173 $maxWidth = max(array_map(array($this, 'strlen'), array_keys($question->getChoices()))); 174 175 $messages = (array) $question->getQuestion(); 176 foreach ($question->getChoices() as $key => $value) { 177 $width = $maxWidth - $this->strlen($key); 178 $messages[] = ' [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value; 179 } 180 181 $output->writeln($messages); 182 183 $message = $question->getPrompt(); 184 } 185 186 $output->write($message); 187 } 188 189 /** 190 * Outputs an error message. 191 */ 192 protected function writeError(OutputInterface $output, \Exception $error) 193 { 194 if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { 195 $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); 196 } else { 197 $message = '<error>'.$error->getMessage().'</error>'; 198 } 199 200 $output->writeln($message); 201 } 202 203 /** 204 * Autocompletes a question. 205 * 206 * @param OutputInterface $output 207 * @param Question $question 208 * @param resource $inputStream 209 * @param array $autocomplete 210 * 211 * @return string 212 */ 213 private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete) 214 { 215 $ret = ''; 216 217 $i = 0; 218 $ofs = -1; 219 $matches = $autocomplete; 220 $numMatches = \count($matches); 221 222 $sttyMode = shell_exec('stty -g'); 223 224 // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) 225 shell_exec('stty -icanon -echo'); 226 227 // Add highlighted text style 228 $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); 229 230 // Read a keypress 231 while (!feof($inputStream)) { 232 $c = fread($inputStream, 1); 233 234 // Backspace Character 235 if ("\177" === $c) { 236 if (0 === $numMatches && 0 !== $i) { 237 --$i; 238 // Move cursor backwards 239 $output->write("\033[1D"); 240 } 241 242 if (0 === $i) { 243 $ofs = -1; 244 $matches = $autocomplete; 245 $numMatches = \count($matches); 246 } else { 247 $numMatches = 0; 248 } 249 250 // Pop the last character off the end of our string 251 $ret = substr($ret, 0, $i); 252 } elseif ("\033" === $c) { 253 // Did we read an escape sequence? 254 $c .= fread($inputStream, 2); 255 256 // A = Up Arrow. B = Down Arrow 257 if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { 258 if ('A' === $c[2] && -1 === $ofs) { 259 $ofs = 0; 260 } 261 262 if (0 === $numMatches) { 263 continue; 264 } 265 266 $ofs += ('A' === $c[2]) ? -1 : 1; 267 $ofs = ($numMatches + $ofs) % $numMatches; 268 } 269 } elseif (\ord($c) < 32) { 270 if ("\t" === $c || "\n" === $c) { 271 if ($numMatches > 0 && -1 !== $ofs) { 272 $ret = $matches[$ofs]; 273 // Echo out remaining chars for current match 274 $output->write(substr($ret, $i)); 275 $i = \strlen($ret); 276 } 277 278 if ("\n" === $c) { 279 $output->write($c); 280 break; 281 } 282 283 $numMatches = 0; 284 } 285 286 continue; 287 } else { 288 $output->write($c); 289 $ret .= $c; 290 ++$i; 291 292 $numMatches = 0; 293 $ofs = 0; 294 295 foreach ($autocomplete as $value) { 296 // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) 297 if (0 === strpos($value, $ret)) { 298 $matches[$numMatches++] = $value; 299 } 300 } 301 } 302 303 // Erase characters from cursor to end of line 304 $output->write("\033[K"); 305 306 if ($numMatches > 0 && -1 !== $ofs) { 307 // Save cursor position 308 $output->write("\0337"); 309 // Write highlighted text 310 $output->write('<hl>'.OutputFormatter::escapeTrailingBackslash(substr($matches[$ofs], $i)).'</hl>'); 311 // Restore cursor position 312 $output->write("\0338"); 313 } 314 } 315 316 // Reset stty so it behaves normally again 317 shell_exec(sprintf('stty %s', $sttyMode)); 318 319 return $ret; 320 } 321 322 /** 323 * Gets a hidden response from user. 324 * 325 * @param OutputInterface $output An Output instance 326 * @param resource $inputStream The handler resource 327 * 328 * @return string The answer 329 * 330 * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden 331 */ 332 private function getHiddenResponse(OutputInterface $output, $inputStream) 333 { 334 if ('\\' === \DIRECTORY_SEPARATOR) { 335 $exe = __DIR__.'/../Resources/bin/hiddeninput.exe'; 336 337 // handle code running from a phar 338 if ('phar:' === substr(__FILE__, 0, 5)) { 339 $tmpExe = sys_get_temp_dir().'/hiddeninput.exe'; 340 copy($exe, $tmpExe); 341 $exe = $tmpExe; 342 } 343 344 $value = rtrim(shell_exec($exe)); 345 $output->writeln(''); 346 347 if (isset($tmpExe)) { 348 unlink($tmpExe); 349 } 350 351 return $value; 352 } 353 354 if ($this->hasSttyAvailable()) { 355 $sttyMode = shell_exec('stty -g'); 356 357 shell_exec('stty -echo'); 358 $value = fgets($inputStream, 4096); 359 shell_exec(sprintf('stty %s', $sttyMode)); 360 361 if (false === $value) { 362 throw new RuntimeException('Aborted'); 363 } 364 365 $value = trim($value); 366 $output->writeln(''); 367 368 return $value; 369 } 370 371 if (false !== $shell = $this->getShell()) { 372 $readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword'; 373 $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd); 374 $value = rtrim(shell_exec($command)); 375 $output->writeln(''); 376 377 return $value; 378 } 379 380 throw new RuntimeException('Unable to hide the response.'); 381 } 382 383 /** 384 * Validates an attempt. 385 * 386 * @param callable $interviewer A callable that will ask for a question and return the result 387 * @param OutputInterface $output An Output instance 388 * @param Question $question A Question instance 389 * 390 * @return mixed The validated response 391 * 392 * @throws \Exception In case the max number of attempts has been reached and no valid response has been given 393 */ 394 private function validateAttempts($interviewer, OutputInterface $output, Question $question) 395 { 396 $error = null; 397 $attempts = $question->getMaxAttempts(); 398 while (null === $attempts || $attempts--) { 399 if (null !== $error) { 400 $this->writeError($output, $error); 401 } 402 403 try { 404 return \call_user_func($question->getValidator(), $interviewer()); 405 } catch (RuntimeException $e) { 406 throw $e; 407 } catch (\Exception $error) { 408 } 409 } 410 411 throw $error; 412 } 413 414 /** 415 * Returns a valid unix shell. 416 * 417 * @return string|bool The valid shell name, false in case no valid shell is found 418 */ 419 private function getShell() 420 { 421 if (null !== self::$shell) { 422 return self::$shell; 423 } 424 425 self::$shell = false; 426 427 if (file_exists('/usr/bin/env')) { 428 // handle other OSs with bash/zsh/ksh/csh if available to hide the answer 429 $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null"; 430 foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) { 431 if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) { 432 self::$shell = $sh; 433 break; 434 } 435 } 436 } 437 438 return self::$shell; 439 } 440 441 /** 442 * Returns whether Stty is available or not. 443 * 444 * @return bool 445 */ 446 private function hasSttyAvailable() 447 { 448 if (null !== self::$stty) { 449 return self::$stty; 450 } 451 452 exec('stty 2>&1', $output, $exitcode); 453 454 return self::$stty = 0 === $exitcode; 455 } 456 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 11 20:33:01 2020 | Cross-referenced by PHPXref 0.7.1 |