3 declare(strict_types=1);
39 'r' => self::MASK_ACCESS_READ,
40 'w+' => self::MASK_ACCESS_READ_WRITE,
41 'r+' => self::MASK_ACCESS_READ_WRITE,
42 'x+' => self::MASK_ACCESS_READ_WRITE,
43 'c+' => self::MASK_ACCESS_READ_WRITE,
44 'rb' => self::MASK_ACCESS_READ,
45 'w+b' => self::MASK_ACCESS_READ_WRITE,
46 'r+b' => self::MASK_ACCESS_READ_WRITE,
47 'x+b' => self::MASK_ACCESS_READ_WRITE,
48 'c+b' => self::MASK_ACCESS_READ_WRITE,
49 'rt' => self::MASK_ACCESS_READ,
50 'w+t' => self::MASK_ACCESS_READ_WRITE,
51 'r+t' => self::MASK_ACCESS_READ_WRITE,
52 'x+t' => self::MASK_ACCESS_READ_WRITE,
53 'c+t' => self::MASK_ACCESS_READ_WRITE,
54 'a+' => self::MASK_ACCESS_READ_WRITE,
55 'w' => self::MASK_ACCESS_WRITE,
56 'rw' => self::MASK_ACCESS_WRITE,
57 'wb' => self::MASK_ACCESS_WRITE,
58 'a' => self::MASK_ACCESS_WRITE
69 private ?
string $uri = null;
85 throw new \InvalidArgumentException(
'Stream must be a valid resource but "' . gettype(
$stream) .
'" was given.');
88 if ($options !== null) {
89 $this->customMetadata = $options->getMetadata();
90 $this->size = ($options->getSize() !== -1) ? $options->getSize() : null;
92 $this->customMetadata = [];
97 $meta = stream_get_meta_data($this->stream);
98 $mode = $meta[
'mode'];
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']);
112 if (is_resource($this->stream)) {
126 $this->stream = $this->size = $this->uri = null;
138 if ($this->size !== null) {
143 if ($this->stream === null) {
148 if ($this->uri !== null) {
149 clearstatcache(
true, $this->uri);
152 $stats = fstat($this->stream);
153 if (array_key_exists(
'size', $stats)) {
154 $this->size = $stats[
'size'];
172 if ($result ===
false) {
173 throw new \RuntimeException(
'Unable to determine stream position');
183 public function eof(): bool
187 return feof($this->stream);
203 public function seek($offset, $whence = SEEK_SET): void
208 throw new \RuntimeException(
'Stream is not seekable');
212 throw new \RuntimeException(
"Unable to seek to stream position \"$offset\" with whence \"$whence\"");
243 throw new \RuntimeException(
'Can not write to a non-writable stream');
250 if ($result ===
false) {
251 throw new \RuntimeException(
'Unable to write to stream');
275 throw new \RuntimeException(
'Can not read from non-readable stream');
279 throw new \RuntimeException(
'Length parameter must not be negative');
287 if ($junk ===
false) {
288 throw new \RuntimeException(
'Unable to read from stream');
304 if ($content ===
false) {
305 throw new \RuntimeException(
'Unable to read stream contents');
319 if ($this->stream === null) {
325 return array_merge(stream_get_meta_data($this->stream), $this->customMetadata);
331 if (array_key_exists(
$key, $this->customMetadata)) {
332 return $this->customMetadata[
$key];
336 $meta = stream_get_meta_data($this->stream);
337 if (array_key_exists(
$key, $meta)) {
367 if (!is_null($this->stream)) {
381 if ($this->stream === null) {
382 throw new \RuntimeException(
'Stream is detached');
static ftell($handle)
ftell wrapper
static fseek($stream, int $offset, int $whence)
static fread($handle, int $length)
seek($offset, $whence=SEEK_SET)
assertStreamAttached()
Checks if the stream is attached to the wrapper.
static array bool $readable
__construct($stream, StreamOptions $options=null)
Stream constructor.
const MASK_ACCESS_READ_WRITE
static fwrite($handle, string $string, ?int $length=null)
static stream_get_contents($handle, $length=-1)