Upgraded drupal core with security updates
[yaffs-website] / vendor / zendframework / zend-diactoros / src / Stream.php
1 <?php
2 /**
3  * Zend Framework (http://framework.zend.com/)
4  *
5  * @see       http://github.com/zendframework/zend-diactoros for the canonical source repository
6  * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
7  * @license   https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
8  */
9
10 namespace Zend\Diactoros;
11
12 use InvalidArgumentException;
13 use RuntimeException;
14 use Psr\Http\Message\StreamInterface;
15
16 /**
17  * Implementation of PSR HTTP streams
18  */
19 class Stream implements StreamInterface
20 {
21     /**
22      * @var resource|null
23      */
24     protected $resource;
25
26     /**
27      * @var string|resource
28      */
29     protected $stream;
30
31     /**
32      * @param string|resource $stream
33      * @param string $mode Mode with which to open stream
34      * @throws InvalidArgumentException
35      */
36     public function __construct($stream, $mode = 'r')
37     {
38         $this->setStream($stream, $mode);
39     }
40
41     /**
42      * {@inheritdoc}
43      */
44     public function __toString()
45     {
46         if (! $this->isReadable()) {
47             return '';
48         }
49
50         try {
51             $this->rewind();
52             return $this->getContents();
53         } catch (RuntimeException $e) {
54             return '';
55         }
56     }
57
58     /**
59      * {@inheritdoc}
60      */
61     public function close()
62     {
63         if (! $this->resource) {
64             return;
65         }
66
67         $resource = $this->detach();
68         fclose($resource);
69     }
70
71     /**
72      * {@inheritdoc}
73      */
74     public function detach()
75     {
76         $resource = $this->resource;
77         $this->resource = null;
78         return $resource;
79     }
80
81     /**
82      * Attach a new stream/resource to the instance.
83      *
84      * @param string|resource $resource
85      * @param string $mode
86      * @throws InvalidArgumentException for stream identifier that cannot be
87      *     cast to a resource
88      * @throws InvalidArgumentException for non-resource stream
89      */
90     public function attach($resource, $mode = 'r')
91     {
92         $this->setStream($resource, $mode);
93     }
94
95     /**
96      * {@inheritdoc}
97      */
98     public function getSize()
99     {
100         if (null === $this->resource) {
101             return null;
102         }
103
104         $stats = fstat($this->resource);
105         return $stats['size'];
106     }
107
108     /**
109      * {@inheritdoc}
110      */
111     public function tell()
112     {
113         if (! $this->resource) {
114             throw new RuntimeException('No resource available; cannot tell position');
115         }
116
117         $result = ftell($this->resource);
118         if (! is_int($result)) {
119             throw new RuntimeException('Error occurred during tell operation');
120         }
121
122         return $result;
123     }
124
125     /**
126      * {@inheritdoc}
127      */
128     public function eof()
129     {
130         if (! $this->resource) {
131             return true;
132         }
133
134         return feof($this->resource);
135     }
136
137     /**
138      * {@inheritdoc}
139      */
140     public function isSeekable()
141     {
142         if (! $this->resource) {
143             return false;
144         }
145
146         $meta = stream_get_meta_data($this->resource);
147         return $meta['seekable'];
148     }
149
150     /**
151      * {@inheritdoc}
152      */
153     public function seek($offset, $whence = SEEK_SET)
154     {
155         if (! $this->resource) {
156             throw new RuntimeException('No resource available; cannot seek position');
157         }
158
159         if (! $this->isSeekable()) {
160             throw new RuntimeException('Stream is not seekable');
161         }
162
163         $result = fseek($this->resource, $offset, $whence);
164
165         if (0 !== $result) {
166             throw new RuntimeException('Error seeking within stream');
167         }
168
169         return true;
170     }
171
172     /**
173      * {@inheritdoc}
174      */
175     public function rewind()
176     {
177         return $this->seek(0);
178     }
179
180     /**
181      * {@inheritdoc}
182      */
183     public function isWritable()
184     {
185         if (! $this->resource) {
186             return false;
187         }
188
189         $meta = stream_get_meta_data($this->resource);
190         $mode = $meta['mode'];
191
192         return (
193             strstr($mode, 'x')
194             || strstr($mode, 'w')
195             || strstr($mode, 'c')
196             || strstr($mode, 'a')
197             || strstr($mode, '+')
198         );
199     }
200
201     /**
202      * {@inheritdoc}
203      */
204     public function write($string)
205     {
206         if (! $this->resource) {
207             throw new RuntimeException('No resource available; cannot write');
208         }
209
210         if (! $this->isWritable()) {
211             throw new RuntimeException('Stream is not writable');
212         }
213
214         $result = fwrite($this->resource, $string);
215
216         if (false === $result) {
217             throw new RuntimeException('Error writing to stream');
218         }
219         return $result;
220     }
221
222     /**
223      * {@inheritdoc}
224      */
225     public function isReadable()
226     {
227         if (! $this->resource) {
228             return false;
229         }
230
231         $meta = stream_get_meta_data($this->resource);
232         $mode = $meta['mode'];
233
234         return (strstr($mode, 'r') || strstr($mode, '+'));
235     }
236
237     /**
238      * {@inheritdoc}
239      */
240     public function read($length)
241     {
242         if (! $this->resource) {
243             throw new RuntimeException('No resource available; cannot read');
244         }
245
246         if (! $this->isReadable()) {
247             throw new RuntimeException('Stream is not readable');
248         }
249
250         $result = fread($this->resource, $length);
251
252         if (false === $result) {
253             throw new RuntimeException('Error reading stream');
254         }
255
256         return $result;
257     }
258
259     /**
260      * {@inheritdoc}
261      */
262     public function getContents()
263     {
264         if (! $this->isReadable()) {
265             throw new RuntimeException('Stream is not readable');
266         }
267
268         $result = stream_get_contents($this->resource);
269         if (false === $result) {
270             throw new RuntimeException('Error reading from stream');
271         }
272         return $result;
273     }
274
275     /**
276      * {@inheritdoc}
277      */
278     public function getMetadata($key = null)
279     {
280         if (null === $key) {
281             return stream_get_meta_data($this->resource);
282         }
283
284         $metadata = stream_get_meta_data($this->resource);
285         if (! array_key_exists($key, $metadata)) {
286             return null;
287         }
288
289         return $metadata[$key];
290     }
291
292     /**
293      * Set the internal stream resource.
294      *
295      * @param string|resource $stream String stream target or stream resource.
296      * @param string $mode Resource mode for stream target.
297      * @throws InvalidArgumentException for invalid streams or resources.
298      */
299     private function setStream($stream, $mode = 'r')
300     {
301         $error    = null;
302         $resource = $stream;
303
304         if (is_string($stream)) {
305             set_error_handler(function ($e) use (&$error) {
306                 $error = $e;
307             }, E_WARNING);
308             $resource = fopen($stream, $mode);
309             restore_error_handler();
310         }
311
312         if ($error) {
313             throw new InvalidArgumentException('Invalid stream reference provided');
314         }
315
316         if (! is_resource($resource) || 'stream' !== get_resource_type($resource)) {
317             throw new InvalidArgumentException(
318                 'Invalid stream provided; must be a string stream identifier or stream resource'
319             );
320         }
321
322         if ($stream !== $resource) {
323             $this->stream = $stream;
324         }
325
326         $this->resource = $resource;
327     }
328 }