Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
433 views
in Technique[技术] by (71.8m points)

stdin - PHP CLI: How to read a single character of input from the TTY (without waiting for the enter key)?

I want to read a single character at-a-time from the command line in PHP, however it seems as though there is some kind of input buffering from somewhere preventing this.

Consider this code:

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

Typing in "foo" as the input (and pressing enter), the output I am getting is:

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

input# 

The output I am expecting is:

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# 

(That is, with characters being read and processed as they are typed).

However, currently, each character is being read only after enter is pressed. I have a suspicion the TTY is buffering the input.

Ultimately I want to be able to read keypresses such as UP arrow, DOWN arrow, etc.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The solution for me was to set -icanon mode on the TTY (using stty). Eg.:

stty -icanon

So, the the code that now works is:

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

Output:

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

input# 

Props to the answer given here:
Is there a way to wait for and get a key press from a (remote) terminal session?

For more information, see:
http://www.faqs.org/docs/Linux-HOWTO/Serial-Programming-HOWTO.html#AEN92

Don't forget to restore the TTY when you're done with it...

Restoring the tty configuration

Resetting the terminal back to the way it was can be done by saving the tty state before you make changes to it. You can then restore to that state when you're done.

For example:

<?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 . "'");

?>

This is the only way to preserve the tty and put it back how the user had it before you began.

Note that if you're not worried about preserving the original state, you can reset it back to a default "sane" configuration simply by doing:

<?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");

?>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...