получить вывод из команды shell_exec при запуске команды - PullRequest
6 голосов
/ 07 декабря 2010

Я кодирую веб-страницу со сценарием 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.Как только команда будет полностью выполнена, другая функция Javascript обработает вывод и отобразит результат в div «results».

Но проблема, которую я вижу здесь, заключается в том, что getOutput.php в конечном итоге станет недоступным во время процессаобновление флэш-памяти устройства, поскольку оно находится в разделе, для которого предназначено обновление.Так что это может оставить меня в том же положении, что и раньше, хотя и без 504 или, казалось бы, вечно загружаемой страницы.

Я мог бы переместить getOutput.php в другой раздел устройства, но тогда я думаю, что все равнонужно сделать что-то интересное с настройкой веб-сервера, чтобы иметь к нему доступ (символическая ссылка на него из webroot, как и любой другой файл, в конечном итоге будет перезаписана во время повторной прошивки).

Есть лилюбой другой способ отображения вывода команды во время ее выполнения, или я должен просто обойтись без решения, которое у меня есть?

Редактировать 1: В настоящее время я тестирую некоторые решения.Я обновлю свой вопрос результатами позже.

Редактировать 2: Кажется, файловая система не перезаписывается, как я первоначально думал.Вместо этого система, кажется, монтирует существующую файловую систему в режиме только для чтения, поэтому я все еще могу получить доступ к getOutput.php даже после повторной прошивки файловой системы.

Второе решение, которое я описал в своем вопросе, похоже, действительноработать также с использованием popen (как указано в ответе ниже) вместо shell_exec.Страница загружается, и через Ajax я могу отображать содержимое файла output.txt.

Однако , похоже, что output.txt не отражает вывод из повторной вспышкиКоманда в режиме реального времени - кажется, ничего не отображается, пока команда обновления не вернется из выполнения.Мне нужно будет провести дополнительное тестирование, чтобы увидеть, что здесь происходит.

Редактировать 3: Не берите в голову, похоже, файл является текущим, как ядоступ к нему.Я просто задерживался, пока ядро ​​выполняло некоторые связанные с JFFS2 задачи, вызванные моим использованием раздела, на котором хранится исходный образ JFFS2.Я не знаю почему, но это, очевидно, вызывает блокировку всех PHP-скриптов, пока это не будет сделано.

Чтобы обойти это, я собираюсь поместить вызов команды update в отдельный скрипт и запросить его через Ajax- таким образом, пользователь, по крайней мере, получит некоторую предварительно упакованную обратную связь, пока технически все еще ожидает в системе.

Ответы [ 4 ]

3 голосов
/ 07 декабря 2010

Посмотрите на попену: http://it.php.net/manual/en/function.popen.php

1 голос
/ 07 декабря 2010

Относительно вашего Однако :

Полагаю, вы пытаетесь использовать файл в качестве потока. Я не проводил никаких производственных тестов, но полагаю, что файл будет записан обратно на диск только через fclose ().

Если вы постоянно выполняете запись в файл в сценарии № 2, эти записи на самом деле идут непосредственно в память, пока файл не будет закрыт.

Опять же - я не могу проверить это, но если вы хотите проверить это, попробуйте заново открывать и закрывать файл для каждой записи. Это подтвердит или опровергнет мою теорию, и вы сможете соответствующим образом изменить свой подход.

1 голос
/ 07 декабря 2010

Если вы сотрете DocRoot, нет ресурса / скрипта, который мог бы отвечать на запросы пользователя в течение этого времени.Поэтому вы должны отправлять обновления пользователю в том же запросе, который выполняет очистку.Это требует от вас запуска процесса оболочки и немедленного возврата к PHP.Это можно сделать с помощью pcntl_fork() и pcntl_exec().Ваш PHP-скрипт теперь должен непрерывно отправлять вывод сценария оболочки клиенту.Если скрипт оболочки добавляет файл в / tmp, вы можете fpassthru() этот файл и очистить его, пока скрипт оболочки не закончится.

1 голос
/ 07 декабря 2010

Интересный сценарий.

Моей первой мыслью было что-то сделать с proc_ * и $ _SESSION, но я не уверен, сработает ли это или нет.Попробуйте, но если нет ...

Если вы беспокоитесь о том, что файл мигает во время процесса, вы всегда можете создать экземпляр базы данных mysql во вторичном процессе и записать в нее.База данных может существовать в другом разделе, и вы можете обратиться к ней по локальному ip, и система позаботится о маршрутизации.

Редактировать

Когда я упомянул proc_ *с сессиями я имел в виду нечто подобное this , где $ descriptorspec станет:

$_SESSION = array(
    1 => array("pipe", "w"),
);

Однако я сомневаюсь, что это сработает.Процесс завершится записью в $ _SESSION в памяти, которая больше не существует после уничтожения первого сценария.

Изменить 2

В действительности, на этой заметке выможет установить memcache и сделать так, чтобы ваш вторичный процесс записывался непосредственно в память, которая затем может быть перечитана вашим веб-интерфейсным процессом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...