2010-12-07 2 views
6

Я кодирую веб-страницу с PHP-скриптом, предназначенную для приема имени файла изображения JFFS2, которое было ранее загружено на сервер. Сценарий должен затем повторно воспроизвести раздел на сервере с изображением и вывести результаты. Я использовал это:получить результат от команды shell_exec по мере запуска команд

$tmp = shell_exec("update_flash -v " . $filename . " 4 2>&1"); 
echo '<h3>' . $tmp . '</h3>'; 

echo verifyResults($tmp); 

(Функция verifyResults возвратит некоторые HTML, который указывает пользователю, выполнена ли команда обновление успешно Ie, в том случае, когда обновление завершится успешно, отображается кнопка для перезагрузки. устройство и т. д.)

Проблема заключается в том, что для выполнения команды обновления требуется несколько минут, а скрипт 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 не отражает вывод команды повторной вспышки в режиме реального time-- это, кажется, не показывать ничего, пока команда обновления возвратов от исполнения. Мне нужно будет продолжить тестирование, чтобы посмотреть, что здесь происходит.

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

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

ответ

3

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

+0

popen, по-видимому, предотвращает блокировку PHP по желанию, но почему-то моя команда не мгновенно обновляет мой выходной файл. Подробности см. В разделе 2 моего вопроса. – 2010-12-07 15:20:33

+0

Ничего, popen работал как ожидалось. – 2010-12-07 18:39:17

1

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

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

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

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

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

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

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

Edit 2

ФАКТИЧЕСКИ, на этой ноте, вы можете установить memcache и ваш вторичный процесс писать непосредственно в памяти, которая может быть повторно читать ваш веб-интерфейсом процесса.

+0

Это легкая встроенная система Linux, поэтому я не думаю, что могу позволить себе пространство для хранения реализации mysql, даже если у меня есть двоичный файл :( – 2010-12-07 15:17:02

1

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

1

Что касается вашего Однако:

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

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

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

Смежные вопросы