comparison vendor/guzzlehttp/psr7/src/Stream.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 129ea1e6d783
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2 namespace GuzzleHttp\Psr7;
3
4 use Psr\Http\Message\StreamInterface;
5
6 /**
7 * PHP stream implementation.
8 *
9 * @var $stream
10 */
11 class Stream implements StreamInterface
12 {
13 private $stream;
14 private $size;
15 private $seekable;
16 private $readable;
17 private $writable;
18 private $uri;
19 private $customMetadata;
20
21 /** @var array Hash of readable and writable stream types */
22 private static $readWriteHash = [
23 'read' => [
24 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
25 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
26 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
27 'x+t' => true, 'c+t' => true, 'a+' => true
28 ],
29 'write' => [
30 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
31 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
32 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
33 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
34 ]
35 ];
36
37 /**
38 * This constructor accepts an associative array of options.
39 *
40 * - size: (int) If a read stream would otherwise have an indeterminate
41 * size, but the size is known due to foreknowledge, then you can
42 * provide that size, in bytes.
43 * - metadata: (array) Any additional metadata to return when the metadata
44 * of the stream is accessed.
45 *
46 * @param resource $stream Stream resource to wrap.
47 * @param array $options Associative array of options.
48 *
49 * @throws \InvalidArgumentException if the stream is not a stream resource
50 */
51 public function __construct($stream, $options = [])
52 {
53 if (!is_resource($stream)) {
54 throw new \InvalidArgumentException('Stream must be a resource');
55 }
56
57 if (isset($options['size'])) {
58 $this->size = $options['size'];
59 }
60
61 $this->customMetadata = isset($options['metadata'])
62 ? $options['metadata']
63 : [];
64
65 $this->stream = $stream;
66 $meta = stream_get_meta_data($this->stream);
67 $this->seekable = $meta['seekable'];
68 $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
69 $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
70 $this->uri = $this->getMetadata('uri');
71 }
72
73 public function __get($name)
74 {
75 if ($name == 'stream') {
76 throw new \RuntimeException('The stream is detached');
77 }
78
79 throw new \BadMethodCallException('No value for ' . $name);
80 }
81
82 /**
83 * Closes the stream when the destructed
84 */
85 public function __destruct()
86 {
87 $this->close();
88 }
89
90 public function __toString()
91 {
92 try {
93 $this->seek(0);
94 return (string) stream_get_contents($this->stream);
95 } catch (\Exception $e) {
96 return '';
97 }
98 }
99
100 public function getContents()
101 {
102 $contents = stream_get_contents($this->stream);
103
104 if ($contents === false) {
105 throw new \RuntimeException('Unable to read stream contents');
106 }
107
108 return $contents;
109 }
110
111 public function close()
112 {
113 if (isset($this->stream)) {
114 if (is_resource($this->stream)) {
115 fclose($this->stream);
116 }
117 $this->detach();
118 }
119 }
120
121 public function detach()
122 {
123 if (!isset($this->stream)) {
124 return null;
125 }
126
127 $result = $this->stream;
128 unset($this->stream);
129 $this->size = $this->uri = null;
130 $this->readable = $this->writable = $this->seekable = false;
131
132 return $result;
133 }
134
135 public function getSize()
136 {
137 if ($this->size !== null) {
138 return $this->size;
139 }
140
141 if (!isset($this->stream)) {
142 return null;
143 }
144
145 // Clear the stat cache if the stream has a URI
146 if ($this->uri) {
147 clearstatcache(true, $this->uri);
148 }
149
150 $stats = fstat($this->stream);
151 if (isset($stats['size'])) {
152 $this->size = $stats['size'];
153 return $this->size;
154 }
155
156 return null;
157 }
158
159 public function isReadable()
160 {
161 return $this->readable;
162 }
163
164 public function isWritable()
165 {
166 return $this->writable;
167 }
168
169 public function isSeekable()
170 {
171 return $this->seekable;
172 }
173
174 public function eof()
175 {
176 return !$this->stream || feof($this->stream);
177 }
178
179 public function tell()
180 {
181 $result = ftell($this->stream);
182
183 if ($result === false) {
184 throw new \RuntimeException('Unable to determine stream position');
185 }
186
187 return $result;
188 }
189
190 public function rewind()
191 {
192 $this->seek(0);
193 }
194
195 public function seek($offset, $whence = SEEK_SET)
196 {
197 if (!$this->seekable) {
198 throw new \RuntimeException('Stream is not seekable');
199 } elseif (fseek($this->stream, $offset, $whence) === -1) {
200 throw new \RuntimeException('Unable to seek to stream position '
201 . $offset . ' with whence ' . var_export($whence, true));
202 }
203 }
204
205 public function read($length)
206 {
207 if (!$this->readable) {
208 throw new \RuntimeException('Cannot read from non-readable stream');
209 }
210 if ($length < 0) {
211 throw new \RuntimeException('Length parameter cannot be negative');
212 }
213
214 if (0 === $length) {
215 return '';
216 }
217
218 $string = fread($this->stream, $length);
219 if (false === $string) {
220 throw new \RuntimeException('Unable to read from stream');
221 }
222
223 return $string;
224 }
225
226 public function write($string)
227 {
228 if (!$this->writable) {
229 throw new \RuntimeException('Cannot write to a non-writable stream');
230 }
231
232 // We can't know the size after writing anything
233 $this->size = null;
234 $result = fwrite($this->stream, $string);
235
236 if ($result === false) {
237 throw new \RuntimeException('Unable to write to stream');
238 }
239
240 return $result;
241 }
242
243 public function getMetadata($key = null)
244 {
245 if (!isset($this->stream)) {
246 return $key ? null : [];
247 } elseif (!$key) {
248 return $this->customMetadata + stream_get_meta_data($this->stream);
249 } elseif (isset($this->customMetadata[$key])) {
250 return $this->customMetadata[$key];
251 }
252
253 $meta = stream_get_meta_data($this->stream);
254
255 return isset($meta[$key]) ? $meta[$key] : null;
256 }
257 }