PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | vendor/wp-php-toolkit/reprint-server/src/class-gzip-output-stream.php +116 -0 16.2-beta → 16.3-beta View file →
@@ -1,0 +1,116 @@
1 +<?php
2 +
3 +// Declared here rather than in export.php so it can live in this package's
4 +// namespace. export.php is a global-namespace file of endpoint functions that
5 +// callers reach by unqualified name.
6 +
7 +namespace WordPress\Reprint\Server;
8 +
9 +/**
10 + * Incremental response writer.
11 + *
12 + * PHP 7.0 and newer can gzip each bounded write without buffering the whole
13 + * response. PHP 5.6 lacks the incremental zlib API, so it sends the same
14 + * multipart stream without a Content-Encoding header.
15 + *
16 + * PHP-side gzip also gives outbound WAF rules that do not decode
17 + * Content-Encoding the encoded byte stream; server-level compression can run
18 + * after those rules inspect the body.
19 + */
20 +class GzipOutputStream
21 +{
22 + private $deflate_ctx;
23 + /** @var bool */
24 + private $enabled = true;
25 +
26 + public function __construct(bool $enabled = true)
27 + {
28 + $this->enabled = $enabled
29 + && function_exists('deflate_init')
30 + && function_exists('deflate_add');
31 + if ($this->enabled) {
32 + $this->deflate_ctx = deflate_init(ZLIB_ENCODING_GZIP, ["level" => 6]);
33 + if ($this->deflate_ctx === false) {
34 + throw new \RuntimeException(
35 + "deflate_init() failed — zlib may be misconfigured"
36 + );
37 + }
38 + if (!headers_sent()) {
39 + @header("Content-Encoding: gzip");
40 + }
41 + }
42 + }
43 +
44 + /**
45 + * Writes data without forcing a sync point.
46 + *
47 + * Uses ZLIB_NO_FLUSH so the compressor can build back-references across
48 + * multiple write() calls, producing significantly better compression
49 + * ratios than ZLIB_SYNC_FLUSH on every call. Data still flows out
50 + * whenever zlib's internal buffer fills — the decompressor on the other
51 + * end will decompress incrementally.
52 + *
53 + * Call sync() after each complete multipart part to guarantee the client
54 + * can decompress everything emitted so far.
55 + */
56 + public function write(string $data): void
57 + {
58 + if (!$this->enabled) {
59 + echo $data;
60 + return;
61 + }
62 + $compressed = deflate_add(
63 + $this->deflate_ctx,
64 + $data,
65 + ZLIB_NO_FLUSH
66 + );
67 + if ($compressed === false) {
68 + throw new \RuntimeException("deflate_add() failed during gzip write");
69 + }
70 + if ($compressed !== "") {
71 + echo $compressed;
72 + }
73 + }
74 +
75 + /**
76 + * Forces a sync flush so the client can decompress all data written so far.
77 + */
78 + public function sync(): void
79 + {
80 + if (!$this->enabled) {
81 + flush();
82 + return;
83 + }
84 + $compressed = deflate_add(
85 + $this->deflate_ctx,
86 + "",
87 + ZLIB_SYNC_FLUSH
88 + );
89 + if ($compressed === false) {
90 + throw new \RuntimeException("deflate_add() failed during gzip sync");
91 + }
92 + if ($compressed !== "") {
93 + echo $compressed;
94 + }
95 + flush();
96 + }
97 +
98 + /**
99 + * Finalizes the gzip stream with ZLIB_FINISH.
100 + */
101 + public function finish(): void
102 + {
103 + if (!$this->enabled) {
104 + flush();
105 + return;
106 + }
107 + $final = deflate_add($this->deflate_ctx, "", ZLIB_FINISH);
108 + if ($final === false) {
109 + throw new \RuntimeException("deflate_add() failed during gzip finish");
110 + }
111 + if ($final !== "") {
112 + echo $final;
113 + }
114 + flush();
115 + }
116 +}