Completed
Push — master ( cedd59...d273ad )
by ignace nyamagana
04:29 queued 02:34
created

CharsetConverter::filter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 4
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 0
b 0
f 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;
16
17
use Iterator;
18
use php_user_filter;
19
use Traversable;
20
21
/**
22
 *  A class to encode your CSV records collection
23
 *
24
 * @package League.csv
25
 * @since   9.0.0
26
 * @author  Ignace Nyamagana Butera <[email protected]>
27
 */
28
class CharsetConverter extends php_user_filter
29
{
30
    use ValidatorTrait;
31
32
    const FILTER_NAME = 'convert.league.csv.';
33
34
    /**
35
     * The records input encoding charset
36
     *
37
     * @var string
38
     */
39
    protected $input_encoding = 'UTF-8';
40
41
    /**
42
     * The records output encoding charset
43
     *
44
     * @var string
45
     */
46
    protected $output_encoding = 'UTF-8';
47
48
    /**
49
     * Static method to register the class as
50
     * a PHP stream filter
51
     *
52
     * @return bool
53
     */
54 4
    public static function registerStreamFilter(): bool
55
    {
56 4
        return stream_filter_register(self::FILTER_NAME.'*', CharsetConverter::class);
57
    }
58
59 2
    public static function createFilterName(string $input_encoding, string $output_encoding)
60
    {
61 2
        return self::FILTER_NAME
62 2
            .self::filterEncoding($input_encoding)
63 2
            .'/'
64 2
            .self::filterEncoding($output_encoding)
65
        ;
66
    }
67
68
    /**
69
     * @inherit
70
     */
71 2
    public function filter($in, $out, &$consumed, $closing)
72
    {
73 2
        while ($res = stream_bucket_make_writeable($in)) {
74 2
            $res->data = @mb_convert_encoding($res->data, $this->output_encoding, $this->input_encoding);
75 2
            $consumed += $res->datalen;
76 2
            stream_bucket_append($out, $res);
77
        }
78
79 2
        return PSFS_PASS_ON;
80
    }
81
82
    /**
83
     * @inherit
84
     */
85 4
    public function onCreate()
86
    {
87 4
        $params = substr($this->filtername, strlen(self::FILTER_NAME));
88 4
        if (!preg_match(',^(?<input>[-\w]+)\/(?<output>[-\w]+)$,', $params, $matches)) {
89 2
            return false;
90
        }
91
92 2
        $this->input_encoding = $this->filterEncoding($matches['input']);
93 2
        $this->output_encoding = $this->filterEncoding($matches['output']);
94 2
        return true;
95
    }
96
97
    /**
98
     * Enable using the class as a formatter for the {@link Writer}
99
     *
100
     * @param array $record CSV record
101
     *
102
     * @return string[]
103
     */
104 2
    public function __invoke(array $record): array
105
    {
106 2
        if ($this->output_encoding !== $this->input_encoding) {
107 2
            array_walk($record, [$this, 'encodeField']);
108
        }
109
110 2
        return $record;
111
    }
112
113
    /**
114
     * Walker method to convert the offset and the value of a CSV record field
115
     *
116
     * @param string|null &$value
117
     * @param string|int  &$offset
118
     */
119 4
    protected function encodeField(&$value, &$offset)
120
    {
121 4
        if (null !== $value) {
122 4
            $value = mb_convert_encoding((string) $value, $this->output_encoding, $this->input_encoding);
123
        }
124
125 4
        if (!is_int($offset)) {
126 4
            $offset = mb_convert_encoding((string) $offset, $this->output_encoding, $this->input_encoding);
127
        }
128 4
    }
129
130
    /**
131
     * Convert Csv file into UTF-8
132
     *
133
     * @param array|Traversable $records the CSV records collection
134
     *
135
     * @return array|Iterator
136
     */
137 4
    public function convert($records)
138
    {
139 4
        $records = $this->filterIterable($records, __METHOD__);
140 4
        if ($this->output_encoding === $this->input_encoding) {
141 2
            return $records;
142
        }
143
144 2
        $convert = function (array $record): array {
145 2
            array_walk($record, [$this, 'encodeField']);
146 2
            return $record;
147 1
        };
148
149 2
        return is_array($records) ? array_map($convert, $records) : new MapIterator($records, $convert);
150
    }
151
152
    /**
153
     * Sets the records input encoding charset
154
     *
155
     * @param string $encoding
156
     *
157
     * @return static
158
     */
159 6
    public function inputEncoding(string $encoding): self
160
    {
161 6
        $encoding = $this->filterEncoding($encoding);
162 4
        if ($encoding === $this->input_encoding) {
163 2
            return $this;
164
        }
165
166 2
        $clone = clone $this;
167 2
        $clone->input_encoding = $encoding;
168
169 2
        return $clone;
170
    }
171
172
    /**
173
     * Sets the records output encoding charset
174
     *
175
     * @param string $encoding
176
     *
177
     * @return static
178
     */
179 4
    public function outputEncoding(string $encoding): self
180
    {
181 4
        $encoding = $this->filterEncoding($encoding);
182 4
        if ($encoding === $this->output_encoding) {
183 2
            return $this;
184
        }
185
186 4
        $clone = clone $this;
187 4
        $clone->output_encoding = $encoding;
188
189 4
        return $clone;
190
    }
191
}
192