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

StreamFilter::isActiveStreamFilter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
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
namespace League\Csv\Config;
14
15
use InvalidArgumentException;
16
use LogicException;
17
use SplFileObject;
18
19
/**
20
 *  Trait to manipulate PHP Stream Filters 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
     * CSV encoding charset
64
     *
65
     * @var string
66
     */
67
    protected $input_encoding = 'UTF-8';
68
69
    /**
70
     * Returns the CSV encoding charset
71
     *
72
     * @return string
73
     */
74
    public function getInputEncoding()
75
    {
76
        return $this->input_encoding;
77
    }
78
79
    /**
80
     * Sets the CSV encoding charset
81
     *
82
     * @param string $str
83
     *
84
     * @return static
85
     */
86
    public function setInputEncoding($str)
87
    {
88
        $str = str_replace('_', '-', $str);
89
        $str = filter_var($str, FILTER_SANITIZE_STRING, ['flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH]);
90
        $str = trim($str);
91
        if ('' === $str) {
92
            throw new InvalidArgumentException('you should use a valid charset');
93
        }
94
        $this->input_encoding = strtoupper($str);
95
96
        return $this;
97
    }
98
99
    /**
100
     * Returns the stream filter mode
101
     *
102
     * @return int
103
     */
104
    public function getStreamFilterMode()
105
    {
106
        $this->assertStreamable();
107
108
        return $this->stream_filter_mode;
109
    }
110
111
    /**
112
     * Internal path setter
113
     *
114
     * The path must be an SplFileInfo object
115
     * an object that implements the `__toString` method
116
     * a path to a file
117
     *
118
     * @param SplFileObject|string $path The file path
119
     */
120
    protected function initStreamFilter($path)
121
    {
122
        $this->stream_filters = [];
123
        if (!is_string($path)) {
124
            $this->stream_uri = null;
125
            return;
126
        }
127
128
        if (!preg_match($this->stream_regex, $path, $matches)) {
129
            $this->stream_uri = $path;
130
            return;
131
        }
132
133
        $this->stream_uri = $matches['resource'];
134
        $this->stream_filters = [];
135
        $filter_mode = $this->fetchStreamModeAsInt($matches['mode']);
136
        if (in_array($filter_mode, [STREAM_FILTER_ALL, $this->stream_filter_mode])) {
137
            $this->stream_filters = array_map('urldecode', explode('|', $matches['filters']));
138
        }
139
    }
140
141
    /**
142
     * Get the stream mode
143
     *
144
     * @param string $mode
145
     *
146
     * @return int
147
     */
148
    protected function fetchStreamModeAsInt($mode)
149
    {
150
        $mode = strtolower($mode);
151
        $mode = rtrim($mode, '=');
152
        if ('write' == $mode) {
153
            return STREAM_FILTER_WRITE;
154
        }
155
156
        if ('read' == $mode) {
157
            return STREAM_FILTER_READ;
158
        }
159
160
        return STREAM_FILTER_ALL;
161
    }
162
163
    /**
164
     * Check if the trait methods can be used
165
     *
166
     * @throws LogicException If the API can not be use
167
     */
168
    protected function assertStreamable()
169
    {
170
        if (!is_string($this->stream_uri)) {
171
            throw new LogicException('The stream filter API can not be used');
172
        }
173
    }
174
175
    /**
176
     * Tells whether the stream filter capabilities can be used
177
     *
178
     * @return bool
179
     */
180
    public function isActiveStreamFilter()
181
    {
182
        return is_string($this->stream_uri);
183
    }
184
185
    /**
186
     * append a stream filter
187
     *
188
     * @param string $filter_name a string or an object that implements the '__toString' method
189
     *
190
     * @return $this
191
     */
192
    public function appendStreamFilter($filter_name)
193
    {
194
        $this->assertStreamable();
195
        $this->stream_filters[] = $this->sanitizeStreamFilter($filter_name);
196
197
        return $this;
198
    }
199
200
    /**
201
     * prepend a stream filter
202
     *
203
     * @param string $filter_name a string or an object that implements the '__toString' method
204
     *
205
     * @return $this
206
     */
207
    public function prependStreamFilter($filter_name)
208
    {
209
        $this->assertStreamable();
210
        array_unshift($this->stream_filters, $this->sanitizeStreamFilter($filter_name));
211
212
        return $this;
213
    }
214
215
    /**
216
     * Sanitize the stream filter name
217
     *
218
     * @param string $filter_name the stream filter name
219
     *
220
     * @return string
221
     */
222
    protected function sanitizeStreamFilter($filter_name)
223
    {
224
        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...
225
    }
226
227
    /**
228
     * Return the filter path
229
     *
230
     * @return string
231
     */
232
    protected function getStreamFilterPath()
233
    {
234
        $this->assertStreamable();
235
        $filters = $this->getStreamFilters();
236
        if (empty($filters)) {
237
            return $this->stream_uri;
238
        }
239
240
        return 'php://filter/'
241
            .$this->getStreamFilterPrefix()
242
            .implode('|', array_map('urlencode', $filters))
243
            .'/resource='.$this->stream_uri;
244
    }
245
246
    /**
247
     * Return the registered stream filters
248
     *
249
     * @return string[]
250
     */
251
    protected function getStreamFilters()
252
    {
253
        if (STREAM_FILTER_READ === $this->stream_filter_mode
254
            && in_array('convert.iconv.*', stream_get_filters(), true)
255
            && 'UTF-8' !== $this->input_encoding
256
        ) {
257
            $filters = $this->stream_filters;
258
            $filters[] = $this->sanitizeStreamFilter('convert.iconv.'.$this->input_encoding.'/UTF-8//TRANSLIT');
259
            return $filters;
260
        }
261
262
        return $this->stream_filters;
263
    }
264
265
    /**
266
     * Return PHP stream filter prefix
267
     *
268
     * @return string
269
     */
270
    protected function getStreamFilterPrefix()
271
    {
272
        if (STREAM_FILTER_READ === $this->stream_filter_mode) {
273
            return 'read=';
274
        }
275
276
        return 'write=';
277
    }
278
}
279