Я кодирую веб-страницу с PHP-скриптом, предназначенную для приема имени файла изображения JFFS2, который ранее был загружен на сервер. Сценарий должен затем повторно воспроизвести раздел на сервере с изображением и вывести результаты. Я использовал это:
$tmp = shell_exec("update_flash -v " . $filename . " 4 2>&1"); echo '<h3>' . $tmp . '</h3>'; echo verifyResults($tmp);
(Функция verifyResults вернет некоторый HTML-код, который указывает пользователю, успешно ли выполнена команда обновления. То есть, в случае успешного завершения обновления отобразите кнопку для перезапуска устройства и т. Д.).
Проблема заключается в том, что для выполнения команды обновления требуется несколько минут, а скрипт PHP блокируется до завершения команды оболочки до того, как она вернет какой-либо вывод. Обычно это означает, что команда обновления будет продолжена, в то время как пользователь увидит ошибку HTTP 504 (в худшем случае) или дождитесь загрузки страницы в течение нескольких минут.
Я думал о том, чтобы сделать что-то вроде этого:
shell_exec("rm /tmp/output.txt"); shell_exec("update_flash -v " . $filename . " 4 2>&1 >> /tmp/output.txt &"); echo '<div id="output"></div>'; echo '<div id="results"></div>';
Это теоретически положило бы команду в фоновом режиме и добавит весь вывод в /tmp/output.txt.
И затем, в функции Javascript, я бы периодически запрашивал getOutput.php, который просто распечатывал содержимое /tmp/output.txt и вставлял его в div «output». Как только команда будет полностью выполнена, другая функция Javascript обработает вывод и отобразит результат в div «results».
Но проблема, которую я вижу здесь, заключается в том, что getOutput.php в конечном итоге станет недоступным во время обновления флеш-памяти устройства, потому что он находится на том сегменте, для которого предназначено обновление. Таким образом, это может оставить меня в том же положении, что и раньше, хотя и без страницы 504 или, казалось бы, бесконечно загружаемой страницы.
Я мог бы переместить getOutput.php на другой раздел в устройстве, но потом я думаю, что мне все равно придется делать какие-то напуганные вещи с конфигурацией веб-сервера, чтобы иметь возможность получить к нему доступ (символическая ссылка на него из webroot будет, как и любая другая файл, в конечном счете, будет перезаписан во время повторной вспышки).
Есть ли другой способ отображения вывода команды во время ее запуска, или я должен просто сделать это с решением, которое у меня есть?
Изменить 1: В настоящее время я тестирую некоторые решения. Я позже обновлю свой вопрос.
Изменить 2: Кажется, что файловая система не перезаписывается, как я думал изначально. Вместо этого система, похоже, монтирует существующую файловую систему в режиме только для чтения, поэтому я все еще могу получить доступ к getOutput.php даже после перезапуска файловой системы.
Второе решение, которое я описал в моем вопросе, похоже, работает в дополнение к использованию popen (как указано в ответе ниже) вместо shell_exec. Загрузка страницы, и через Ajax я могу отображать содержимое output.txt.
Однако кажется, что output.txt не отражает вывод команды re-flash в реальном времени – кажется, ничего не отображается, пока команда обновления не вернется из исполнения. Мне нужно будет продолжить тестирование, чтобы посмотреть, что здесь происходит.
Редактировать 3: Не обращайте внимания, похоже, что файл работает, когда я обращаюсь к нему. Я просто задерживал задержку, в то время как ядро выполняло некоторые связанные с JFFS2 задачи, вызванные моим использованием раздела, на котором хранится исходное изображение JFFS2. Я не знаю почему, но это, по-видимому, заставляет все PHP-скрипты блокироваться, пока это не будет сделано.
Чтобы обойти это, я собираюсь включить вызов команды обновления в отдельный скрипт и запросить его через Ajax. Таким образом, пользователь, по крайней мере, получит некоторую предварительно упакованную обратную связь, пока технически все еще ждет в системе.
Посмотрите на popen: http://it.php.net/manual/en/function.popen.php
Интересный сценарий.
Моя первая мысль заключалась в том, чтобы что-то делать с proc_ * и $ _SESSION, но я не уверен, что это сработает или нет. Попробуйте, но если нет …
Если вы беспокоитесь о том, что файл во время процесса вспыхнул, вы всегда можете создать базу данных mysql во вторичном процессе и написать на это. База данных может существовать в другом разделе, и вы можете адресовать ее локальным ip, и система позаботится о маршрутизации.
редактировать
Когда я упоминал proc_ * с сеансами, я имел в виду нечто похожее на это, где $ descriptorspec стал бы:
$_SESSION = array( 1 => array("pipe", "w"), );
Однако я сомневаюсь, что это сработает. Процесс завершится записью в $ _SESSION в памяти, которая больше не существует, когда первый скрипт убит.
Изменить 2
В этом случае вы можете установить memcache и записать вторичный процесс в память, который затем может быть перечитан вашим веб-интерфейсом.
Если вы уничтожите DocRoot, в это время нет ресурсов / скриптов, которые могут отвечать на запросы пользователя. Поэтому вы должны отправлять обновления пользователю в том же запросе, который выполняет очистку. Это требует, чтобы вы начали процесс оболочки и сразу возвращались к PHP. Это можно выполнить с помощью pcntl_fork()
и pcntl_exec()
. Ваш PHP-скрипт должен теперь непрерывно отправлять результат сценария оболочки клиенту. Если сценарий оболочки присоединяется к файлу в / tmp, вы можете fpassthru()
этот файл и очистить его до окончания сценария оболочки.
Что касается вашего, тем не менее :
Я предполагаю, что вы пытаетесь использовать этот файл в качестве потока. Я не делал никаких производственных тестов, но считаю, что файл будет записан на диск только на fclose ().
Если вы постоянно пишете файл в скрипте # 2, эти записи фактически переходят непосредственно в память, пока файл не будет закрыт.
Опять же – я не могу это проверить, но если вы хотите протестировать его, попробуйте повторно открыть и закрыть файл для каждой записи. Это подтвердит или отклонит мою теорию, и вы можете соответствующим образом изменить свой подход.