Completed
Pull Request — master (#207)
by ignace nyamagana
02:14
created

StreamTrait::assertStreamable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 0
1
<?php
2
/**
3
* This file is part of the League.csv library
4
*
5
* @license http://opensource.org/licenses/MIT
6
* @link https://github.com/thephpleague/csv/
7
* @version 9.0.0
8
* @package League.csv
9
*
10
* For the full copyright and license information, please view the LICENSE
11
* file that was distributed with this source code.
12
*/
13
declare(strict_types=1);
14
15
namespace League\Csv\Config;
16
17
use LogicException;
18
use OutOfBoundsException;
19
use SplFileObject;
20
21
/**
22
 *  An abstract class to enable basic CSV manipulation
23
 *
24
 * @package League.csv
25
 * @since  9.0.0
26
 * @internal
27
 */
28
trait StreamTrait
29
{
30
    /**
31
     * The path
32
     *
33
     * can be a StreamIterator object, a SplFileObject object or the string path to a file
34
     *
35
     * @var StreamIterator|SplFileObject|string
36
     */
37
    protected $path;
38
39
    /**
40
     * collection of stream filters
41
     *
42
     * @var array
43
     */
44
    protected $stream_filters = [];
45
46
    /**
47
     * Stream filtering mode to apply on all filters
48
     *
49
     * @var int
50
     */
51
    protected $stream_filter_mode = STREAM_FILTER_ALL;
52
53
    /**
54
     *the real path
55
     *
56
     * @var string the real path to the file
57
     *
58
     */
59
    protected $stream_uri;
60
61
    /**
62
     * PHP Stream Filter Regex
63
     *
64
     * @var string
65
     */
66
    protected $stream_regex = ',^
67
        php://filter/
68
        (?P<mode>:?read=|write=)?  # The resource open mode
69
        (?P<filters>.*?)           # The resource registered filters
70
        /resource=(?P<resource>.*) # The resource path
71
        $,ix';
72
73
    /**
74
     * Internal path setter
75
     */
76
    protected function initStreamFilter()
77
    {
78
        if (!is_string($this->path)) {
79
            return;
80
        }
81
82
        if (!preg_match($this->stream_regex, $this->path, $matches)) {
83
            $this->stream_uri = $this->path;
84
85
            return;
86
        }
87
88
        $this->stream_uri = $matches['resource'];
89
        $this->stream_filters = array_map('urldecode', explode('|', $matches['filters']));
90
        $this->stream_filter_mode = $this->fetchStreamModeAsInt($matches['mode']);
91
    }
92
93
    /**
94
     * Get the stream mode
95
     *
96
     * @param string $mode
97
     *
98
     * @return int
99
     */
100
    protected function fetchStreamModeAsInt(string $mode): int
101
    {
102
        $mode = strtolower($mode);
103
        $mode = rtrim($mode, '=');
104
        if ('write' == $mode) {
105
            return STREAM_FILTER_WRITE;
106
        }
107
108
        if ('read' == $mode) {
109
            return STREAM_FILTER_READ;
110
        }
111
112
        return STREAM_FILTER_ALL;
113
    }
114
115
    /**
116
     * Check if the trait methods can be used
117
     *
118
     * @throws LogicException If the API can not be use
119
     */
120
    protected function assertStreamable()
121
    {
122
        if (!is_string($this->stream_uri)) {
123
            throw new LogicException('The stream filter API can not be used');
124
        }
125
    }
126
127
    /**
128
     * Tells whether the stream filter capabilities can be used
129
     *
130
     * @return bool
131
     */
132
    public function isActiveStreamFilter(): bool
133
    {
134
        return is_string($this->stream_uri);
135
    }
136
137
    /**
138
     * stream filter mode Setter
139
     *
140
     * Set the new Stream Filter mode and remove all
141
     * previously attached stream filters
142
     *
143
     * @param int $mode
144
     *
145
     * @throws OutOfBoundsException If the mode is invalid
146
     *
147
     * @return $this
148
     */
149
    public function setStreamFilterMode(int $mode): self
150
    {
151
        $this->assertStreamable();
152
        if (!in_array($mode, [STREAM_FILTER_ALL, STREAM_FILTER_READ, STREAM_FILTER_WRITE])) {
153
            throw new OutOfBoundsException('the $mode should be a valid `STREAM_FILTER_*` constant');
154
        }
155
156
        $this->stream_filter_mode = $mode;
157
        $this->stream_filters = [];
158
159
        return $this;
160
    }
161
162
    /**
163
     * stream filter mode getter
164
     *
165
     * @return int
166
     */
167
    public function getStreamFilterMode(): int
168
    {
169
        $this->assertStreamable();
170
171
        return $this->stream_filter_mode;
172
    }
173
174
    /**
175
     * append a stream filter
176
     *
177
     * @param string $filter_name a string or an object that implements the '__toString' method
178
     *
179
     * @return $this
180
     */
181
    public function appendStreamFilter(string $filter_name): self
182
    {
183
        $this->assertStreamable();
184
        $this->stream_filters[] = $this->sanitizeStreamFilter($filter_name);
185
186
        return $this;
187
    }
188
189
    /**
190
     * prepend a stream filter
191
     *
192
     * @param string $filter_name a string or an object that implements the '__toString' method
193
     *
194
     * @return $this
195
     */
196
    public function prependStreamFilter(string $filter_name): self
197
    {
198
        $this->assertStreamable();
199
        array_unshift($this->stream_filters, $this->sanitizeStreamFilter($filter_name));
200
201
        return $this;
202
    }
203
204
    /**
205
     * Sanitize the stream filter name
206
     *
207
     * @param string $filter_name the stream filter name
208
     *
209
     * @return string
210
     */
211
    protected function sanitizeStreamFilter(string $filter_name): string
212
    {
213
        return urldecode($filter_name);
214
    }
215
216
    /**
217
     * Detect if the stream filter is already present
218
     *
219
     * @param string $filter_name
220
     *
221
     * @return bool
222
     */
223
    public function hasStreamFilter(string $filter_name): bool
224
    {
225
        $this->assertStreamable();
226
227
        return false !== array_search(urldecode($filter_name), $this->stream_filters, true);
228
    }
229
230
    /**
231
     * Remove a filter from the collection
232
     *
233
     * @param string $filter_name
234
     *
235
     * @return $this
236
     */
237
    public function removeStreamFilter(string $filter_name): self
238
    {
239
        $this->assertStreamable();
240
        $res = array_search(urldecode($filter_name), $this->stream_filters, true);
241
        if (false !== $res) {
242
            unset($this->stream_filters[$res]);
243
        }
244
245
        return $this;
246
    }
247
248
    /**
249
     * Remove all registered stream filter
250
     *
251
     * @return $this
252
     */
253
    public function clearStreamFilter(): self
254
    {
255
        $this->assertStreamable();
256
        $this->stream_filters = [];
257
258
        return $this;
259
    }
260
261
    /**
262
     * Return the filter path
263
     *
264
     * @return string
265
     */
266
    protected function getStreamFilterPath(): string
267
    {
268
        $this->assertStreamable();
269
        if (!$this->stream_filters) {
270
            return $this->stream_uri;
271
        }
272
273
        return 'php://filter/'
274
            .$this->getStreamFilterPrefix()
275
            .implode('|', array_map('urlencode', $this->stream_filters))
276
            .'/resource='.$this->stream_uri;
277
    }
278
279
    /**
280
     * Return PHP stream filter prefix
281
     *
282
     * @return string
283
     */
284
    protected function getStreamFilterPrefix(): string
285
    {
286
        if (STREAM_FILTER_READ == $this->stream_filter_mode) {
287
            return 'read=';
288
        }
289
290
        if (STREAM_FILTER_WRITE == $this->stream_filter_mode) {
291
            return 'write=';
292
        }
293
294
        return '';
295
    }
296
}
297