Stream::getContents()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.2098

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 0
dl 0
loc 13
ccs 5
cts 7
cp 0.7143
crap 3.2098
rs 10
c 0
b 0
f 0
1
<?php
2
namespace DevOp\Core\Http;
3
4
use Psr\Http\Message\StreamInterface;
5
6
class Stream implements StreamInterface
7
{
8
9
    /**
10
     * @var array
11
     */
12
    private static $modes = [
13
        'readable' => [
14
            'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
15
            'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
16
            'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
17
            'x+t' => true, 'c+t' => true, 'a+' => true
18
        ],
19
        'writable' => [
20
            'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
21
            'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
22
            'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
23
            'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
24
        ],
25
    ];
26
27
    /**
28
     * @var resource
29
     */
30
    private $stream;
31
32
    /**
33
     * @param resource $handle
34
     */
35 36
    public function __construct($handle)
36
    {
37 36
        $this->stream = $handle;
38 36
    }
39
40
    /**
41
     * @return string
42
     */
43 2
    public function __toString()
44
    {
45
        try {
46 2
            return $this->getContents();
47
        } catch (\Exception $e) {
48
            return '';
49
        }
50
    }
51
52
    /**
53
     * @return boolean
54
     */
55
    public function close()
56
    {
57
        if (!$this->stream) {
58
            return;
59
        }
60
61
        $handle = $this->detach();
62
        fclose($handle);
63
    }
64
65
    /**
66
     * @return resource
67
     */
68
    public function detach()
69
    {
70
        $handle = $this->stream;
71
        $this->stream = null;
72
73
        return $handle;
74
    }
75
76
    /**
77
     * @return boolean
78
     */
79
    public function eof()
80
    {
81
        if (!$this->stream) {
82
            return true;
83
        }
84
85
        return feof($this->stream);
86
    }
87
88
    /**
89
     * @return string
90
     * @throws \RuntimeException
91
     */
92 2
    public function getContents()
93
    {
94 2
        if (!$this->stream) {
95
            throw new \RuntimeException('Empty stream');
96
        }
97
98 2
        if (!$this->isReadable()) {
99
            throw new \RuntimeException('Unable to read stream');
100
        }
101
102 2
        $this->rewind();
103
104 2
        return stream_get_contents($this->stream);
105
    }
106
107
    /**
108
     * @param string|null $key
109
     * @return mixed
110
     */
111 8
    public function getMetadata($key = null)
112
    {
113 8
        $metadata = stream_get_meta_data($this->stream);
114
115 8
        if (null === $key) {
116
            return $metadata;
117
        }
118
119 8
        if (isset($metadata[$key])) {
120 8
            return $metadata[$key];
121
        }
122
123
        return null;
124
    }
125
126
    /**
127
     * @return int
128
     */
129
    public function getSize()
130
    {
131
        $fstats = fstat($this->stream);
132
        if (isset($fstats['size'])) {
133
            return $fstats['size'];
134
        }
135
136
        return null;
137
    }
138
139
    /**
140
     * @return boolean
141
     */
142 4
    public function isReadable()
143
    {
144 4
        if (!$this->stream) {
145
            return false;
146
        }
147
148 4
        $mode = $this->getMetadata('mode');
149 4
        return isset(self::$modes['readable'][$mode]);
150
    }
151
152
    /**
153
     * @return boolean
154
     */
155 4
    public function isSeekable()
156
    {
157 4
        if (!$this->stream) {
158
            return false;
159
        }
160
161 4
        if ($this->getMetadata('seekable')) {
162 4
            return true;
163
        }
164
165
        return false;
166
    }
167
168
    /**
169
     * @return boolean
170
     */
171 2
    public function isWritable()
172
    {
173 2
        if (!$this->stream) {
174
            return false;
175
        }
176
177 2
        $mode = $this->getMetadata('mode');
178 2
        return isset(self::$modes['writable'][$mode]);
179
    }
180
181
    /**
182
     * @param int $length
183
     * @return string
184
     * @throws \RuntimeException
185
     */
186
    public function read($length)
187
    {
188
        if (!$this->isReadable()) {
189
            throw new \RuntimeException('Stream is not readable');
190
        }
191
192
        return fread($this->stream, $length);
193
    }
194
195
    /**
196
     * @throws \RuntimeException
197
     */
198 2
    public function rewind()
199
    {
200 2
        if (!$this->isSeekable()) {
201
            throw new \RuntimeException('Stream is not seekable');
202
        }
203
204 2
        $this->seek(0);
205 2
    }
206
207
    /**
208
     * @param int $offset
209
     * @param int $whence
210
     * @throws \RuntimeException
211
     */
212 2
    public function seek($offset, $whence = SEEK_SET)
213
    {
214 2
        if (!$this->isSeekable()) {
215
            throw new \RuntimeException('Stream is not seekable');
216
        }
217
218 2
        return fseek($this->stream, $offset, $whence);
219
    }
220
221
    /**
222
     * @return int
223
     * @throws \RuntimeException
224
     */
225
    public function tell()
226
    {
227
        if (!$this->stream) {
228
            throw new \RuntimeException('Invalid stream handle');
229
        }
230
231
        return ftell($this->stream);
232
    }
233
234
    /**
235
     * @param string $string
236
     * @return int
237
     * @throws \RuntimeException
238
     */
239
    public function write($string)
240
    {
241
        if (!$this->isWritable()) {
242
            throw new \RuntimeException('Stream is not writable');
243
        }
244
245
        return fwrite($this->stream, $string);
246
    }
247
}
248