Completed
Push — master ( c1d4a3...71015f )
by James Ekow Abaka
07:22
created

StringStream::setFlags()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 3
1
<?php
2
3
/*
4
 * Adapted for use in ntentan\utils from dvdoug\stringstream package.
5
 */
6
7
/**
8
 * Stream wrapper for strings.
9
 * 
10
 * @author Doug Wright
11
 */
12
13
namespace ntentan\utils;
14
15
/**
16
 * Stream wrapper for strings which allows you to read strings as though they
17
 * were I/O streams.
18
 * @author Doug Wright
19
 * @package StringStream
20
 */
21
class StringStream 
22
{
23
24
    /**
25
     * Content of stream
26
     * @var string
27
     */
28
    private static $string = [];
29
30
    /**
31
     * Whether this stream can be read
32
     * @var boolean
33
     */
34
    private $read;
35
36
    /**
37
     * Whether this stream can be written
38
     * @var boolean
39
     */
40
    private $write;
41
42
    /**
43
     * Options
44
     * @var int
45
     */
46
    private $options;
47
48
    /**
49
     * Current position within stream
50
     * @var int
51
     */
52
    private $position;
53
    private $path;
54
    private static $registered = false;
55
56
    private function setFlags($read, $write, $position)
57
    {
58
        $this->read = $read;
59
        $this->write = $write;
60
        $this->position = $position;
61
    }
62
63
    /**
64
     * Open stream
65
     * @param string $aPath
66
     * @param string $aMode
67
     * @param int $aOptions
68
     * @param string $aOpenedPath
69
     * @return boolean
70
     */
71
    public function stream_open($aPath, $aMode, $aOptions, &$aOpenedPath) 
72
    {
73
        $this->path = substr($aPath, 9);
74
        if (!isset(self::$string[$this->path])) {
75
            self::$string[$this->path] = '';
76
        }
77
        $this->options = $aOptions;
78
        $aOpenedPath = $this->path;
79
80
        switch ($aMode) {
81
82
            case 'r':
83
            case 'rb':
84
                $this->setFlags(true, false, 0);
85
                break;
86
87
            case 'r+':
88
            case 'c+':
89
                $this->setFlags(true, true, 0);
90
                break;
91
92
            case 'w':
93
            case 'wb':
94
                $this->setFlags(false, true, 0);
95
                break;
96
97
            case 'w+':
98
                $this->setFlags(true, true, 0);
99
                $this->stream_truncate(0);
100
                break;
101
102 View Code Duplication
            case 'a':
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
103
                $this->setFlags(false, true, strlen(self::$string[$this->path]));
104
                break;
105
106 View Code Duplication
            case 'a+':
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
107
                $this->setFlags(true, true, strlen(self::$string[$this->path]));
108
                break;
109
110
            case 'c':
111
                $this->setFlags(false, true, 0);
112
                break;
113
114
            default:
115
                trigger_error($aMode . 'Invalid mode specified (mode specified makes no sense for this stream implementation)', E_USER_ERROR);
116
        }
117
118
        return true;
119
    }
120
121
    /**
122
     * Read from stream
123
     * @param int $aBytes number of bytes to return
124
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
125
     */
126
    function stream_read($aBytes) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
127
        if ($this->read) {
128
            $read = substr(self::$string[$this->path], $this->position, $aBytes);
129
            $this->position += strlen($read);
130
            return $read;
131
        } else {
132
            return false;
133
        }
134
    }
135
136
    /**
137
     * Write to stream
138
     * @param string $aData data to write
139
     * @return int
140
     */
141
    function stream_write($aData) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
142
        if ($this->write) {
143
            $left = substr(self::$string[$this->path], 0, $this->position);
144
            $right = substr(self::$string[$this->path], $this->position + strlen($aData));
145
            self::$string[$this->path] = $left . $aData . $right;
146
            $this->position += strlen($aData);
147
            return strlen($aData);
148
        } else {
149
            return 0;
150
        }
151
    }
152
153
    /**
154
     * Return current position
155
     * @return int
156
     */
157
    function stream_tell() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
158
        return $this->position;
159
    }
160
161
    /**
162
     * Return if EOF
163
     * @return boolean
164
     */
165
    function stream_eof() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
166
        return $this->position >= strlen(self::$string[$this->path]);
167
    }
168
169
    /**
170
     * Seek to new position
171
     * @param int $aOffset
172
     * @param int $aWhence
173
     * @return boolean
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
174
     */
175
    function stream_seek($aOffset, $aWhence) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
176
        switch ($aWhence) {
177
            case SEEK_SET:
178
                $this->position = $aOffset;
179
                if ($aOffset > strlen(self::$string[$this->path])) {
180
                    $this->stream_truncate($aOffset);
181
                }
182
                return true;
183
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
184
185
            //XXX Code coverage testing shows PHP truncates automatically for SEEK_CUR
186
            case SEEK_CUR:
187
                $this->position += $aOffset;
188
                return true;
189
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
190
191
            case SEEK_END:
192
                $this->position = strlen(self::$string[$this->path]) + $aOffset;
193
                if (($this->position + $aOffset) > strlen(self::$string[$this->path])) {
194
                    $this->stream_truncate(strlen(self::$string[$this->path]) + $aOffset);
195
                }
196
                return true;
197
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
198
199
            default:
200
                return false;
201
        }
202
    }
203
204
    /**
205
     * Truncate to given size
206
     * @param int $aSize
207
     */
208
    public function stream_truncate($aSize) {
209
        if (strlen(self::$string[$this->path]) > $aSize) {
210
            self::$string[$this->path] = substr(self::$string[$this->path], 0, $aSize);
211
        } else if (strlen(self::$string[$this->path]) < $aSize) {
212
            self::$string[$this->path] = str_pad(self::$string[$this->path], $aSize, "\0", STR_PAD_RIGHT);
213
        }
214
        return true;
215
    }
216
217
    /**
218
     * Return info about stream
219
     * @return array
220
     */
221
    public function stream_stat() {
222
        return array('dev' => 0,
223
            'ino' => 0,
224
            'mode' => 0,
225
            'nlink' => 0,
226
            'uid' => 0,
227
            'gid' => 0,
228
            'rdev' => 0,
229
            'size' => strlen(self::$string[$this->path]),
230
            'atime' => 0,
231
            'mtime' => 0,
232
            'ctime' => 0,
233
            'blksize' => -1,
234
            'blocks' => -1);
235
    }
236
237
    /**
238
     * Return info about stream
239
     * @param string $aPath
240
     * @param array $aOptions
241
     * @return array
242
     */
243
    public function url_stat($aPath, $aOptions) {
0 ignored issues
show
Unused Code introduced by
The parameter $aOptions is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
244
        $resource = fopen($aPath, 'r');
245
        return fstat($resource);
246
    }
247
248
    public static function register() {
249
        if (!self::$registered) {
250
            if (in_array("string", stream_get_wrappers())) {
251
                stream_wrapper_unregister("string");
252
            }
253
            stream_wrapper_register("string", __CLASS__);
254
            self::$registered = true;
255
        }
256
    }
257
258
    public static function unregister() {
259
        if (self::$registered) {
260
            stream_wrapper_unregister('string');
261
        }
262
    }
263
264
}
265