I've also tried using stream_append_filter() with the zlib.deflate filter, which I think could solve the problem, but I don't know because filtered streams don't work with stream_select() so my polling stopped working.
If anyone cares, I figured out how to do this in PHP. The core doesn't expose the flush flags required, meaning we can't flush on write (SYNC_FLUSH), but there is a PECL extension, pecl_http, which contains a class that allows us to to this, HttpDeflateStream:
<?php $stream = new HttpDeflateStream(HttpDeflateStream::FLUSH_SYNC); $compressedData = $stream->update($data);
Note that this extension requires that you have the zlib and zlib-devel packages installed (use yum, apt, or whatever).