Я хочу, чтобы каждый раз читал один символ из командной строки в 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..."; }