Вопрос
Я пытаюсь создать PHP-скрипт, у меня есть готовый скрипт, но для завершения процесса, для которого он предназначен, требуется около 10 минут.Это не проблема, однако я предполагаю, что мне нужно поддерживать загрузку страницы все это время, что раздражает.Могу ли я сделать так, чтобы я запустил процесс, а затем вернулся через 10 минут и просто просмотрел файл журнала, который он сгенерировал?
Решение
Ну, вы можете использовать " ignore_user_abort а> (истина) <> Quot;! р>
Таким образом, сценарий продолжит работать (следите за продолжительностью сценария, возможно, добавьте " set_time_limit (0) ") Но здесь есть предупреждение: вы не сможете остановить скрипт с этими двумя строками: Кроме того, вы можете получить прямой доступ к серверу и завершить процесс там! (Был там, сделал бесконечный цикл, снова и снова вызывая себя, заставил сервер прийти к визговой остановке, крикнул на ...) ignore_user_abort(true);
set_time_limit(0);
Другие советы
Похоже, у вас должна быть очередь и внешний сценарий для обработки очереди. Р>
Например, ваш PHP-скрипт должен поместить запись в таблицу базы данных и сразу же вернуться. Затем cron, работающий каждую минуту, проверяет очередь и разветвляет процесс для каждого задания.
Преимущество здесь в том, что вы не блокируете поток apache в течение 10 минут. Р>
У меня было много проблем с такого рода процессами в Windows;Моя ситуация была немного иной в том смысле, что меня не заботил ответ "скрипта" - я хотел, чтобы скрипт запустился и разрешал другим запросам страницы проходить, пока он был занят работой.
По какой - то причине;У меня были проблемы с этим, либо зависанием других запросов, либо тайм-аутом примерно через 60 секунд (и apache, и php были установлены на тайм-аут примерно через 20 минут);Также оказывается, что время ожидания firefox в любом случае истекает через 5 минут (по умолчанию), поэтому после этого момента вы не можете знать, что происходит через браузер, не изменяя настройки в firefox.
В итоге я использовал методы process open и process close для открытия php в режиме cli следующим образом:
pclose(popen("start php myscript.php", "r"));
Это (используя start ) открыло бы процесс php, а затем остановило бы процесс start, оставив php работать столько, сколько ему нужно, - опять же, вам нужно было бы остановить процесс, чтобы вручную завершить его.Вам не нужно было устанавливать какие-либо тайм-ауты, и вы могли позволить текущей странице, которая ее вызвала, продолжить работу и вывести дополнительные сведения.
Единственная проблема заключается в том, что если вам нужно отправить скрипту какие-либо данные, вы должны либо сделать это через другой источник, либо передать их через "командную строку" в качестве параметров;что не так уж безопасно.
Тем не менее, он прекрасно справлялся с тем, что нам было нужно, и гарантировал, что скрипт всегда запускается и ему разрешено работать без каких-либо перерывов.
Это также может помочь: Exec асинхронной оболочки в PHP р>
Я думаю, что вам нужна команда shell_exec.
Однако он отключается в безопасном режиме.
Статья об PHP-руководстве по этому вопросу находится здесь: http://php.net/shell_exec
Вы можете использовать ignore_user_abort()
- таким образом, скрипт продолжит работу, даже если вы закроете в вашем браузере или перейдите на другую страницу.
Подумайте о Gearman р>
Gearman - это универсальная прикладная среда для работы над несколько машин или процессов. Это позволяет приложениям завершать параллельные задачи, обработка баланса нагрузки и вызов функций между языками. Каркас может быть использован в различных приложений, от веб-сайтов высокой доступности до транспорта События репликации базы данных.
Это расширение предоставляет классы для написания клиентов Gearman и работников. - Руководство по исходному тексту
Официальный веб-сайт Gearman
В дополнение к ответу бастиандоина вы можете объединить ignore_user_abort(true);
с помощью Запрос на скручивание.
Подделать запрос на аборт, установив низкий уровень CURLOPT_TIMEOUT_MS
и продолжайте обработку после закрытия соединения:
function async_curl($background_process=''){
//-------------get curl contents----------------
$ch = curl_init($background_process);
curl_setopt_array($ch, array(
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER =>true,
CURLOPT_NOSIGNAL => 1, //to timeout immediately if the value is < 1000 ms
CURLOPT_TIMEOUT_MS => 50, //The maximum number of mseconds to allow cURL functions to execute
CURLOPT_VERBOSE => 1,
CURLOPT_HEADER => 1
));
$out = curl_exec($ch);
//-------------parse curl contents----------------
//$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
//$header = substr($out, 0, $header_size);
//$body = substr($out, $header_size);
curl_close($ch);
return true;
}
async_curl('http://example.com/background_process_1.php');
Примечание
Если вы хотите, чтобы тайм-аут cURL истек менее чем за одну секунду, вы можете использовать CURLOPT_TIMEOUT_MS, хотя в "Unix-подобных системах" есть ошибка / "особенность", которая приводит к немедленному отключению libcurl, если значение равно < 1000 мс с ошибкой "Ошибка скручивания (28):Тайм-аут был исчерпан".В Объяснение такого поведения заключается в следующем:
[...]
Решение состоит в том, чтобы отключить сигналы с помощью CURLOPT_NOSIGNAL
плюсы
- Нет необходимости переключать методы (Совместимые Windows и linux)
- Нет необходимости реализовывать обработку соединений через заголовки и буфер (независимо от браузера и версии PHP).
минусы
- Нужно наращивать локоны
Ресурсы
Зук.
Я почти уверен, что это сработает:
<?php
pclose(popen('php /path/to/file/server.php &'));
echo "Server started. [OK]";
?>
Символ "и" очень важен.Он сообщает командной оболочке не ждать завершения процесса.
Также вы можете использовать этот код в своем php (как сказал "bastiandoeen").
ignore_user_abort(true);
set_time_limit(0);
в команде остановки вашего сервера:
<?php
$output;
exec('ps aux | grep -ie /path/to/file/server.php | awk \'{print $2}\' | xargs kill -9 ', $output);
echo "Server stopped. [OK]";
?>
Просто вызовите StartBuffer () перед любым выводом и EndBuffer (), когда вы хотите, чтобы клиент закрыл соединение. Код после вызова EndBuffer () будет выполнен на сервере без клиентского подключения.
private function StartBuffer(){ @ini_set('zlib.output_compression',0); @ini_set('implicit_flush',1); @ob_end_clean(); @set_time_limit(0); @ob_implicit_flush(1); @ob_start(); } private function EndBuffer(){ $size = ob_get_length(); header("Content-Length: $size"); header('Connection: close'); ob_flush();ob_implicit_flush(1); }