Ignore user abort: примеры (PHP)
ignore_user_abort(bool $enable = false): intФункция ignore_user_abort в PHP управляет поведением скрипта при отключении клиента. Когда пользователь прерывает соединение (например, закрывает браузер), скрипт по умолчанию завершается. Эта функция позволяет продолжить выполнение.
Использование актуально для длительных операций, которые должны завершиться независимо от действий пользователя: обработка файлов, отправка почты, синхронизация данных, выполнение cron-подобных задач через веб-интерфейс.
- $enable (bool|null): Необязательный параметр. Если передан
true, игнорирование отключения клиента включается. Приfalse— отключается. Если параметрnull, функция возвращает текущее значение без изменений. - Возвращаемое значение: Предыдущее значение настройки в виде булева типа.
<?php
$currentSetting = ignore_user_abort(null);
echo 'Текущее значение: ' . ($currentSetting ? 'true' : 'false');
?>Текущее значение: false
<?php
$oldValue = ignore_user_abort(true);
echo 'Предыдущее значение: ' . ($oldValue ? 'true' : 'false');
?>Предыдущее значение: false
<?php
ignore_user_abort(true);
set_time_limit(0);
for ($i = 0; $i < 10; $i++) {
file_put_contents('log.txt', "Итерация $i\n", FILE_APPEND);
sleep(1);
}
?>// Скрипт продолжит работу даже при закрытии браузера, // записав 10 строк в файл log.txt
- connection_status(): Возвращает статус соединения (0 - NORMAL, 1 - ABORTED, 2 - TIMEOUT). Используется для проверки, осталось ли соединение активным.
- connection_aborted(): Возвращает true, если клиент отключился. Часто применяется внутри длительных циклов для проверки необходимости продолжения работы.
- set_time_limit(0): Часто используется вместе с ignore_user_abort для отключения ограничения времени выполнения.
- fastcgi_finish_request() (для PHP-FPM): Более современная альтернатива, которая завершает ответ клиенту и позволяет продолжить выполнение скрипта в фоне.
Когда что использовать: ignore_user_abort подходит для простых фоновых задач в среде mod_php. Для PHP-FPM предпочтительнее fastcgi_finish_request. Функции connection_status и connection_aborted полезны для мониторинга состояния соединения внутри выполняющегося скрипта.
from flask import Flask, Response
import threading
app = Flask(__name__)
def background_task():
# Долгая задача
pass
@app.route('/long')
def long_process():
threading.Thread(target=background_task).start()
return 'Задача запущена в фоне'
if __name__ == '__main__':
app.run()В Python используются потоки или очереди задач (Celery) для фоновой обработки, что более надежно, чем ignore_user_abort.
const http = require('http');
http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Ответ отправлен');
// Продолжение выполнения после отправки ответа
setTimeout(() => {
console.log('Фоновая задача выполнена');
}, 5000);
}).listen(8080);В Node.js не требуется специальных функций — асинхронная архитектура позволяет выполнять задачи после ответа клиенту.
CREATE EVENT my_event
ON SCHEDULE EVERY 1 HOUR
DO
UPDATE статистика SET значения = значения + 1;Вместо фоновых PHP-скриптов часто используются планировщики событий СУБД или системный cron.
<?php
ignore_user_abort(true);
// Долгая операция без set_time_limit
for ($i = 0; $i < 300; $i++) {
file_put_contents('test.txt', $i, FILE_APPEND);
sleep(1);
}
?>// Скрипт может быть остановлен из-за лимита времени выполнения (по умолчанию 30 секунд)
<?php
session_start();
ignore_user_abort(true);
// Долгая операция блокирует файл сессии для других запросов
sleep(30);
?>// Другие скрипты этого пользователя будут ждать освобождения файла сессии
<?php
ignore_user_abort(true);
echo 'Старт задачи';
flush(); // Важно принудительно отправить данные
// Без flush браузер может не разорвать соединение сразу
sleep(10);
echo 'Задача завершена'; // Это сообщение пользователь не увидит
?>- PHP 8.0: Строгая типизация параметра
$enable. Передача небулевых значений теперь вызывает TypeError. - PHP 7.2: Функция начала возвращать предыдущее значение в виде bool, ранее возвращалась int (1 или 0).
- Ранние версии: Поведение могло отличаться на разных SAPI (например, CLI vs Apache).
<?php
// PHP 8.x: ошибка типа
ignore_user_abort(1); // TypeError: expect bool, int given
?><?php
ignore_user_abort(true);
set_time_limit(0);
// Отправляем пользователю immediate response
header('Content-Type: text/plain');
echo 'Фоновая обработка начата';
flush();
// Основная задача с проверкой состояния соединения
for ($i = 1; $i <= 100; $i++) {
if (connection_aborted()) {
file_put_contents('status.log', "Задача прервана на шаге $i", FILE_APPEND);
exit;
}
// Имитация работы
file_put_contents('data.txt', "Обработано $i%\n", FILE_APPEND);
sleep(1);
}
?><?php
ignore_user_abort(true);
set_time_limit(0);
header('Content-Encoding: none');
header('Content-Length: 13');
echo 'started';
flush();
$lines = file('big_file.csv');
$total = count($lines);
$log = fopen('progress.log', 'w');
foreach ($lines as $index => $line) {
// Обработка строки
process_line($line);
// Запись прогресса каждые 10%
if ($index % (int)($total/10) == 0) {
$percent = round(($index/$total)*100);
fwrite($log, "Выполнено: $percent%\n");
}
}
fclose($log);
file_put_contents('complete.flag', time());
?><?php
function shutdown_function() {
if (connection_aborted()) {
file_put_contents('abort.log', date('Y-m-d H:i:s') . " - клиент отключился\n", FILE_APPEND);
}
}
register_shutdown_function('shutdown_function');
ignore_user_abort(false); // Намеренно отключаем игнорирование
// Длительная операция
sleep(5);
?>