Goal: run a PHP file in cmd, script loops x times and on every iteration checks to see if user has entered any input (stream_select() with STDIN) and if so - pauses the loop until the user hits enter, then prints out the input and continues with iteration.
Problem: Script runs perfectly as long as cmd.exe window is in focus - when I click on another window the script pauses at stream_select
and doesn't continue until I but the cmd window back in focus and send it some input (a simple enter key press would do the trick). No errors.
Question: why does losing focus on cmd affect stream_select and block the loop? ...and is there a workaround? (e.g. is it possible to check if the current cmd window is in focus?)
Code example, used cmd php script.php
in working directory.
<?php
$loopCount = 20;
while ($loopCount) {
$start = microtime(true);
echo 'check on "' . $loopCount . '"' . PHP_EOL;
$stream = fopen('php://stdin', 'r');
$stream_array = array($stream);
$write = array();
$except = array();
if (stream_select($stream_array, $write, $except, 1, 0)) {
$input = trim(fgets($stream));
if ($input) {
echo 'input was "' . $input . '"' . PHP_EOL;
}
}
fclose($stream);
echo $loopCount . ' in ' . (microtime(true) - $start) . PHP_EOL;
$loopCount--;
}
Things I have tried with no luck:
- moving
fopen
andfclose
outside the loop ignore_user_abort(1);
stream_set_blocking($stream, 0);
null
,0
and higher values for bothtv_sec
andtv_usec
params ofstream_select()
- checking for connection_aborted() and connection_status()
Environment: Windows 7, XAMPP for windows, PHP 5.4.19 (cli), Zend Engine v2.4.0
I think the problem is because stream_select() will also return 1 for STDIN when the stream receives EOL, which is what I think happens when cmd loses focus.
From http://www.php.net/manual/en/function.stream-select.php
When focus is not lost and no input is given, stream_select returns 0 and the $read array passed in is emptied by reference. When focus is lost OR when input is given, the $read array remains intact and you are expected to read from each index.
But that leaves us window's users in a bad situation because we don't have a way to non-blockingly read that zero length string with stream_get_(contents|line) or fread or fgets. And since we cannot differentiate between losing focus and supplying actual data I believe we have to wait for one of these bugs to get fixed:
https://bugs.php.net/bug.php?id=36030
https://bugs.php.net/bug.php?id=34972
I'm currently exploring an option to prevent the window from losing focus via the win32 API, but that looks impractical for even my needs.
Here is the workaround I'm using for now...
https://gist.github.com/anonymous/80080060869f875e7214