Verzeichnisstruktur phpBB-3.3.16
- Veröffentlicht
- 27.04.2026
So funktioniert es
|
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
Mbstring.php
0001 <?php
0002
0003 /*
0004 * This file is part of the Symfony package.
0005 *
0006 * (c) Fabien Potencier <fabien@symfony.com>
0007 *
0008 * For the full copyright and license information, please view the LICENSE
0009 * file that was distributed with this source code.
0010 */
0011
0012 namespace Symfony\Polyfill\Mbstring;
0013
0014 /**
0015 * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
0016 *
0017 * Implemented:
0018 * - mb_chr - Returns a specific character from its Unicode code point
0019 * - mb_convert_encoding - Convert character encoding
0020 * - mb_convert_variables - Convert character code in variable(s)
0021 * - mb_decode_mimeheader - Decode string in MIME header field
0022 * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
0023 * - mb_decode_numericentity - Decode HTML numeric string reference to character
0024 * - mb_encode_numericentity - Encode character to HTML numeric string reference
0025 * - mb_convert_case - Perform case folding on a string
0026 * - mb_detect_encoding - Detect character encoding
0027 * - mb_get_info - Get internal settings of mbstring
0028 * - mb_http_input - Detect HTTP input character encoding
0029 * - mb_http_output - Set/Get HTTP output character encoding
0030 * - mb_internal_encoding - Set/Get internal character encoding
0031 * - mb_list_encodings - Returns an array of all supported encodings
0032 * - mb_ord - Returns the Unicode code point of a character
0033 * - mb_output_handler - Callback function converts character encoding in output buffer
0034 * - mb_scrub - Replaces ill-formed byte sequences with substitute characters
0035 * - mb_strlen - Get string length
0036 * - mb_strpos - Find position of first occurrence of string in a string
0037 * - mb_strrpos - Find position of last occurrence of a string in a string
0038 * - mb_str_split - Convert a string to an array
0039 * - mb_strtolower - Make a string lowercase
0040 * - mb_strtoupper - Make a string uppercase
0041 * - mb_substitute_character - Set/Get substitution character
0042 * - mb_substr - Get part of string
0043 * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive
0044 * - mb_stristr - Finds first occurrence of a string within another, case insensitive
0045 * - mb_strrchr - Finds the last occurrence of a character in a string within another
0046 * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive
0047 * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive
0048 * - mb_strstr - Finds first occurrence of a string within another
0049 * - mb_strwidth - Return width of string
0050 * - mb_substr_count - Count the number of substring occurrences
0051 * - mb_ucfirst - Make a string's first character uppercase
0052 * - mb_lcfirst - Make a string's first character lowercase
0053 * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string
0054 * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string
0055 * - mb_rtrim - Strip whitespace (or other characters) from the end of a string
0056 *
0057 * Not implemented:
0058 * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
0059 * - mb_ereg_* - Regular expression with multibyte support
0060 * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable
0061 * - mb_preferred_mime_name - Get MIME charset string
0062 * - mb_regex_encoding - Returns current encoding for multibyte regex as string
0063 * - mb_regex_set_options - Set/Get the default options for mbregex functions
0064 * - mb_send_mail - Send encoded mail
0065 * - mb_split - Split multibyte string using regular expression
0066 * - mb_strcut - Get part of string
0067 * - mb_strimwidth - Get truncated string with specified width
0068 *
0069 * @author Nicolas Grekas <p@tchwork.com>
0070 *
0071 * @internal
0072 */
0073 final class Mbstring
0074 {
0075 public const MB_CASE_FOLD = \PHP_INT_MAX;
0076
0077 private const SIMPLE_CASE_FOLD = [
0078 ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
0079 ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'],
0080 ];
0081
0082 private static $encodingList = ['ASCII', 'UTF-8'];
0083 private static $language = 'neutral';
0084 private static $internalEncoding = 'UTF-8';
0085
0086 public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
0087 {
0088 if (\is_array($s)) {
0089 $r = [];
0090 foreach ($s as $str) {
0091 $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding);
0092 }
0093
0094 return $r;
0095 }
0096
0097 if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
0098 $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
0099 } else {
0100 $fromEncoding = self::getEncoding($fromEncoding);
0101 }
0102
0103 $toEncoding = self::getEncoding($toEncoding);
0104
0105 if ('BASE64' === $fromEncoding) {
0106 $s = base64_decode($s);
0107 $fromEncoding = $toEncoding;
0108 }
0109
0110 if ('BASE64' === $toEncoding) {
0111 return base64_encode($s);
0112 }
0113
0114 if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
0115 if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
0116 $fromEncoding = 'Windows-1252';
0117 }
0118 if ('UTF-8' !== $fromEncoding) {
0119 $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
0120 }
0121
0122 return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
0123 }
0124
0125 if ('HTML-ENTITIES' === $fromEncoding) {
0126 $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
0127 $fromEncoding = 'UTF-8';
0128 }
0129
0130 return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
0131 }
0132
0133 public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
0134 {
0135 $ok = true;
0136 array_walk_recursive($vars, static function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
0137 if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
0138 $ok = false;
0139 }
0140 });
0141
0142 return $ok ? $fromEncoding : false;
0143 }
0144
0145 public static function mb_decode_mimeheader($s)
0146 {
0147 return iconv_mime_decode($s, 2, self::$internalEncoding);
0148 }
0149
0150 public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
0151 {
0152 trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
0153 }
0154
0155 public static function mb_decode_numericentity($s, $convmap, $encoding = null)
0156 {
0157 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
0158 trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
0159
0160 return null;
0161 }
0162
0163 if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
0164 return false;
0165 }
0166
0167 if (null !== $encoding && !\is_scalar($encoding)) {
0168 trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
0169
0170 return ''; // Instead of null (cf. mb_encode_numericentity).
0171 }
0172
0173 $s = (string) $s;
0174 if ('' === $s) {
0175 return '';
0176 }
0177
0178 $encoding = self::getEncoding($encoding);
0179
0180 if ('UTF-8' === $encoding) {
0181 $encoding = null;
0182 if (!preg_match('//u', $s)) {
0183 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
0184 }
0185 } else {
0186 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
0187 }
0188
0189 $cnt = floor(\count($convmap) / 4) * 4;
0190
0191 for ($i = 0; $i < $cnt; $i += 4) {
0192 // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
0193 $convmap[$i] += $convmap[$i + 2];
0194 $convmap[$i + 1] += $convmap[$i + 2];
0195 }
0196
0197 $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))'.(\PHP_VERSION_ID >= 80200 ? '' : '(?!&)').';?/', static function (array $m) use ($cnt, $convmap) {
0198 $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
0199 for ($i = 0; $i < $cnt; $i += 4) {
0200 if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
0201 return self::mb_chr($c - $convmap[$i + 2]);
0202 }
0203 }
0204
0205 return $m[0];
0206 }, $s);
0207
0208 if (null === $encoding) {
0209 return $s;
0210 }
0211
0212 return iconv('UTF-8', $encoding.'//IGNORE', $s);
0213 }
0214
0215 public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
0216 {
0217 if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
0218 trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
0219
0220 return null;
0221 }
0222
0223 if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
0224 return false;
0225 }
0226
0227 if (null !== $encoding && !\is_scalar($encoding)) {
0228 trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
0229
0230 return null; // Instead of '' (cf. mb_decode_numericentity).
0231 }
0232
0233 if (null !== $is_hex && !\is_scalar($is_hex)) {
0234 trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
0235
0236 return null;
0237 }
0238
0239 $s = (string) $s;
0240 if ('' === $s) {
0241 return '';
0242 }
0243
0244 $encoding = self::getEncoding($encoding);
0245
0246 if ('UTF-8' === $encoding) {
0247 $encoding = null;
0248 if (!preg_match('//u', $s)) {
0249 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
0250 }
0251 } else {
0252 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
0253 }
0254
0255 static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
0256
0257 $cnt = floor(\count($convmap) / 4) * 4;
0258 $i = 0;
0259 $len = \strlen($s);
0260 $result = '';
0261
0262 while ($i < $len) {
0263 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
0264 $uchr = substr($s, $i, $ulen);
0265 $i += $ulen;
0266 $c = self::mb_ord($uchr);
0267
0268 for ($j = 0; $j < $cnt; $j += 4) {
0269 if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
0270 $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
0271 $result .= $is_hex ? \sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
0272 continue 2;
0273 }
0274 }
0275 $result .= $uchr;
0276 }
0277
0278 if (null === $encoding) {
0279 return $result;
0280 }
0281
0282 return iconv('UTF-8', $encoding.'//IGNORE', $result);
0283 }
0284
0285 public static function mb_convert_case($s, $mode, $encoding = null)
0286 {
0287 $s = (string) $s;
0288 if ('' === $s) {
0289 return '';
0290 }
0291
0292 $encoding = self::getEncoding($encoding);
0293
0294 if ('UTF-8' === $encoding) {
0295 $encoding = null;
0296 if (!preg_match('//u', $s)) {
0297 $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
0298 }
0299 } else {
0300 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
0301 }
0302
0303 if (\MB_CASE_TITLE == $mode) {
0304 static $titleRegexp = null;
0305 if (null === $titleRegexp) {
0306 $titleRegexp = self::getData('titleCaseRegexp');
0307 }
0308 $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
0309 } else {
0310 if (\MB_CASE_UPPER == $mode) {
0311 static $upper = null;
0312 if (null === $upper) {
0313 $upper = self::getData('upperCase');
0314 }
0315 $map = $upper;
0316 } else {
0317 if (self::MB_CASE_FOLD === $mode) {
0318 static $caseFolding = null;
0319 if (null === $caseFolding) {
0320 $caseFolding = self::getData('caseFolding');
0321 }
0322 $s = strtr($s, $caseFolding);
0323 }
0324
0325 static $lower = null;
0326 if (null === $lower) {
0327 $lower = self::getData('lowerCase');
0328 }
0329 $map = $lower;
0330 }
0331
0332 static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
0333
0334 $i = 0;
0335 $len = \strlen($s);
0336
0337 while ($i < $len) {
0338 $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
0339 $uchr = substr($s, $i, $ulen);
0340 $i += $ulen;
0341
0342 if (isset($map[$uchr])) {
0343 $uchr = $map[$uchr];
0344 $nlen = \strlen($uchr);
0345
0346 if ($nlen == $ulen) {
0347 $nlen = $i;
0348 do {
0349 $s[--$nlen] = $uchr[--$ulen];
0350 } while ($ulen);
0351 } else {
0352 $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
0353 $len += $nlen - $ulen;
0354 $i += $nlen - $ulen;
0355 }
0356 }
0357 }
0358 }
0359
0360 if (null === $encoding) {
0361 return $s;
0362 }
0363
0364 return iconv('UTF-8', $encoding.'//IGNORE', $s);
0365 }
0366
0367 public static function mb_internal_encoding($encoding = null)
0368 {
0369 if (null === $encoding) {
0370 return self::$internalEncoding;
0371 }
0372
0373 $normalizedEncoding = self::getEncoding($encoding);
0374
0375 if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
0376 self::$internalEncoding = $normalizedEncoding;
0377
0378 return true;
0379 }
0380
0381 if (80000 > \PHP_VERSION_ID) {
0382 return false;
0383 }
0384
0385 throw new \ValueError(\sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
0386 }
0387
0388 public static function mb_language($lang = null)
0389 {
0390 if (null === $lang) {
0391 return self::$language;
0392 }
0393
0394 switch ($normalizedLang = strtolower($lang)) {
0395 case 'uni':
0396 case 'neutral':
0397 self::$language = $normalizedLang;
0398
0399 return true;
0400 }
0401
0402 if (80000 > \PHP_VERSION_ID) {
0403 return false;
0404 }
0405
0406 throw new \ValueError(\sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
0407 }
0408
0409 public static function mb_list_encodings()
0410 {
0411 return ['UTF-8'];
0412 }
0413
0414 public static function mb_encoding_aliases($encoding)
0415 {
0416 switch (strtoupper($encoding)) {
0417 case 'UTF8':
0418 case 'UTF-8':
0419 return ['utf8'];
0420 }
0421
0422 return false;
0423 }
0424
0425 public static function mb_check_encoding($var = null, $encoding = null)
0426 {
0427 if (null === $encoding) {
0428 if (null === $var) {
0429 return false;
0430 }
0431 $encoding = self::$internalEncoding;
0432 }
0433
0434 if (!\is_array($var)) {
0435 return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
0436 }
0437
0438 foreach ($var as $key => $value) {
0439 if (!self::mb_check_encoding($key, $encoding)) {
0440 return false;
0441 }
0442 if (!self::mb_check_encoding($value, $encoding)) {
0443 return false;
0444 }
0445 }
0446
0447 return true;
0448 }
0449
0450 public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
0451 {
0452 if (null === $encodingList) {
0453 $encodingList = self::$encodingList;
0454 } else {
0455 if (!\is_array($encodingList)) {
0456 $encodingList = array_map('trim', explode(',', $encodingList));
0457 }
0458 $encodingList = array_map('strtoupper', $encodingList);
0459 }
0460
0461 foreach ($encodingList as $enc) {
0462 switch ($enc) {
0463 case 'ASCII':
0464 if (!preg_match('/[\x80-\xFF]/', $str)) {
0465 return $enc;
0466 }
0467 break;
0468
0469 case 'UTF8':
0470 case 'UTF-8':
0471 if (preg_match('//u', $str)) {
0472 return 'UTF-8';
0473 }
0474 break;
0475
0476 default:
0477 if (0 === strncmp($enc, 'ISO-8859-', 9)) {
0478 return $enc;
0479 }
0480 }
0481 }
0482
0483 return false;
0484 }
0485
0486 public static function mb_detect_order($encodingList = null)
0487 {
0488 if (null === $encodingList) {
0489 return self::$encodingList;
0490 }
0491
0492 if (!\is_array($encodingList)) {
0493 $encodingList = array_map('trim', explode(',', $encodingList));
0494 }
0495 $encodingList = array_map('strtoupper', $encodingList);
0496
0497 foreach ($encodingList as $enc) {
0498 switch ($enc) {
0499 default:
0500 if (strncmp($enc, 'ISO-8859-', 9)) {
0501 return false;
0502 }
0503 // no break
0504 case 'ASCII':
0505 case 'UTF8':
0506 case 'UTF-8':
0507 }
0508 }
0509
0510 self::$encodingList = $encodingList;
0511
0512 return true;
0513 }
0514
0515 public static function mb_strlen($s, $encoding = null)
0516 {
0517 $encoding = self::getEncoding($encoding);
0518 if ('CP850' === $encoding || 'ASCII' === $encoding) {
0519 return \strlen($s);
0520 }
0521
0522 return @iconv_strlen($s, $encoding);
0523 }
0524
0525 public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
0526 {
0527 $encoding = self::getEncoding($encoding);
0528 if ('CP850' === $encoding || 'ASCII' === $encoding) {
0529 return strpos($haystack, $needle, $offset);
0530 }
0531
0532 $needle = (string) $needle;
0533 if ('' === $needle) {
0534 if (80000 > \PHP_VERSION_ID) {
0535 trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
0536
0537 return false;
0538 }
0539
0540 return 0;
0541 }
0542
0543 return iconv_strpos($haystack, $needle, $offset, $encoding);
0544 }
0545
0546 public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
0547 {
0548 $encoding = self::getEncoding($encoding);
0549 if ('CP850' === $encoding || 'ASCII' === $encoding) {
0550 return strrpos($haystack, $needle, $offset);
0551 }
0552
0553 if ($offset != (int) $offset) {
0554 $offset = 0;
0555 } elseif ($offset = (int) $offset) {
0556 if ($offset < 0) {
0557 if (0 > $offset += self::mb_strlen($needle)) {
0558 $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
0559 }
0560 $offset = 0;
0561 } else {
0562 $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
0563 }
0564 }
0565
0566 $pos = '' !== $needle || 80000 > \PHP_VERSION_ID
0567 ? iconv_strrpos($haystack, $needle, $encoding)
0568 : self::mb_strlen($haystack, $encoding);
0569
0570 return false !== $pos ? $offset + $pos : false;
0571 }
0572
0573 public static function mb_str_split($string, $split_length = 1, $encoding = null)
0574 {
0575 if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
0576 trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
0577
0578 return null;
0579 }
0580
0581 if (1 > $split_length = (int) $split_length) {
0582 if (80000 > \PHP_VERSION_ID) {
0583 trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
0584
0585 return false;
0586 }
0587
0588 throw new \ValueError('Argument #2 ($length) must be greater than 0');
0589 }
0590
0591 if (null === $encoding) {
0592 $encoding = mb_internal_encoding();
0593 }
0594
0595 if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
0596 $rx = '/(';
0597 while (65535 < $split_length) {
0598 $rx .= '.{65535}';
0599 $split_length -= 65535;
0600 }
0601 $rx .= '.{'.$split_length.'})/us';
0602
0603 return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
0604 }
0605
0606 $result = [];
0607 $length = mb_strlen($string, $encoding);
0608
0609 for ($i = 0; $i < $length; $i += $split_length) {
0610 $result[] = mb_substr($string, $i, $split_length, $encoding);
0611 }
0612
0613 return $result;
0614 }
0615
0616 public static function mb_strtolower($s, $encoding = null)
0617 {
0618 return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
0619 }
0620
0621 public static function mb_strtoupper($s, $encoding = null)
0622 {
0623 return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
0624 }
0625
0626 public static function mb_substitute_character($c = null)
0627 {
0628 if (null === $c) {
0629 return 'none';
0630 }
0631 if (0 === strcasecmp($c, 'none')) {
0632 return true;
0633 }
0634 if (80000 > \PHP_VERSION_ID) {
0635 return false;
0636 }
0637 if (\is_int($c) || 'long' === $c || 'entity' === $c) {
0638 return false;
0639 }
0640
0641 throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
0642 }
0643
0644 public static function mb_substr($s, $start, $length = null, $encoding = null)
0645 {
0646 $encoding = self::getEncoding($encoding);
0647 if ('CP850' === $encoding || 'ASCII' === $encoding) {
0648 return (string) substr($s, $start, null === $length ? 2147483647 : $length);
0649 }
0650
0651 if ($start < 0) {
0652 $start = iconv_strlen($s, $encoding) + $start;
0653 if ($start < 0) {
0654 $start = 0;
0655 }
0656 }
0657
0658 if (null === $length) {
0659 $length = 2147483647;
0660 } elseif ($length < 0) {
0661 $length = iconv_strlen($s, $encoding) + $length - $start;
0662 if ($length < 0) {
0663 return '';
0664 }
0665 }
0666
0667 return (string) iconv_substr($s, $start, $length, $encoding);
0668 }
0669
0670 public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
0671 {
0672 [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
0673 self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
0674 self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
0675 ]);
0676
0677 return self::mb_strpos($haystack, $needle, $offset, $encoding);
0678 }
0679
0680 public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
0681 {
0682 $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
0683
0684 return self::getSubpart($pos, $part, $haystack, $encoding);
0685 }
0686
0687 public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
0688 {
0689 $encoding = self::getEncoding($encoding);
0690 if ('CP850' === $encoding || 'ASCII' === $encoding) {
0691 $pos = strrpos($haystack, $needle);
0692 } else {
0693 $needle = self::mb_substr($needle, 0, 1, $encoding);
0694 $pos = iconv_strrpos($haystack, $needle, $encoding);
0695 }
0696
0697 return self::getSubpart($pos, $part, $haystack, $encoding);
0698 }
0699
0700 public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
0701 {
0702 $needle = self::mb_substr($needle, 0, 1, $encoding);
0703 $pos = self::mb_strripos($haystack, $needle, $encoding);
0704
0705 return self::getSubpart($pos, $part, $haystack, $encoding);
0706 }
0707
0708 public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
0709 {
0710 $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
0711 $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
0712
0713 $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
0714 $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
0715
0716 return self::mb_strrpos($haystack, $needle, $offset, $encoding);
0717 }
0718
0719 public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
0720 {
0721 $pos = strpos($haystack, $needle);
0722 if (false === $pos) {
0723 return false;
0724 }
0725 if ($part) {
0726 return substr($haystack, 0, $pos);
0727 }
0728
0729 return substr($haystack, $pos);
0730 }
0731
0732 public static function mb_get_info($type = 'all')
0733 {
0734 $info = [
0735 'internal_encoding' => self::$internalEncoding,
0736 'http_output' => 'pass',
0737 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
0738 'func_overload' => 0,
0739 'func_overload_list' => 'no overload',
0740 'mail_charset' => 'UTF-8',
0741 'mail_header_encoding' => 'BASE64',
0742 'mail_body_encoding' => 'BASE64',
0743 'illegal_chars' => 0,
0744 'encoding_translation' => 'Off',
0745 'language' => self::$language,
0746 'detect_order' => self::$encodingList,
0747 'substitute_character' => 'none',
0748 'strict_detection' => 'Off',
0749 ];
0750
0751 if ('all' === $type) {
0752 return $info;
0753 }
0754 if (isset($info[$type])) {
0755 return $info[$type];
0756 }
0757
0758 return false;
0759 }
0760
0761 public static function mb_http_input($type = '')
0762 {
0763 return false;
0764 }
0765
0766 public static function mb_http_output($encoding = null)
0767 {
0768 return null !== $encoding ? 'pass' === $encoding : 'pass';
0769 }
0770
0771 public static function mb_strwidth($s, $encoding = null)
0772 {
0773 $encoding = self::getEncoding($encoding);
0774
0775 if ('UTF-8' !== $encoding) {
0776 $s = iconv($encoding, 'UTF-8//IGNORE', $s);
0777 }
0778
0779 $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);
0780
0781 return ($wide << 1) + iconv_strlen($s, 'UTF-8');
0782 }
0783
0784 public static function mb_substr_count($haystack, $needle, $encoding = null)
0785 {
0786 return substr_count($haystack, $needle);
0787 }
0788
0789 public static function mb_output_handler($contents, $status)
0790 {
0791 return $contents;
0792 }
0793
0794 public static function mb_chr($code, $encoding = null)
0795 {
0796 if (0x80 > $code %= 0x200000) {
0797 $s = \chr($code);
0798 } elseif (0x800 > $code) {
0799 $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
0800 } elseif (0x10000 > $code) {
0801 $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
0802 } else {
0803 $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
0804 }
0805
0806 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
0807 $s = mb_convert_encoding($s, $encoding, 'UTF-8');
0808 }
0809
0810 return $s;
0811 }
0812
0813 public static function mb_ord($s, $encoding = null)
0814 {
0815 if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
0816 $s = mb_convert_encoding($s, 'UTF-8', $encoding);
0817 }
0818
0819 if (1 === \strlen($s)) {
0820 return \ord($s);
0821 }
0822
0823 $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
0824 if (0xF0 <= $code) {
0825 return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
0826 }
0827 if (0xE0 <= $code) {
0828 return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
0829 }
0830 if (0xC0 <= $code) {
0831 return (($code - 0xC0) << 6) + $s[2] - 0x80;
0832 }
0833
0834 return $code;
0835 }
0836
0837 /** @return string|false */
0838 public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null)
0839 {
0840 if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
0841 if (\PHP_VERSION_ID < 80000) {
0842 trigger_error('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH', \E_USER_WARNING);
0843
0844 return false;
0845 }
0846
0847 throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
0848 }
0849
0850 if (null === $encoding) {
0851 $encoding = self::mb_internal_encoding();
0852 } elseif (!self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given')) {
0853 return false;
0854 }
0855
0856 if (self::mb_strlen($pad_string, $encoding) <= 0) {
0857 if (\PHP_VERSION_ID < 80000) {
0858 trigger_error('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string', \E_USER_WARNING);
0859
0860 return false;
0861 }
0862
0863 throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
0864 }
0865
0866 $paddingRequired = $length - self::mb_strlen($string, $encoding);
0867
0868 if ($paddingRequired < 1) {
0869 return $string;
0870 }
0871
0872 switch ($pad_type) {
0873 case \STR_PAD_LEFT:
0874 return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
0875 case \STR_PAD_RIGHT:
0876 return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
0877 default:
0878 $leftPaddingLength = floor($paddingRequired / 2);
0879 $rightPaddingLength = $paddingRequired - $leftPaddingLength;
0880
0881 return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
0882 }
0883 }
0884
0885 /** @return string|false */
0886 public static function mb_ucfirst(string $string, ?string $encoding = null)
0887 {
0888 if (null === $encoding) {
0889 $encoding = self::mb_internal_encoding();
0890 } elseif (!self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
0891 return false;
0892 }
0893
0894 $firstChar = mb_substr($string, 0, 1, $encoding);
0895 $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding);
0896
0897 return $firstChar.mb_substr($string, 1, null, $encoding);
0898 }
0899
0900 /** @return string|false */
0901 public static function mb_lcfirst(string $string, ?string $encoding = null)
0902 {
0903 if (null === $encoding) {
0904 $encoding = self::mb_internal_encoding();
0905 } elseif (!self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given')) {
0906 return false;
0907 }
0908
0909 $firstChar = mb_substr($string, 0, 1, $encoding);
0910 $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding);
0911
0912 return $firstChar.mb_substr($string, 1, null, $encoding);
0913 }
0914
0915 private static function getSubpart($pos, $part, $haystack, $encoding)
0916 {
0917 if (false === $pos) {
0918 return false;
0919 }
0920 if ($part) {
0921 return self::mb_substr($haystack, 0, $pos, $encoding);
0922 }
0923
0924 return self::mb_substr($haystack, $pos, null, $encoding);
0925 }
0926
0927 private static function html_encoding_callback(array $m)
0928 {
0929 $i = 1;
0930 $entities = '';
0931 $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
0932
0933 while (isset($m[$i])) {
0934 if (0x80 > $m[$i]) {
0935 $entities .= \chr($m[$i++]);
0936 continue;
0937 }
0938 if (0xF0 <= $m[$i]) {
0939 $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
0940 } elseif (0xE0 <= $m[$i]) {
0941 $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
0942 } else {
0943 $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
0944 }
0945
0946 $entities .= '&#'.$c.';';
0947 }
0948
0949 return $entities;
0950 }
0951
0952 private static function title_case(array $s)
0953 {
0954 return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
0955 }
0956
0957 private static function getData($file)
0958 {
0959 if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
0960 return require $file;
0961 }
0962
0963 return false;
0964 }
0965
0966 private static function getEncoding($encoding)
0967 {
0968 if (null === $encoding) {
0969 return self::$internalEncoding;
0970 }
0971
0972 if ('UTF-8' === $encoding) {
0973 return 'UTF-8';
0974 }
0975
0976 $encoding = strtoupper($encoding);
0977
0978 if ('8BIT' === $encoding || 'BINARY' === $encoding) {
0979 return 'CP850';
0980 }
0981
0982 if ('UTF8' === $encoding) {
0983 return 'UTF-8';
0984 }
0985
0986 if ('UTF-32' === $encoding) {
0987 return 'UTF-32BE';
0988 }
0989
0990 if ('UTF-16' === $encoding) {
0991 return 'UTF-16BE';
0992 }
0993
0994 return $encoding;
0995 }
0996
0997 /** @return string|false */
0998 public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null)
0999 {
1000 return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
1001 }
1002
1003 /** @return string|false */
1004 public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null)
1005 {
1006 return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__);
1007 }
1008
1009 /** @return string|false */
1010 public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null)
1011 {
1012 return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__);
1013 }
1014
1015 /** @return string|false */
1016 private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function)
1017 {
1018 if (null === $encoding) {
1019 $encoding = self::mb_internal_encoding();
1020 } elseif (!self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given')) {
1021 return false;
1022 }
1023
1024 if ('' === $characters) {
1025 return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding);
1026 }
1027
1028 if ('UTF-8' === $encoding) {
1029 $encoding = null;
1030 if (!preg_match('//u', $string)) {
1031 $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string);
1032 }
1033 if (null !== $characters && !preg_match('//u', $characters)) {
1034 $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters);
1035 }
1036 } else {
1037 $string = iconv($encoding, 'UTF-8//IGNORE', $string);
1038
1039 if (null !== $characters) {
1040 $characters = iconv($encoding, 'UTF-8//IGNORE', $characters);
1041 }
1042 }
1043
1044 if (null === $characters) {
1045 $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}";
1046 } else {
1047 $characters = preg_quote($characters);
1048 }
1049
1050 $string = preg_replace(\sprintf($regex, $characters), '', $string);
1051
1052 if (null === $encoding) {
1053 return $string;
1054 }
1055
1056 return iconv('UTF-8', $encoding.'//IGNORE', $string);
1057 }
1058
1059 private static function assertEncoding(string $encoding, string $errorFormat): bool
1060 {
1061 try {
1062 $validEncoding = @self::mb_check_encoding('', $encoding);
1063 } catch (\ValueError $e) {
1064 throw new \ValueError(\sprintf($errorFormat, $encoding));
1065 }
1066
1067 if (!$validEncoding) {
1068 if (80000 > \PHP_VERSION_ID) {
1069 trigger_error(\sprintf($errorFormat, $encoding), \E_USER_WARNING);
1070 } else {
1071 throw new \ValueError(\sprintf($errorFormat, $encoding));
1072 }
1073 }
1074
1075 return $validEncoding;
1076 }
1077 }
1078