@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class AphrontRequestStream extends Phobject {
4
5 private $encoding;
6 private $stream;
7 private $closed;
8 private $iterator;
9
10 public function setEncoding($encoding) {
11 $this->encoding = $encoding;
12 return $this;
13 }
14
15 public function getEncoding() {
16 return $this->encoding;
17 }
18
19 public function getIterator() {
20 if (!$this->iterator) {
21 $this->iterator = new PhutilStreamIterator($this->getStream());
22 }
23 return $this->iterator;
24 }
25
26 public function readData() {
27 if (!$this->iterator) {
28 $iterator = $this->getIterator();
29 $iterator->rewind();
30 } else {
31 $iterator = $this->getIterator();
32 }
33
34 if (!$iterator->valid()) {
35 return null;
36 }
37
38 $data = $iterator->current();
39 $iterator->next();
40
41 return $data;
42 }
43
44 private function getStream() {
45 if (!$this->stream) {
46 $this->stream = $this->newStream();
47 }
48
49 return $this->stream;
50 }
51
52 private function newStream() {
53 $stream = fopen('php://input', 'rb');
54 if (!$stream) {
55 throw new Exception(
56 pht(
57 'Failed to open stream "%s" for reading.',
58 'php://input'));
59 }
60
61 $encoding = $this->getEncoding();
62 if ($encoding === 'gzip') {
63 // This parameter is magic. Values 0-15 express a time/memory tradeoff,
64 // but the largest value (15) corresponds to only 32KB of memory and
65 // data encoded with a smaller window size than the one we pass can not
66 // be decompressed. Always pass the maximum window size.
67
68 // Additionally, you can add 16 (to enable gzip) or 32 (to enable both
69 // gzip and zlib). Add 32 to support both.
70 $zlib_window = 15 + 32;
71
72 $ok = stream_filter_append(
73 $stream,
74 'zlib.inflate',
75 STREAM_FILTER_READ,
76 array(
77 'window' => $zlib_window,
78 ));
79 if (!$ok) {
80 throw new Exception(
81 pht(
82 'Failed to append filter "%s" to input stream while processing '.
83 'a request with "%s" encoding.',
84 'zlib.inflate',
85 $encoding));
86 }
87 }
88
89 return $stream;
90 }
91
92 public static function supportsGzip() {
93 if (!function_exists('gzencode') || !function_exists('gzdecode')) {
94 return false;
95 }
96
97 $has_zlib = false;
98
99 // NOTE: At least locally, this returns "zlib.*", which is not terribly
100 // reassuring. We care about "zlib.inflate".
101
102 $filters = stream_get_filters();
103 foreach ($filters as $filter) {
104 if (!strncasecmp($filter, 'zlib.', strlen('zlib.'))) {
105 $has_zlib = true;
106 break;
107 }
108 }
109
110 return $has_zlib;
111 }
112
113}