PluginProbe
WebTotem Security / 2.4.14
WebTotem Security v2.4.14
3.0.2 3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 All 110 releases
wt-security / vendor / symfony / polyfill-mbstring / Mbstring.php

Mbstring.php in WebTotem Security 2.4.14, at vendor/symfony/polyfill-mbstring/Mbstring.php

871 lines 28.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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
12 namespace 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 *
52 * Not implemented:
53 * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
54 * - mb_ereg_* - Regular expression with multibyte support
55 * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
56 * - mb_preferred_mime_name - Get MIME charset string
57 * - mb_regex_encoding - Returns current encoding for multibyte regex as string
58 * - mb_regex_set_options - Set/Get the default options for mbregex functions
59 * - mb_send_mail - Send encoded mail
60 * - mb_split - Split multibyte string using regular expression
61 * - mb_strcut - Get part of string
62 * - mb_strimwidth - Get truncated string with specified width
63 *
64 * @author Nicolas Grekas <p@tchwork.com>
65 *
66 * @internal
67 */
68 final class Mbstring
69 {
70 public const MB_CASE_FOLD = \PHP_INT_MAX;
71
72 private const CASE_FOLD = [
73 ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
74 ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
75 ];
76
77 private static $encodingList = ['ASCII', 'UTF-8'];
78 private static $language = 'neutral';
79 private static $internalEncoding = 'UTF-8';
80
81 public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
82 {
83 if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
84 $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
85 } else {
86 $fromEncoding = self::getEncoding($fromEncoding);
87 }
88
89 $toEncoding = self::getEncoding($toEncoding);
90
91 if ('BASE64' === $fromEncoding) {
92 $s = base64_decode($s);
93 $fromEncoding = $toEncoding;
94 }
95
96 if ('BASE64' === $toEncoding) {
97 return base64_encode($s);
98 }
99
100 if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
101 if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
102 $fromEncoding = 'Windows-1252';
103 }
104 if ('UTF-8' !== $fromEncoding) {
105 $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s);
106 }
107
108 return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
109 }
110
111 if ('HTML-ENTITIES' === $fromEncoding) {
112 $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
113 $fromEncoding = 'UTF-8';
114 }
115
116 return \iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
117 }
118
119 public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
120 {
121 $ok = true;
122 array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
123 if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
124 $ok = false;
125 }
126 });
127
128 return $ok ? $fromEncoding : false;
129 }
130
131 public static function mb_decode_mimeheader($s)
132 {
133 return \iconv_mime_decode($s, 2, self::$internalEncoding);
134 }
135
136 public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
137 {
138 trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
139 }
140
141 public static function mb_decode_numericentity($s, $convmap, $encoding = null)
142 {
143 if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
144 trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
145
146 return null;
147 }
148
149 if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
150 return false;
151 }
152
153 if (null !== $encoding && !is_scalar($encoding)) {
154 trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
155
156 return ''; // Instead of null (cf. mb_encode_numericentity).
157 }
158
159 $s = (string) $s;
160 if ('' === $s) {
161 return '';
162 }
163
164 $encoding = self::getEncoding($encoding);
165
166 if ('UTF-8' === $encoding) {
167 $encoding = null;
168 if (!preg_match('//u', $s)) {
169 $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
170 }
171 } else {
172 $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
173 }
174
175 $cnt = floor(\count($convmap) / 4) * 4;
176
177 for ($i = 0; $i < $cnt; $i += 4) {
178 // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
179 $convmap[$i] += $convmap[$i + 2];
180 $convmap[$i + 1] += $convmap[$i + 2];
181 }
182
183 $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
184 $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
185 for ($i = 0; $i < $cnt; $i += 4) {
186 if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
187 return self::mb_chr($c - $convmap[$i + 2]);
188 }
189 }
190
191 return $m[0];
192 }, $s);
193
194 if (null === $encoding) {
195 return $s;
196 }
197
198 return \iconv('UTF-8', $encoding.'//IGNORE', $s);
199 }
200
201 public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
202 {
203 if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
204 trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
205
206 return null;
207 }
208
209 if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
210 return false;
211 }
212
213 if (null !== $encoding && !is_scalar($encoding)) {
214 trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
215
216 return null; // Instead of '' (cf. mb_decode_numericentity).
217 }
218
219 if (null !== $is_hex && !is_scalar($is_hex)) {
220 trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
221
222 return null;
223 }
224
225 $s = (string) $s;
226 if ('' === $s) {
227 return '';
228 }
229
230 $encoding = self::getEncoding($encoding);
231
232 if ('UTF-8' === $encoding) {
233 $encoding = null;
234 if (!preg_match('//u', $s)) {
235 $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
236 }
237 } else {
238 $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
239 }
240
241 static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
242
243 $cnt = floor(\count($convmap) / 4) * 4;
244 $i = 0;
245 $len = \strlen($s);
246 $result = '';
247
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
254 for ($j = 0; $j < $cnt; $j += 4) {
255 if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
256 $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
257 $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
258 continue 2;
259 }
260 }
261 $result .= $uchr;
262 }
263
264 if (null === $encoding) {
265 return $result;
266 }
267
268 return \iconv('UTF-8', $encoding.'//IGNORE', $result);
269 }
270
271 public static function mb_convert_case($s, $mode, $encoding = null)
272 {
273 $s = (string) $s;
274 if ('' === $s) {
275 return '';
276 }
277
278 $encoding = self::getEncoding($encoding);
279
280 if ('UTF-8' === $encoding) {
281 $encoding = null;
282 if (!preg_match('//u', $s)) {
283 $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
284 }
285 } else {
286 $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
287 }
288
289 if (\MB_CASE_TITLE == $mode) {
290 static $titleRegexp = null;
291 if (null === $titleRegexp) {
292 $titleRegexp = self::getData('titleCaseRegexp');
293 }
294 $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
295 } else {
296 if (\MB_CASE_UPPER == $mode) {
297 static $upper = null;
298 if (null === $upper) {
299 $upper = self::getData('upperCase');
300 }
301 $map = $upper;
302 } else {
303 if (self::MB_CASE_FOLD === $mode) {
304 $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
305 }
306
307 static $lower = null;
308 if (null === $lower) {
309 $lower = self::getData('lowerCase');
310 }
311 $map = $lower;
312 }
313
314 static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
315
316 $i = 0;
317 $len = \strlen($s);
318
319 while ($i < $len) {
320 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
321 $uchr = substr($s, $i, $ulen);
322 $i += $ulen;
323
324 if (isset($map[$uchr])) {
325 $uchr = $map[$uchr];
326 $nlen = \strlen($uchr);
327
328 if ($nlen == $ulen) {
329 $nlen = $i;
330 do {
331 $s[--$nlen] = $uchr[--$ulen];
332 } while ($ulen);
333 } else {
334 $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
335 $len += $nlen - $ulen;
336 $i += $nlen - $ulen;
337 }
338 }
339 }
340 }
341
342 if (null === $encoding) {
343 return $s;
344 }
345
346 return \iconv('UTF-8', $encoding.'//IGNORE', $s);
347 }
348
349 public static function mb_internal_encoding($encoding = null)
350 {
351 if (null === $encoding) {
352 return self::$internalEncoding;
353 }
354
355 $normalizedEncoding = self::getEncoding($encoding);
356
357 if ('UTF-8' === $normalizedEncoding || false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
358 self::$internalEncoding = $normalizedEncoding;
359
360 return true;
361 }
362
363 if (80000 > \PHP_VERSION_ID) {
364 return false;
365 }
366
367 throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
368 }
369
370 public static function mb_language($lang = null)
371 {
372 if (null === $lang) {
373 return self::$language;
374 }
375
376 switch ($normalizedLang = strtolower($lang)) {
377 case 'uni':
378 case 'neutral':
379 self::$language = $normalizedLang;
380
381 return true;
382 }
383
384 if (80000 > \PHP_VERSION_ID) {
385 return false;
386 }
387
388 throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
389 }
390
391 public static function mb_list_encodings()
392 {
393 return ['UTF-8'];
394 }
395
396 public static function mb_encoding_aliases($encoding)
397 {
398 switch (strtoupper($encoding)) {
399 case 'UTF8':
400 case 'UTF-8':
401 return ['utf8'];
402 }
403
404 return false;
405 }
406
407 public static function mb_check_encoding($var = null, $encoding = null)
408 {
409 if (null === $encoding) {
410 if (null === $var) {
411 return false;
412 }
413 $encoding = self::$internalEncoding;
414 }
415
416 return self::mb_detect_encoding($var, [$encoding]) || false !== @\iconv($encoding, $encoding, $var);
417 }
418
419 public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
420 {
421 if (null === $encodingList) {
422 $encodingList = self::$encodingList;
423 } else {
424 if (!\is_array($encodingList)) {
425 $encodingList = array_map('trim', explode(',', $encodingList));
426 }
427 $encodingList = array_map('strtoupper', $encodingList);
428 }
429
430 foreach ($encodingList as $enc) {
431 switch ($enc) {
432 case 'ASCII':
433 if (!preg_match('/[\x80-\xFF]/', $str)) {
434 return $enc;
435 }
436 break;
437
438 case 'UTF8':
439 case 'UTF-8':
440 if (preg_match('//u', $str)) {
441 return 'UTF-8';
442 }
443 break;
444
445 default:
446 if (0 === strncmp($enc, 'ISO-8859-', 9)) {
447 return $enc;
448 }
449 }
450 }
451
452 return false;
453 }
454
455 public static function mb_detect_order($encodingList = null)
456 {
457 if (null === $encodingList) {
458 return self::$encodingList;
459 }
460
461 if (!\is_array($encodingList)) {
462 $encodingList = array_map('trim', explode(',', $encodingList));
463 }
464 $encodingList = array_map('strtoupper', $encodingList);
465
466 foreach ($encodingList as $enc) {
467 switch ($enc) {
468 default:
469 if (strncmp($enc, 'ISO-8859-', 9)) {
470 return false;
471 }
472 // no break
473 case 'ASCII':
474 case 'UTF8':
475 case 'UTF-8':
476 }
477 }
478
479 self::$encodingList = $encodingList;
480
481 return true;
482 }
483
484 public static function mb_strlen($s, $encoding = null)
485 {
486 $encoding = self::getEncoding($encoding);
487 if ('CP850' === $encoding || 'ASCII' === $encoding) {
488 return \strlen($s);
489 }
490
491 return @\iconv_strlen($s, $encoding);
492 }
493
494 public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
495 {
496 $encoding = self::getEncoding($encoding);
497 if ('CP850' === $encoding || 'ASCII' === $encoding) {
498 return strpos($haystack, $needle, $offset);
499 }
500
501 $needle = (string) $needle;
502 if ('' === $needle) {
503 if (80000 > \PHP_VERSION_ID) {
504 trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
505
506 return false;
507 }
508
509 return 0;
510 }
511
512 return \iconv_strpos($haystack, $needle, $offset, $encoding);
513 }
514
515 public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
516 {
517 $encoding = self::getEncoding($encoding);
518 if ('CP850' === $encoding || 'ASCII' === $encoding) {
519 return strrpos($haystack, $needle, $offset);
520 }
521
522 if ($offset != (int) $offset) {
523 $offset = 0;
524 } elseif ($offset = (int) $offset) {
525 if ($offset < 0) {
526 if (0 > $offset += self::mb_strlen($needle)) {
527 $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
528 }
529 $offset = 0;
530 } else {
531 $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
532 }
533 }
534
535 $pos = '' !== $needle || 80000 > \PHP_VERSION_ID
536 ? \iconv_strrpos($haystack, $needle, $encoding)
537 : self::mb_strlen($haystack, $encoding);
538
539 return false !== $pos ? $offset + $pos : false;
540 }
541
542 public static function mb_str_split($string, $split_length = 1, $encoding = null)
543 {
544 if (null !== $string && !is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
545 trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
546
547 return null;
548 }
549
550 if (1 > $split_length = (int) $split_length) {
551 if (80000 > \PHP_VERSION_ID) {
552 trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
553 return false;
554 }
555
556 throw new \ValueError('Argument #2 ($length) must be greater than 0');
557 }
558
559 if (null === $encoding) {
560 $encoding = mb_internal_encoding();
561 }
562
563 if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
564 $rx = '/(';
565 while (65535 < $split_length) {
566 $rx .= '.{65535}';
567 $split_length -= 65535;
568 }
569 $rx .= '.{'.$split_length.'})/us';
570
571 return preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
572 }
573
574 $result = [];
575 $length = mb_strlen($string, $encoding);
576
577 for ($i = 0; $i < $length; $i += $split_length) {
578 $result[] = mb_substr($string, $i, $split_length, $encoding);
579 }
580
581 return $result;
582 }
583
584 public static function mb_strtolower($s, $encoding = null)
585 {
586 return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
587 }
588
589 public static function mb_strtoupper($s, $encoding = null)
590 {
591 return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
592 }
593
594 public static function mb_substitute_character($c = null)
595 {
596 if (null === $c) {
597 return 'none';
598 }
599 if (0 === strcasecmp($c, 'none')) {
600 return true;
601 }
602 if (80000 > \PHP_VERSION_ID) {
603 return false;
604 }
605
606 throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
607 }
608
609 public static function mb_substr($s, $start, $length = null, $encoding = null)
610 {
611 $encoding = self::getEncoding($encoding);
612 if ('CP850' === $encoding || 'ASCII' === $encoding) {
613 return (string) substr($s, $start, null === $length ? 2147483647 : $length);
614 }
615
616 if ($start < 0) {
617 $start = \iconv_strlen($s, $encoding) + $start;
618 if ($start < 0) {
619 $start = 0;
620 }
621 }
622
623 if (null === $length) {
624 $length = 2147483647;
625 } elseif ($length < 0) {
626 $length = \iconv_strlen($s, $encoding) + $length - $start;
627 if ($length < 0) {
628 return '';
629 }
630 }
631
632 return (string) \iconv_substr($s, $start, $length, $encoding);
633 }
634
635 public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
636 {
637 $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
638 $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
639
640 return self::mb_strpos($haystack, $needle, $offset, $encoding);
641 }
642
643 public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
644 {
645 $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
646
647 return self::getSubpart($pos, $part, $haystack, $encoding);
648 }
649
650 public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
651 {
652 $encoding = self::getEncoding($encoding);
653 if ('CP850' === $encoding || 'ASCII' === $encoding) {
654 $pos = strrpos($haystack, $needle);
655 } else {
656 $needle = self::mb_substr($needle, 0, 1, $encoding);
657 $pos = \iconv_strrpos($haystack, $needle, $encoding);
658 }
659
660 return self::getSubpart($pos, $part, $haystack, $encoding);
661 }
662
663 public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
664 {
665 $needle = self::mb_substr($needle, 0, 1, $encoding);
666 $pos = self::mb_strripos($haystack, $needle, $encoding);
667
668 return self::getSubpart($pos, $part, $haystack, $encoding);
669 }
670
671 public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
672 {
673 $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
674 $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
675
676 return self::mb_strrpos($haystack, $needle, $offset, $encoding);
677 }
678
679 public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
680 {
681 $pos = strpos($haystack, $needle);
682 if (false === $pos) {
683 return false;
684 }
685 if ($part) {
686 return substr($haystack, 0, $pos);
687 }
688
689 return substr($haystack, $pos);
690 }
691
692 public static function mb_get_info($type = 'all')
693 {
694 $info = [
695 'internal_encoding' => self::$internalEncoding,
696 'http_output' => 'pass',
697 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
698 'func_overload' => 0,
699 'func_overload_list' => 'no overload',
700 'mail_charset' => 'UTF-8',
701 'mail_header_encoding' => 'BASE64',
702 'mail_body_encoding' => 'BASE64',
703 'illegal_chars' => 0,
704 'encoding_translation' => 'Off',
705 'language' => self::$language,
706 'detect_order' => self::$encodingList,
707 'substitute_character' => 'none',
708 'strict_detection' => 'Off',
709 ];
710
711 if ('all' === $type) {
712 return $info;
713 }
714 if (isset($info[$type])) {
715 return $info[$type];
716 }
717
718 return false;
719 }
720
721 public static function mb_http_input($type = '')
722 {
723 return false;
724 }
725
726 public static function mb_http_output($encoding = null)
727 {
728 return null !== $encoding ? 'pass' === $encoding : 'pass';
729 }
730
731 public static function mb_strwidth($s, $encoding = null)
732 {
733 $encoding = self::getEncoding($encoding);
734
735 if ('UTF-8' !== $encoding) {
736 $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
737 }
738
739 $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);
740
741 return ($wide << 1) + \iconv_strlen($s, 'UTF-8');
742 }
743
744 public static function mb_substr_count($haystack, $needle, $encoding = null)
745 {
746 return substr_count($haystack, $needle);
747 }
748
749 public static function mb_output_handler($contents, $status)
750 {
751 return $contents;
752 }
753
754 public static function mb_chr($code, $encoding = null)
755 {
756 if (0x80 > $code %= 0x200000) {
757 $s = \chr($code);
758 } elseif (0x800 > $code) {
759 $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
760 } elseif (0x10000 > $code) {
761 $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
762 } else {
763 $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
764 }
765
766 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
767 $s = mb_convert_encoding($s, $encoding, 'UTF-8');
768 }
769
770 return $s;
771 }
772
773 public static function mb_ord($s, $encoding = null)
774 {
775 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
776 $s = mb_convert_encoding($s, 'UTF-8', $encoding);
777 }
778
779 if (1 === \strlen($s)) {
780 return \ord($s);
781 }
782
783 $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
784 if (0xF0 <= $code) {
785 return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
786 }
787 if (0xE0 <= $code) {
788 return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
789 }
790 if (0xC0 <= $code) {
791 return (($code - 0xC0) << 6) + $s[2] - 0x80;
792 }
793
794 return $code;
795 }
796
797 private static function getSubpart($pos, $part, $haystack, $encoding)
798 {
799 if (false === $pos) {
800 return false;
801 }
802 if ($part) {
803 return self::mb_substr($haystack, 0, $pos, $encoding);
804 }
805
806 return self::mb_substr($haystack, $pos, null, $encoding);
807 }
808
809 private static function html_encoding_callback(array $m)
810 {
811 $i = 1;
812 $entities = '';
813 $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
814
815 while (isset($m[$i])) {
816 if (0x80 > $m[$i]) {
817 $entities .= \chr($m[$i++]);
818 continue;
819 }
820 if (0xF0 <= $m[$i]) {
821 $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
822 } elseif (0xE0 <= $m[$i]) {
823 $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
824 } else {
825 $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
826 }
827
828 $entities .= '&#'.$c.';';
829 }
830
831 return $entities;
832 }
833
834 private static function title_case(array $s)
835 {
836 return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
837 }
838
839 private static function getData($file)
840 {
841 if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
842 return require $file;
843 }
844
845 return false;
846 }
847
848 private static function getEncoding($encoding)
849 {
850 if (null === $encoding) {
851 return self::$internalEncoding;
852 }
853
854 if ('UTF-8' === $encoding) {
855 return 'UTF-8';
856 }
857
858 $encoding = strtoupper($encoding);
859
860 if ('8BIT' === $encoding || 'BINARY' === $encoding) {
861 return 'CP850';
862 }
863
864 if ('UTF8' === $encoding) {
865 return 'UTF-8';
866 }
867
868 return $encoding;
869 }
870 }
871