1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Http\Message\Encoding; |
4
|
|
|
|
5
|
|
|
use Clue\StreamFilter as Filter; |
6
|
|
|
use Http\Message\Decorator\StreamDecorator; |
7
|
|
|
use Psr\Http\Message\StreamInterface; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* A filtered stream has a filter for filtering output and a filter for filtering input made to a underlying stream. |
11
|
|
|
* |
12
|
|
|
* @author Joel Wurtz <[email protected]> |
13
|
|
|
*/ |
14
|
|
|
abstract class FilteredStream implements StreamInterface |
15
|
|
|
{ |
16
|
|
|
const BUFFER_SIZE = 8192; |
17
|
|
|
|
18
|
|
|
use StreamDecorator; |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* @var callable |
22
|
|
|
*/ |
23
|
|
|
protected $readFilterCallback; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var resource |
27
|
|
|
* |
28
|
|
|
* @deprecated since version 1.5, will be removed in 2.0 |
29
|
|
|
*/ |
30
|
|
|
protected $readFilter; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var callable |
34
|
|
|
* |
35
|
|
|
* @deprecated since version 1.5, will be removed in 2.0 |
36
|
|
|
*/ |
37
|
|
|
protected $writeFilterCallback; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var resource |
41
|
|
|
* |
42
|
|
|
* @deprecated since version 1.5, will be removed in 2.0 |
43
|
|
|
*/ |
44
|
|
|
protected $writeFilter; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Internal buffer. |
48
|
|
|
* |
49
|
|
|
* @var string |
50
|
|
|
*/ |
51
|
|
|
protected $buffer = ''; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @param StreamInterface $stream |
55
|
|
|
* @param mixed|null $readFilterOptions |
56
|
|
|
* @param mixed|null $writeFilterOptions deprecated since 1.5, will be removed in 2.0 |
57
|
|
|
*/ |
58
|
45 |
|
public function __construct(StreamInterface $stream, $readFilterOptions = null, $writeFilterOptions = null) |
59
|
|
|
{ |
60
|
45 |
|
if (null !== $readFilterOptions) { |
61
|
34 |
|
$this->readFilterCallback = Filter\fun($this->readFilter(), $readFilterOptions); |
62
|
33 |
|
} else { |
63
|
11 |
|
$this->readFilterCallback = Filter\fun($this->readFilter()); |
64
|
|
|
} |
65
|
|
|
|
66
|
44 |
|
if (null !== $writeFilterOptions) { |
67
|
1 |
|
$this->writeFilterCallback = Filter\fun($this->writeFilter(), $writeFilterOptions); |
|
|
|
|
68
|
|
|
|
69
|
|
|
@trigger_error('The $writeFilterOptions argument is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); |
|
|
|
|
70
|
|
|
} else { |
71
|
43 |
|
$this->writeFilterCallback = Filter\fun($this->writeFilter()); |
|
|
|
|
72
|
|
|
} |
73
|
|
|
|
74
|
43 |
|
$this->stream = $stream; |
75
|
43 |
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* {@inheritdoc} |
79
|
|
|
*/ |
80
|
18 |
|
public function read($length) |
81
|
|
|
{ |
82
|
18 |
|
if (strlen($this->buffer) >= $length) { |
83
|
8 |
|
$read = substr($this->buffer, 0, $length); |
84
|
8 |
|
$this->buffer = substr($this->buffer, $length); |
85
|
|
|
|
86
|
8 |
|
return $read; |
87
|
|
|
} |
88
|
|
|
|
89
|
18 |
|
if ($this->stream->eof()) { |
90
|
11 |
|
$buffer = $this->buffer; |
91
|
11 |
|
$this->buffer = ''; |
92
|
|
|
|
93
|
11 |
|
return $buffer; |
94
|
|
|
} |
95
|
|
|
|
96
|
18 |
|
$read = $this->buffer; |
97
|
18 |
|
$this->buffer = ''; |
98
|
18 |
|
$this->fill(); |
99
|
|
|
|
100
|
18 |
|
return $read.$this->read($length - strlen($read)); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* {@inheritdoc} |
105
|
|
|
*/ |
106
|
10 |
|
public function eof() |
107
|
|
|
{ |
108
|
10 |
|
return $this->stream->eof() && '' === $this->buffer; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Buffer is filled by reading underlying stream. |
113
|
|
|
* |
114
|
|
|
* Callback is reading once more even if the stream is ended. |
115
|
|
|
* This allow to get last data in the PHP buffer otherwise this |
116
|
|
|
* bug is present : https://bugs.php.net/bug.php?id=48725 |
117
|
|
|
*/ |
118
|
18 |
|
protected function fill() |
119
|
|
|
{ |
120
|
18 |
|
$readFilterCallback = $this->readFilterCallback; |
121
|
18 |
|
$this->buffer .= $readFilterCallback($this->stream->read(self::BUFFER_SIZE)); |
122
|
|
|
|
123
|
18 |
|
if ($this->stream->eof()) { |
124
|
18 |
|
$this->buffer .= $readFilterCallback(); |
125
|
18 |
|
} |
126
|
18 |
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* {@inheritdoc} |
130
|
|
|
*/ |
131
|
10 |
|
public function getContents() |
132
|
|
|
{ |
133
|
10 |
|
$buffer = ''; |
134
|
|
|
|
135
|
10 |
|
while (!$this->eof()) { |
136
|
10 |
|
$buf = $this->read(self::BUFFER_SIZE); |
137
|
|
|
// Using a loose equality here to match on '' and false. |
138
|
10 |
|
if (null == $buf) { |
139
|
|
|
break; |
140
|
|
|
} |
141
|
|
|
|
142
|
10 |
|
$buffer .= $buf; |
143
|
10 |
|
} |
144
|
|
|
|
145
|
10 |
|
return $buffer; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* {@inheritdoc} |
150
|
|
|
*/ |
151
|
9 |
|
public function getSize() |
152
|
|
|
{ |
153
|
9 |
|
return; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* {@inheritdoc} |
158
|
|
|
*/ |
159
|
|
|
public function __toString() |
160
|
|
|
{ |
161
|
|
|
return $this->getContents(); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* {@inheritdoc} |
166
|
|
|
*/ |
167
|
|
|
public function isSeekable() |
168
|
|
|
{ |
169
|
|
|
return false; |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* {@inheritdoc} |
174
|
|
|
*/ |
175
|
|
|
public function rewind() |
176
|
|
|
{ |
177
|
|
|
throw new \RuntimeException('Cannot rewind a filtered stream'); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* {@inheritdoc} |
182
|
|
|
*/ |
183
|
|
|
public function seek($offset, $whence = SEEK_SET) |
184
|
|
|
{ |
185
|
|
|
throw new \RuntimeException('Cannot seek a filtered stream'); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Returns the read filter name. |
190
|
|
|
* |
191
|
|
|
* @return string |
192
|
|
|
* |
193
|
|
|
* @deprecated since version 1.5, will be removed in 2.0 |
194
|
|
|
*/ |
195
|
|
|
public function getReadFilter() |
196
|
|
|
{ |
197
|
|
|
@trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); |
|
|
|
|
198
|
|
|
|
199
|
|
|
return $this->readFilter(); |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Returns the write filter name. |
204
|
|
|
* |
205
|
|
|
* @return string |
206
|
|
|
*/ |
207
|
|
|
abstract protected function readFilter(); |
208
|
|
|
|
209
|
|
|
/** |
210
|
|
|
* Returns the write filter name. |
211
|
|
|
* |
212
|
|
|
* @return string |
213
|
|
|
* |
214
|
|
|
* @deprecated since version 1.5, will be removed in 2.0 |
215
|
|
|
*/ |
216
|
|
|
public function getWriteFilter() |
217
|
|
|
{ |
218
|
|
|
@trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED); |
|
|
|
|
219
|
|
|
|
220
|
|
|
return $this->writeFilter(); |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Returns the write filter name. |
225
|
|
|
* |
226
|
|
|
* @return string |
227
|
|
|
*/ |
228
|
|
|
abstract protected function writeFilter(); |
229
|
|
|
} |
230
|
|
|
|
This property has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.