ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
Stream.php
Go to the documentation of this file.
1 <?php
2 
4 
6 
17 class Stream implements FileStream
18 {
19  const MASK_ACCESS_READ = 01;
20  const MASK_ACCESS_WRITE = 02;
22 
23  private static $accessMap = [
24  'r' => self::MASK_ACCESS_READ,
25  'w+' => self::MASK_ACCESS_READ_WRITE,
26  'r+' => self::MASK_ACCESS_READ_WRITE,
27  'x+' => self::MASK_ACCESS_READ_WRITE,
28  'c+' => self::MASK_ACCESS_READ_WRITE,
29  'rb' => self::MASK_ACCESS_READ,
30  'w+b' => self::MASK_ACCESS_READ_WRITE,
31  'r+b' => self::MASK_ACCESS_READ_WRITE,
32  'x+b' => self::MASK_ACCESS_READ_WRITE,
33  'c+b' => self::MASK_ACCESS_READ_WRITE,
34  'rt' => self::MASK_ACCESS_READ,
35  'w+t' => self::MASK_ACCESS_READ_WRITE,
36  'r+t' => self::MASK_ACCESS_READ_WRITE,
37  'x+t' => self::MASK_ACCESS_READ_WRITE,
38  'c+t' => self::MASK_ACCESS_READ_WRITE,
39  'a+' => self::MASK_ACCESS_READ_WRITE,
40  'w' => self::MASK_ACCESS_WRITE,
41  'rw' => self::MASK_ACCESS_WRITE,
42  'wb' => self::MASK_ACCESS_WRITE,
43  'a' => self::MASK_ACCESS_WRITE
44  ];
45 
49  private $readable;
53  private $writeable;
57  private $seekable;
61  private $stream;
65  private $size;
69  private $uri;
73  private $customMetadata;
74 
75 
82  public function __construct($stream, StreamOptions $options = null)
83  {
84  if (!is_resource($stream)) {
85  throw new \InvalidArgumentException('Stream must be a valid resource but "' . gettype($stream) . '" was given.');
86  }
87 
88  if ($options !== null) {
89  $this->customMetadata = $options->getMetadata();
90  $this->size = ($options->getSize() !== -1) ? $options->getSize() : null;
91  } else {
92  $this->customMetadata = [];
93  }
94 
95  $this->stream = $stream;
96 
97  $meta = stream_get_meta_data($this->stream);
98  $mode = $meta['mode'];
99 
100  $this->readable = array_key_exists($mode, self::$accessMap) && boolval(self::$accessMap[$mode] & self::MASK_ACCESS_READ);
101  $this->writeable = array_key_exists($mode, self::$accessMap) && boolval(self::$accessMap[$mode] & self::MASK_ACCESS_WRITE);
102  $this->seekable = boolval($meta['seekable']);
103  $this->uri = $this->getMetadata('uri');
104  }
105 
106 
110  public function close()
111  {
112  if ($this->stream !== null && is_resource($this->stream)) {
113  PHPStreamFunctions::fclose($this->stream);
114  }
115 
116  $this->detach();
117  }
118 
119 
123  public function detach()
124  {
126  $this->stream = $this->size = $this->uri = null;
127 
128  return $stream;
129  }
130 
131 
135  public function getSize()
136  {
137 
138  //check if we know the size
139  if ($this->size !== null) {
140  return $this->size;
141  }
142 
143  //check if stream is detached
144  if ($this->stream === null) {
145  return null;
146  }
147 
148  //clear stat cache if we got a uri (indicates that we have a file resource)
149  if ($this->uri !== null) {
150  clearstatcache(true, $this->uri);
151  }
152 
153  $stats = fstat($this->stream);
154  if (array_key_exists('size', $stats)) {
155  $this->size = $stats['size'];
156  return $this->size;
157  }
158 
159  //unable to determine stream size
160  return null;
161  }
162 
163 
167  public function tell()
168  {
169  $this->assertStreamAttached();
170 
171  $result = PHPStreamFunctions::ftell($this->stream);
172 
173  if ($result === false) {
174  throw new \RuntimeException('Unable to determine stream position');
175  }
176 
177  return $result;
178  }
179 
180 
184  public function eof()
185  {
186  $this->assertStreamAttached();
187 
188  return feof($this->stream);
189  }
190 
191 
195  public function isSeekable()
196  {
197  return $this->seekable;
198  }
199 
200 
204  public function seek($offset, $whence = SEEK_SET)
205  {
206  $this->assertStreamAttached();
207 
208  if (!$this->isSeekable()) {
209  throw new \RuntimeException('Stream is not seekable');
210  }
211 
212  if (PHPStreamFunctions::fseek($this->stream, $offset, $whence) === -1) {
213  throw new \RuntimeException("Unable to seek to stream position \"$offset\" with whence \"$whence\"");
214  }
215  }
216 
217 
221  public function rewind()
222  {
223  $this->seek(0);
224  }
225 
226 
230  public function isWritable()
231  {
232  return $this->writeable;
233  }
234 
235 
239  public function write($string)
240  {
241  $this->assertStreamAttached();
242 
243  if (!$this->isWritable()) {
244  throw new \RuntimeException('Can not write to a non-writable stream');
245  }
246 
247  //we can't know the new size
248  $this->size = null;
249  $result = PHPStreamFunctions::fwrite($this->stream, $string);
250 
251  if ($result === false) {
252  throw new \RuntimeException('Unable to write to stream');
253  }
254 
255  return $result;
256  }
257 
258 
262  public function isReadable()
263  {
264  return $this->readable;
265  }
266 
267 
271  public function read($length)
272  {
273  $this->assertStreamAttached();
274 
275  if (!$this->isReadable()) {
276  throw new \RuntimeException('Can not read from non-readable stream');
277  }
278 
279  if ($length < 0) {
280  throw new \RuntimeException('Length parameter must not be negative');
281  }
282 
283  if ($length === 0) {
284  return '';
285  }
286 
287  $junk = PHPStreamFunctions::fread($this->stream, $length);
288  if ($junk === false) {
289  throw new \RuntimeException('Unable to read from stream');
290  }
291 
292  return $junk;
293  }
294 
295 
299  public function getContents()
300  {
301  $this->assertStreamAttached();
302 
303  $content = PHPStreamFunctions::stream_get_contents($this->stream);
304 
305  if ($content === false) {
306  throw new \RuntimeException('Unable to read stream contents');
307  }
308 
309  return $content;
310  }
311 
312 
316  public function getMetadata($key = null)
317  {
318 
319  //return empty array if stream is detached
320  if ($this->stream === null) {
321  return [];
322  }
323 
324  //return merged metadata if key is missing
325  if ($key === null) {
326  return array_merge(stream_get_meta_data($this->stream), $this->customMetadata);
327  }
328 
329  //return value if key was provided
330 
331  //try fetch data from custom metadata
332  if (array_key_exists($key, $this->customMetadata)) {
333  return $this->customMetadata[$key];
334  }
335 
336  //try to fetch data from php resource metadata
337  $meta = stream_get_meta_data($this->stream);
338  if (array_key_exists($key, $meta)) {
339  return $meta[$key];
340  }
341 
342  //the key was not found in standard and custom metadata.
343  return null;
344  }
345 
349  public function __toString()
350  {
351  try {
352  $this->rewind();
353  return strval($this->getContents());
354  } catch (\Exception $ex) {
355  //to string must not throw an error.
356  return '';
357  }
358  }
359 
360 
364  public function __destruct()
365  {
366 
367  //cleanup the resource on object destruction if the stream is not detached.
368  if (!is_null($this->stream)) {
369  $this->close();
370  }
371  }
372 
373 
380  private function assertStreamAttached()
381  {
382  if ($this->stream === null) {
383  throw new \RuntimeException('Stream is detached');
384  }
385  }
386 }
$result
seek($offset, $whence=SEEK_SET)
Definition: Stream.php:204
assertStreamAttached()
Checks if the stream is attached to the wrapper.
Definition: Stream.php:380
static fseek($stream, $offset, $whence)
fseek wrapper.
static fread($handle, $length)
fread wrapper
static fclose($handle)
fclose wrapper
__construct($stream, StreamOptions $options=null)
Stream constructor.
Definition: Stream.php:82
$stats
static fwrite($handle, $string, $length=null)
fwrite wrapper
static stream_get_contents($handle, $length=-1)
stream_get_contents wrapper
$key
Definition: croninfo.php:18
Interface FileStream.
Definition: FileStream.php:20
if(!isset($_REQUEST['ReturnTo'])) if(!isset($_REQUEST['AuthId'])) $options
Definition: as_login.php:20
Set page orientation and size
Definition: 04printing.php:77