1 | <?php |
||
19 | { |
||
20 | /** |
||
21 | * @var int |
||
22 | */ |
||
23 | protected const STAT_MTIME_NUMERIC_OFFSET = 9; |
||
24 | |||
25 | /** |
||
26 | * @var string |
||
27 | */ |
||
28 | protected const STAT_MTIME_ASSOC_OFFSET = 'mtime'; |
||
29 | |||
30 | /** |
||
31 | * @var string |
||
32 | */ |
||
33 | protected string $protocol; |
||
|
|||
34 | |||
35 | /** |
||
36 | * @var string |
||
37 | */ |
||
38 | protected string $pathname; |
||
39 | |||
40 | /** |
||
41 | * @var StreamInterface |
||
42 | */ |
||
43 | protected StreamInterface $stream; |
||
44 | |||
45 | /** |
||
46 | * {@inheritDoc} |
||
47 | */ |
||
48 | public function stream_open(string $uri, string $mode, int $options, &$openedPath): bool |
||
49 | 7 | { |
|
50 | [$this->protocol, $this->pathname] = $this->parseUri($uri); |
||
51 | 7 | ||
52 | $this->stream = Stream::get($this->protocol); |
||
53 | 7 | ||
54 | if (\STREAM_USE_PATH & $options && ! \is_file($this->pathname)) { |
||
55 | 7 | $trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS); |
|
56 | 1 | ||
57 | $this->pathname = \dirname($trace[1]['file']) . '/' . $this->pathname; |
||
58 | 1 | } |
|
59 | |||
60 | $this->resource = \fopen('php://memory', 'rb+'); |
||
61 | 7 | ||
62 | \fwrite($this->resource, $this->stream->read($this->pathname)); |
||
63 | 7 | \rewind($this->resource); |
|
64 | 4 | ||
65 | return true; |
||
66 | 4 | } |
|
67 | |||
68 | /** |
||
69 | * @param string $uri |
||
70 | * @return array<string> |
||
71 | * @throws StreamException |
||
72 | */ |
||
73 | private function parseUri(string $uri): array |
||
74 | 7 | { |
|
75 | $chunks = \explode('://', $uri); |
||
76 | 7 | ||
77 | if (\count($chunks) !== 2) { |
||
78 | 7 | $error = \sprintf('Bad protocol format "%s"', $uri); |
|
79 | throw new StreamException($error, StreamException::CODE_STREAM_OPEN); |
||
80 | } |
||
81 | |||
82 | return $chunks; |
||
83 | 7 | } |
|
84 | |||
85 | /** |
||
86 | * {@inheritDoc} |
||
87 | */ |
||
88 | public function stream_read(int $length): string |
||
89 | 4 | { |
|
90 | return ! \feof($this->resource) ? \fread($this->resource, $length) : ''; |
||
91 | 4 | } |
|
92 | |||
93 | /** |
||
94 | * {@inheritDoc} |
||
95 | */ |
||
96 | public function stream_eof(): bool |
||
97 | 4 | { |
|
98 | return \feof($this->resource); |
||
99 | 4 | } |
|
100 | |||
101 | /** |
||
102 | * {@inheritDoc} |
||
103 | */ |
||
104 | public function stream_stat(): array |
||
105 | 3 | { |
|
106 | $stat = \fstat($this->resource); |
||
107 | 3 | ||
108 | if ($stat) { |
||
109 | 3 | ++$stat[static::STAT_MTIME_ASSOC_OFFSET]; |
|
110 | 3 | ++$stat[static::STAT_MTIME_NUMERIC_OFFSET]; |
|
111 | 3 | } |
|
112 | |||
113 | return $stat; |
||
114 | 3 | } |
|
115 | |||
116 | /** |
||
117 | * {@inheritDoc} |
||
118 | */ |
||
119 | public function stream_close(): void |
||
120 | 4 | { |
|
121 | \fclose($this->resource); |
||
122 | 4 | } |
|
123 | 4 | ||
124 | /** |
||
125 | * {@inheritDoc} |
||
126 | */ |
||
127 | public function stream_tell(): int |
||
128 | 1 | { |
|
129 | return (int)\ftell($this->resource); |
||
130 | 1 | } |
|
131 | |||
132 | /** |
||
133 | * {@inheritDoc} |
||
134 | */ |
||
135 | public function stream_seek(int $offset, int $whence = \SEEK_SET): bool |
||
136 | 1 | { |
|
137 | return \fseek($this->resource, $offset, $whence) >= 0; |
||
138 | 1 | } |
|
139 | } |
||
140 |