Completed
Pull Request — master (#178)
by ignace nyamagana
22:48 queued 14:18
created

StreamFilter::getStreamFilterPrefix()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 12
rs 9.4285
cc 3
eloc 6
nc 3
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 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 LogicException;
16
use OutOfBoundsException;
17
18
/**
19
 *  A Trait to ease PHP Stream Filters manipulation
20
 *  with a SplFileObject
21
 *
22
 * @package League.csv
23
 * @since  6.0.0
24
 *
25
 */
26
trait StreamFilter
27
{
28
    /**
29
     * collection of stream filters
30
     *
31
     * @var array
32
     */
33
    protected $stream_filters = [];
34
35
    /**
36
     * Stream filtering mode to apply on all filters
37
     *
38
     * @var int
39
     */
40
    protected $stream_filter_mode = STREAM_FILTER_ALL;
41
42
    /**
43
     *the real path
44
     *
45
     * @var string the real path to the file
46
     *
47
     */
48
    protected $stream_uri;
49
50
    /**
51
     * PHP Stream Filter Regex
52
     *
53
     * @var string
54
     */
55
    protected $stream_regex = ',^
56
        php://filter/
57
        (?P<mode>:?read=|write=)?  # The resource open mode
58
        (?P<filters>.*?)           # The resource registered filters
59
        /resource=(?P<resource>.*) # The resource path
60
        $,ix';
61
62
    /**
63
     * Internal path setter
64
     *
65
     * The path must be an SplFileInfo object
66
     * an object that implements the `__toString` method
67
     * a path to a file
68
     *
69
     * @param \SplFileObject|string $path The file path
70
     */
71
    protected function initStreamFilter($path)
72
    {
73
        $this->stream_filters = [];
74
        if (!is_string($path)) {
75
            $this->stream_uri = null;
76
77
            return;
78
        }
79
80
        if (!preg_match($this->stream_regex, $path, $matches)) {
81
            $this->stream_uri = $path;
82
83
            return;
84
        }
85
        $this->stream_uri = $matches['resource'];
86
        $this->stream_filters = array_map('urldecode', explode('|', $matches['filters']));
87
        $this->stream_filter_mode = $this->fetchStreamModeAsInt($matches['mode']);
88
    }
89
90
    /**
91
     * Get the stream mode
92
     *
93
     * @param string $mode
94
     *
95
     * @return int
96
     */
97
    protected function fetchStreamModeAsInt($mode)
98
    {
99
        $mode = strtolower($mode);
100
        $mode = rtrim($mode, '=');
101
        if ('write' == $mode) {
102
            return STREAM_FILTER_WRITE;
103
        }
104
105
        if ('read' == $mode) {
106
            return STREAM_FILTER_READ;
107
        }
108
109
        return STREAM_FILTER_ALL;
110
    }
111
112
    /**
113
     * Check if the trait methods can be used
114
     *
115
     * @throws LogicException If the API can not be use
116
     */
117
    protected function assertStreamable()
118
    {
119
        if (!is_string($this->stream_uri)) {
120
            throw new LogicException('The stream filter API can not be used');
121
        }
122
    }
123
124
    /**
125
     * Tells whether the stream filter capabilities can be used
126
     *
127
     * @return bool
128
     */
129
    public function isActiveStreamFilter()
130
    {
131
        return is_string($this->stream_uri);
132
    }
133
134
    /**
135
     * stream filter mode Setter
136
     *
137
     * Set the new Stream Filter mode and remove all
138
     * previously attached stream filters
139
     *
140
     * @param int $mode
141
     *
142
     * @throws OutOfBoundsException If the mode is invalid
143
     *
144
     * @return $this
145
     */
146
    public function setStreamFilterMode($mode)
147
    {
148
        $this->assertStreamable();
149
        if (!in_array($mode, [STREAM_FILTER_ALL, STREAM_FILTER_READ, STREAM_FILTER_WRITE])) {
150
            throw new OutOfBoundsException('the $mode should be a valid `STREAM_FILTER_*` constant');
151
        }
152
153
        $this->stream_filter_mode = $mode;
154
        $this->stream_filters = [];
155
156
        return $this;
157
    }
158
159
    /**
160
     * stream filter mode getter
161
     *
162
     * @return int
163
     */
164
    public function getStreamFilterMode()
165
    {
166
        $this->assertStreamable();
167
168
        return $this->stream_filter_mode;
169
    }
170
171
    /**
172
     * append a stream filter
173
     *
174
     * @param string $filter_name a string or an object that implements the '__toString' method
175
     *
176
     * @return $this
177
     */
178
    public function appendStreamFilter($filter_name)
179
    {
180
        $this->assertStreamable();
181
        $this->stream_filters[] = $this->sanitizeStreamFilter($filter_name);
182
183
        return $this;
184
    }
185
186
    /**
187
     * prepend a stream filter
188
     *
189
     * @param string $filter_name a string or an object that implements the '__toString' method
190
     *
191
     * @return $this
192
     */
193
    public function prependStreamFilter($filter_name)
194
    {
195
        $this->assertStreamable();
196
        array_unshift($this->stream_filters, $this->sanitizeStreamFilter($filter_name));
197
198
        return $this;
199
    }
200
201
    /**
202
     * Sanitize the stream filter name
203
     *
204
     * @param string $filter_name the stream filter name
205
     *
206
     * @return string
207
     */
208
    protected function sanitizeStreamFilter($filter_name)
209
    {
210
        return urldecode($this->validateString($filter_name));
0 ignored issues
show
Bug introduced by
It seems like validateString() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
211
    }
212
213
    /**
214
     * Detect if the stream filter is already present
215
     *
216
     * @param string $filter_name
217
     *
218
     * @return bool
219
     */
220
    public function hasStreamFilter($filter_name)
221
    {
222
        $this->assertStreamable();
223
224
        return false !== array_search(urldecode($filter_name), $this->stream_filters, true);
225
    }
226
227
    /**
228
     * Remove a filter from the collection
229
     *
230
     * @param string $filter_name
231
     *
232
     * @return $this
233
     */
234
    public function removeStreamFilter($filter_name)
235
    {
236
        $this->assertStreamable();
237
        $res = array_search(urldecode($filter_name), $this->stream_filters, true);
238
        if (false !== $res) {
239
            unset($this->stream_filters[$res]);
240
        }
241
242
        return $this;
243
    }
244
245
    /**
246
     * Remove all registered stream filter
247
     *
248
     * @return $this
249
     */
250
    public function clearStreamFilter()
251
    {
252
        $this->assertStreamable();
253
        $this->stream_filters = [];
254
255
        return $this;
256
    }
257
258
    /**
259
     * Return the filter path
260
     *
261
     * @return string
262
     */
263
    protected function getStreamFilterPath()
264
    {
265
        $this->assertStreamable();
266
        if (!$this->stream_filters) {
267
            return $this->stream_uri;
268
        }
269
270
        return 'php://filter/'
271
            .$this->getStreamFilterPrefix()
272
            .implode('|', array_map('urlencode', $this->stream_filters))
273
            .'/resource='.$this->stream_uri;
274
    }
275
276
    /**
277
     * Return PHP stream filter prefix
278
     *
279
     * @return string
280
     */
281
    protected function getStreamFilterPrefix()
282
    {
283
        if (STREAM_FILTER_READ == $this->stream_filter_mode) {
284
            return 'read=';
285
        }
286
287
        if (STREAM_FILTER_WRITE == $this->stream_filter_mode) {
288
            return 'write=';
289
        }
290
291
        return '';
292
    }
293
}
294