Ignore user abort: примеры (PHP)

Руководство по использованию 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
Комбинирование с set_time_limit
<?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
Похожие функции в PHP
  • 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 полезны для мониторинга состояния соединения внутри выполняющегося скрипта.

Аналоги в других языках
Python (Flask)
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.

JavaScript (Node.js)
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 не требуется специальных функций — асинхронная архитектура позволяет выполнять задачи после ответа клиенту.

MySQL (Events)
CREATE EVENT my_event
ON SCHEDULE EVERY 1 HOUR
DO
  UPDATE статистика SET значения = значения + 1;

Вместо фоновых PHP-скриптов часто используются планировщики событий СУБД или системный cron.

Распространенные ошибки
Отсутствие set_time_limit
<?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
  • 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
<?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
<?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
<?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);
?>

PHP ignore_user_abort function comments

En
Ignore user abort Set whether a client disconnect should abort script execution