Intereting Posts
Тестирование уязвимостей безопасности в веб-приложениях: лучшие практики? Результаты группы после присоединения? Как написать маршруты маршрутизации для субдомена в Zend Framework в файле INI маршрутизации? PHP Warning: POST Content-Length из 8978294 байт превышает предел 8388608 байт в Unknown в строке 0 file_put_contents php разрешения PHPUnit: ожидание вызова метода с массивом в качестве аргумента Преобразование разделов Woo Commerce в кнопки радиосвязи Глобальные функции Symfony2 Laravel 4: Как решены Фасады? Angularjs и jquery не работают в моей обычной простой форме PHP: печать неопределенных переменных без предупреждения Как получить идентификатор адреса доставки / биллинга заказа за пределами API-интерфейса Magento? время 30 секунд превысило ошибку? файл получить содержимое значение поиска многомерного массива и вернуть его ключ php css исчезает при попытке создать чистый URL-адрес

PHP CLI: как читать один символ ввода из TTY (не дожидаясь ввода ключа)?

Я хочу, чтобы каждый раз читал один символ из командной строки в PHP, но кажется, что где-то есть некоторая входная буферизация, предотвращающая это.

Рассмотрим этот код:

#!/usr/bin/php <?php echo "input# "; while ($c = fread(STDIN, 1)) { echo "Read from STDIN: " . $c . "\ninput# "; } ?> 

Набрав «foo» в качестве ввода (и нажав enter), вывод, который я получаю, следующий:

 input# foo Read from STDIN: f input# Read from STDIN: o input# Read from STDIN: o input# Read from STDIN: input# 

Ожидаемый результат :

 input# f input# Read from STDIN: f input# o input# Read from STDIN: o input# o input# Read from STDIN: o input# input# Read from STDIN: input# 

(То есть, когда символы считываются и обрабатываются по мере их ввода).

Однако в настоящее время каждый символ считывается только после нажатия клавиши ввода. У меня есть подозрение, что TTY выполняет буферизацию ввода.

В конечном счете я хочу иметь возможность читать нажатия клавиш, такие как стрелка ВВЕРХ, стрелка ВНИЗ и т. Д.

Заранее спасибо!

Решение для меня состояло в том, чтобы установить режим записи в TTY (используя stty ). Например.:

 stty -icanon 

Итак, код, который теперь работает:

 #!/usr/bin/php <?php system("stty -icanon"); echo "input# "; while ($c = fread(STDIN, 1)) { echo "Read from STDIN: " . $c . "\ninput# "; } ?> 

Вывод:

 input# fRead from STDIN: f input# oRead from STDIN: o input# oRead from STDIN: o input# Read from STDIN: input# 

Подкрепление ответа, приведенного здесь:
Есть ли способ подождать и получить нажатие клавиши с (удаленного) сеанса терминала?

Для получения дополнительной информации см.
http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html#AEN92

Не забудьте восстановить TTY, когда закончите с ним …

Восстановление конфигурации tty

Сброс терминала обратно до того, как это было сделано, можно сохранить, сохраняя состояние tty, прежде чем вносить в него изменения. После этого вы сможете восстановить это состояние.

Например:

 <?php // Save existing tty configuration $term = `stty -g`; // Make lots of drastic changes to the tty system("stty raw opost -ocrnl onlcr -onocr -onlret icrnl -inlcr -echo isig intr undef"); // Reset the tty back to the original configuration system("stty '" . $term . "'"); ?> 

Это единственный способ сохранить tty и вернуть его, как это было у пользователя перед тем, как вы начали.

Обратите внимание, что если вы не беспокоитесь о сохранении исходного состояния, вы можете вернуть его обратно в стандартную «нормальную» конфигурацию, просто выполнив:

 <?php // Make lots of drastic changes to the tty system("stty raw opost -ocrnl onlcr -onocr -onlret icrnl -inlcr -echo isig intr undef"); // Reset the tty back to sane defaults system("stty sane"); ?> 

Вот способ, который работает для меня с функциями readline и stream, без необходимости возиться с вещами tty.

 readline_callback_handler_install('', function() { }); while (true) { $r = array(STDIN); $w = NULL; $e = NULL; $n = stream_select($r, $w, $e, null); if ($n && in_array(STDIN, $r)) { $c = stream_get_contents(STDIN, 1); echo "Char read: $c\n"; break; } } 

Протестировано с помощью PHP 5.5.8 на OSX.

Ниже приведена упрощенная версия ответа @ seb, которая может использоваться для захвата одного символа. Он не требует stream_select и использует readline_callback_handler_install блокировку readline_callback_handler_install вместо создания цикла while. Он также удаляет обработчик, чтобы обеспечить дополнительный ввод как обычно (например, readline).

 function readchar($prompt) { readline_callback_handler_install($prompt, function() {}); $char = stream_get_contents(STDIN, 1); readline_callback_handler_remove(); return $char; } // example: if (!in_array( readchar('Continue? [Y/n] '), ["\n", 'y', 'Y'] // enter/return key ("\n") for default 'Y' )) die("Good Bye\n"); $name = readline("Name: "); echo "Hello {$name}.\n"; 
 <?php // this will do it stream_set_blocking(STDIN, 0); echo "Press 'Q' to quit\n"; while(1){ if (ord(fgetc(STDIN)) == 113) { echo "QUIT detected..."; break; } echo "we are waiting for something..."; } в <?php // this will do it stream_set_blocking(STDIN, 0); echo "Press 'Q' to quit\n"; while(1){ if (ord(fgetc(STDIN)) == 113) { echo "QUIT detected..."; break; } echo "we are waiting for something..."; }