ignore_user_abort()
Функция PHP ignore_user_abort(): описание, синтаксис, параметры, возвращаемое значение и практические примеры использования.
Функция PHP ignore_user_abort() управляет тем, продолжает ли скрипт выполняться после отключения клиента (браузера пользователя). На этой странице описано, что делает функция, её сигнатура и возвращаемое значение, как она взаимодействует с connection_aborted(), типичные ошибки и полный пример фонового задания.
Что делает ignore_user_abort()
Когда пользователь закрывает вкладку браузера, нажимает «Стоп» или переходит на другую страницу, соединение с сервером разрывается. По умолчанию PHP не останавливает скрипт немедленно — он замечает разорванное соединение лишь в следующий раз, когда пытается отправить вывод в браузер, и только тогда завершает скрипт. Функция ignore_user_abort() меняет это поведение: при её включении PHP продолжает выполнять скрипт до конца, даже если никто больше не прослушивает.
Это важно для операций, которые нельзя оставлять незавершёнными — запись в базу данных, обработка платежа, отправка письма или формирование отчёта. Если пользователь отключается в середине процесса, как правило, нужно завершить работу, а не оставлять систему в несогласованном состоянии.
«Прерывание клиента» — это событие на транспортном уровне: PHP обнаруживает его только при попытке записи в уже закрытое соединение. Именно поэтому момент обнаружения кажется косвенным — см. раздел Почему прерывание обнаруживается поздно ниже.
Синтаксис
ignore_user_abort(?bool $enable = null): int$enable— передайтеtrue, чтобы игнорировать отключения клиента, илиfalse, чтобы вернуть поведение по умолчанию (прерывание при отключении). Если аргумент не указан, текущее значение остаётся без изменений и просто возвращается.- Возвращаемое значение — предыдущее значение настройки в виде целого числа (
1= прерывания игнорировались,0= не игнорировались). Это позволяет сохранить и восстановить состояние.
<?php
$previous = ignore_user_abort(true); // turn it on, remember old value
// ... critical work ...
ignore_user_abort($previous); // restore whatever it was beforeТу же настройку можно задать глобально в php.ini с помощью директивы ignore_user_abort; вызов функции переопределяет её для текущего запроса.
Базовое использование
Вызовите функцию один раз в начале кода, который нужно защитить:
<?php
// Keep running even if the user disconnects.
ignore_user_abort(true);
// Critical code that must not be interrupted.
saveOrderToDatabase();
chargePayment();
sendConfirmationEmail();
// Optional: go back to the default behaviour.
ignore_user_abort(false);Обратите внимание: ignore_user_abort() сохраняет скрипт активным, но не снимает ограничение max_execution_time. Долго выполняющаяся задача всё равно может быть прервана по таймауту, поэтому при необходимости используйте её совместно с set_time_limit().
Обнаружение прерывания с помощью connection_aborted()
Игнорировать прерывание не значит не реагировать на него. Функция connection_aborted() возвращает 1, как только клиент отключился, и 0 в остальных случаях — её можно проверять внутри цикла и решать, продолжать ли выполнение, очистить ли ресурсы и выйти.
Одна тонкость: PHP обновляет статус соединения только при попытке отправить вывод и сброске буфера. Чтобы обнаружить прерывание в середине цикла, обычно выводят что-нибудь с помощью echo и вызывают flush() — это вынуждает PHP заметить закрытый сокет.
<?php
ignore_user_abort(true);
for ($i = 0; $i < 10; $i++) {
// Push some output so PHP checks the connection state.
echo "Step $i\n";
flush();
// connection_aborted() returns 1 after the client disconnects.
if (connection_aborted()) {
// The user left — stop early and clean up if we want to.
break;
}
doExpensiveStep($i);
}
ignore_user_abort(false);Здесь connection_aborted() позволяет скрипту самостоятельно принять решение: завершиться тихо, записать в лог факт отключения пользователя или прервать выполнение досрочно. Связанная функция: connection_status() возвращает все три состояния (нормальное, прерванное, таймаут) в виде битовой маски.
Практический пример фонового задания
Распространённый паттерн — отправить ответ, закрыть соединение, чтобы браузер перестал ждать, и продолжить тяжёлую работу в фоне. ignore_user_abort(true) — это то, что делает возможной «продолжающуюся» часть.
<?php
// 1. Keep running after the browser is released.
ignore_user_abort(true);
set_time_limit(0); // no execution-time cap for the background work
// 2. Send the response and flush the output buffers.
ob_start();
echo "Thanks! Your request is being processed.";
$size = ob_get_length();
header("Content-Length: $size");
header("Connection: close");
ob_end_flush();
flush();
if (function_exists('fastcgi_finish_request')) {
fastcgi_finish_request(); // PHP-FPM: detach from the client now
}
// 3. The user's browser is already done. This runs regardless.
processLargeReport();Браузер получает быстрый ответ и перестаёт ждать, пока сервер завершает медленную задачу. Без ignore_user_abort(true) фоновая работа была бы прервана, как только PHP обнаружил закрытое соединение.
Почему прерывание обнаруживается поздно
PHP буферизирует вывод. Пока буфер не сброшен клиенту, PHP не обращается к сокету и поэтому не узнаёт, что он закрыт. Вот почему скрипты, которые ничего не выводят (или чей вывод остаётся в буфере), могут выполняться до конца после отключения, так и не получив connection_aborted() === 1. Если требуется своевременное обнаружение прерывания, периодически выводите небольшой «heartbeat» и вызывайте flush(), как в цикле выше. Вспомогательные функции буферизации вывода ob_flush() и ob_end_flush() дают более тонкий контроль над тем, когда данные покидают буфер.
Типичные ошибки
- Не переопределяет ограничение по времени. Для длительных заданий используйте
set_time_limit(0)(или достаточно большое значение) вместе с ней. - Для обнаружения нужны вывод и flush.
connection_aborted()не переключится в1само по себе, если скрипт ничего не пишет клиенту. - Неуправляемый скрипт сложнее остановить. При игнорировании прерываний ошибочный бесконечный цикл продолжает потреблять ресурсы, поскольку пользователь больше не может его отменить. Всегда устанавливайте разумные ограничения.
- На CLI-скрипты не влияет. В командной строке нет клиентского соединения, поэтому функция является пустой операцией — используйте её только в веб-контексте (при обработке запросов).
Заключение
ignore_user_abort() позволяет PHP-скрипту продолжать выполнение после отключения клиента, что необходимо для безопасного завершения критических или фоновых операций. Используйте её совместно с connection_aborted() для обнаружения отключений, flush() для принудительного обнаружения и set_time_limit() для защиты от прерывания в середине задачи — и вы получите надёжный паттерн для работы, которую нельзя оставлять незавершённой.