1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* This file is part of the miBadger package. |
5
|
|
|
* |
6
|
|
|
* @author Michael Webbers <[email protected]> |
7
|
|
|
* @license http://opensource.org/licenses/Apache-2.0 Apache v2 License |
8
|
|
|
* @version 1.0.0 |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace miBadger\Http; |
12
|
|
|
|
13
|
|
|
use Psr\Http\Message\StreamInterface; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* The stream class |
17
|
|
|
* |
18
|
|
|
* @see http://www.php-fig.org/psr/psr-7/ |
19
|
|
|
* @since 1.0.0 |
20
|
|
|
*/ |
21
|
|
|
class Stream implements StreamInterface |
22
|
|
|
{ |
23
|
|
|
/** @var resource The resource. */ |
24
|
|
|
private $resource; |
25
|
|
|
|
26
|
|
|
/** @var array The metadata. */ |
27
|
|
|
private $metadata; |
28
|
|
|
|
29
|
|
|
/** @var string[] The read modes. */ |
30
|
|
|
private static $readModes = ['r', 'w+', 'r+', 'x+', 'c+', 'rb', 'w+b', 'r+b', 'x+b', 'c+b', 'rt', 'w+t', 'r+t', 'x+t', 'c+t', 'a+']; |
31
|
|
|
|
32
|
|
|
/** @var string[] The write modes. */ |
33
|
|
|
private static $writeModes = ['w', 'w+', 'rw', 'r+', 'x+', 'c+', 'wb', 'w+b', 'r+b', 'x+b', 'c+b', 'w+t', 'r+t', 'x+t', 'c+t', 'a', 'a+']; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Construct a Stream object with the given resource. |
37
|
|
|
* |
38
|
|
|
* @param resource $resource |
39
|
|
|
*/ |
40
|
71 |
|
public function __construct($resource) |
41
|
|
|
{ |
42
|
71 |
|
if (!is_resource($resource)) { |
43
|
1 |
|
throw new \InvalidArgumentException('Invalid resource'); |
44
|
|
|
} |
45
|
|
|
|
46
|
71 |
|
$this->resource = $resource; |
47
|
71 |
|
$this->metadata = stream_get_meta_data($resource); |
48
|
71 |
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Destruct the Stream object. |
52
|
|
|
*/ |
53
|
6 |
|
public function __destruct() |
54
|
|
|
{ |
55
|
6 |
|
$this->close(); |
56
|
6 |
|
} |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* {@inheritdoc} |
60
|
|
|
*/ |
61
|
4 |
|
public function __toString() |
62
|
|
|
{ |
63
|
|
|
try { |
64
|
4 |
|
$this->seek(0); |
65
|
|
|
|
66
|
2 |
|
return $this->getContents(); |
67
|
2 |
|
} catch (\Exception $e) { |
68
|
2 |
|
return ''; |
69
|
|
|
} |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* {@inheritdoc} |
74
|
|
|
*/ |
75
|
7 |
|
public function close() |
76
|
|
|
{ |
77
|
7 |
|
if (isset($this->resource)) { |
78
|
7 |
|
if (is_resource($this->resource)) { |
79
|
7 |
|
fclose($this->resource); |
80
|
7 |
|
} |
81
|
|
|
|
82
|
7 |
|
$this->detach(); |
83
|
7 |
|
} |
84
|
7 |
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* {@inheritdoc} |
88
|
|
|
*/ |
89
|
14 |
|
public function detach() |
90
|
|
|
{ |
91
|
14 |
|
if (!isset($this->resource)) { |
92
|
1 |
|
return null; |
93
|
|
|
} |
94
|
|
|
|
95
|
14 |
|
$result = $this->resource; |
96
|
14 |
|
unset($this->resource); |
97
|
|
|
|
98
|
14 |
|
return $result; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* {@inheritdoc} |
103
|
|
|
*/ |
104
|
2 |
|
public function getSize() |
105
|
|
|
{ |
106
|
2 |
|
if (!isset($this->resource)) { |
107
|
1 |
|
return null; |
108
|
|
|
} |
109
|
|
|
|
110
|
1 |
|
if ($this->getMetadata('uri')) { |
111
|
1 |
|
clearstatcache(true, $this->getMetadata('uri')); |
112
|
1 |
|
} |
113
|
|
|
|
114
|
1 |
|
$stats = fstat($this->resource); |
115
|
|
|
|
116
|
1 |
|
return isset($stats['size']) ? $stats['size'] : null; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* {@inheritdoc} |
121
|
|
|
*/ |
122
|
2 |
|
public function tell() |
123
|
|
|
{ |
124
|
2 |
|
$result = ftell($this->resource); |
125
|
|
|
|
126
|
2 |
|
if ($result === false) { |
127
|
1 |
|
throw new \RuntimeException('Error while getting the position of the pointer'); |
128
|
|
|
} |
129
|
|
|
|
130
|
1 |
|
return $result; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* {@inheritdoc} |
135
|
|
|
*/ |
136
|
1 |
|
public function eof() |
137
|
|
|
{ |
138
|
1 |
|
return isset($this->resource) && feof($this->resource); |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* {@inheritdoc} |
143
|
|
|
*/ |
144
|
9 |
|
public function isSeekable() |
145
|
|
|
{ |
146
|
9 |
|
return isset($this->resource) && $this->getMetadata('seekable'); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* {@inheritdoc} |
151
|
|
|
*/ |
152
|
8 |
|
public function seek($offset, $whence = SEEK_SET) |
153
|
|
|
{ |
154
|
8 |
|
if (!$this->isSeekable()) { |
155
|
3 |
|
throw new \RuntimeException('Stream is not seekable'); |
156
|
|
|
} |
157
|
|
|
|
158
|
5 |
|
if (fseek($this->resource, $offset, $whence) === false) { |
159
|
1 |
|
throw new \RuntimeException('Error while seeking the stream'); |
160
|
|
|
} |
161
|
4 |
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* {@inheritdoc} |
165
|
|
|
*/ |
166
|
1 |
|
public function rewind() |
167
|
|
|
{ |
168
|
1 |
|
$this->seek(0); |
169
|
1 |
|
} |
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* {@inheritdoc} |
173
|
|
|
*/ |
174
|
6 |
|
public function isWritable() |
175
|
|
|
{ |
176
|
6 |
|
return isset($this->resource) && in_array($this->getMetadata('mode'), self::$writeModes); |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* {@inheritdoc} |
181
|
|
|
*/ |
182
|
5 |
|
public function write($string) |
183
|
|
|
{ |
184
|
5 |
|
if (!$this->isWritable()) { |
185
|
1 |
|
throw new \RuntimeException('Stream is not writable'); |
186
|
|
|
} |
187
|
|
|
|
188
|
4 |
|
$result = fwrite($this->resource, $string); |
189
|
|
|
|
190
|
4 |
|
if ($result === false) { |
191
|
1 |
|
throw new \RuntimeException('Error while writing the stream'); |
192
|
|
|
} |
193
|
|
|
|
194
|
3 |
|
return $result; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* {@inheritdoc} |
199
|
|
|
*/ |
200
|
10 |
|
public function isReadable() |
201
|
|
|
{ |
202
|
10 |
|
return isset($this->resource) && in_array($this->getMetadata('mode'), self::$readModes); |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* {@inheritdoc} |
207
|
|
|
*/ |
208
|
3 |
View Code Duplication |
public function read($length) |
|
|
|
|
209
|
|
|
{ |
210
|
3 |
|
if (!$this->isReadable()) { |
211
|
1 |
|
throw new \RuntimeException('Stream is not readable'); |
212
|
|
|
} |
213
|
|
|
|
214
|
2 |
|
$result = fread($this->resource, $length); |
215
|
|
|
|
216
|
2 |
|
if ($result === false) { |
217
|
1 |
|
throw new \RuntimeException('Error while reading the stream'); |
218
|
|
|
} |
219
|
|
|
|
220
|
1 |
|
return $result; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* {@inheritdoc} |
225
|
|
|
*/ |
226
|
6 |
View Code Duplication |
public function getContents() |
|
|
|
|
227
|
|
|
{ |
228
|
6 |
|
if (!$this->isReadable()) { |
229
|
1 |
|
throw new \RuntimeException('Stream is not readable'); |
230
|
|
|
} |
231
|
|
|
|
232
|
5 |
|
$result = stream_get_contents($this->resource); |
233
|
|
|
|
234
|
5 |
|
if ($result === false) { |
235
|
1 |
|
throw new \RuntimeException('Error while reading the stream'); |
236
|
|
|
} |
237
|
|
|
|
238
|
4 |
|
return $result; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* {@inheritdoc} |
243
|
|
|
*/ |
244
|
18 |
|
public function getMetadata($key = null) |
245
|
|
|
{ |
246
|
18 |
|
if ($key === null) { |
247
|
1 |
|
return $this->metadata; |
248
|
|
|
} |
249
|
|
|
|
250
|
17 |
|
return isset($this->metadata[$key]) ? $this->metadata[$key] : null; |
251
|
|
|
} |
252
|
|
|
} |
253
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.