ignore_user_abort()
In questo articolo ci concentriamo sulla funzione PHP ignore_user_abort(). Panoramica, funzionamento ed esempi pratici.
La funzione PHP ignore_user_abort() controlla se uno script continua l'esecuzione dopo che il client (il browser dell'utente) si disconnette. Questa pagina illustra cosa fa la funzione, la sua firma e il valore restituito, come interagisce con connection_aborted(), gli errori comuni e un esempio completo di attività in background.
Cosa fa ignore_user_abort()
Quando un utente chiude la scheda del browser, preme Stop o naviga altrove, la connessione al server viene interrotta. Per impostazione predefinita PHP non ferma lo script immediatamente — se ne accorge solo al successivo tentativo di inviare output al browser, momento in cui termina lo script. ignore_user_abort() modifica questo comportamento: con essa abilitata, PHP continua l'esecuzione dello script fino alla fine anche se nessuno è più in ascolto.
Questo è importante per le operazioni che non devono essere lasciate a metà — scrittura su un database, elaborazione di un pagamento, invio di un'email o generazione di un report. Se l'utente si disconnette nel mezzo dell'operazione, di solito si preferisce che il lavoro si completi piuttosto che lasciare il sistema in uno stato incoerente.
Un "client abort" è un evento a livello di trasporto: PHP lo rileva solo quando tenta di scrivere su una connessione già chiusa. Ecco perché il rilevamento sembra indiretto — vedere Perché l'interruzione viene rilevata in ritardo più avanti.
Sintassi
ignore_user_abort(?bool $enable = null): int$enable— passatrueper ignorare le disconnessioni del client, oppurefalseper ripristinare il comportamento predefinito (interruzione alla disconnessione). Se si omette l'argomento, l'impostazione corrente rimane invariata e viene solo restituita.- Valore restituito — l'impostazione precedente come intero (
1= stava ignorando le interruzioni,0= non le ignorava). Questo permette di salvare e ripristinare lo stato.
<?php
$previous = ignore_user_abort(true); // turn it on, remember old value
// ... critical work ...
ignore_user_abort($previous); // restore whatever it was beforeLa stessa impostazione può essere configurata globalmente in php.ini tramite la direttiva ignore_user_abort; la chiamata alla funzione la sovrascrive per la richiesta corrente.
Utilizzo di base
Chiama la funzione una volta vicino all'inizio del lavoro che vuoi proteggere:
<?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);Nota che ignore_user_abort() mantiene in vita lo script, ma non rimuove il limite max_execution_time di PHP. Un'attività di lunga durata può comunque essere interrotta dal limite di tempo, quindi combinala con set_time_limit() quando necessario.
Rilevare l'interruzione con connection_aborted()
Ignorare un'interruzione non significa che non si possa reagire ad essa. La funzione connection_aborted() restituisce 1 una volta che il client si è disconnesso e 0 altrimenti, così puoi controllarla all'interno di un ciclo e decidere se continuare, fare pulizia ed uscire.
Una sottigliezza: PHP aggiorna lo stato della connessione solo quando tenta di inviare output e il buffer viene svuotato. Quindi per rilevare un'interruzione nel mezzo di un ciclo di solito si fa echo di qualcosa e lo si invia con flush(), il che forza PHP ad accorgersi del socket chiuso.
<?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);Qui connection_aborted() lascia allo script la decisione: può terminare silenziosamente, registrare che l'utente è uscito, o interrompere anticipatamente. Funzione correlata: connection_status() riporta tutti e tre gli stati (normale, interrotto, scaduto) come bitmask.
Un esempio pratico di attività in background
Un pattern comune è inviare la risposta, chiudere la connessione in modo che il browser smetta di aspettare, e poi continuare il lavoro pesante in background. ignore_user_abort(true) è ciò che rende funzionante la parte "continua".
<?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();Il browser riceve una risposta rapida e smette di girare, mentre il server termina il lavoro lento. Senza ignore_user_abort(true), quel lavoro in background verrebbe interrotto nel momento in cui PHP si accorgesse della connessione chiusa.
Perché l'interruzione viene rilevata in ritardo
PHP bufferizza l'output. Finché quel buffer non viene svuotato verso il client, PHP non ha motivo di toccare il socket e quindi non sa mai che è chiuso. Ecco perché gli script che non producono output (o il cui output rimane bufferizzato) possono arrivare al completamento dopo una disconnessione senza mai riportare connection_aborted() === 1. Se hai bisogno di un rilevamento tempestivo delle interruzioni, emetti un piccolo heartbeat e invialo con flush() periodicamente, come nel ciclo precedente. Gli helper di output buffering come ob_flush() e ob_end_flush() offrono un controllo più preciso su quando i dati lasciano il buffer.
Errori comuni
- Non sovrascrive il limite di tempo. Usa
set_time_limit(0)(o un valore generoso) insieme a essa per i lavori lunghi. - Il rilevamento richiede output + flush.
connection_aborted()non passerà a1da solo se lo script non scrive mai al client. - Uno script fuori controllo è più difficile da fermare. Con le interruzioni ignorate, un ciclo infinito difettoso continua a consumare risorse perché l'utente non può più annullarlo. Abbinalo sempre a limiti ragionevoli.
- Gli script CLI non sono interessati. Non esiste una connessione client sulla riga di comando, quindi la funzione è un no-op lì — usala nei contesti web (di richiesta).
Conclusione
ignore_user_abort() mantiene in esecuzione uno script PHP dopo che il client si disconnette, il che è essenziale per completare in modo sicuro lavori critici o in background. Combinala con connection_aborted() per rilevare le disconnessioni, flush() per forzare quel rilevamento, e set_time_limit() per evitare di essere interrotti a metà attività, e avrai un pattern affidabile per il lavoro che non deve essere lasciato a metà.