summaryrefslogtreecommitdiff
path: root/vendor/symfony/polyfill-mbstring/Mbstring.php
diff options
context:
space:
mode:
authorpolo <ordipolo@gmx.fr>2024-08-13 23:45:21 +0200
committerpolo <ordipolo@gmx.fr>2024-08-13 23:45:21 +0200
commitbf6655a534a6775d30cafa67bd801276bda1d98d (patch)
treec6381e3f6c81c33eab72508f410b165ba05f7e9c /vendor/symfony/polyfill-mbstring/Mbstring.php
parent94d67a4b51f8e62e7d518cce26a526ae1ec48278 (diff)
downloadAppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.zip
VERSION 0.2 doctrine ORM et entités
Diffstat (limited to 'vendor/symfony/polyfill-mbstring/Mbstring.php')
-rw-r--r--vendor/symfony/polyfill-mbstring/Mbstring.php996
1 files changed, 996 insertions, 0 deletions
diff --git a/vendor/symfony/polyfill-mbstring/Mbstring.php b/vendor/symfony/polyfill-mbstring/Mbstring.php
new file mode 100644
index 0000000..1ad33a8
--- /dev/null
+++ b/vendor/symfony/polyfill-mbstring/Mbstring.php
@@ -0,0 +1,996 @@
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
12namespace Symfony\Polyfill\Mbstring;
13
14/**
15 * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
16 *
17 * Implemented:
18 * - mb_chr - Returns a specific character from its Unicode code point
19 * - mb_convert_encoding - Convert character encoding
20 * - mb_convert_variables - Convert character code in variable(s)
21 * - mb_decode_mimeheader - Decode string in MIME header field
22 * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
23 * - mb_decode_numericentity - Decode HTML numeric string reference to character
24 * - mb_encode_numericentity - Encode character to HTML numeric string reference
25 * - mb_convert_case - Perform case folding on a string
26 * - mb_detect_encoding - Detect character encoding
27 * - mb_get_info - Get internal settings of mbstring
28 * - mb_http_input - Detect HTTP input character encoding
29 * - mb_http_output - Set/Get HTTP output character encoding
30 * - mb_internal_encoding - Set/Get internal character encoding
31 * - mb_list_encodings - Returns an array of all supported encodings
32 * - mb_ord - Returns the Unicode code point of a character
33 * - mb_output_handler - Callback function converts character encoding in output buffer
34 * - mb_scrub - Replaces ill-formed byte sequences with substitute characters
35 * - mb_strlen - Get string length
36 * - mb_strpos - Find position of first occurrence of string in a string
37 * - mb_strrpos - Find position of last occurrence of a string in a string
38 * - mb_str_split - Convert a string to an array
39 * - mb_strtolower - Make a string lowercase
40 * - mb_strtoupper - Make a string uppercase
41 * - mb_substitute_character - Set/Get substitution character
42 * - mb_substr - Get part of string
43 * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive
44 * - mb_stristr - Finds first occurrence of a string within another, case insensitive
45 * - mb_strrchr - Finds the last occurrence of a character in a string within another
46 * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive
47 * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive
48 * - mb_strstr - Finds first occurrence of a string within another
49 * - mb_strwidth - Return width of string
50 * - mb_substr_count - Count the number of substring occurrences
51 * - mb_ucfirst - Make a string's first character uppercase
52 * - mb_lcfirst - Make a string's first character lowercase
53 *
54 * Not implemented:
55 * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
56 * - mb_ereg_* - Regular expression with multibyte support
57 * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
58 * - mb_preferred_mime_name - Get MIME charset string
59 * - mb_regex_encoding - Returns current encoding for multibyte regex as string
60 * - mb_regex_set_options - Set/Get the default options for mbregex functions
61 * - mb_send_mail - Send encoded mail
62 * - mb_split - Split multibyte string using regular expression
63 * - mb_strcut - Get part of string
64 * - mb_strimwidth - Get truncated string with specified width
65 *
66 * @author Nicolas Grekas <p@tchwork.com>
67 *
68 * @internal
69 */
70final class Mbstring
71{
72 public const MB_CASE_FOLD = \PHP_INT_MAX;
73
74 private const SIMPLE_CASE_FOLD = [
75 ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
76 ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
77 ];
78
79 private static $encodingList = ['ASCII', 'UTF-8'];
80 private static $language = 'neutral';
81 private static $internalEncoding = 'UTF-8';
82
83 public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
84 {
85 if (\is_array($s)) {
86 if (PHP_VERSION_ID < 70200) {
87 trigger_error('mb_convert_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING);
88
89 return null;
90 }
91
92 $r = [];
93 foreach ($s as $str) {
94 $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding);
95 }
96
97 return $r;
98 }
99
100 if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
101 $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
102 } else {
103 $fromEncoding = self::getEncoding($fromEncoding);
104 }
105
106 $toEncoding = self::getEncoding($toEncoding);
107
108 if ('BASE64' === $fromEncoding) {
109 $s = base64_decode($s);
110 $fromEncoding = $toEncoding;
111 }
112
113 if ('BASE64' === $toEncoding) {
114 return base64_encode($s);
115 }
116
117 if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
118 if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
119 $fromEncoding = 'Windows-1252';
120 }
121 if ('UTF-8' !== $fromEncoding) {
122 $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
123 }
124
125 return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
126 }
127
128 if ('HTML-ENTITIES' === $fromEncoding) {
129 $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
130 $fromEncoding = 'UTF-8';
131 }
132
133 return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
134 }
135
136 public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
137 {
138 $ok = true;
139 array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
140 if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
141 $ok = false;
142 }
143 });
144
145 return $ok ? $fromEncoding : false;
146 }
147
148 public static function mb_decode_mimeheader($s)
149 {
150 return iconv_mime_decode($s, 2, self::$internalEncoding);
151 }
152
153 public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
154 {
155 trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
156 }
157
158 public static function mb_decode_numericentity($s, $convmap, $encoding = null)
159 {
160 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
161 trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
162
163 return null;
164 }
165
166 if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
167 return false;
168 }
169
170 if (null !== $encoding && !\is_scalar($encoding)) {
171 trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
172
173 return ''; // Instead of null (cf. mb_encode_numericentity).
174 }
175
176 $s = (string) $s;
177 if ('' === $s) {
178 return '';
179 }
180
181 $encoding = self::getEncoding($encoding);
182
183 if ('UTF-8' === $encoding) {
184 $encoding = null;
185 if (!preg_match('//u', $s)) {
186 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
187 }
188 } else {
189 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
190 }
191
192 $cnt = floor(\count($convmap) / 4) * 4;
193
194 for ($i = 0; $i < $cnt; $i += 4) {
195 // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
196 $convmap[$i] += $convmap[$i + 2];
197 $convmap[$i + 1] += $convmap[$i + 2];
198 }
199
200 $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
201 $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
202 for ($i = 0; $i < $cnt; $i += 4) {
203 if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
204 return self::mb_chr($c - $convmap[$i + 2]);
205 }
206 }
207
208 return $m[0];
209 }, $s);
210
211 if (null === $encoding) {
212 return $s;
213 }
214
215 return iconv('UTF-8', $encoding.'//IGNORE', $s);
216 }
217
218 public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
219 {
220 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
221 trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
222
223 return null;
224 }
225
226 if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
227 return false;
228 }
229
230 if (null !== $encoding && !\is_scalar($encoding)) {
231 trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
232
233 return null; // Instead of '' (cf. mb_decode_numericentity).
234 }
235
236 if (null !== $is_hex && !\is_scalar($is_hex)) {
237 trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
238
239 return null;
240 }
241
242 $s = (string) $s;
243 if ('' === $s) {
244 return '';
245 }
246
247 $encoding = self::getEncoding($encoding);
248
249 if ('UTF-8' === $encoding) {
250 $encoding = null;
251 if (!preg_match('//u', $s)) {
252 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
253 }
254 } else {
255 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
256 }
257
258 static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
259
260 $cnt = floor(\count($convmap) / 4) * 4;
261 $i = 0;
262 $len = \strlen($s);
263 $result = '';
264
265 while ($i < $len) {
266 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
267 $uchr = substr($s, $i, $ulen);
268 $i += $ulen;
269 $c = self::mb_ord($uchr);
270
271 for ($j = 0; $j < $cnt; $j += 4) {
272 if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
273 $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
274 $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
275 continue 2;
276 }
277 }
278 $result .= $uchr;
279 }
280
281 if (null === $encoding) {
282 return $result;
283 }
284
285 return iconv('UTF-8', $encoding.'//IGNORE', $result);
286 }
287
288 public static function mb_convert_case($s, $mode, $encoding = null)
289 {
290 $s = (string) $s;
291 if ('' === $s) {
292 return '';
293 }
294
295 $encoding = self::getEncoding($encoding);
296
297 if ('UTF-8' === $encoding) {
298 $encoding = null;
299 if (!preg_match('//u', $s)) {
300 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
301 }
302 } else {
303 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
304 }
305
306 if (\MB_CASE_TITLE == $mode) {
307 static $titleRegexp = null;
308 if (null === $titleRegexp) {
309 $titleRegexp = self::getData('titleCaseRegexp');
310 }
311 $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
312 } else {
313 if (\MB_CASE_UPPER == $mode) {
314 static $upper = null;
315 if (null === $upper) {
316 $upper = self::getData('upperCase');
317 }
318 $map = $upper;
319 } else {
320 if (self::MB_CASE_FOLD === $mode) {
321 static $caseFolding = null;
322 if (null === $caseFolding) {
323 $caseFolding = self::getData('caseFolding');
324 }
325 $s = strtr($s, $caseFolding);
326 }
327
328 static $lower = null;
329 if (null === $lower) {
330 $lower = self::getData('lowerCase');
331 }
332 $map = $lower;
333 }
334
335 static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
336
337 $i = 0;
338 $len = \strlen($s);
339
340 while ($i < $len) {
341 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
342 $uchr = substr($s, $i, $ulen);
343 $i += $ulen;
344
345 if (isset($map[$uchr])) {
346 $uchr = $map[$uchr];
347 $nlen = \strlen($uchr);
348
349 if ($nlen == $ulen) {
350 $nlen = $i;
351 do {
352 $s[--$nlen] = $uchr[--$ulen];
353 } while ($ulen);
354 } else {
355 $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
356 $len += $nlen - $ulen;
357 $i += $nlen - $ulen;
358 }
359 }
360 }
361 }
362
363 if (null === $encoding) {
364 return $s;
365 }
366
367 return iconv('UTF-8', $encoding.'//IGNORE', $s);
368 }
369
370 public static function mb_internal_encoding($encoding = null)
371 {
372 if (null === $encoding) {
373 return self::$internalEncoding;
374 }
375
376 $normalizedEncoding = self::getEncoding($encoding);
377
378 if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
379 self::$internalEncoding = $normalizedEncoding;
380
381 return true;
382 }
383
384 if (80000 > \PHP_VERSION_ID) {
385 return false;
386 }
387
388 throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
389 }
390
391 public static function mb_language($lang = null)
392 {
393 if (null === $lang) {
394 return self::$language;
395 }
396
397 switch ($normalizedLang = strtolower($lang)) {
398 case 'uni':
399 case 'neutral':
400 self::$language = $normalizedLang;
401
402 return true;
403 }
404
405 if (80000 > \PHP_VERSION_ID) {
406 return false;
407 }
408
409 throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
410 }
411
412 public static function mb_list_encodings()
413 {
414 return ['UTF-8'];
415 }
416
417 public static function mb_encoding_aliases($encoding)
418 {
419 switch (strtoupper($encoding)) {
420 case 'UTF8':
421 case 'UTF-8':
422 return ['utf8'];
423 }
424
425 return false;
426 }
427
428 public static function mb_check_encoding($var = null, $encoding = null)
429 {
430 if (\PHP_VERSION_ID < 70200 && \is_array($var)) {
431 trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING);
432
433 return null;
434 }
435
436 if (null === $encoding) {
437 if (null === $var) {
438 return false;
439 }
440 $encoding = self::$internalEncoding;
441 }
442
443 if (!\is_array($var)) {
444 return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
445 }
446
447 foreach ($var as $key => $value) {
448 if (!self::mb_check_encoding($key, $encoding)) {
449 return false;
450 }
451 if (!self::mb_check_encoding($value, $encoding)) {
452 return false;
453 }
454 }
455
456 return true;
457 }
458
459 public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
460 {
461 if (null === $encodingList) {
462 $encodingList = self::$encodingList;
463 } else {
464 if (!\is_array($encodingList)) {
465 $encodingList = array_map('trim', explode(',', $encodingList));
466 }
467 $encodingList = array_map('strtoupper', $encodingList);
468 }
469
470 foreach ($encodingList as $enc) {
471 switch ($enc) {
472 case 'ASCII':
473 if (!preg_match('/[\x80-\xFF]/', $str)) {
474 return $enc;
475 }
476 break;
477
478 case 'UTF8':
479 case 'UTF-8':
480 if (preg_match('//u', $str)) {
481 return 'UTF-8';
482 }
483 break;
484
485 default:
486 if (0 === strncmp($enc, 'ISO-8859-', 9)) {
487 return $enc;
488 }
489 }
490 }
491
492 return false;
493 }
494
495 public static function mb_detect_order($encodingList = null)
496 {
497 if (null === $encodingList) {
498 return self::$encodingList;
499 }
500
501 if (!\is_array($encodingList)) {
502 $encodingList = array_map('trim', explode(',', $encodingList));
503 }
504 $encodingList = array_map('strtoupper', $encodingList);
505
506 foreach ($encodingList as $enc) {
507 switch ($enc) {
508 default:
509 if (strncmp($enc, 'ISO-8859-', 9)) {
510 return false;
511 }
512 // no break
513 case 'ASCII':
514 case 'UTF8':
515 case 'UTF-8':
516 }
517 }
518
519 self::$encodingList = $encodingList;
520
521 return true;
522 }
523
524 public static function mb_strlen($s, $encoding = null)
525 {
526 $encoding = self::getEncoding($encoding);
527 if ('CP850' === $encoding || 'ASCII' === $encoding) {
528 return \strlen($s);
529 }
530
531 return @iconv_strlen($s, $encoding);
532 }
533
534 public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
535 {
536 $encoding = self::getEncoding($encoding);
537 if ('CP850' === $encoding || 'ASCII' === $encoding) {
538 return strpos($haystack, $needle, $offset);
539 }
540
541 $needle = (string) $needle;
542 if ('' === $needle) {
543 if (80000 > \PHP_VERSION_ID) {
544 trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
545
546 return false;
547 }
548
549 return 0;
550 }
551
552 return iconv_strpos($haystack, $needle, $offset, $encoding);
553 }
554
555 public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
556 {
557 $encoding = self::getEncoding($encoding);
558 if ('CP850' === $encoding || 'ASCII' === $encoding) {
559 return strrpos($haystack, $needle, $offset);
560 }
561
562 if ($offset != (int) $offset) {
563 $offset = 0;
564 } elseif ($offset = (int) $offset) {
565 if ($offset < 0) {
566 if (0 > $offset += self::mb_strlen($needle)) {
567 $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
568 }
569 $offset = 0;
570 } else {
571 $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
572 }
573 }
574
575 $pos = '' !== $needle || 80000 > \PHP_VERSION_ID
576 ? iconv_strrpos($haystack, $needle, $encoding)
577 : self::mb_strlen($haystack, $encoding);
578
579 return false !== $pos ? $offset + $pos : false;
580 }
581
582 public static function mb_str_split($string, $split_length = 1, $encoding = null)
583 {
584 if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
585 trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
586
587 return null;
588 }
589
590 if (1 > $split_length = (int) $split_length) {
591 if (80000 > \PHP_VERSION_ID) {
592 trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
593
594 return false;
595 }
596
597 throw new \ValueError('Argument #2 ($length) must be greater than 0');
598 }
599
600 if (null === $encoding) {
601 $encoding = mb_internal_encoding();
602 }
603
604 if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
605 $rx = '/(';
606 while (65535 < $split_length) {
607 $rx .= '.{65535}';
608 $split_length -= 65535;
609 }
610 $rx .= '.{'.$split_length.'})/us';
611
612 return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
613 }
614
615 $result = [];
616 $length = mb_strlen($string, $encoding);
617
618 for ($i = 0; $i < $length; $i += $split_length) {
619 $result[] = mb_substr($string, $i, $split_length, $encoding);
620 }
621
622 return $result;
623 }
624
625 public static function mb_strtolower($s, $encoding = null)
626 {
627 return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
628 }
629
630 public static function mb_strtoupper($s, $encoding = null)
631 {
632 return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
633 }
634
635 public static function mb_substitute_character($c = null)
636 {
637 if (null === $c) {
638 return 'none';
639 }
640 if (0 === strcasecmp($c, 'none')) {
641 return true;
642 }
643 if (80000 > \PHP_VERSION_ID) {
644 return false;
645 }
646 if (\is_int($c) || 'long' === $c || 'entity' === $c) {
647 return false;
648 }
649
650 throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
651 }
652
653 public static function mb_substr($s, $start, $length = null, $encoding = null)
654 {
655 $encoding = self::getEncoding($encoding);
656 if ('CP850' === $encoding || 'ASCII' === $encoding) {
657 return (string) substr($s, $start, null === $length ? 2147483647 : $length);
658 }
659
660 if ($start < 0) {
661 $start = iconv_strlen($s, $encoding) + $start;
662 if ($start < 0) {
663 $start = 0;
664 }
665 }
666
667 if (null === $length) {
668 $length = 2147483647;
669 } elseif ($length < 0) {
670 $length = iconv_strlen($s, $encoding) + $length - $start;
671 if ($length < 0) {
672 return '';
673 }
674 }
675
676 return (string) iconv_substr($s, $start, $length, $encoding);
677 }
678
679 public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
680 {
681 [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
682 self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
683 self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
684 ]);
685
686 return self::mb_strpos($haystack, $needle, $offset, $encoding);
687 }
688
689 public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
690 {
691 $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
692
693 return self::getSubpart($pos, $part, $haystack, $encoding);
694 }
695
696 public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
697 {
698 $encoding = self::getEncoding($encoding);
699 if ('CP850' === $encoding || 'ASCII' === $encoding) {
700 $pos = strrpos($haystack, $needle);
701 } else {
702 $needle = self::mb_substr($needle, 0, 1, $encoding);
703 $pos = iconv_strrpos($haystack, $needle, $encoding);
704 }
705
706 return self::getSubpart($pos, $part, $haystack, $encoding);
707 }
708
709 public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
710 {
711 $needle = self::mb_substr($needle, 0, 1, $encoding);
712 $pos = self::mb_strripos($haystack, $needle, $encoding);
713
714 return self::getSubpart($pos, $part, $haystack, $encoding);
715 }
716
717 public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
718 {
719 $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
720 $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
721
722 $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
723 $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
724
725 return self::mb_strrpos($haystack, $needle, $offset, $encoding);
726 }
727
728 public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
729 {
730 $pos = strpos($haystack, $needle);
731 if (false === $pos) {
732 return false;
733 }
734 if ($part) {
735 return substr($haystack, 0, $pos);
736 }
737
738 return substr($haystack, $pos);
739 }
740
741 public static function mb_get_info($type = 'all')
742 {
743 $info = [
744 'internal_encoding' => self::$internalEncoding,
745 'http_output' => 'pass',
746 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
747 'func_overload' => 0,
748 'func_overload_list' => 'no overload',
749 'mail_charset' => 'UTF-8',
750 'mail_header_encoding' => 'BASE64',
751 'mail_body_encoding' => 'BASE64',
752 'illegal_chars' => 0,
753 'encoding_translation' => 'Off',
754 'language' => self::$language,
755 'detect_order' => self::$encodingList,
756 'substitute_character' => 'none',
757 'strict_detection' => 'Off',
758 ];
759
760 if ('all' === $type) {
761 return $info;
762 }
763 if (isset($info[$type])) {
764 return $info[$type];
765 }
766
767 return false;
768 }
769
770 public static function mb_http_input($type = '')
771 {
772 return false;
773 }
774
775 public static function mb_http_output($encoding = null)
776 {
777 return null !== $encoding ? 'pass' === $encoding : 'pass';
778 }
779
780 public static function mb_strwidth($s, $encoding = null)
781 {
782 $encoding = self::getEncoding($encoding);
783
784 if ('UTF-8' !== $encoding) {
785 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
786 }
787
788 $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);
789
790 return ($wide << 1) + iconv_strlen($s, 'UTF-8');
791 }
792
793 public static function mb_substr_count($haystack, $needle, $encoding = null)
794 {
795 return substr_count($haystack, $needle);
796 }
797
798 public static function mb_output_handler($contents, $status)
799 {
800 return $contents;
801 }
802
803 public static function mb_chr($code, $encoding = null)
804 {
805 if (0x80 > $code %= 0x200000) {
806 $s = \chr($code);
807 } elseif (0x800 > $code) {
808 $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
809 } elseif (0x10000 > $code) {
810 $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
811 } else {
812 $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
813 }
814
815 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
816 $s = mb_convert_encoding($s, $encoding, 'UTF-8');
817 }
818
819 return $s;
820 }
821
822 public static function mb_ord($s, $encoding = null)
823 {
824 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
825 $s = mb_convert_encoding($s, 'UTF-8', $encoding);
826 }
827
828 if (1 === \strlen($s)) {
829 return \ord($s);
830 }
831
832 $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
833 if (0xF0 <= $code) {
834 return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
835 }
836 if (0xE0 <= $code) {
837 return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
838 }
839 if (0xC0 <= $code) {
840 return (($code - 0xC0) << 6) + $s[2] - 0x80;
841 }
842
843 return $code;
844 }
845
846 public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string
847 {
848 if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
849 throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
850 }
851
852 if (null === $encoding) {
853 $encoding = self::mb_internal_encoding();
854 } else {
855 self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given');
856 }
857
858 if (self::mb_strlen($pad_string, $encoding) <= 0) {
859 throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
860 }
861
862 $paddingRequired = $length - self::mb_strlen($string, $encoding);
863
864 if ($paddingRequired < 1) {
865 return $string;
866 }
867
868 switch ($pad_type) {
869 case \STR_PAD_LEFT:
870 return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
871 case \STR_PAD_RIGHT:
872 return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
873 default:
874 $leftPaddingLength = floor($paddingRequired / 2);
875 $rightPaddingLength = $paddingRequired - $leftPaddingLength;
876
877 return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
878 }
879 }
880
881 public static function mb_ucfirst(string $string, ?string $encoding = null): string
882 {
883 if (null === $encoding) {
884 $encoding = self::mb_internal_encoding();
885 } else {
886 self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
887 }
888
889 $firstChar = mb_substr($string, 0, 1, $encoding);
890 $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding);
891
892 return $firstChar.mb_substr($string, 1, null, $encoding);
893 }
894
895 public static function mb_lcfirst(string $string, ?string $encoding = null): string
896 {
897 if (null === $encoding) {
898 $encoding = self::mb_internal_encoding();
899 } else {
900 self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given');
901 }
902
903 $firstChar = mb_substr($string, 0, 1, $encoding);
904 $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding);
905
906 return $firstChar.mb_substr($string, 1, null, $encoding);
907 }
908
909 private static function getSubpart($pos, $part, $haystack, $encoding)
910 {
911 if (false === $pos) {
912 return false;
913 }
914 if ($part) {
915 return self::mb_substr($haystack, 0, $pos, $encoding);
916 }
917
918 return self::mb_substr($haystack, $pos, null, $encoding);
919 }
920
921 private static function html_encoding_callback(array $m)
922 {
923 $i = 1;
924 $entities = '';
925 $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
926
927 while (isset($m[$i])) {
928 if (0x80 > $m[$i]) {
929 $entities .= \chr($m[$i++]);
930 continue;
931 }
932 if (0xF0 <= $m[$i]) {
933 $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
934 } elseif (0xE0 <= $m[$i]) {
935 $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
936 } else {
937 $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
938 }
939
940 $entities .= '&#'.$c.';';
941 }
942
943 return $entities;
944 }
945
946 private static function title_case(array $s)
947 {
948 return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
949 }
950
951 private static function getData($file)
952 {
953 if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
954 return require $file;
955 }
956
957 return false;
958 }
959
960 private static function getEncoding($encoding)
961 {
962 if (null === $encoding) {
963 return self::$internalEncoding;
964 }
965
966 if ('UTF-8' === $encoding) {
967 return 'UTF-8';
968 }
969
970 $encoding = strtoupper($encoding);
971
972 if ('8BIT' === $encoding || 'BINARY' === $encoding) {
973 return 'CP850';
974 }
975
976 if ('UTF8' === $encoding) {
977 return 'UTF-8';
978 }
979
980 return $encoding;
981 }
982
983 private static function assertEncoding(string $encoding, string $errorFormat): void
984 {
985 try {
986 $validEncoding = @self::mb_check_encoding('', $encoding);
987 } catch (\ValueError $e) {
988 throw new \ValueError(\sprintf($errorFormat, $encoding));
989 }
990
991 // BC for PHP 7.3 and lower
992 if (!$validEncoding) {
993 throw new \ValueError(\sprintf($errorFormat, $encoding));
994 }
995 }
996}