PHP ob_gzhandler() Function: Everything You Need to Know
As a PHP developer, you may need to compress your output to reduce bandwidth usage and improve the speed of your website. The ob_gzhandler() function is a
Compressing HTML, CSS, or JSON before it leaves the server reduces bandwidth and makes pages load faster. PHP's built-in ob_gzhandler() function is a ready-made way to do this from inside your script: you hand it to the output buffer, and it gzip-compresses everything your script echoes — but only when the browser says it can decompress it. This article covers its syntax, a complete example, how it negotiates with the client, the gotchas that bite people, and when you should reach for it versus letting the server handle compression.
What the ob_gzhandler() Function Does
ob_gzhandler() is a callback designed to be passed to ob_start(). You never call it directly — instead, the output buffering system calls it for you with the buffered content as its argument, and it returns the compressed (or, when compression isn't possible, unmodified) bytes.
Before compressing, it inspects the request's Accept-Encoding header and picks the best supported scheme:
- If the client supports gzip, it compresses with gzip and sets
Content-Encoding: gzip. - If the client supports only deflate, it uses deflate instead.
- If the client supports neither, it returns the content untouched and
ob_start()fails (returnsfalse), so the response is sent uncompressed.
Because it sets the Content-Encoding and Vary response headers automatically, you must register it before any output is sent — see headers_sent() if you hit a "headers already sent" error.
Syntax
ob_start("ob_gzhandler");ob_gzhandler() takes two parameters internally ($buffer and $mode), but you never supply them — the buffering engine does. You just register the string "ob_gzhandler" as the callback name.
A Complete Example
<?php
ob_start("ob_gzhandler");
echo "This will be compressed using gzip compression";
ob_end_flush();
?>Here, ob_start() opens an output buffer with ob_gzhandler() as its handler, the echo writes into that buffer instead of straight to the client, and ob_end_flush() closes the buffer and sends its (now compressed) contents. From the visitor's point of view nothing changes — the browser transparently decompresses the response — but fewer bytes travel over the network.
Falling Back for Clients That Don't Support gzip
ob_start("ob_gzhandler") returns false when the client doesn't advertise gzip or deflate support. If you ignore that, no buffer is started and your later ob_end_flush() will warn. Check the return value and fall back to a plain buffer:
<?php
if (!ob_start("ob_gzhandler")) {
ob_start(); // plain buffer, no compression
}
echo "Served either compressed or uncompressed, but always buffered.";
ob_end_flush();
?>Setting the Compression Level
ob_start() doesn't accept a compression level — ob_gzhandler() uses zlib's default (controlled by the zlib.output_compression_level INI setting, default -1). To force a specific level from 1 (fastest, least compression) to 9 (slowest, smallest), skip ob_gzhandler() and use your own callback with gzencode():
<?php
ob_start(function ($buffer) {
return gzencode($buffer, 9);
});
echo "Compressed at the maximum level.";
ob_end_flush();
?>Note that this custom callback does not negotiate Accept-Encoding or set Content-Encoding: gzip for you — ob_gzhandler() does both automatically. If you roll your own, you must send those headers yourself, which is why ob_gzhandler() remains convenient for the common case.
ob_gzhandler() vs. zlib.output_compression
PHP offers a second, even simpler way to compress output: the zlib.output_compression INI directive. Set it to On (or a byte threshold) and PHP gzips the whole response with no code at all:
zlib.output_compression = OnThe two approaches are mutually exclusive — enabling zlib.output_compression while also calling ob_start("ob_gzhandler") triggers a warning and double-compresses nothing useful. Prefer zlib.output_compression when you can edit php.ini or use ini_set(), and reserve ob_gzhandler() for cases where you need it inside a script you don't control the configuration for.
Common Gotchas
- Don't nest gzip layers. Combining
ob_gzhandler()with server-level compression (Nginx/Apachegzip) or withzlib.output_compressioncan produce corrupted, double-encoded responses. - Register it first. Any prior
echo, whitespace before<?php, or BOM in the file sends headers early and breaks compression. - Not for binary that's already compressed. Gzipping JPEGs, PNGs, or ZIPs wastes CPU for almost no size win.
- It needs the zlib extension.
ob_gzhandler()requires PHP to be built with zlib (it almost always is, but worth knowing on minimal builds).
Conclusion
The ob_gzhandler() function provides a simple, self-contained way to gzip PHP output: register it as a callback to ob_start(), and it negotiates encoding and sets headers for you. In modern setups, however, server-level compression (Nginx, Apache) or a CDN handling gzip/brotli is usually preferred — it offloads CPU from PHP and compresses static assets too. Knowing ob_gzhandler() still matters for legacy codebases and scripts where you can't touch the server config. For the broader picture of working with buffers, see the PHP Output Control overview.