Passed
Push — master ( b65012...5ddc87 )
by Zlatin
01:29
created

Stream   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 240
Duplicated Lines 0 %

Test Coverage

Coverage 49.35%

Importance

Changes 0
Metric Value
dl 0
loc 240
ccs 38
cts 77
cp 0.4935
rs 9.3999
c 0
b 0
f 0
wmc 33

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getMetadata() 0 13 3
A isWritable() 0 8 2
A isSeekable() 0 11 3
A write() 0 7 2
A isReadable() 0 8 2
A tell() 0 7 2
A read() 0 7 2
A __toString() 0 6 2
A close() 0 8 2
A getContents() 0 13 3
A eof() 0 7 2
A detach() 0 6 1
A __construct() 0 3 1
A rewind() 0 7 2
A getSize() 0 8 2
A seek() 0 7 2
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 84
    public function __construct($handle)
36
    {
37 84
        $this->stream = $handle;
38 84
    }
39
40
    /**
41
     * @return string
42
     */
43 12
    public function __toString()
44
    {
45
        try {
46 12
            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 12
    public function getContents()
93
    {
94 12
        if (!$this->stream) {
95
            throw new \RuntimeException('Empty stream');
96
        }
97
98 12
        if (!$this->isReadable()) {
99
            throw new \RuntimeException('Unable to read stream');
100
        }
101
102 12
        $this->rewind();
103
104 12
        return stream_get_contents($this->stream);
105
    }
106
107
    /**
108
     * @param string|null $key
109
     * @return mixed
110
     */
111 18
    public function getMetadata($key = null)
112
    {
113 18
        $metadata = stream_get_meta_data($this->stream);
114
115 18
        if (null === $key) {
116
            return $metadata;
117
        }
118
119 18
        if (isset($metadata[$key])) {
120 18
            return $metadata[$key];
121
        }
122
123
        return null;
124
    }
125
126
    /**
127
     * @return int
128
     */
129 4
    public function getSize()
130
    {
131 4
        $fstats = fstat($this->stream);
132 4
        if (isset($fstats['size'])) {
133 4
            return $fstats['size'];
134
        }
135
136
        return null;
137
    }
138
139
    /**
140
     * @return boolean
141
     */
142 14
    public function isReadable()
143
    {
144 14
        if (!$this->stream) {
145
            return false;
146
        }
147
148 14
        $mode = $this->getMetadata('mode');
149 14
        return isset(self::$modes['readable'][$mode]);
150
    }
151
152
    /**
153
     * @return boolean
154
     */
155 14
    public function isSeekable()
156
    {
157 14
        if (!$this->stream) {
158
            return false;
159
        }
160
161 14
        if ($this->getMetadata('seekable')) {
162 14
            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 12
    public function rewind()
199
    {
200 12
        if (!$this->isSeekable()) {
201
            throw new \RuntimeException('Stream is not seekable');
202
        }
203
204 12
        $this->seek(0);
205 12
    }
206
207
    /**
208
     * @param int $offset
209
     * @param int $whence
210
     * @throws \RuntimeException
211
     */
212 12
    public function seek($offset, $whence = SEEK_SET)
213
    {
214 12
        if (!$this->isSeekable()) {
215
            throw new \RuntimeException('Stream is not seekable');
216
        }
217
218 12
        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