PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / trunk
Matomo Analytics – Powerful, Privacy-First Insights for WordPress vtrunk
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / vendor / symfony / polyfill-mbstring / Mbstring.php
matomo / app / vendor / symfony / polyfill-mbstring Last commit date
Resources 2 years ago LICENSE 2 years ago Mbstring.php 1 month ago README.md 3 years ago bootstrap.php 1 month ago bootstrap72.php 1 month ago bootstrap80.php 1 month ago
Mbstring.php
907 lines
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 namespace Symfony\Polyfill\Mbstring;
12
13 /**
14 * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
15 *
16 * Implemented:
17 * - mb_chr - Returns a specific character from its Unicode code point
18 * - mb_convert_encoding - Convert character encoding
19 * - mb_convert_variables - Convert character code in variable(s)
20 * - mb_decode_mimeheader - Decode string in MIME header field
21 * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
22 * - mb_decode_numericentity - Decode HTML numeric string reference to character
23 * - mb_encode_numericentity - Encode character to HTML numeric string reference
24 * - mb_convert_case - Perform case folding on a string
25 * - mb_detect_encoding - Detect character encoding
26 * - mb_get_info - Get internal settings of mbstring
27 * - mb_http_input - Detect HTTP input character encoding
28 * - mb_http_output - Set/Get HTTP output character encoding
29 * - mb_internal_encoding - Set/Get internal character encoding
30 * - mb_list_encodings - Returns an array of all supported encodings
31 * - mb_ord - Returns the Unicode code point of a character
32 * - mb_output_handler - Callback function converts character encoding in output buffer
33 * - mb_scrub - Replaces ill-formed byte sequences with substitute characters
34 * - mb_strlen - Get string length
35 * - mb_strpos - Find position of first occurrence of string in a string
36 * - mb_strrpos - Find position of last occurrence of a string in a string
37 * - mb_str_split - Convert a string to an array
38 * - mb_strtolower - Make a string lowercase
39 * - mb_strtoupper - Make a string uppercase
40 * - mb_substitute_character - Set/Get substitution character
41 * - mb_substr - Get part of string
42 * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive
43 * - mb_stristr - Finds first occurrence of a string within another, case insensitive
44 * - mb_strrchr - Finds the last occurrence of a character in a string within another
45 * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive
46 * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive
47 * - mb_strstr - Finds first occurrence of a string within another
48 * - mb_strwidth - Return width of string
49 * - mb_substr_count - Count the number of substring occurrences
50 * - mb_ucfirst - Make a string's first character uppercase
51 * - mb_lcfirst - Make a string's first character lowercase
52 * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string
53 * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string
54 * - mb_rtrim - Strip whitespace (or other characters) from the end of a string
55 *
56 * Not implemented:
57 * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
58 * - mb_ereg_* - Regular expression with multibyte support
59 * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
60 * - mb_preferred_mime_name - Get MIME charset string
61 * - mb_regex_encoding - Returns current encoding for multibyte regex as string
62 * - mb_regex_set_options - Set/Get the default options for mbregex functions
63 * - mb_send_mail - Send encoded mail
64 * - mb_split - Split multibyte string using regular expression
65 * - mb_strcut - Get part of string
66 * - mb_strimwidth - Get truncated string with specified width
67 *
68 * @author Nicolas Grekas <p@tchwork.com>
69 *
70 * @internal
71 */
72 final class Mbstring
73 {
74 public const MB_CASE_FOLD = \PHP_INT_MAX;
75 private const SIMPLE_CASE_FOLD = [['µ', 'ſ', "�
76 ", 'ς', "ϐ", "ϑ", "ϕ", "ϖ", "ϰ", "ϱ", "ϵ", "", ""], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "", 'ι']];
77 private static $encodingList = ['ASCII', 'UTF-8'];
78 private static $language = 'neutral';
79 private static $internalEncoding = 'UTF-8';
80 private static $iconvSupportsIgnore;
81 public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
82 {
83 if (\is_array($s)) {
84 $r = [];
85 foreach ($s as $str) {
86 $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding);
87 }
88 return $r;
89 }
90 if (\is_array($fromEncoding) || null !== $fromEncoding && \false !== strpos($fromEncoding, ',')) {
91 $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
92 } else {
93 $fromEncoding = self::getEncoding($fromEncoding);
94 }
95 $toEncoding = self::getEncoding($toEncoding);
96 if ('BASE64' === $fromEncoding) {
97 $s = base64_decode($s);
98 $fromEncoding = $toEncoding;
99 }
100 if ('BASE64' === $toEncoding) {
101 return base64_encode($s);
102 }
103 if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
104 if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
105 $fromEncoding = 'Windows-1252';
106 }
107 if ('UTF-8' !== $fromEncoding) {
108 $s = self::iconv($fromEncoding, 'UTF-8', $s);
109 }
110 return preg_replace_callback('/[\\x80-\\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
111 }
112 if ('HTML-ENTITIES' === $fromEncoding) {
113 $decodeControlChars = static function ($m) {
114 $code = '' !== ($m[2] ?? '') ? hexdec($m[2]) : (int) $m[1];
115 if ($code < 32 || 127 === $code) {
116 return \chr($code);
117 }
118 if (128 <= $code && $code <= 159) {
119 return "\xc2" . \chr(0x80 | $code & 0x3f);
120 }
121 return $m[0];
122 };
123 if (\PHP_VERSION_ID >= 70400) {
124 $s = html_entity_decode($s, \ENT_QUOTES, 'UTF-8');
125 // html_entity_decode() leaves numeric entities for C0/C1 control
126 // characters as-is (HTML spec), but mb_convert_encoding() decodes
127 // them. Catch what html_entity_decode() missed.
128 if (\false !== strpos($s, '&#')) {
129 $s = preg_replace_callback('/&#(?:0*([0-9]++)|[xX]0*([0-9a-fA-F]++));/', $decodeControlChars, $s);
130 }
131 } else {
132 // PHP < 7.4: html_entity_decode() truncates strings at NUL bytes,
133 // so decode the control character entities first then call
134 // html_entity_decode() on each NUL-delimited chunk independently.
135 $s = preg_replace_callback('/&#(?:0*([0-9]++)|[xX]0*([0-9a-fA-F]++));/', $decodeControlChars, $s);
136 $s = implode("\x00", array_map(static function ($chunk) {
137 return html_entity_decode($chunk, \ENT_QUOTES, 'UTF-8');
138 }, explode("\x00", $s)));
139 }
140 $fromEncoding = 'UTF-8';
141 }
142 if ($fromEncoding === $toEncoding) {
143 return $s;
144 }
145 return self::iconv($fromEncoding, $toEncoding, $s);
146 }
147 public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
148 {
149 $ok = \true;
150 array_walk_recursive($vars, static function (&$v) use(&$ok, $toEncoding, $fromEncoding) {
151 if (\false === ($v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding))) {
152 $ok = \false;
153 }
154 });
155 return $ok ? $fromEncoding : \false;
156 }
157 public static function mb_decode_mimeheader($s)
158 {
159 return iconv_mime_decode($s, 2, self::$internalEncoding);
160 }
161 public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
162 {
163 trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
164 }
165 public static function mb_decode_numericentity($s, $convmap, $encoding = null)
166 {
167 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
168 trigger_error('mb_decode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
169 return null;
170 }
171 if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) {
172 return \false;
173 }
174 if (null !== $encoding && !\is_scalar($encoding)) {
175 trigger_error('mb_decode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
176 return '';
177 // Instead of null (cf. mb_encode_numericentity).
178 }
179 $s = (string) $s;
180 if ('' === $s) {
181 return '';
182 }
183 $encoding = self::getEncoding($encoding);
184 if ('UTF-8' === $encoding) {
185 $encoding = null;
186 if (!preg_match('//u', $s)) {
187 $s = @self::iconv('UTF-8', 'UTF-8', $s);
188 }
189 } else {
190 $s = self::iconv($encoding, 'UTF-8', $s);
191 }
192 $cnt = floor(\count($convmap) / 4) * 4;
193 for ($i = 0; $i < $cnt; $i += 4) {
194 // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
195 $convmap[$i] += $convmap[$i + 2];
196 $convmap[$i + 1] += $convmap[$i + 2];
197 }
198 $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))' . (\PHP_VERSION_ID >= 80200 ? '' : '(?!&)') . ';?/', static function (array $m) use($cnt, $convmap) {
199 $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
200 for ($i = 0; $i < $cnt; $i += 4) {
201 if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
202 return self::mb_chr($c - $convmap[$i + 2]);
203 }
204 }
205 return $m[0];
206 }, $s);
207 if (null === $encoding) {
208 return $s;
209 }
210 return self::iconv('UTF-8', $encoding, $s);
211 }
212 public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = \false)
213 {
214 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
215 trigger_error('mb_encode_numericentity() expects parameter 1 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
216 return null;
217 }
218 if (!\is_array($convmap) || 80000 > \PHP_VERSION_ID && !$convmap) {
219 return \false;
220 }
221 if (null !== $encoding && !\is_scalar($encoding)) {
222 trigger_error('mb_encode_numericentity() expects parameter 3 to be string, ' . \gettype($s) . ' given', \E_USER_WARNING);
223 return null;
224 // Instead of '' (cf. mb_decode_numericentity).
225 }
226 if (null !== $is_hex && !\is_scalar($is_hex)) {
227 trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, ' . \gettype($s) . ' given', \E_USER_WARNING);
228 return null;
229 }
230 $s = (string) $s;
231 if ('' === $s) {
232 return '';
233 }
234 $encoding = self::getEncoding($encoding);
235 if ('UTF-8' === $encoding) {
236 $encoding = null;
237 if (!preg_match('//u', $s)) {
238 $s = @self::iconv('UTF-8', 'UTF-8', $s);
239 }
240 } else {
241 $s = self::iconv($encoding, 'UTF-8', $s);
242 }
243 static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4];
244 $cnt = floor(\count($convmap) / 4) * 4;
245 $i = 0;
246 $len = \strlen($s);
247 $result = '';
248 while ($i < $len) {
249 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"];
250 $uchr = substr($s, $i, $ulen);
251 $i += $ulen;
252 $c = self::mb_ord($uchr);
253 for ($j = 0; $j < $cnt; $j += 4) {
254 if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
255 $cOffset = $c + $convmap[$j + 2] & $convmap[$j + 3];
256 $result .= $is_hex ? \sprintf('&#x%X;', $cOffset) : '&#' . $cOffset . ';';
257 continue 2;
258 }
259 }
260 $result .= $uchr;
261 }
262 if (null === $encoding) {
263 return $result;
264 }
265 return self::iconv('UTF-8', $encoding, $result);
266 }
267 public static function mb_convert_case($s, $mode, $encoding = null)
268 {
269 $s = (string) $s;
270 if ('' === $s) {
271 return '';
272 }
273 $encoding = self::getEncoding($encoding);
274 if ('UTF-8' === $encoding) {
275 $encoding = null;
276 if (!preg_match('//u', $s)) {
277 $s = @self::iconv('UTF-8', 'UTF-8', $s);
278 }
279 } else {
280 $s = self::iconv($encoding, 'UTF-8', $s);
281 }
282 if (\MB_CASE_TITLE == $mode) {
283 static $titleRegexp = null;
284 if (null === $titleRegexp) {
285 $titleRegexp = self::getData('titleCaseRegexp');
286 }
287 $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
288 } else {
289 if (\MB_CASE_UPPER == $mode) {
290 static $upper = null;
291 if (null === $upper) {
292 $upper = self::getData('upperCase');
293 }
294 $map = $upper;
295 } else {
296 if (self::MB_CASE_FOLD === $mode) {
297 static $caseFolding = null;
298 if (null === $caseFolding) {
299 $caseFolding = self::getData('caseFolding');
300 }
301 $s = strtr($s, $caseFolding);
302 }
303 static $lower = null;
304 if (null === $lower) {
305 $lower = self::getData('lowerCase');
306 }
307 $map = $lower;
308 }
309 static $ulenMask = ["\xc0" => 2, "\xd0" => 2, "\xe0" => 3, "\xf0" => 4];
310 $i = 0;
311 $len = \strlen($s);
312 while ($i < $len) {
313 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xf0"];
314 $uchr = substr($s, $i, $ulen);
315 $i += $ulen;
316 if (isset($map[$uchr])) {
317 $uchr = $map[$uchr];
318 $nlen = \strlen($uchr);
319 if ($nlen == $ulen) {
320 $nlen = $i;
321 do {
322 $s[--$nlen] = $uchr[--$ulen];
323 } while ($ulen);
324 } else {
325 $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
326 $len += $nlen - $ulen;
327 $i += $nlen - $ulen;
328 }
329 }
330 }
331 }
332 if (null === $encoding) {
333 return $s;
334 }
335 return self::iconv('UTF-8', $encoding, $s);
336 }
337 public static function mb_internal_encoding($encoding = null)
338 {
339 if (null === $encoding) {
340 return self::$internalEncoding;
341 }
342 $normalizedEncoding = self::getEncoding($encoding);
343 if ('UTF-8' === $normalizedEncoding || \false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
344 self::$internalEncoding = $normalizedEncoding;
345 return \true;
346 }
347 if (80000 > \PHP_VERSION_ID) {
348 return \false;
349 }
350 throw new \ValueError(\sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
351 }
352 public static function mb_language($lang = null)
353 {
354 if (null === $lang) {
355 return self::$language;
356 }
357 switch ($normalizedLang = strtolower($lang)) {
358 case 'uni':
359 case 'neutral':
360 self::$language = $normalizedLang;
361 return \true;
362 }
363 if (80000 > \PHP_VERSION_ID) {
364 return \false;
365 }
366 throw new \ValueError(\sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
367 }
368 public static function mb_list_encodings()
369 {
370 return ['UTF-8'];
371 }
372 public static function mb_encoding_aliases($encoding)
373 {
374 switch (strtoupper($encoding)) {
375 case 'UTF8':
376 case 'UTF-8':
377 return ['utf8'];
378 }
379 return \false;
380 }
381 public static function mb_check_encoding($var = null, $encoding = null)
382 {
383 if (null === $encoding) {
384 if (null === $var) {
385 return \false;
386 }
387 $encoding = self::$internalEncoding;
388 }
389 if (!\is_array($var)) {
390 return self::mb_detect_encoding($var, [$encoding]) || \false !== @iconv($encoding, $encoding, $var);
391 }
392 foreach ($var as $key => $value) {
393 if (!self::mb_check_encoding($key, $encoding)) {
394 return \false;
395 }
396 if (!self::mb_check_encoding($value, $encoding)) {
397 return \false;
398 }
399 }
400 return \true;
401 }
402 public static function mb_detect_encoding($str, $encodingList = null, $strict = \false)
403 {
404 if (null === $encodingList) {
405 $encodingList = self::$encodingList;
406 } else {
407 if (!\is_array($encodingList)) {
408 $encodingList = array_map('trim', explode(',', $encodingList));
409 }
410 $encodingList = array_map('strtoupper', $encodingList);
411 }
412 foreach ($encodingList as $enc) {
413 switch ($enc) {
414 case 'ASCII':
415 if (!preg_match('/[\\x80-\\xFF]/', $str)) {
416 return $enc;
417 }
418 break;
419 case 'UTF8':
420 case 'UTF-8':
421 if (preg_match('//u', $str)) {
422 return 'UTF-8';
423 }
424 break;
425 default:
426 if (0 === strncmp($enc, 'ISO-8859-', 9)) {
427 return $enc;
428 }
429 }
430 }
431 return \false;
432 }
433 public static function mb_detect_order($encodingList = null)
434 {
435 if (null === $encodingList) {
436 return self::$encodingList;
437 }
438 if (!\is_array($encodingList)) {
439 $encodingList = array_map('trim', explode(',', $encodingList));
440 }
441 $encodingList = array_map('strtoupper', $encodingList);
442 foreach ($encodingList as $enc) {
443 switch ($enc) {
444 default:
445 if (strncmp($enc, 'ISO-8859-', 9)) {
446 return \false;
447 }
448 // no break
449 case 'ASCII':
450 case 'UTF8':
451 case 'UTF-8':
452 }
453 }
454 self::$encodingList = $encodingList;
455 return \true;
456 }
457 public static function mb_strlen($s, $encoding = null)
458 {
459 $encoding = self::getEncoding($encoding);
460 if ('CP850' === $encoding || 'ASCII' === $encoding) {
461 return \strlen($s);
462 }
463 if (\false !== ($len = @iconv_strlen($s, $encoding))) {
464 return $len;
465 }
466 if ('UTF-8' !== $encoding) {
467 return $len;
468 }
469 return preg_match_all('/[\\x00-\\x7F]|[\\xC0-\\xDF][\\x80-\\xBF]?|[\\xE0-\\xEF][\\x80-\\xBF]{0,2}|[\\xF0-\\xF7][\\x80-\\xBF]{0,3}|[\\xF8-\\xFB][\\x80-\\xBF]{0,4}|[\\xFC-\\xFD][\\x80-\\xBF]{0,5}|[\\x80-\\xBF\\xFE\\xFF]/s', $s);
470 }
471 public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
472 {
473 $encoding = self::getEncoding($encoding);
474 if ('CP850' === $encoding || 'ASCII' === $encoding) {
475 return strpos($haystack, $needle, $offset);
476 }
477 $needle = (string) $needle;
478 if ('' === $needle) {
479 if (80000 > \PHP_VERSION_ID) {
480 trigger_error(__METHOD__ . ': Empty delimiter', \E_USER_WARNING);
481 return \false;
482 }
483 return 0;
484 }
485 return iconv_strpos($haystack, $needle, $offset, $encoding);
486 }
487 public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
488 {
489 $encoding = self::getEncoding($encoding);
490 if ('CP850' === $encoding || 'ASCII' === $encoding) {
491 return strrpos($haystack, $needle, $offset);
492 }
493 if ($offset != (int) $offset) {
494 $offset = 0;
495 } elseif ($offset = (int) $offset) {
496 if ($offset < 0) {
497 if (0 > ($offset += self::mb_strlen($needle))) {
498 $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
499 }
500 $offset = 0;
501 } else {
502 $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
503 }
504 }
505 $pos = '' !== $needle || 80000 > \PHP_VERSION_ID ? iconv_strrpos($haystack, $needle, $encoding) : self::mb_strlen($haystack, $encoding);
506 return \false !== $pos ? $offset + $pos : \false;
507 }
508 public static function mb_str_split($string, $split_length = 1, $encoding = null)
509 {
510 if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
511 trigger_error('mb_str_split() expects parameter 1 to be string, ' . \gettype($string) . ' given', \E_USER_WARNING);
512 return null;
513 }
514 if (1 > ($split_length = (int) $split_length)) {
515 if (80000 > \PHP_VERSION_ID) {
516 trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
517 return \false;
518 }
519 throw new \ValueError('Argument #2 ($length) must be greater than 0');
520 }
521 if (null === $encoding) {
522 $encoding = mb_internal_encoding();
523 }
524 if ('UTF-8' === ($encoding = self::getEncoding($encoding))) {
525 $rx = '/(';
526 while (65535 < $split_length) {
527 $rx .= '.{65535}';
528 $split_length -= 65535;
529 }
530 $rx .= '.{' . $split_length . '})/us';
531 return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
532 }
533 $result = [];
534 $length = mb_strlen($string, $encoding);
535 for ($i = 0; $i < $length; $i += $split_length) {
536 $result[] = mb_substr($string, $i, $split_length, $encoding);
537 }
538 return $result;
539 }
540 public static function mb_strtolower($s, $encoding = null)
541 {
542 return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
543 }
544 public static function mb_strtoupper($s, $encoding = null)
545 {
546 return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
547 }
548 public static function mb_substitute_character($c = null)
549 {
550 if (null === $c) {
551 return 'none';
552 }
553 if (0 === strcasecmp($c, 'none')) {
554 return \true;
555 }
556 if (80000 > \PHP_VERSION_ID) {
557 return \false;
558 }
559 if (\is_int($c) || 'long' === $c || 'entity' === $c) {
560 return \false;
561 }
562 throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
563 }
564 public static function mb_substr($s, $start, $length = null, $encoding = null)
565 {
566 $encoding = self::getEncoding($encoding);
567 if ('CP850' === $encoding || 'ASCII' === $encoding) {
568 return (string) substr($s, $start, null === $length ? 2147483647 : $length);
569 }
570 if ($start < 0) {
571 $start = iconv_strlen($s, $encoding) + $start;
572 if ($start < 0) {
573 $start = 0;
574 }
575 }
576 if (null === $length) {
577 $length = 2147483647;
578 } elseif ($length < 0) {
579 $length = iconv_strlen($s, $encoding) + $length - $start;
580 if ($length < 0) {
581 return '';
582 }
583 }
584 return (string) iconv_substr($s, $start, $length, $encoding);
585 }
586 public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
587 {
588 [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding)]);
589 return self::mb_strpos($haystack, $needle, $offset, $encoding);
590 }
591 public static function mb_stristr($haystack, $needle, $part = \false, $encoding = null)
592 {
593 $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
594 return self::getSubpart($pos, $part, $haystack, $encoding);
595 }
596 public static function mb_strrchr($haystack, $needle, $part = \false, $encoding = null)
597 {
598 $encoding = self::getEncoding($encoding);
599 if ('CP850' === $encoding || 'ASCII' === $encoding) {
600 $pos = strrpos($haystack, $needle);
601 } else {
602 $needle = self::mb_substr($needle, 0, 1, $encoding);
603 $pos = iconv_strrpos($haystack, $needle, $encoding);
604 }
605 return self::getSubpart($pos, $part, $haystack, $encoding);
606 }
607 public static function mb_strrichr($haystack, $needle, $part = \false, $encoding = null)
608 {
609 $needle = self::mb_substr($needle, 0, 1, $encoding);
610 $pos = self::mb_strripos($haystack, $needle, $encoding);
611 return self::getSubpart($pos, $part, $haystack, $encoding);
612 }
613 public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
614 {
615 $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
616 $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
617 $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
618 $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
619 return self::mb_strrpos($haystack, $needle, $offset, $encoding);
620 }
621 public static function mb_strstr($haystack, $needle, $part = \false, $encoding = null)
622 {
623 $pos = strpos($haystack, $needle);
624 if (\false === $pos) {
625 return \false;
626 }
627 if ($part) {
628 return substr($haystack, 0, $pos);
629 }
630 return substr($haystack, $pos);
631 }
632 public static function mb_get_info($type = 'all')
633 {
634 $info = ['internal_encoding' => self::$internalEncoding, 'http_output' => 'pass', 'http_output_conv_mimetypes' => '^(text/|application/xhtml\\+xml)', 'func_overload' => 0, 'func_overload_list' => 'no overload', 'mail_charset' => 'UTF-8', 'mail_header_encoding' => 'BASE64', 'mail_body_encoding' => 'BASE64', 'illegal_chars' => 0, 'encoding_translation' => 'Off', 'language' => self::$language, 'detect_order' => self::$encodingList, 'substitute_character' => 'none', 'strict_detection' => 'Off'];
635 if ('all' === $type) {
636 return $info;
637 }
638 if (isset($info[$type])) {
639 return $info[$type];
640 }
641 return \false;
642 }
643 public static function mb_http_input($type = '')
644 {
645 return \false;
646 }
647 public static function mb_http_output($encoding = null)
648 {
649 return null !== $encoding ? 'pass' === $encoding : 'pass';
650 }
651 public static function mb_strwidth($s, $encoding = null)
652 {
653 $encoding = self::getEncoding($encoding);
654 if ('UTF-8' !== $encoding) {
655 $s = self::iconv($encoding, 'UTF-8', $s);
656 }
657 $s = preg_replace('/[\\x{1100}-\\x{115F}\\x{2329}\\x{232A}\\x{2E80}-\\x{303E}\\x{3040}-\\x{A4CF}\\x{AC00}-\\x{D7A3}\\x{F900}-\\x{FAFF}\\x{FE10}-\\x{FE19}\\x{FE30}-\\x{FE6F}\\x{FF00}-\\x{FF60}\\x{FFE0}-\\x{FFE6}\\x{20000}-\\x{2FFFD}\\x{30000}-\\x{3FFFD}]/u', '', $s, -1, $wide);
658 return ($wide << 1) + iconv_strlen($s, 'UTF-8');
659 }
660 public static function mb_substr_count($haystack, $needle, $encoding = null)
661 {
662 return substr_count($haystack, $needle);
663 }
664 public static function mb_output_handler($contents, $status)
665 {
666 return $contents;
667 }
668 public static function mb_chr($code, $encoding = null)
669 {
670 if (0x80 > ($code %= 0x200000)) {
671 $s = \chr($code);
672 } elseif (0x800 > $code) {
673 $s = \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f);
674 } elseif (0x10000 > $code) {
675 $s = \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
676 } else {
677 $s = \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f);
678 }
679 if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) {
680 $s = mb_convert_encoding($s, $encoding, 'UTF-8');
681 }
682 return $s;
683 }
684 public static function mb_ord($s, $encoding = null)
685 {
686 if ('UTF-8' !== ($encoding = self::getEncoding($encoding))) {
687 $s = mb_convert_encoding($s, 'UTF-8', $encoding);
688 }
689 if (1 === \strlen($s)) {
690 return \ord($s);
691 }
692 $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
693 if (0xf0 <= $code) {
694 return ($code - 0xf0 << 18) + ($s[2] - 0x80 << 12) + ($s[3] - 0x80 << 6) + $s[4] - 0x80;
695 }
696 if (0xe0 <= $code) {
697 return ($code - 0xe0 << 12) + ($s[2] - 0x80 << 6) + $s[3] - 0x80;
698 }
699 if (0xc0 <= $code) {
700 return ($code - 0xc0 << 6) + $s[2] - 0x80;
701 }
702 return $code;
703 }
704 /** @return string|false */
705 public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null)
706 {
707 if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], \true)) {
708 if (\PHP_VERSION_ID < 80000) {
709 trigger_error('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH', \E_USER_WARNING);
710 return \false;
711 }
712 throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
713 }
714 if (null === $encoding) {
715 $encoding = self::mb_internal_encoding();
716 } elseif (!self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given')) {
717 return \false;
718 }
719 if (self::mb_strlen($pad_string, $encoding) <= 0) {
720 if (\PHP_VERSION_ID < 80000) {
721 trigger_error('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string', \E_USER_WARNING);
722 return \false;
723 }
724 throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
725 }
726 $paddingRequired = $length - self::mb_strlen($string, $encoding);
727 if ($paddingRequired < 1) {
728 return $string;
729 }
730 switch ($pad_type) {
731 case \STR_PAD_LEFT:
732 return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding) . $string;
733 case \STR_PAD_RIGHT:
734 return $string . self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
735 default:
736 $leftPaddingLength = floor($paddingRequired / 2);
737 $rightPaddingLength = $paddingRequired - $leftPaddingLength;
738 return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding) . $string . self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
739 }
740 }
741 /** @return string|false */
742 public static function mb_ucfirst(string $string, ?string $encoding = null)
743 {
744 if (null === $encoding) {
745 $encoding = self::mb_internal_encoding();
746 } elseif (!self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
747 return \false;
748 }
749 $firstChar = mb_substr($string, 0, 1, $encoding);
750 $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding);
751 return $firstChar . mb_substr($string, 1, null, $encoding);
752 }
753 /** @return string|false */
754 public static function mb_lcfirst(string $string, ?string $encoding = null)
755 {
756 if (null === $encoding) {
757 $encoding = self::mb_internal_encoding();
758 } elseif (!self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
759 return \false;
760 }
761 $firstChar = mb_substr($string, 0, 1, $encoding);
762 $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding);
763 return $firstChar . mb_substr($string, 1, null, $encoding);
764 }
765 /** @return string|false */
766 public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null)
767 {
768 return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
769 }
770 /** @return string|false */
771 public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null)
772 {
773 return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);
774 }
775 /** @return string|false */
776 public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null)
777 {
778 return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
779 }
780 private static function getSubpart($pos, $part, $haystack, $encoding)
781 {
782 if (\false === $pos) {
783 return \false;
784 }
785 if ($part) {
786 return self::mb_substr($haystack, 0, $pos, $encoding);
787 }
788 return self::mb_substr($haystack, $pos, null, $encoding);
789 }
790 private static function html_encoding_callback(array $m)
791 {
792 $i = 1;
793 $entities = '';
794 $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
795 while (isset($m[$i])) {
796 if (0x80 > $m[$i]) {
797 $entities .= \chr($m[$i++]);
798 continue;
799 }
800 if (0xf0 <= $m[$i]) {
801 $c = ($m[$i++] - 0xf0 << 18) + ($m[$i++] - 0x80 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80;
802 } elseif (0xe0 <= $m[$i]) {
803 $c = ($m[$i++] - 0xe0 << 12) + ($m[$i++] - 0x80 << 6) + $m[$i++] - 0x80;
804 } else {
805 $c = ($m[$i++] - 0xc0 << 6) + $m[$i++] - 0x80;
806 }
807 $entities .= '&#' . $c . ';';
808 }
809 return $entities;
810 }
811 private static function title_case(array $s)
812 {
813 return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8') . self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
814 }
815 private static function getData($file)
816 {
817 if (file_exists($file = __DIR__ . '/Resources/unidata/' . $file . '.php')) {
818 return require $file;
819 }
820 return \false;
821 }
822 private static function getEncoding($encoding)
823 {
824 if (null === $encoding) {
825 return self::$internalEncoding;
826 }
827 if ('UTF-8' === $encoding) {
828 return 'UTF-8';
829 }
830 $encoding = strtoupper($encoding);
831 if ('8BIT' === $encoding || 'BINARY' === $encoding) {
832 return 'CP850';
833 }
834 if ('UTF8' === $encoding) {
835 return 'UTF-8';
836 }
837 if ('UTF-32' === $encoding) {
838 return 'UTF-32BE';
839 }
840 if ('UTF-16' === $encoding) {
841 return 'UTF-16BE';
842 }
843 return $encoding;
844 }
845 private static function iconv($fromEncoding, $toEncoding, $s)
846 {
847 if (null === self::$iconvSupportsIgnore) {
848 self::$iconvSupportsIgnore = \false !== @iconv('UTF-8', 'UTF-8//IGNORE', '');
849 }
850 return self::$iconvSupportsIgnore ? iconv($fromEncoding, $toEncoding . '//IGNORE', $s) : iconv($fromEncoding, $toEncoding, $s);
851 }
852 /** @return string|false */
853 private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function)
854 {
855 if (null === $encoding) {
856 $encoding = self::mb_internal_encoding();
857 } elseif (!self::assertEncoding($encoding, $function . '(): Argument #3 ($encoding) must be a valid encoding, "%s" given')) {
858 return \false;
859 }
860 if ('' === $characters) {
861 return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding);
862 }
863 if ('UTF-8' === $encoding) {
864 $encoding = null;
865 if (!preg_match('//u', $string)) {
866 $string = @self::iconv('UTF-8', 'UTF-8', $string);
867 }
868 if (null !== $characters && !preg_match('//u', $characters)) {
869 $characters = @self::iconv('UTF-8', 'UTF-8', $characters);
870 }
871 } else {
872 $string = self::iconv($encoding, 'UTF-8', $string);
873 if (null !== $characters) {
874 $characters = self::iconv($encoding, 'UTF-8', $characters);
875 }
876 }
877 if (null === $characters) {
878 $characters = "\\0 \f\n\r\t\v       �
879      

   �
880 ";
881 } else {
882 $characters = preg_quote($characters);
883 }
884 $string = preg_replace(\sprintf($regex, $characters), '', $string);
885 if (null === $encoding) {
886 return $string;
887 }
888 return self::iconv('UTF-8', $encoding, $string);
889 }
890 private static function assertEncoding(string $encoding, string $errorFormat) : bool
891 {
892 try {
893 $validEncoding = @self::mb_check_encoding('', $encoding);
894 } catch (\ValueError $e) {
895 throw new \ValueError(\sprintf($errorFormat, $encoding));
896 }
897 if (!$validEncoding) {
898 if (80000 > \PHP_VERSION_ID) {
899 trigger_error(\sprintf($errorFormat, $encoding), \E_USER_WARNING);
900 } else {
901 throw new \ValueError(\sprintf($errorFormat, $encoding));
902 }
903 }
904 return $validEncoding;
905 }
906 }
907