ignore_user_abort()
In this article, we will focus on the PHP ignore_user_abort() function. We will provide you with an overview of the function, how it works, and examples of its
The PHP ignore_user_abort() function controls whether a script keeps running after the client (the user's browser) disconnects. This page covers what the function does, its signature and return value, how it works together with connection_aborted(), the gotchas that trip people up, and a complete background-task example.
What ignore_user_abort() does
When a user closes the browser tab, hits Stop, or navigates away, the connection to the server is dropped. By default PHP does not stop your script the instant this happens — it only notices the dead connection the next time it tries to send output to the browser, at which point it ends the script. ignore_user_abort() changes that behaviour: with it enabled, PHP keeps executing your script to the end even though no one is listening anymore.
This matters for operations that must not be left half-finished — writing to a database, processing a payment, sending an email, or generating a report. If the user disconnects mid-way, you usually want the work to complete rather than leave the system in an inconsistent state.
A "client abort" is a transport-level event: PHP detects it only when it attempts to write to a connection that is already closed. That is why the timing feels indirect — see Why the abort is detected late below.
Syntax
ignore_user_abort(?bool $enable = null): int$enable— passtrueto ignore client disconnects, orfalseto restore the default (abort on disconnect). If you omit the argument, the current setting is left unchanged and only returned.- Return value — the previous setting as an integer (
1= was ignoring aborts,0= was not). This lets you save and restore the state.
<?php
$previous = ignore_user_abort(true); // turn it on, remember old value
// ... critical work ...
ignore_user_abort($previous); // restore whatever it was beforeThe same setting can be configured globally in php.ini with the ignore_user_abort directive; calling the function overrides it for the current request.
Basic usage
Call the function once near the top of the work you want to protect:
<?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);Note that ignore_user_abort() keeps the script alive, but it does not lift PHP's max_execution_time limit. A long-running task can still be killed by the time limit, so combine it with set_time_limit() when needed.
Detecting the abort with connection_aborted()
Ignoring an abort does not mean you can't react to it. The connection_aborted() function returns 1 once the client has disconnected and 0 otherwise, so you can check it inside a loop and decide whether to keep going, clean up, and exit.
One subtlety: PHP only updates the connection status when it tries to send output and the buffer is flushed. So to detect an abort mid-loop you typically echo something and flush() it, which forces PHP to notice the dead socket.
<?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);Here connection_aborted() lets the script decide for itself: it can finish quietly, log that the user left, or break out early. Related: connection_status() reports all three states (normal, aborted, timed out) as a bitmask.
A practical background-task example
A common pattern is to send the response, close the connection so the browser stops waiting, and then continue heavy work in the background. ignore_user_abort(true) is what makes the "continue" part work.
<?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();The browser receives a quick response and stops spinning, while the server finishes the slow job. Without ignore_user_abort(true), that background work would be killed the moment PHP noticed the closed connection.
Why the abort is detected late
PHP buffers output. Until that buffer is flushed to the client, PHP has no reason to touch the socket and therefore never learns it is closed. This is why scripts that do no output (or whose output stays buffered) can run to completion after a disconnect without ever reporting connection_aborted() === 1. If you need timely abort detection, emit a small heartbeat and flush() it periodically, as in the loop above. Output buffering helpers like ob_flush() and ob_end_flush() give you finer control over when data leaves the buffer.
Common pitfalls
- It does not override the time limit. Use
set_time_limit(0)(or a generous value) alongside it for long jobs. - Detection requires output + flush.
connection_aborted()won't flip to1on its own if your script never writes to the client. - A runaway script is harder to stop. With aborts ignored, a buggy infinite loop keeps consuming resources because the user can no longer cancel it. Always pair it with sensible limits.
- CLI scripts are unaffected. There is no client connection on the command line, so the function is a no-op there — use it in web (request) contexts.
Conclusion
ignore_user_abort() keeps a PHP script running after the client disconnects, which is essential for finishing critical or background work safely. Combine it with connection_aborted() to detect disconnects, flush() to force that detection, and set_time_limit() to avoid being cut off mid-task, and you have a reliable pattern for work that must not be left half-done.