kjdev / php-ext-zstd

Zstd Extension for PHP
MIT License
201 stars 27 forks source link

Chrome finally ships Accept-Encoding: zstd — Please update example #70

Open jab4 opened 3 months ago

jab4 commented 3 months ago

Hi and late Happy Easter all!

As the title suggests, no issue in the buggy sense.

I ran some benchmarks against a 4 MB HTML file:

  # none......:  4,039,229 Bytes;  100 requests in   3.16 secs  (avg=0.0316 s per req)
  # gzip......:  1,290,963 Bytes;  100 requests in  17.65 secs  (avg=0.1765 s per req)
  # obgz......:  1,290,963 Bytes;  100 requests in  17.27 secs  (avg=0.1727 s per req)
  # zstd1.....:  1,392,549 Bytes;  100 requests in   4.01 secs  (avg=0.0401 s per req)
  # zstd2.....:  1,310,025 Bytes;  100 requests in   4.32 secs  (avg=0.0432 s per req)
  # zstd3.....:  1,240,800 Bytes;  100 requests in   4.45 secs  (avg=0.0445 s per req)
  # zstd4.....:  1,222,309 Bytes;  100 requests in   4.76 secs  (avg=0.0476 s per req)
  # zstd5.....:  1,195,749 Bytes;  100 requests in   5.84 secs  (avg=0.0584 s per req)
  # zstd6.....:  1,157,140 Bytes;  100 requests in   6.94 secs  (avg=0.0694 s per req)
  # zstd7.....:  1,133,898 Bytes;  100 requests in   8.18 secs  (avg=0.0818 s per req)
  # zstd8.....:  1,120,307 Bytes;  100 requests in   9.71 secs  (avg=0.0971 s per req)
  # zstd9.....:  1,115,600 Bytes;  100 requests in   9.80 secs  (avg=0.0980 s per req)
  # zstd10....:  1,095,873 Bytes;  100 requests in  12.33 secs  (avg=0.1233 s per req)
  # zstd11....:  1,082,522 Bytes;  100 requests in  18.20 secs  (avg=0.1820 s per req)
  # zstd12....:  1,081,317 Bytes;  100 requests in  21.91 secs  (avg=0.2191 s per req)
  # zstd13....:  1,059,720 Bytes;  100 requests in  52.40 secs  (avg=0.5240 s per req)
  # zstd14....:  1,044,099 Bytes;  100 requests in  67.91 secs  (avg=0.6791 s per req)
  # zstd15....:  1,036,078 Bytes;  100 requests in  87.37 secs  (avg=0.8737 s per req)
  # zstd16....:    983,006 Bytes;  100 requests in 103.78 secs  (avg=1.0378 s per req)
  # zstd17....:    980,923 Bytes;  100 requests in 115.09 secs  (avg=1.1509 s per req)
  # zstd18....:    972,316 Bytes;  100 requests in 141.62 secs  (avg=1.4162 s per req)
  # zstd19....:    971,972 Bytes;  100 requests in 145.05 secs  (avg=1.4505 s per req)
  # zstd20....:    971,972 Bytes;  100 requests in 146.45 secs  (avg=1.4645 s per req)
  # zstd21....:    971,972 Bytes;  100 requests in 148.13 secs  (avg=1.4813 s per req)
  # zstd22....:    971,962 Bytes;  100 requests in 152.34 secs  (avg=1.5234 s per req)

Kindly suggest updating your README's example section to include output buffering:


# Serve ZSTD compressed PHP pages to modern 2024 web browsers:
# Place this snippet *before* any of your HTML output begins.
if (false !== strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'zstd')) {
    header("Content-Encoding: zstd");
    ob_start(function(&$data) {
        return zstd_compress($data, 3); # level 3 is default, max. and slowest is 22
    });
} else {
    ob_start('ob_gzhandler'); # fallback for older browsers
}

Perhaps @remicollet could put some soft pressure on the PHP core team to bundle this extension? 🚀

Thanks!

BelleNottelling commented 2 months ago

I'm quite happy chromium browsers now announce that they accept zstd. It's far faster than either gzip or brotli.

Of course, based on my own testing brotli is still a great upgrade over gzip both in terms of speed and compression ratio, but zstd offers very similar compression ratios to brotli while being significantly faster which makes it the clear winner in all cases in my eyes.

I've actually gone ahead and created my own replacement for PHP's ob_gzhandler function which is able to auto select between zstd, brotli, gzip, and deflate content encoding based on the server it's running on and the client that's connecting to it. https://github.com/HostByBelle/CompressionBuffer

Here's the PHP developer server sending zstd compressed output to chrome: image

I haven't yet made a release of CompressionBuffer as it's only had minimal testing done plus no unit tests written, but the logic behind it is pretty straightforward and PHPStan is happy on it's highest level.

Although it's not super important for just an example, I personally include it over the above code example as that one is what I would consider incomplete. At the very least it would probably be worth mentioning that false !== strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'zstd') will also trigger if the client is trying to inform the server to not use zstd encoding, along with suggesting that Vary: Accept-Encoding be sent in the headers for caching compatibility.

Either way, thank you @kjdev for building both this and the brotli extension! They are great additions to the PHP ecosystem. I for one am exciting knowing that some clever handling of the output buffer means PHP apps can utilize zstd compression before either NGINX or Apache get official support for it. Awesome!

jab4 commented 2 months ago

Thanks @BelleNottelling, much appreciated!

BelleNottelling commented 2 months ago

You're welcome @jab4!

Feel free to submit issues if you come across any issues & notice potential improvements.

Hope it comes in handy :)