Completed
Push — remove-yii-autoloader ( 560d61...5f8600 )
by Alexander
27:04 queued 23:12
created

FileStream   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 36
lcom 1
cbo 4
dl 0
loc 234
rs 8.8
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __destruct() 0 4 1
A getResource() 0 11 3
A __toString() 0 12 2
A close() 0 8 2
A detach() 0 10 2
A getSize() 0 14 3
A tell() 0 8 2
A eof() 0 4 1
A isSeekable() 0 4 1
A seek() 0 6 2
A rewind() 0 4 1
A isWritable() 0 10 3
A write() 0 8 2
A isReadable() 0 10 3
A read() 0 8 2
A getContents() 0 8 2
A getMetadata() 0 12 4
1
<?php
2
/**
3
 * @link http://www.yiiframework.com/
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5
 * @license http://www.yiiframework.com/license/
6
 */
7
8
namespace yii\http;
9
10
use Psr\Http\Message\StreamInterface;
11
use Yii;
12
use yii\base\BaseObject;
13
use yii\base\ErrorHandler;
14
use yii\base\InvalidConfigException;
15
16
/**
17
 * FileStream represents file stream.
18
 *
19
 * Example:
20
 *
21
 * ```php
22
 * $stream = new FileSteam([
23
 *     'filename' => '@app/files/items.txt',
24
 *     'mode' => 'w+',
25
 * ]);
26
 *
27
 * $stream->write('some content...');
28
 * $stream->close();
29
 * ```
30
 *
31
 * @author Paul Klimov <[email protected]>
32
 * @since 2.1.0
33
 */
34
class FileStream extends BaseObject implements StreamInterface
35
{
36
    /**
37
     * @var string file or stream name.
38
     * Path alias can be used here, for example: '@app/runtime/items.csv'.
39
     * This field can also be PHP stream name, e.g. anything which can be passed to `fopen()`, for example: 'php://input'.
40
     */
41
    public $filename;
42
    /**
43
     * @var string file open mode.
44
     */
45
    public $mode = 'r';
46
47
    /**
48
     * @var resource|null stream resource
49
     */
50
    private $_resource;
51
    /**
52
     * @var array a resource metadata.
53
     */
54
    private $_metadata;
55
56
57
    /**
58
     * Destructor.
59
     * Closes the stream resource when destroyed.
60
     */
61
    public function __destruct()
62
    {
63
        $this->close();
64
    }
65
66
    /**
67
     * @return resource a file pointer resource.
68
     * @throws InvalidConfigException if unable to open a resource.
69
     */
70
    public function getResource()
71
    {
72
        if ($this->_resource === null) {
73
            $resource = fopen(Yii::getAlias($this->filename), $this->mode);
74
            if ($resource === false) {
75
                throw new InvalidConfigException("Unable to open file '{$this->filename}' with mode '{$this->mode}'");
76
            }
77
            $this->_resource = $resource;
78
        }
79
        return $this->_resource;
80
    }
81
82
    /**
83
     * {@inheritdoc}
84
     */
85
    public function __toString()
86
    {
87
        // __toString cannot throw exception
88
        // use trigger_error to bypass this limitation
89
        try {
90
            $this->seek(0);
91
            return $this->getContents();
92
        } catch (\Exception $e) {
93
            ErrorHandler::convertExceptionToError($e);
94
            return '';
95
        }
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function close()
102
    {
103
        if ($this->_resource !== null) {
104
            fclose($this->_resource);
105
            $this->_resource = null;
106
            $this->_metadata = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_metadata.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
107
        }
108
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113
    public function detach()
114
    {
115
        if ($this->_resource === null) {
116
            return null;
117
        }
118
        $result = $this->_resource;
119
        $this->_resource = null;
120
        $this->_metadata = null;
0 ignored issues
show
Documentation Bug introduced by
It seems like null of type null is incompatible with the declared type array of property $_metadata.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
121
        return $result;
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function getSize()
128
    {
129
        $uri = $this->getMetadata('uri');
130
        if (!empty($uri)) {
131
            // clear the stat cache in case stream has a URI
132
            clearstatcache(true, $uri);
133
        }
134
135
        $stats = fstat($this->getResource());
136
        if (isset($stats['size'])) {
137
            return $stats['size'];
138
        }
139
        return null;
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function tell()
146
    {
147
        $result = ftell($this->getResource());
148
        if ($result === false) {
149
            throw new \RuntimeException('Unable to determine stream position');
150
        }
151
        return $result;
152
    }
153
154
    /**
155
     * {@inheritdoc}
156
     */
157
    public function eof()
158
    {
159
        return feof($this->getResource());
160
    }
161
162
    /**
163
     * {@inheritdoc}
164
     */
165
    public function isSeekable()
166
    {
167
        return (bool)$this->getMetadata('seekable');
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173
    public function seek($offset, $whence = SEEK_SET)
174
    {
175
        if (fseek($this->getResource(), $offset, $whence) === -1) {
176
            throw new \RuntimeException("Unable to seek to stream position '{$offset}' with whence '{$whence}'");
177
        }
178
    }
179
180
    /**
181
     * {@inheritdoc}
182
     */
183
    public function rewind()
184
    {
185
        $this->seek(0);
186
    }
187
188
    /**
189
     * {@inheritdoc}
190
     */
191
    public function isWritable()
192
    {
193
        $mode = $this->getMetadata('mode');
194
        foreach (['w', 'c', 'a', 'x', 'r+'] as $key) {
195
            if (strpos($mode, $key) !== false) {
196
                return true;
197
            }
198
        }
199
        return false;
200
    }
201
202
    /**
203
     * {@inheritdoc}
204
     */
205
    public function write($string)
206
    {
207
        $result = fwrite($this->getResource(), $string);
208
        if ($result === false) {
209
            throw new \RuntimeException('Unable to write to stream');
210
        }
211
        return $result;
212
    }
213
214
    /**
215
     * {@inheritdoc}
216
     */
217
    public function isReadable()
218
    {
219
        $mode = $this->getMetadata('mode');
220
        foreach (['r', 'w+', 'a+', 'c+', 'x+'] as $key) {
221
            if (strpos($mode, $key) !== false) {
222
                return true;
223
            }
224
        }
225
        return false;
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    public function read($length)
232
    {
233
        $string = fread($this->getResource(), $length);
234
        if ($string === false) {
235
            throw new \RuntimeException('Unable to read from stream');
236
        }
237
        return $string;
238
    }
239
240
    /**
241
     * {@inheritdoc}
242
     */
243
    public function getContents()
244
    {
245
        $contents = stream_get_contents($this->getResource());
246
        if ($contents === false) {
247
            throw new \RuntimeException('Unable to read stream contents');
248
        }
249
        return $contents;
250
    }
251
252
    /**
253
     * {@inheritdoc}
254
     */
255
    public function getMetadata($key = null)
256
    {
257
        if ($this->_metadata === null) {
258
            $this->_metadata = stream_get_meta_data($this->getResource());
259
        }
260
261
        if ($key === null) {
262
            return $this->_metadata;
263
        }
264
265
        return isset($this->_metadata[$key]) ? $this->_metadata[$key] : null;
266
    }
267
}