Passed
Push — master ( 8fd177...8c2cea )
by Rougin
03:08
created

Stream::rewind()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Zapheus\Bridge\Psr;
4
5
use Psr\Http\Message\StreamInterface;
6
7
/**
8
 * Stream
9
 *
10
 * @package Zapheus
11
 * @author  Rougin Royce Gutib <[email protected]>
12
 */
13
class Stream implements StreamInterface
14
{
15
    /**
16
     * @var array|null
17
     */
18
    protected $meta = null;
19
20
    /**
21
     * @var array
22
     */
23
    protected $readable = array('r', 'r+', 'w+', 'a+', 'x+', 'c+', 'w+b');
24
25
    /**
26
     * @var integer|null
27
     */
28
    protected $size = null;
29
30
    /**
31
     * @var resource|null
32
     */
33
    protected $stream = null;
34
35
    /**
36
     * @var array
37
     */
38
    protected $writable = array('r+', 'w', 'w+', 'a', 'a+', 'x', 'x+', 'c', 'c+', 'w+b');
39
40
    /**
41
     * Initializes the stream instance.
42
     *
43
     * @param resource|null $stream
44
     */
45 6
    public function __construct($stream = null)
46
    {
47 6
        $this->stream = $stream;
48 6
    }
49
50
    /**
51
     * Reads all data from the stream into a string, from the beginning to end.
52
     *
53
     * @return string
54
     */
55
    public function __toString()
56
    {
57
        $this->rewind();
58
59
        return $this->getContents();
60
    }
61
62
    /**
63
     * Closes the stream and any underlying resources.
64
     *
65
     * @return void
66
     */
67
    public function close()
68
    {
69
        $this->stream === null ?: fclose($this->stream);
70
71
        $this->detach();
72
    }
73
74
    /**
75
     * Separates any underlying resources from the stream.
76
     *
77
     * @return resource|null
78
     */
79
    public function detach()
80
    {
81
        $stream = $this->stream;
82
83
        $this->meta = null;
84
85
        $this->size = null;
86
87
        $this->stream = null;
88
89
        return $stream;
90
    }
91
92
    /**
93
     * Returns true if the stream is at the end of the stream.
94
     *
95
     * @return boolean
96
     */
97
    public function eof()
98
    {
99
        return $this->stream === null ?: feof($this->stream);
100
    }
101
102
    /**
103
     * Returns the remaining contents in a string
104
     *
105
     * @return string
106
     *
107
     * @throws \RuntimeException
108
     */
109
    public function getContents()
110
    {
111
        if ($this->stream === null || ! $this->isReadable()) {
112
            $message = 'Could not get contents of stream';
113
114
            throw new \RuntimeException((string) $message);
115
        }
116
117
        return stream_get_contents($this->stream);
118
    }
119
120
    /**
121
     * Returns stream metadata as an associative array or retrieve a specific key.
122
     *
123
     * @param  string $key
124
     * @return array|mixed|null
125
     */
126
    public function getMetadata($key = null)
127
    {
128
        isset($this->stream) && $this->meta = stream_get_meta_data($this->stream);
129
130
        $metadata = isset($this->meta[$key]) ? $this->meta[$key] : null;
131
132
        return $key === null ? (array) $this->meta : $metadata;
133
    }
134
135
    /**
136
     * Returns the size of the stream if known.
137
     *
138
     * @return integer|null
139
     */
140
    public function getSize()
141
    {
142
        if (is_null($this->size) === true) {
143
            $stats = fstat($this->stream);
144
145
            $this->size = $stats['size'];
146
        }
147
148
        return $this->size;
149
    }
150
151
    /**
152
     * Returns whether or not the stream is readable.
153
     *
154
     * @return boolean
155
     */
156
    public function isReadable()
157
    {
158
        $mode = (string) $this->getMetadata('mode');
159
160
        return in_array($mode, $this->readable);
161
    }
162
163
    /**
164
     * Returns whether or not the stream is seekable.
165
     *
166
     * @return boolean
167
     */
168
    public function isSeekable()
169
    {
170
        return $this->getMetadata('seekable');
171
    }
172
173
    /**
174
     * Returns whether or not the stream is writable.
175
     *
176
     * @return boolean
177
     */
178
    public function isWritable()
179
    {
180
        $mode = (string) $this->getMetadata('mode');
181
182
        return in_array($mode, $this->writable);
183
    }
184
185
    /**
186
     * Read data from the stream.
187
     *
188
     * @param  integer $length
189
     * @return string
190
     *
191
     * @throws \RuntimeException
192
     */
193
    public function read($length)
194
    {
195
        $data = fread($this->stream, $length);
196
197
        if (! $this->isReadable() || $data === false) {
198
            $message = 'Could not read from stream';
199
200
            throw new \RuntimeException($message);
201
        }
202
203
        return $data;
204
    }
205
206
    /**
207
     * Seek to the beginning of the stream.
208
     *
209
     * @throws \RuntimeException
210
     */
211
    public function rewind()
212
    {
213
        $this->seek(0);
214
    }
215
216
    /**
217
     * Seek to a position in the stream.
218
     *
219
     * @param integer $offset
220
     * @param integer $whence
221
     *
222
     * @throws \RuntimeException
223
     */
224
    public function seek($offset, $whence = SEEK_SET)
225
    {
226
        $seek = -1;
227
228
        $this->stream && $seek = fseek($this->stream, $offset, $whence);
229
230
        if (! $this->isSeekable() || $seek === -1) {
231
            $message = 'Could not seek in stream';
232
233
            throw new \RuntimeException($message);
234
        }
235
    }
236
237
    /**
238
     * Returns the current position of the file read/write pointer.
239
     *
240
     * @return integer
241
     *
242
     * @throws \RuntimeException
243
     */
244
    public function tell()
245
    {
246
        $position = false;
247
248
        $this->stream && $position = ftell($this->stream);
249
250
        if ($this->stream === null || $position === false) {
251
            $message = 'Could not get position of pointer in stream';
252
253
            throw new \RuntimeException((string) $message);
254
        }
255
256
        return $position;
257
    }
258
259
    /**
260
     * Write data to the stream.
261
     *
262
     * @param  string $string
263
     * @return integer
264
     *
265
     * @throws \RuntimeException
266
     */
267
    public function write($string)
268
    {
269
        if ($this->isWritable() === false) {
270
            $message = 'Stream is not writable';
271
272
            throw new \RuntimeException($message);
273
        }
274
275
        $this->size = null;
276
277
        return fwrite($this->stream, $string);
278
    }
279
}
280