Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

QuestionHelper.php

Zuletzt modifiziert: 09.10.2024, 12:56 - Dateigröße: 13.35 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\Console\Helper;
013   
014  use Symfony\Component\Console\Exception\InvalidArgumentException;
015  use Symfony\Component\Console\Exception\RuntimeException;
016  use Symfony\Component\Console\Input\InputInterface;
017  use Symfony\Component\Console\Output\ConsoleOutputInterface;
018  use Symfony\Component\Console\Output\OutputInterface;
019  use Symfony\Component\Console\Formatter\OutputFormatterStyle;
020  use Symfony\Component\Console\Question\Question;
021  use Symfony\Component\Console\Question\ChoiceQuestion;
022   
023  /**
024   * The QuestionHelper class provides helpers to interact with the user.
025   *
026   * @author Fabien Potencier <fabien@symfony.com>
027   */
028  class QuestionHelper extends Helper
029  {
030      private $inputStream;
031      private static $shell;
032      private static $stty;
033   
034      /**
035       * Asks a question to the user.
036       *
037       * @param InputInterface  $input    An InputInterface instance
038       * @param OutputInterface $output   An OutputInterface instance
039       * @param Question        $question The question to ask
040       *
041       * @return string The user answer
042       *
043       * @throws RuntimeException If there is no data to read in the input stream
044       */
045      public function ask(InputInterface $input, OutputInterface $output, Question $question)
046      {
047          if ($output instanceof ConsoleOutputInterface) {
048              $output = $output->getErrorOutput();
049          }
050   
051          if (!$input->isInteractive()) {
052              return $question->getDefault();
053          }
054   
055          if (!$question->getValidator()) {
056              return $this->doAsk($output, $question);
057          }
058   
059          $that = $this;
060   
061          $interviewer = function () use ($output, $question, $that) {
062              return $that->doAsk($output, $question);
063          };
064   
065          return $this->validateAttempts($interviewer, $output, $question);
066      }
067   
068      /**
069       * Sets the input stream to read from when interacting with the user.
070       *
071       * This is mainly useful for testing purpose.
072       *
073       * @param resource $stream The input stream
074       *
075       * @throws InvalidArgumentException In case the stream is not a resource
076       */
077      public function setInputStream($stream)
078      {
079          if (!is_resource($stream)) {
080              throw new InvalidArgumentException('Input stream must be a valid resource.');
081          }
082   
083          $this->inputStream = $stream;
084      }
085   
086      /**
087       * Returns the helper's input stream.
088       *
089       * @return resource
090       */
091      public function getInputStream()
092      {
093          return $this->inputStream;
094      }
095   
096      /**
097       * {@inheritdoc}
098       */
099      public function getName()
100      {
101          return 'question';
102      }
103   
104      /**
105       * Asks the question to the user.
106       *
107       * This method is public for PHP 5.3 compatibility, it should be private.
108       *
109       * @param OutputInterface $output
110       * @param Question        $question
111       *
112       * @return bool|mixed|null|string
113       *
114       * @throws \Exception
115       * @throws \RuntimeException
116       */
117      public function doAsk(OutputInterface $output, Question $question)
118      {
119          $this->writePrompt($output, $question);
120   
121          $inputStream = $this->inputStream ?: STDIN;
122          $autocomplete = $question->getAutocompleterValues();
123   
124          if (null === $autocomplete || !$this->hasSttyAvailable()) {
125              $ret = false;
126              if ($question->isHidden()) {
127                  try {
128                      $ret = trim($this->getHiddenResponse($output, $inputStream));
129                  } catch (\RuntimeException $e) {
130                      if (!$question->isHiddenFallback()) {
131                          throw $e;
132                      }
133                  }
134              }
135   
136              if (false === $ret) {
137                  $ret = fgets($inputStream, 4096);
138                  if (false === $ret) {
139                      throw new RuntimeException('Aborted');
140                  }
141                  $ret = trim($ret);
142              }
143          } else {
144              $ret = trim($this->autocomplete($output, $question, $inputStream));
145          }
146   
147          $ret = strlen($ret) > 0 ? $ret : $question->getDefault();
148   
149          if ($normalizer = $question->getNormalizer()) {
150              return $normalizer($ret);
151          }
152   
153          return $ret;
154      }
155   
156      /**
157       * Outputs the question prompt.
158       *
159       * @param OutputInterface $output
160       * @param Question        $question
161       */
162      protected function writePrompt(OutputInterface $output, Question $question)
163      {
164          $message = $question->getQuestion();
165   
166          if ($question instanceof ChoiceQuestion) {
167              $maxWidth = max(array_map(array($this, 'strlen'), array_keys($question->getChoices())));
168   
169              $messages = (array) $question->getQuestion();
170              foreach ($question->getChoices() as $key => $value) {
171                  $width = $maxWidth - $this->strlen($key);
172                  $messages[] = '  [<info>'.$key.str_repeat(' ', $width).'</info>] '.$value;
173              }
174   
175              $output->writeln($messages);
176   
177              $message = $question->getPrompt();
178          }
179   
180          $output->write($message);
181      }
182   
183      /**
184       * Outputs an error message.
185       *
186       * @param OutputInterface $output
187       * @param \Exception      $error
188       */
189      protected function writeError(OutputInterface $output, \Exception $error)
190      {
191          if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) {
192              $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error');
193          } else {
194              $message = '<error>'.$error->getMessage().'</error>';
195          }
196   
197          $output->writeln($message);
198      }
199   
200      /**
201       * Autocompletes a question.
202       *
203       * @param OutputInterface $output
204       * @param Question        $question
205       * @param resource        $inputStream
206       *
207       * @return string
208       */
209      private function autocomplete(OutputInterface $output, Question $question, $inputStream)
210      {
211          $autocomplete = $question->getAutocompleterValues();
212          $ret = '';
213   
214          $i = 0;
215          $ofs = -1;
216          $matches = $autocomplete;
217          $numMatches = count($matches);
218   
219          $sttyMode = shell_exec('stty -g');
220   
221          // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
222          shell_exec('stty -icanon -echo');
223   
224          // Add highlighted text style
225          $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white'));
226   
227          // Read a keypress
228          while (!feof($inputStream)) {
229              $c = fread($inputStream, 1);
230   
231              // Backspace Character
232              if ("\177" === $c) {
233                  if (0 === $numMatches && 0 !== $i) {
234                      --$i;
235                      // Move cursor backwards
236                      $output->write("\033[1D");
237                  }
238   
239                  if ($i === 0) {
240                      $ofs = -1;
241                      $matches = $autocomplete;
242                      $numMatches = count($matches);
243                  } else {
244                      $numMatches = 0;
245                  }
246   
247                  // Pop the last character off the end of our string
248                  $ret = substr($ret, 0, $i);
249              } elseif ("\033" === $c) {
250                  // Did we read an escape sequence?
251                  $c .= fread($inputStream, 2);
252   
253                  // A = Up Arrow. B = Down Arrow
254                  if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
255                      if ('A' === $c[2] && -1 === $ofs) {
256                          $ofs = 0;
257                      }
258   
259                      if (0 === $numMatches) {
260                          continue;
261                      }
262   
263                      $ofs += ('A' === $c[2]) ? -1 : 1;
264                      $ofs = ($numMatches + $ofs) % $numMatches;
265                  }
266              } elseif (ord($c) < 32) {
267                  if ("\t" === $c || "\n" === $c) {
268                      if ($numMatches > 0 && -1 !== $ofs) {
269                          $ret = $matches[$ofs];
270                          // Echo out remaining chars for current match
271                          $output->write(substr($ret, $i));
272                          $i = strlen($ret);
273                      }
274   
275                      if ("\n" === $c) {
276                          $output->write($c);
277                          break;
278                      }
279   
280                      $numMatches = 0;
281                  }
282   
283                  continue;
284              } else {
285                  $output->write($c);
286                  $ret .= $c;
287                  ++$i;
288   
289                  $numMatches = 0;
290                  $ofs = 0;
291   
292                  foreach ($autocomplete as $value) {
293                      // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
294                      if (0 === strpos($value, $ret) && $i !== strlen($value)) {
295                          $matches[$numMatches++] = $value;
296                      }
297                  }
298              }
299   
300              // Erase characters from cursor to end of line
301              $output->write("\033[K");
302   
303              if ($numMatches > 0 && -1 !== $ofs) {
304                  // Save cursor position
305                  $output->write("\0337");
306                  // Write highlighted text
307                  $output->write('<hl>'.substr($matches[$ofs], $i).'</hl>');
308                  // Restore cursor position
309                  $output->write("\0338");
310              }
311          }
312   
313          // Reset stty so it behaves normally again
314          shell_exec(sprintf('stty %s', $sttyMode));
315   
316          return $ret;
317      }
318   
319      /**
320       * Gets a hidden response from user.
321       *
322       * @param OutputInterface $output      An Output instance
323       * @param resource        $inputStream The handler resource
324       *
325       * @return string The answer
326       *
327       * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
328       */
329      private function getHiddenResponse(OutputInterface $output, $inputStream)
330      {
331          if ('\\' === DIRECTORY_SEPARATOR) {
332              $exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
333   
334              // handle code running from a phar
335              if ('phar:' === substr(__FILE__, 0, 5)) {
336                  $tmpExe = sys_get_temp_dir().'/hiddeninput.exe';
337                  copy($exe, $tmpExe);
338                  $exe = $tmpExe;
339              }
340   
341              $value = rtrim(shell_exec($exe));
342              $output->writeln('');
343   
344              if (isset($tmpExe)) {
345                  unlink($tmpExe);
346              }
347   
348              return $value;
349          }
350   
351          if ($this->hasSttyAvailable()) {
352              $sttyMode = shell_exec('stty -g');
353   
354              shell_exec('stty -echo');
355              $value = fgets($inputStream, 4096);
356              shell_exec(sprintf('stty %s', $sttyMode));
357   
358              if (false === $value) {
359                  throw new RuntimeException('Aborted');
360              }
361   
362              $value = trim($value);
363              $output->writeln('');
364   
365              return $value;
366          }
367   
368          if (false !== $shell = $this->getShell()) {
369              $readCmd = $shell === 'csh' ? 'set mypassword = $<' : 'read -r mypassword';
370              $command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
371              $value = rtrim(shell_exec($command));
372              $output->writeln('');
373   
374              return $value;
375          }
376   
377          throw new RuntimeException('Unable to hide the response.');
378      }
379   
380      /**
381       * Validates an attempt.
382       *
383       * @param callable        $interviewer A callable that will ask for a question and return the result
384       * @param OutputInterface $output      An Output instance
385       * @param Question        $question    A Question instance
386       *
387       * @return string The validated response
388       *
389       * @throws \Exception In case the max number of attempts has been reached and no valid response has been given
390       */
391      private function validateAttempts($interviewer, OutputInterface $output, Question $question)
392      {
393          $error = null;
394          $attempts = $question->getMaxAttempts();
395          while (null === $attempts || $attempts--) {
396              if (null !== $error) {
397                  $this->writeError($output, $error);
398              }
399   
400              try {
401                  return call_user_func($question->getValidator(), $interviewer());
402              } catch (RuntimeException $e) {
403                  throw $e;
404              } catch (\Exception $error) {
405              }
406          }
407   
408          throw $error;
409      }
410   
411      /**
412       * Returns a valid unix shell.
413       *
414       * @return string|bool The valid shell name, false in case no valid shell is found
415       */
416      private function getShell()
417      {
418          if (null !== self::$shell) {
419              return self::$shell;
420          }
421   
422          self::$shell = false;
423   
424          if (file_exists('/usr/bin/env')) {
425              // handle other OSs with bash/zsh/ksh/csh if available to hide the answer
426              $test = "/usr/bin/env %s -c 'echo OK' 2> /dev/null";
427              foreach (array('bash', 'zsh', 'ksh', 'csh') as $sh) {
428                  if ('OK' === rtrim(shell_exec(sprintf($test, $sh)))) {
429                      self::$shell = $sh;
430                      break;
431                  }
432              }
433          }
434   
435          return self::$shell;
436      }
437   
438      /**
439       * Returns whether Stty is available or not.
440       *
441       * @return bool
442       */
443      private function hasSttyAvailable()
444      {
445          if (null !== self::$stty) {
446              return self::$stty;
447          }
448   
449          exec('stty 2>&1', $output, $exitcode);
450   
451          return self::$stty = $exitcode === 0;
452      }
453  }
454