StringStream::stream_write()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 10
ccs 8
cts 8
cp 1
crap 2
rs 10
1
<?php
2
3
/*
4
 * Adapted for use in ntentan\utils from dvdoug\stringstream package.
5
 */
6
7
namespace ntentan\utils;
8
9
/**
10
 * Stream wrapper for strings which allows you to read strings as though they
11
 * were I/O streams.
12
 * @author Doug Wright, James Ainooson
13
 * @package StringStream
14
 */
15
class StringStream
16
{
17
18
    /**
19
     * Content of stream
20
     * @var array
21
     */
22
    private static $string = [];
23
24
    /**
25
     * Whether this stream can be read
26
     * @var boolean
27
     */
28
    private $read;
29
30
    /**
31
     * Whether this stream can be written
32
     * @var boolean
33
     */
34
    private $write;
35
36
    /**
37
     * Options
38
     * @var int
39
     */
40
    private $options;
41
42
    /**
43
     * Current position within stream
44
     * @var int
45
     */
46
    private $position;
47
    private $path;
48
    private static $registered = false;
49
    
50
    public $context;
51
52 9
    private function setFlags($read, $write, $position)
53
    {
54 9
        $this->read = $read;
55 9
        $this->write = $write;
56 9
        $this->position = $position;
57
    }
58
59
    /**
60
     * Open a stream
61
     *
62
     * @param string $aPath
63
     * @param string $aMode
64
     * @param int $aOptions
65
     * @param string $aOpenedPath
66
     * @return boolean
67
     * @throws exceptions\StringStreamException
68
     */
69 10
    public function stream_open($aPath, $aMode, $aOptions, &$aOpenedPath)
70
    {
71 10
        $this->path = substr($aPath, 9);
72 10
        if (!isset(self::$string[$this->path])) {
73 10
            self::$string[$this->path] = '';
74
        }
75 10
        $this->options = $aOptions;
76 10
        $aOpenedPath = $this->path;
77 10
        $lenght = strlen(self::$string[$this->path]);
78 10
        $flags = [
79 10
            'r' => [true, false, 0],
80 10
            'rb' => [true, false, 0],
81 10
            'r+' => [true, true, 0],
82 10
            'c+' => [true, true, 0],
83 10
            'w' => [false, true, 0],
84 10
            'wb' => [false, true, 0],
85 10
            'w+' => [true, true, 0],
86 10
            'a' => [false, true, $lenght],
87 10
            'a+' => [true, true, $lenght],
88 10
            'c' => [false, true, 0]
89 10
        ];
90
91 10
        if (isset($flags[$aMode])) {
92 9
            $flag = $flags[$aMode];
93 9
            $this->setFlags($flag[0], $flag[1], $flag[2]);
94
        } else {
95 1
            throw new exceptions\StringStreamException("Unknown stream mode '{$aMode}'");
96
        }
97
98 9
        if ($aMode === 'w+') {
99 1
            $this->stream_truncate(0);
100
        }
101
102 9
        return true;
103
    }
104
105
    /**
106
     * Read from stream
107
     * @param int $aBytes number of bytes to return
108
     * @return string|bool
109
     */
110 7
    public function stream_read($aBytes)
111
    {
112 7
        if ($this->read) {
113 6
            $read = substr(self::$string[$this->path], $this->position, $aBytes);
114 6
            $this->position += strlen($read);
115 6
            return $read;
116
        } else {
117 1
            return false;
118
        }
119
    }
120
121
    /**
122
     * Write to stream
123
     * @param string $aData data to write
124
     * @return int|bool
125
     */
126 9
    public function stream_write($aData)
127
    {
128 9
        if ($this->write) {
129 9
            $left = substr(self::$string[$this->path], 0, $this->position);
130 9
            $right = substr(self::$string[$this->path], $this->position + strlen($aData));
131 9
            self::$string[$this->path] = $left . $aData . $right;
132 9
            $this->position += strlen($aData);
133 9
            return strlen($aData);
134
        } else {
135 1
            return false;
136
        }
137
    }
138
139
    /**
140
     * Return current position
141
     * @return int
142
     */
143 6
    public function stream_tell()
144
    {
145 6
        return $this->position;
146
    }
147
148
    /**
149
     * Return if EOF
150
     * @return boolean
151
     */
152 6
    public function stream_eof()
153
    {
154 6
        return $this->position >= strlen(self::$string[$this->path]);
155
    }
156
157
    /**
158
     * Seek to new position
159
     * @param int $aOffset
160
     * @param int $aWhence
161
     * @return boolean
162
     */
163 6
    public function stream_seek($aOffset, $aWhence)
164
    {
165
        switch ($aWhence) {
166 6
            case SEEK_SET:
167 3
                $this->position = $aOffset;
168 3
                if ($aOffset > strlen(self::$string[$this->path])) {
169 1
                    $this->stream_truncate($aOffset);
170
                }
171 3
                return true;
172
173 4
            case SEEK_CUR:
174 4
                $this->position += $aOffset;
175 4
                return true;
176
177 2
            case SEEK_END:
178 2
                $this->position = strlen(self::$string[$this->path]) + $aOffset;
179 2
                if (($this->position + $aOffset) > strlen(self::$string[$this->path])) {
180 1
                    $this->stream_truncate(strlen(self::$string[$this->path]) + $aOffset);
181
                }
182 2
                return true;
183
184
            default:
185
                return false;
186
        }
187
    }
188
189
    /**
190
     * Truncate to given size
191
     * @param int $aSize
192
     * @return bool
193
     */
194 3
    public function stream_truncate($aSize)
195
    {
196 3
        if (strlen(self::$string[$this->path]) > $aSize) {
197 1
            self::$string[$this->path] = substr(self::$string[$this->path], 0, $aSize);
198 2
        } else if (strlen(self::$string[$this->path]) < $aSize) {
199 2
            self::$string[$this->path] = str_pad(self::$string[$this->path], $aSize, "\0", STR_PAD_RIGHT);
200
        }
201 3
        return true;
202
    }
203
204
    /**
205
     * Return info about stream
206
     * @return array
207
     */
208 1
    public function stream_stat()
209
    {
210 1
        return array('dev' => 0,
211 1
            'ino' => 0,
212 1
            'mode' => 0,
213 1
            'nlink' => 0,
214 1
            'uid' => 0,
215 1
            'gid' => 0,
216 1
            'rdev' => 0,
217 1
            'size' => strlen(self::$string[$this->path]),
218 1
            'atime' => 0,
219 1
            'mtime' => 0,
220 1
            'ctime' => 0,
221 1
            'blksize' => -1,
222 1
            'blocks' => -1);
223
    }
224
225
    /**
226
     * Return info about stream
227
     * @param string $aPath
228
     * @return array
229
     */
230 1
    public function url_stat($aPath)
231
    {
232 1
        $resource = fopen($aPath, 'r');
233 1
        return fstat($resource);
234
    }
235
236
    /**
237
     * @param string $protocol
238
     * @throws exceptions\StringStreamException
239
     */
240 10
    public static function register($protocol = 'string')
241
    {
242 10
        if (!self::$registered) {
243 10
            if (in_array($protocol, stream_get_wrappers())) {
244
                throw new exceptions\StringStreamException("An existing wrapper already exists for '$protocol'");
245
            }
246 10
            stream_wrapper_register("string", __CLASS__);
247 10
            self::$registered = true;
248
        }
249
    }
250
251 10
    public static function unregister()
252
    {
253 10
        if (self::$registered) {
254 10
            stream_wrapper_unregister('string');
255 10
            self::$registered = false;
256 10
            self::$string = [];
257
        }
258
    }
259
260
}
261