Completed
Push — master ( 71015f...3f6794 )
by James Ekow Abaka
01:26
created

StringStream::stream_open()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 35
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 25
nc 8
nop 4
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
        $lenght = strlen(self::$string[$this->path]);
80
        $flags = [
81
            'r' => [true, false, 0],
82
            'rb' => [true, false, 0],
83
            'r+' => [true, true, 0],
84
            'c+' => [true, true, 0],
85
            'w' => [false, true, 0],
86
            'wb' => [false, true, 0],
87
            'w+' => [true, true, 0],
88
            'a' => [false, true, $lenght],
89
            'a+' => [true, true, $lenght],
90
            'c' => [false, true, 0]
91
        ];
92
        
93
        if(isset($flags[$aMode])) {
94
            $flag = $flagss[$aMode];
0 ignored issues
show
Bug introduced by
The variable $flagss does not exist. Did you mean $flags?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
95
            $this->setFlags($flag[0], $flag[1], $flag[2]);
96
        } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
97
            // Throw an exception here
98
        }
99
100
        if($aMode === 'w+') {
101
            $this->stream_truncate(0);
102
        }
103
104
        return true;
105
    }
106
107
    /**
108
     * Read from stream
109
     * @param int $aBytes number of bytes to return
110
     * @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...
111
     */
112
    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...
113
        if ($this->read) {
114
            $read = substr(self::$string[$this->path], $this->position, $aBytes);
115
            $this->position += strlen($read);
116
            return $read;
117
        } else {
118
            return false;
119
        }
120
    }
121
122
    /**
123
     * Write to stream
124
     * @param string $aData data to write
125
     * @return int
126
     */
127
    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...
128
        if ($this->write) {
129
            $left = substr(self::$string[$this->path], 0, $this->position);
130
            $right = substr(self::$string[$this->path], $this->position + strlen($aData));
131
            self::$string[$this->path] = $left . $aData . $right;
132
            $this->position += strlen($aData);
133
            return strlen($aData);
134
        } else {
135
            return 0;
136
        }
137
    }
138
139
    /**
140
     * Return current position
141
     * @return int
142
     */
143
    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...
144
        return $this->position;
145
    }
146
147
    /**
148
     * Return if EOF
149
     * @return boolean
150
     */
151
    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...
152
        return $this->position >= strlen(self::$string[$this->path]);
153
    }
154
155
    /**
156
     * Seek to new position
157
     * @param int $aOffset
158
     * @param int $aWhence
159
     * @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...
160
     */
161
    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...
162
        switch ($aWhence) {
163
            case SEEK_SET:
164
                $this->position = $aOffset;
165
                if ($aOffset > strlen(self::$string[$this->path])) {
166
                    $this->stream_truncate($aOffset);
167
                }
168
                return true;
169
                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...
170
171
            //XXX Code coverage testing shows PHP truncates automatically for SEEK_CUR
172
            case SEEK_CUR:
173
                $this->position += $aOffset;
174
                return true;
175
                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...
176
177
            case SEEK_END:
178
                $this->position = strlen(self::$string[$this->path]) + $aOffset;
179
                if (($this->position + $aOffset) > strlen(self::$string[$this->path])) {
180
                    $this->stream_truncate(strlen(self::$string[$this->path]) + $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
            default:
186
                return false;
187
        }
188
    }
189
190
    /**
191
     * Truncate to given size
192
     * @param int $aSize
193
     */
194
    public function stream_truncate($aSize) {
195
        if (strlen(self::$string[$this->path]) > $aSize) {
196
            self::$string[$this->path] = substr(self::$string[$this->path], 0, $aSize);
197
        } else if (strlen(self::$string[$this->path]) < $aSize) {
198
            self::$string[$this->path] = str_pad(self::$string[$this->path], $aSize, "\0", STR_PAD_RIGHT);
199
        }
200
        return true;
201
    }
202
203
    /**
204
     * Return info about stream
205
     * @return array
206
     */
207
    public function stream_stat() {
208
        return array('dev' => 0,
209
            'ino' => 0,
210
            'mode' => 0,
211
            'nlink' => 0,
212
            'uid' => 0,
213
            'gid' => 0,
214
            'rdev' => 0,
215
            'size' => strlen(self::$string[$this->path]),
216
            'atime' => 0,
217
            'mtime' => 0,
218
            'ctime' => 0,
219
            'blksize' => -1,
220
            'blocks' => -1);
221
    }
222
223
    /**
224
     * Return info about stream
225
     * @param string $aPath
226
     * @param array $aOptions
227
     * @return array
228
     */
229
    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...
230
        $resource = fopen($aPath, 'r');
231
        return fstat($resource);
232
    }
233
234
    public static function register() {
235
        if (!self::$registered) {
236
            if (in_array("string", stream_get_wrappers())) {
237
                stream_wrapper_unregister("string");
238
            }
239
            stream_wrapper_register("string", __CLASS__);
240
            self::$registered = true;
241
        }
242
    }
243
244
    public static function unregister() {
245
        if (self::$registered) {
246
            stream_wrapper_unregister('string');
247
        }
248
    }
249
250
}
251