Stream::write()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

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