30 private $customMetadata;
48 if (!is_resource($stream)) {
49 throw new \InvalidArgumentException(
'Stream must be a resource');
52 if (isset($options[
'size'])) {
53 $this->size = $options[
'size'];
56 $this->customMetadata = isset($options[
'metadata'])
57 ? $options[
'metadata']
60 $this->stream = $stream;
61 $meta = stream_get_meta_data($this->stream);
62 $this->seekable = $meta[
'seekable'];
63 $this->readable = (bool)preg_match(self::READABLE_MODES, $meta[
'mode']);
64 $this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta[
'mode']);
80 return (
string) stream_get_contents($this->stream);
81 }
catch (\Exception $e) {
88 if (!isset($this->stream)) {
89 throw new \RuntimeException(
'Stream is detached');
92 $contents = stream_get_contents($this->stream);
94 if ($contents ===
false) {
95 throw new \RuntimeException(
'Unable to read stream contents');
103 if (isset($this->stream)) {
104 if (is_resource($this->stream)) {
105 fclose($this->stream);
113 if (!isset($this->stream)) {
117 $result = $this->stream;
118 unset($this->stream);
119 $this->size = $this->uri =
null;
120 $this->readable = $this->writable = $this->seekable =
false;
127 if ($this->size !==
null) {
131 if (!isset($this->stream)) {
137 clearstatcache(
true, $this->uri);
140 $stats = fstat($this->stream);
141 if (isset($stats[
'size'])) {
142 $this->size = $stats[
'size'];
151 return $this->readable;
156 return $this->writable;
161 return $this->seekable;
166 if (!isset($this->stream)) {
167 throw new \RuntimeException(
'Stream is detached');
170 return feof($this->stream);
175 if (!isset($this->stream)) {
176 throw new \RuntimeException(
'Stream is detached');
179 $result = ftell($this->stream);
181 if ($result ===
false) {
182 throw new \RuntimeException(
'Unable to determine stream position');
193 public function seek($offset, $whence = SEEK_SET)
195 $whence = (int) $whence;
197 if (!isset($this->stream)) {
198 throw new \RuntimeException(
'Stream is detached');
200 if (!$this->seekable) {
201 throw new \RuntimeException(
'Stream is not seekable');
203 if (fseek($this->stream, $offset, $whence) === -1) {
204 throw new \RuntimeException(
'Unable to seek to stream position '
205 . $offset .
' with whence ' . var_export($whence,
true));
211 if (!isset($this->stream)) {
212 throw new \RuntimeException(
'Stream is detached');
214 if (!$this->readable) {
215 throw new \RuntimeException(
'Cannot read from non-readable stream');
218 throw new \RuntimeException(
'Length parameter cannot be negative');
225 $string = fread($this->stream, $length);
226 if (
false === $string) {
227 throw new \RuntimeException(
'Unable to read from stream');
235 if (!isset($this->stream)) {
236 throw new \RuntimeException(
'Stream is detached');
238 if (!$this->writable) {
239 throw new \RuntimeException(
'Cannot write to a non-writable stream');
244 $result = fwrite($this->stream, $string);
246 if ($result ===
false) {
247 throw new \RuntimeException(
'Unable to write to stream');
255 if (!isset($this->stream)) {
256 return $key ? null : [];
258 return $this->customMetadata + stream_get_meta_data($this->stream);
259 } elseif (isset($this->customMetadata[$key])) {
260 return $this->customMetadata[$key];
263 $meta = stream_get_meta_data($this->stream);
265 return isset($meta[$key]) ? $meta[$key] :
null;