Funzione PHP ob_gzhandler(): Tutto quello che devi sapere
Scopri come usare ob_gzhandler() in PHP per comprimere l'output con gzip, ridurre la larghezza di banda e velocizzare il caricamento delle pagine.
Comprimere HTML, CSS o JSON prima che lasci il server riduce la larghezza di banda e velocizza il caricamento delle pagine. La funzione integrata ob_gzhandler() di PHP è un modo pronto all'uso per farlo direttamente nello script: la si passa al buffer di output, e comprimerebbe con gzip tutto ciò che lo script restituisce tramite echo — ma solo quando il browser dichiara di poterlo decomprimere. Questo articolo tratta la sua sintassi, un esempio completo, come negozia con il client, le insidie più comuni e quando conviene usarla rispetto a lasciare che sia il server a gestire la compressione.
Cosa fa la funzione ob_gzhandler()
ob_gzhandler() è una callback progettata per essere passata a ob_start(). Non la si chiama mai direttamente — è il sistema di output buffering a chiamarla con il contenuto bufferizzato come argomento, e restituisce i byte compressi (oppure, quando la compressione non è possibile, i byte invariati).
Prima di comprimere, ispeziona l'intestazione Accept-Encoding della richiesta e sceglie il miglior schema supportato:
- Se il client supporta gzip, comprime con gzip e imposta
Content-Encoding: gzip. - Se il client supporta solo deflate, usa deflate al suo posto.
- Se il client non supporta nessuno dei due, restituisce il contenuto invariato e
ob_start()fallisce (restituiscefalse), quindi la risposta viene inviata non compressa.
Poiché imposta automaticamente le intestazioni di risposta Content-Encoding e Vary, è necessario registrarla prima che venga inviato qualsiasi output — consulta headers_sent() se si riceve un errore "headers already sent".
Sintassi
ob_start("ob_gzhandler");ob_gzhandler() accetta internamente due parametri ($buffer e $mode), ma non li si fornisce mai — lo fa il motore di buffering. Si registra semplicemente la stringa "ob_gzhandler" come nome della callback.
Un esempio completo
<?php
ob_start("ob_gzhandler");
echo "This will be compressed using gzip compression";
ob_end_flush();
?>Qui, ob_start() apre un buffer di output con ob_gzhandler() come handler, l'echo scrive in quel buffer invece di inviare direttamente al client, e ob_end_flush() chiude il buffer e invia il suo contenuto (ora compresso). Dal punto di vista del visitatore non cambia nulla — il browser decomprime la risposta in modo trasparente — ma viaggiano meno byte sulla rete.
Fallback per i client che non supportano gzip
ob_start("ob_gzhandler") restituisce false quando il client non dichiara supporto per gzip o deflate. Se lo si ignora, non viene avviato alcun buffer e il successivo ob_end_flush() genererà un avviso. Bisogna controllare il valore restituito e ricorrere a un buffer semplice:
<?php
if (!ob_start("ob_gzhandler")) {
ob_start(); // plain buffer, no compression
}
echo "Served either compressed or uncompressed, but always buffered.";
ob_end_flush();
?>Impostare il livello di compressione
ob_start() non accetta un livello di compressione — ob_gzhandler() usa quello predefinito di zlib (controllato dall'impostazione INI zlib.output_compression_level, default -1). Per forzare un livello specifico da 1 (più veloce, meno compressione) a 9 (più lento, dimensione minore), si bypassa ob_gzhandler() e si usa una propria callback con gzencode():
<?php
ob_start(function ($buffer) {
return gzencode($buffer, 9);
});
echo "Compressed at the maximum level.";
ob_end_flush();
?>Attenzione: questa callback personalizzata non negozia Accept-Encoding né imposta Content-Encoding: gzip automaticamente — ob_gzhandler() fa entrambe le cose in automatico. Se si crea una propria callback, bisogna inviare manualmente quelle intestazioni, il che spiega perché ob_gzhandler() rimanga comoda per il caso comune.
ob_gzhandler() vs. zlib.output_compression
PHP offre un secondo modo, ancora più semplice, per comprimere l'output: la direttiva INI zlib.output_compression. Impostata su On (o una soglia in byte), PHP comprime con gzip l'intera risposta senza alcun codice aggiuntivo:
zlib.output_compression = OnI due approcci sono mutualmente esclusivi — abilitare zlib.output_compression mentre si chiama anche ob_start("ob_gzhandler") genera un avviso e non produce alcuna doppia compressione utile. Si preferisce zlib.output_compression quando si può modificare php.ini o usare ini_set(), riservando ob_gzhandler() ai casi in cui serve all'interno di uno script su cui non si controlla la configurazione.
Insidie comuni
- Non sovrapporre livelli gzip. Combinare
ob_gzhandler()con la compressione a livello server (Nginx/Apachegzip) o conzlib.output_compressionpuò produrre risposte corrotte, con doppia codifica. - Registrarlo per primo. Qualsiasi
echoprecedente, spazio bianco prima di<?php, o BOM nel file invia le intestazioni in anticipo e compromette la compressione. - Non adatto a dati già compressi. Comprimere con gzip JPEG, PNG o ZIP spreca CPU per un guadagno di dimensioni quasi nullo.
- Richiede l'estensione zlib.
ob_gzhandler()richiede che PHP sia compilato con zlib (quasi sempre lo è, ma vale la pena saperlo su build minimali).
Conclusione
La funzione ob_gzhandler() offre un modo semplice e autonomo per comprimere con gzip l'output di PHP: la si registra come callback di ob_start() e si occupa da sola di negoziare la codifica e impostare le intestazioni. Nelle configurazioni moderne, tuttavia, di solito si preferisce la compressione a livello server (Nginx, Apache) o un CDN che gestisca gzip/brotli — questo scarica la CPU da PHP e comprime anche le risorse statiche. Conoscere ob_gzhandler() resta comunque importante per codebase legacy e script in cui non è possibile toccare la configurazione del server. Per un quadro più ampio del lavoro con i buffer, consulta la panoramica su PHP Output Control.