Completed
Push — master ( 887877...a525f2 )
by James Ekow Abaka
02:03
created

StringStream::stream_read()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
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
17
 * @author Doug Wright
18
 * @package StringStream
19
 */
20
class StringStream
21
{
22
23
    /**
24
     * Content of stream
25
     * @var string
26
     */
27
    private static $string = [];
28
29
    /**
30
     * Whether this stream can be read
31
     * @var boolean
32
     */
33
    private $read;
34
35
    /**
36
     * Whether this stream can be written
37
     * @var boolean
38
     */
39
    private $write;
40
41
    /**
42
     * Options
43
     * @var int
44
     */
45
    private $options;
46
47
    /**
48
     * Current position within stream
49
     * @var int
50
     */
51
    private $position;
52
    private $path;
53
    private static $registered = false;
54
55
    /**
56
     * Open stream
57
     * @param string $aPath
58
     * @param string $aMode
59
     * @param int $aOptions
60
     * @param string $aOpenedPath
61
     * @return boolean
62
     */
63
    function stream_open($aPath, $aMode, $aOptions, &$aOpenedPath)
0 ignored issues
show
Unused Code introduced by
The parameter $aOpenedPath 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...
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...
64
    {
65
        $this->path = substr($aPath, 9);
66
        if (!isset(self::$string[$this->path])) {
67
            self::$string[$this->path] = '';
68
        }
69
        $this->options = $aOptions;
70
71
        switch ($aMode) {
72
73
            case 'r':
74
            case 'rb':
75
                $this->read = true;
76
                $this->write = false;
77
                $this->position = 0;
78
                break;
79
80
81
            case 'r+':
82
            case 'c+':
83
                $this->read = true;
84
                $this->write = true;
85
                $this->position = 0;
86
                break;
87
88
            case 'w':
89 View Code Duplication
            case 'wb':
0 ignored issues
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...
90
                $this->read = false;
91
                $this->write = true;
92
                $this->position = 0;
93
                $this->stream_truncate(0);
94
                break;
95
96 View Code Duplication
            case 'w+':
0 ignored issues
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...
97
                $this->read = true;
98
                $this->write = true;
99
                $this->position = 0;
100
                $this->stream_truncate(0);
101
                break;
102
103 View Code Duplication
            case 'a':
0 ignored issues
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...
104
                $this->read = false;
105
                $this->write = true;
106
                $this->position = strlen(self::$string[$this->path]);
107
                break;
108
109 View Code Duplication
            case 'a+':
0 ignored issues
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...
110
                $this->read = true;
111
                $this->write = true;
112
                $this->position = strlen(self::$string[$this->path]);
113
                break;
114
115
            case 'c':
116
                $this->read = false;
117
                $this->write = true;
118
                $this->position = 0;
119
                break;
120
121
            default:
122
                trigger_error($aMode . 'Invalid mode specified (mode specified makes no sense for this stream implementation)', E_USER_ERROR);
123
        }
124
125
126
        return true;
127
    }
128
129
    /**
130
     * Read from stream
131
     * @param int $aBytes number of bytes to return
132
     * @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...
133
     */
134
    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...
135
    {
136
        if ($this->read) {
137
            $read = substr(self::$string[$this->path], $this->position, $aBytes);
138
            $this->position += strlen($read);
139
            return $read;
140
        } else {
141
            return false;
142
        }
143
    }
144
145
    /**
146
     * Write to stream
147
     * @param string $aData data to write
148
     * @return int
149
     */
150
    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...
151
    {
152
        if ($this->write) {
153
            $left = substr(self::$string[$this->path], 0, $this->position);
154
            $right = substr(self::$string[$this->path], $this->position + strlen($aData));
155
            self::$string[$this->path] = $left . $aData . $right;
156
            $this->position += strlen($aData);
157
            return strlen($aData);
158
        } else {
159
            return 0;
160
        }
161
    }
162
163
    /**
164
     * Return current position
165
     * @return int
166
     */
167
    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...
168
    {
169
        return $this->position;
170
    }
171
172
    /**
173
     * Return if EOF
174
     * @return boolean
175
     */
176
    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...
177
    {
178
        return $this->position >= strlen(self::$string[$this->path]);
179
    }
180
181
    /**
182
     * Seek to new position
183
     * @param int $aOffset
184
     * @param int $aWhence
185
     * @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...
186
     */
187
    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...
188
    {
189
        switch ($aWhence) {
190
            case SEEK_SET:
191
                $this->position = $aOffset;
192
                if ($aOffset > strlen(self::$string[$this->path])) {
193
                    $this->stream_truncate($aOffset);
194
                }
195
                return true;
196
                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...
197
198
            //XXX Code coverage testing shows PHP truncates automatically for SEEK_CUR
199
            case SEEK_CUR:
200
                $this->position += $aOffset;
201
                return true;
202
                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...
203
204
            case SEEK_END:
205
                $this->position = strlen(self::$string[$this->path]) + $aOffset;
206
                if (($this->position + $aOffset) > strlen(self::$string[$this->path])) {
207
                    $this->stream_truncate(strlen(self::$string[$this->path]) + $aOffset);
208
                }
209
                return true;
210
                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...
211
212
            default:
213
                return false;
214
        }
215
    }
216
217
    /**
218
     * Truncate to given size
219
     * @param int $aSize
220
     */
221
    public function stream_truncate($aSize)
222
    {
223
        if (strlen(self::$string[$this->path]) > $aSize) {
224
            self::$string[$this->path] = substr(self::$string[$this->path], 0, $aSize);
225
        } else if (strlen(self::$string[$this->path]) < $aSize) {
226
            self::$string[$this->path] = str_pad(self::$string[$this->path], $aSize, "\0", STR_PAD_RIGHT);
227
        }
228
        return true;
229
    }
230
231
    /**
232
     * Return info about stream
233
     * @return array
234
     */
235
    public function stream_stat()
236
    {
237
        return array('dev' => 0,
238
            'ino' => 0,
239
            'mode' => 0,
240
            'nlink' => 0,
241
            'uid' => 0,
242
            'gid' => 0,
243
            'rdev' => 0,
244
            'size' => strlen(self::$string[$this->path]),
245
            'atime' => 0,
246
            'mtime' => 0,
247
            'ctime' => 0,
248
            'blksize' => -1,
249
            'blocks' => -1);
250
    }
251
252
    /**
253
     * Return info about stream
254
     * @param string $aPath
255
     * @param array $aOptions
256
     * @return array
257
     */
258
    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...
259
    {
260
        $resource = fopen($aPath, 'r');
261
        return fstat($resource);
262
    }
263
    
264
    public static function register()
265
    {
266
        if(!self::$registered)
267
        {
268
            if (in_array("string", stream_get_wrappers())) {
269
                stream_wrapper_unregister("string");
270
            }            
271
            stream_wrapper_register("string", __CLASS__);
272
            self::$registered = true;
273
        }
274
        
275
    }
276
    
277
    public static function unregister()
278
    {
279
        if(self::$registered)
280
        {
281
            stream_wrapper_unregister('string');
282
        }
283
    }
284
}
285