ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Stream.php
Go to the documentation of this file.
1<?php
2declare(strict_types=1);
3
5
7
18class Stream implements FileStream
19{
20 const MASK_ACCESS_READ = 01;
23
24 private static $accessMap = [
45 ];
46
50 private $readable;
54 private $writeable;
58 private $seekable;
62 private $stream;
66 private $size;
70 private $uri;
75
76
83 public function __construct($stream, StreamOptions $options = null)
84 {
85 if (!is_resource($stream)) {
86 throw new \InvalidArgumentException('Stream must be a valid resource but "' . gettype($stream) . '" was given.');
87 }
88
89 if ($options !== null) {
90 $this->customMetadata = $options->getMetadata();
91 $this->size = ($options->getSize() !== -1) ? $options->getSize() : null;
92 } else {
93 $this->customMetadata = [];
94 }
95
96 $this->stream = $stream;
97
98 $meta = stream_get_meta_data($this->stream);
99 $mode = $meta['mode'];
100
101 $this->readable = array_key_exists($mode, self::$accessMap) && boolval(self::$accessMap[$mode] & self::MASK_ACCESS_READ);
102 $this->writeable = array_key_exists($mode, self::$accessMap) && boolval(self::$accessMap[$mode] & self::MASK_ACCESS_WRITE);
103 $this->seekable = boolval($meta['seekable']);
104 $this->uri = $this->getMetadata('uri');
105 }
106
107
111 public function close()
112 {
113 if ($this->stream !== null && is_resource($this->stream)) {
114 PHPStreamFunctions::fclose($this->stream);
115 }
116
117 $this->detach();
118 }
119
120
124 public function detach()
125 {
127 $this->stream = $this->size = $this->uri = null;
128
129 return $stream;
130 }
131
132
136 public function getSize()
137 {
138
139 //check if we know the size
140 if ($this->size !== null) {
141 return $this->size;
142 }
143
144 //check if stream is detached
145 if ($this->stream === null) {
146 return null;
147 }
148
149 //clear stat cache if we got a uri (indicates that we have a file resource)
150 if ($this->uri !== null) {
151 clearstatcache(true, $this->uri);
152 }
153
154 $stats = fstat($this->stream);
155 if (array_key_exists('size', $stats)) {
156 $this->size = $stats['size'];
157 return $this->size;
158 }
159
160 //unable to determine stream size
161 return null;
162 }
163
164
168 public function tell()
169 {
170 $this->assertStreamAttached();
171
172 $result = PHPStreamFunctions::ftell($this->stream);
173
174 if ($result === false) {
175 throw new \RuntimeException('Unable to determine stream position');
176 }
177
178 return $result;
179 }
180
181
185 public function eof()
186 {
187 $this->assertStreamAttached();
188
189 return feof($this->stream);
190 }
191
192
196 public function isSeekable()
197 {
198 return $this->seekable;
199 }
200
201
205 public function seek($offset, $whence = SEEK_SET)
206 {
207 $this->assertStreamAttached();
208
209 if (!$this->isSeekable()) {
210 throw new \RuntimeException('Stream is not seekable');
211 }
212
213 if (PHPStreamFunctions::fseek($this->stream, $offset, $whence) === -1) {
214 throw new \RuntimeException("Unable to seek to stream position \"$offset\" with whence \"$whence\"");
215 }
216 }
217
218
222 public function rewind()
223 {
224 $this->seek(0);
225 }
226
227
231 public function isWritable()
232 {
233 return $this->writeable;
234 }
235
236
240 public function write($string)
241 {
242 $this->assertStreamAttached();
243
244 if (!$this->isWritable()) {
245 throw new \RuntimeException('Can not write to a non-writable stream');
246 }
247
248 //we can't know the new size
249 $this->size = null;
250 $result = PHPStreamFunctions::fwrite($this->stream, $string);
251
252 if ($result === false) {
253 throw new \RuntimeException('Unable to write to stream');
254 }
255
256 return $result;
257 }
258
259
263 public function isReadable()
264 {
265 return $this->readable;
266 }
267
268
272 public function read($length)
273 {
274 $this->assertStreamAttached();
275
276 if (!$this->isReadable()) {
277 throw new \RuntimeException('Can not read from non-readable stream');
278 }
279
280 if ($length < 0) {
281 throw new \RuntimeException('Length parameter must not be negative');
282 }
283
284 if ($length === 0) {
285 return '';
286 }
287
288 $junk = PHPStreamFunctions::fread($this->stream, $length);
289 if ($junk === false) {
290 throw new \RuntimeException('Unable to read from stream');
291 }
292
293 return $junk;
294 }
295
296
300 public function getContents()
301 {
302 $this->assertStreamAttached();
303
304 $content = PHPStreamFunctions::stream_get_contents($this->stream);
305
306 if ($content === false) {
307 throw new \RuntimeException('Unable to read stream contents');
308 }
309
310 return $content;
311 }
312
313
317 public function getMetadata($key = null)
318 {
319
320 //return empty array if stream is detached
321 if ($this->stream === null) {
322 return [];
323 }
324
325 //return merged metadata if key is missing
326 if ($key === null) {
327 return array_merge(stream_get_meta_data($this->stream), $this->customMetadata);
328 }
329
330 //return value if key was provided
331
332 //try fetch data from custom metadata
333 if (array_key_exists($key, $this->customMetadata)) {
334 return $this->customMetadata[$key];
335 }
336
337 //try to fetch data from php resource metadata
338 $meta = stream_get_meta_data($this->stream);
339 if (array_key_exists($key, $meta)) {
340 return $meta[$key];
341 }
342
343 //the key was not found in standard and custom metadata.
344 return null;
345 }
346
350 public function __toString()
351 {
352 try {
353 $this->rewind();
354 return strval($this->getContents());
355 } catch (\Exception $ex) {
356 //to string must not throw an error.
357 return '';
358 }
359 }
360
361
365 public function __destruct()
366 {
367
368 //cleanup the resource on object destruction if the stream is not detached.
369 if (!is_null($this->stream)) {
370 $this->close();
371 }
372 }
373
374
381 private function assertStreamAttached()
382 {
383 if ($this->stream === null) {
384 throw new \RuntimeException('Stream is detached');
385 }
386 }
387}
$result
An exception for terminatinating execution or to throw for unit testing.
getMetadata($key=null)
@inheritDoc
Definition: Stream.php:317
__construct($stream, StreamOptions $options=null)
Stream constructor.
Definition: Stream.php:83
assertStreamAttached()
Checks if the stream is attached to the wrapper.
Definition: Stream.php:381
write($string)
@inheritDoc
Definition: Stream.php:240
read($length)
@inheritDoc
Definition: Stream.php:272
seek($offset, $whence=SEEK_SET)
@inheritDoc
Definition: Stream.php:205
static fwrite($handle, $string, $length=null)
fwrite wrapper
static fread($handle, $length)
fread wrapper
static stream_get_contents($handle, $length=-1)
stream_get_contents wrapper
static fclose($handle)
fclose wrapper
static fseek($stream, $offset, $whence)
fseek wrapper.
$key
Definition: croninfo.php:18
font size
Definition: langcheck.php:162