PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.2.2
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.2.2
2.4.0 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 All 67 releases
better-payment / vendor / league / csv / src / CharsetConverter.php

CharsetConverter.php in Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More 2.2.2, at vendor/league/csv/src/CharsetConverter.php

221 lines 6.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * League.Csv (https://csv.thephpleague.com)
5 *
6 * (c) Ignace Nyamagana Butera <[email protected]>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 declare(strict_types=1);
13
14 namespace League\Csv;
15
16 use OutOfRangeException;
17 use php_user_filter;
18 use Traversable;
19 use function array_combine;
20 use function array_map;
21 use function in_array;
22 use function is_numeric;
23 use function mb_convert_encoding;
24 use function mb_list_encodings;
25 use function preg_match;
26 use function sprintf;
27 use function stream_bucket_append;
28 use function stream_bucket_make_writeable;
29 use function stream_filter_register;
30 use function stream_get_filters;
31 use function strpos;
32 use function strtolower;
33 use function substr;
34
35 /**
36 * Converts resource stream or tabular data content charset.
37 */
38 class CharsetConverter extends php_user_filter
39 {
40 const FILTERNAME = 'convert.league.csv';
41
42 protected string $input_encoding = 'UTF-8';
43 protected string $output_encoding = 'UTF-8';
44
45 /**
46 * Static method to add the stream filter to a {@link AbstractCsv} object.
47 */
48 public static function addTo(AbstractCsv $csv, string $input_encoding, string $output_encoding): AbstractCsv
49 {
50 self::register();
51
52 return $csv->addStreamFilter(self::getFiltername($input_encoding, $output_encoding));
53 }
54
55 /**
56 * Static method to register the class as a stream filter.
57 */
58 public static function register(): void
59 {
60 $filter_name = self::FILTERNAME.'.*';
61 if (!in_array($filter_name, stream_get_filters(), true)) {
62 stream_filter_register($filter_name, self::class);
63 }
64 }
65
66 /**
67 * Static method to return the stream filter filtername.
68 */
69 public static function getFiltername(string $input_encoding, string $output_encoding): string
70 {
71 return sprintf(
72 '%s.%s/%s',
73 self::FILTERNAME,
74 self::filterEncoding($input_encoding),
75 self::filterEncoding($output_encoding)
76 );
77 }
78
79 /**
80 * Filter encoding charset.
81 *
82 * @throws OutOfRangeException if the charset is malformed or unsupported
83 */
84 protected static function filterEncoding(string $encoding): string
85 {
86 static $encoding_list;
87 if (null === $encoding_list) {
88 $list = mb_list_encodings();
89 $encoding_list = array_combine(array_map('strtolower', $list), $list);
90 }
91
92 $key = strtolower($encoding);
93 if (isset($encoding_list[$key])) {
94 return $encoding_list[$key];
95 }
96
97 throw new OutOfRangeException('The submitted charset '.$encoding.' is not supported by the mbstring extension.');
98 }
99
100 public function onCreate(): bool
101 {
102 $prefix = self::FILTERNAME.'.';
103 if (0 !== strpos($this->filtername, $prefix)) {
104 return false;
105 }
106
107 $encodings = substr($this->filtername, strlen($prefix));
108 if (1 !== preg_match(',^(?<input>[-\w]+)\/(?<output>[-\w]+)$,', $encodings, $matches)) {
109 return false;
110 }
111
112 try {
113 $this->input_encoding = self::filterEncoding($matches['input']);
114 $this->output_encoding = self::filterEncoding($matches['output']);
115 } catch (OutOfRangeException $e) {
116 return false;
117 }
118
119 return true;
120 }
121
122 /**
123 * @param resource $in
124 * @param resource $out
125 * @param int $consumed
126 * @param bool $closing
127 */
128 public function filter($in, $out, &$consumed, $closing): int
129 {
130 while (null !== ($bucket = stream_bucket_make_writeable($in))) {
131 $bucket->data = @mb_convert_encoding($bucket->data, $this->output_encoding, $this->input_encoding);
132 $consumed += $bucket->datalen;
133 stream_bucket_append($out, $bucket);
134 }
135
136 return PSFS_PASS_ON;
137 }
138
139 /**
140 * Convert Csv records collection into UTF-8.
141 */
142 public function convert(iterable $records): iterable
143 {
144 if ($this->output_encoding === $this->input_encoding) {
145 return $records;
146 }
147
148 if (is_array($records)) {
149 return array_map($this, $records);
150 }
151
152 /* @var Traversable $records */
153 return new MapIterator($records, $this);
154 }
155
156 /**
157 * Enable using the class as a formatter for the {@link Writer}.
158 */
159 public function __invoke(array $record): array
160 {
161 $outputRecord = [];
162 foreach ($record as $offset => $value) {
163 [$newOffset, $newValue] = $this->encodeField($value, $offset);
164 $outputRecord[$newOffset] = $newValue;
165 }
166
167 return $outputRecord;
168 }
169
170 /**
171 * Walker method to convert the offset and the value of a CSV record field.
172 *
173 * @param int|float|string|null $value can be a scalar type or null
174 * @param int|string $offset can be a string or an int
175 */
176 protected function encodeField($value, $offset): array
177 {
178 if (null !== $value && !is_numeric($value)) {
179 $value = mb_convert_encoding($value, $this->output_encoding, $this->input_encoding);
180 }
181
182 if (!is_numeric($offset)) {
183 $offset = mb_convert_encoding($offset, $this->output_encoding, $this->input_encoding);
184 }
185
186 return [$offset, $value];
187 }
188
189 /**
190 * Sets the records input encoding charset.
191 */
192 public function inputEncoding(string $encoding): self
193 {
194 $encoding = self::filterEncoding($encoding);
195 if ($encoding === $this->input_encoding) {
196 return $this;
197 }
198
199 $clone = clone $this;
200 $clone->input_encoding = $encoding;
201
202 return $clone;
203 }
204
205 /**
206 * Sets the records output encoding charset.
207 */
208 public function outputEncoding(string $encoding): self
209 {
210 $encoding = self::filterEncoding($encoding);
211 if ($encoding === $this->output_encoding) {
212 return $this;
213 }
214
215 $clone = clone $this;
216 $clone->output_encoding = $encoding;
217
218 return $clone;
219 }
220 }
221