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

StreamFilter::filterString()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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