PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
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 13.7.2 13.8.3 All 506 releases
jetpack / vendor / wp-php-toolkit / reprint-server / src / class-gzip-output-stream.php

class-gzip-output-stream.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at vendor/wp-php-toolkit/reprint-server/src/class-gzip-output-stream.php

117 lines 3.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 }
117