Цель: запустить PHP-файл в cmd, цикл скриптов x раз и на каждой итерационной проверке, чтобы узнать, ввел ли пользователь какой-либо вход ( stream_select () с STDIN ), и если это так – приостанавливает цикл до тех пор, пока пользователь не наткнется на ввод, затем распечатает ввода и продолжается с итерацией.
Проблема: сценарий работает отлично до тех пор, пока окно cmd.exe находится в фокусе – когда я нажимаю на другое окно, сценарий приостанавливается в stream_select
и не продолжается до тех пор, пока я, кроме CMd-окна, не окажусь в фокусе и не отправлю ему некоторый ввод (просто введите нажатие клавиши будет делать трюк). Нет ошибок.
Вопрос: почему потеря фокуса на cmd влияет на stream_select и блокирует цикл? … и есть ли обходной путь? (например, можно ли проверить, находится ли текущее окно cmd?)
Пример кода, используемый cmd php script.php
в рабочем каталоге.
<?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--; }
Вещи, которые я пробовал, не повезло:
fopen
и fclose
вне цикла ignore_user_abort(1);
stream_set_blocking($stream, 0);
null
, 0
и более высокие значения для параметров tv_sec
и tv_usec
для tv_sec
stream_select()
Окружающая среда: Windows 7, XAMPP для Windows, PHP 5.4.19 (cli), Zend Engine v2.4.0
Я думаю, проблема связана с тем, что stream_select () также возвращает 1 для STDIN, когда поток получает EOL, что, как мне кажется, происходит, когда cmd теряет фокус.
С http://www.php.net/manual/en/function.stream-select.php
в частности, ресурс потока также готов к концу файла, и в этом случае fread () вернет строку нулевой длины
Когда фокус не теряется и данные не вводятся, stream_select возвращает 0, а принятый массив $ read освобождается ссылкой. Когда фокус теряется ИЛИ когда ввод задан, массив $ read остается неповрежденным, и вы должны читать из каждого индекса.
Но это оставляет нам пользователей окна в плохой ситуации, потому что у нас нет способа неблокировать чтение строки нулевой длины с помощью stream_get_ (content | line) или fread или fgets. И поскольку мы не можем различать потери фокуса и поставки фактических данных, я считаю, что нам нужно подождать, пока одна из этих ошибок будет исправлена:
https://bugs.php.net/bug.php?id=36030
https://bugs.php.net/bug.php?id=34972
В настоящее время я изучаю вариант, чтобы предотвратить потерять фокус через API win32, но это выглядит непрактичным даже для моих нужд.
Вот обходной путь, который я использую сейчас …