PHPのコマンドラインから一度に1文字ずつ読み取りたいのですが、どこかから何らかの入力バッファリングがあり、これを妨げているようです。
このコードを検討してください:
#!/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#
(つまり、文字は入力時に読み取られて処理されます)。
ただし、現在、各文字はEnterキーを押した後にのみ読み取られます。 TTYが入力をバッファリングしているのではないかと疑っています。
最終的には、上矢印、下矢印などのキー押下を読み取れるようにしたいと思います。
私にとっての解決策は、TTYで-icanon
モードを設定することでした(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");
?>
これは、ttyのものをいじる必要なしに、readlineおよびstream関数で私のために働く方法です。
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;
}
}
OSXでPHP 5.5.8)でテスト済み。
以下の関数は、単一の文字をキャプチャするために使用できる@sebの回答の簡略版です。 stream_select
を必要とせず、whileループを作成するのではなく、readline_callback_handler_install
の固有のブロッキングを使用します。また、ハンドラーを削除して、通常どおりさらに入力できるようにします(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
`stty -icanon`;
// 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...";
}