Completed
Pull Request — master (#178)
by ignace nyamagana
02:10
created

StreamFilter::removeStreamFilter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 1
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 8.1.1
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
namespace League\Csv\Config;
14
15
use InvalidArgumentException;
16
use LogicException;
17
use OutOfBoundsException;
18
19
/**
20
 *  A Trait to ease PHP Stream Filters manipulation
21
 *  with a SplFileObject
22
 *
23
 * @package League.csv
24
 * @since  6.0.0
25
 *
26
 */
27
trait StreamFilter
28
{
29
    /**
30
     * collection of stream filters
31
     *
32
     * @var array
33
     */
34
    protected $stream_filters = [];
35
36
    /**
37
     * Stream filtering mode to apply on all filters
38
     *
39
     * @var int
40
     */
41
    protected $stream_filter_mode = STREAM_FILTER_ALL;
42
43
    /**
44
     *the real path
45
     *
46
     * @var string the real path to the file
47
     *
48
     */
49
    protected $stream_uri;
50
51
    /**
52
     * PHP Stream Filter Regex
53
     *
54
     * @var string
55
     */
56
    protected $stream_regex = ',^
57
        php://filter/
58
        (?P<mode>:?read=|write=)?  # The resource open mode
59
        (?P<filters>.*?)           # The resource registered filters
60
        /resource=(?P<resource>.*) # The resource path
61
        $,ix';
62
63
    /**
64
     * Charset Encoding for the CSV
65
     *
66
     * @var string
67
     */
68
    protected $input_encoding = 'UTF-8';
69
70
    /**
71
     * Gets the source CSV encoding charset
72
     *
73
     * @return string
74
     */
75
    public function getInputEncoding()
76
    {
77
        return $this->input_encoding;
78
    }
79
80
    /**
81
     * Sets the CSV encoding charset
82
     *
83
     * @param string $str
84
     *
85
     * @return static
86
     */
87
    public function setInputEncoding($str)
88
    {
89
        $str = str_replace('_', '-', $str);
90
        $str = filter_var($str, FILTER_SANITIZE_STRING, ['flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH]);
91
        $str = trim($str);
92
        if ('' === $str) {
93
            throw new InvalidArgumentException('you should use a valid charset');
94
        }
95
        $this->input_encoding = strtoupper($str);
96
97
        return $this;
98
    }
99
100
    /**
101
     * Internal path setter
102
     *
103
     * The path must be an SplFileInfo object
104
     * an object that implements the `__toString` method
105
     * a path to a file
106
     *
107
     * @param \SplFileObject|string $path The file path
108
     */
109
    protected function initStreamFilter($path)
110
    {
111
        $this->stream_filters = [];
112
        if (!is_string($path)) {
113
            $this->stream_uri = null;
114
115
            return;
116
        }
117
118
        if (!preg_match($this->stream_regex, $path, $matches)) {
119
            $this->stream_uri = $path;
120
121
            return;
122
        }
123
        $this->stream_uri = $matches['resource'];
124
        $this->stream_filters = array_map('urldecode', explode('|', $matches['filters']));
125
        $this->stream_filter_mode = $this->fetchStreamModeAsInt($matches['mode']);
126
    }
127
128
    /**
129
     * Get the stream mode
130
     *
131
     * @param string $mode
132
     *
133
     * @return int
134
     */
135
    protected function fetchStreamModeAsInt($mode)
136
    {
137
        $mode = strtolower($mode);
138
        $mode = rtrim($mode, '=');
139
        if ('write' == $mode) {
140
            return STREAM_FILTER_WRITE;
141
        }
142
143
        if ('read' == $mode) {
144
            return STREAM_FILTER_READ;
145
        }
146
147
        return STREAM_FILTER_ALL;
148
    }
149
150
    /**
151
     * Check if the trait methods can be used
152
     *
153
     * @throws LogicException If the API can not be use
154
     */
155
    protected function assertStreamable()
156
    {
157
        if (!is_string($this->stream_uri)) {
158
            throw new LogicException('The stream filter API can not be used');
159
        }
160
    }
161
162
    /**
163
     * Tells whether the stream filter capabilities can be used
164
     *
165
     * @return bool
166
     */
167
    public function isActiveStreamFilter()
168
    {
169
        return is_string($this->stream_uri);
170
    }
171
172
    /**
173
     * stream filter mode Setter
174
     *
175
     * Set the new Stream Filter mode and remove all
176
     * previously attached stream filters
177
     *
178
     * @param int $mode
179
     *
180
     * @throws OutOfBoundsException If the mode is invalid
181
     *
182
     * @return $this
183
     */
184
    public function setStreamFilterMode($mode)
185
    {
186
        $this->assertStreamable();
187
        if (!in_array($mode, [STREAM_FILTER_ALL, STREAM_FILTER_READ, STREAM_FILTER_WRITE])) {
188
            throw new OutOfBoundsException('the $mode should be a valid `STREAM_FILTER_*` constant');
189
        }
190
191
        $this->stream_filter_mode = $mode;
192
        $this->stream_filters = [];
193
194
        return $this;
195
    }
196
197
    /**
198
     * stream filter mode getter
199
     *
200
     * @return int
201
     */
202
    public function getStreamFilterMode()
203
    {
204
        $this->assertStreamable();
205
206
        return $this->stream_filter_mode;
207
    }
208
209
    /**
210
     * append a stream filter
211
     *
212
     * @param string $filter_name a string or an object that implements the '__toString' method
213
     *
214
     * @return $this
215
     */
216
    public function appendStreamFilter($filter_name)
217
    {
218
        $this->assertStreamable();
219
        $this->stream_filters[] = $this->sanitizeStreamFilter($filter_name);
220
221
        return $this;
222
    }
223
224
    /**
225
     * prepend a stream filter
226
     *
227
     * @param string $filter_name a string or an object that implements the '__toString' method
228
     *
229
     * @return $this
230
     */
231
    public function prependStreamFilter($filter_name)
232
    {
233
        $this->assertStreamable();
234
        array_unshift($this->stream_filters, $this->sanitizeStreamFilter($filter_name));
235
236
        return $this;
237
    }
238
239
    /**
240
     * Sanitize the stream filter name
241
     *
242
     * @param string $filter_name the stream filter name
243
     *
244
     * @return string
245
     */
246
    protected function sanitizeStreamFilter($filter_name)
247
    {
248
        return urldecode($this->validateString($filter_name));
249
    }
250
251
    /**
252
     * validate a string
253
     *
254
     * @param mixed $str the value to evaluate as a string
255
     *
256
     * @throws InvalidArgumentException if the submitted data can not be converted to string
257
     *
258
     * @return string
259
     */
260
    abstract protected function validateString($str);
261
262
    /**
263
     * Detect if the stream filter is already present
264
     *
265
     * @param string $filter_name
266
     *
267
     * @return bool
268
     */
269
    public function hasStreamFilter($filter_name)
270
    {
271
        $this->assertStreamable();
272
273
        return false !== array_search(urldecode($filter_name), $this->stream_filters, true);
274
    }
275
276
    /**
277
     * Remove a filter from the collection
278
     *
279
     * @param string $filter_name
280
     *
281
     * @return $this
282
     */
283
    public function removeStreamFilter($filter_name)
284
    {
285
        $this->assertStreamable();
286
        $res = array_search(urldecode($filter_name), $this->stream_filters, true);
287
        if (false !== $res) {
288
            unset($this->stream_filters[$res]);
289
        }
290
291
        return $this;
292
    }
293
294
    /**
295
     * Remove all registered stream filter
296
     *
297
     * @return $this
298
     */
299
    public function clearStreamFilter()
300
    {
301
        $this->assertStreamable();
302
        $this->stream_filters = [];
303
304
        return $this;
305
    }
306
307
    /**
308
     * Return the filter path
309
     *
310
     * @return string
311
     */
312
    protected function getStreamFilterPath()
313
    {
314
        $this->assertStreamable();
315
        $filters = $this->getStreamFilters();
316
        if (empty($filters)) {
317
            return $this->stream_uri;
318
        }
319
320
        return 'php://filter/'
321
            .$this->getStreamFilterPrefix()
322
            .implode('|', array_map('urlencode', $filters))
323
            .'/resource='.$this->stream_uri;
324
    }
325
326
    /**
327
     * Return the registered stream filters
328
     *
329
     * @return string[]
330
     */
331
    protected function getStreamFilters()
332
    {
333
        if (STREAM_FILTER_READ === $this->stream_filter_mode
334
            && in_array('convert.iconv.*', stream_get_filters(), true)
335
            && 'UTF-8' !== $this->input_encoding
336
        ) {
337
            $filters = $this->stream_filters;
338
            $filters[] = $this->sanitizeStreamFilter('convert.iconv.'.$this->input_encoding.'/UTF-8//TRANSLIT');
339
            return $filters;
340
        }
341
342
        return $this->stream_filters;
343
    }
344
345
    /**
346
     * Return PHP stream filter prefix
347
     *
348
     * @return string
349
     */
350
    protected function getStreamFilterPrefix()
351
    {
352
        if (STREAM_FILTER_READ == $this->stream_filter_mode) {
353
            return 'read=';
354
        }
355
356
        if (STREAM_FILTER_WRITE == $this->stream_filter_mode) {
357
            return 'write=';
358
        }
359
360
        return '';
361
    }
362
}
363