Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Mbstring.php

Zuletzt modifiziert: 02.04.2025, 15:02 - Dateigröße: 31.41 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Polyfill\Mbstring;
013   
014  /**
015   * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
016   *
017   * Implemented:
018   * - mb_chr                  - Returns a specific character from its Unicode code point
019   * - mb_convert_encoding     - Convert character encoding
020   * - mb_convert_variables    - Convert character code in variable(s)
021   * - mb_decode_mimeheader    - Decode string in MIME header field
022   * - mb_encode_mimeheader    - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
023   * - mb_decode_numericentity - Decode HTML numeric string reference to character
024   * - mb_encode_numericentity - Encode character to HTML numeric string reference
025   * - mb_convert_case         - Perform case folding on a string
026   * - mb_detect_encoding      - Detect character encoding
027   * - mb_get_info             - Get internal settings of mbstring
028   * - mb_http_input           - Detect HTTP input character encoding
029   * - mb_http_output          - Set/Get HTTP output character encoding
030   * - mb_internal_encoding    - Set/Get internal character encoding
031   * - mb_list_encodings       - Returns an array of all supported encodings
032   * - mb_ord                  - Returns the Unicode code point of a character
033   * - mb_output_handler       - Callback function converts character encoding in output buffer
034   * - mb_scrub                - Replaces ill-formed byte sequences with substitute characters
035   * - mb_strlen               - Get string length
036   * - mb_strpos               - Find position of first occurrence of string in a string
037   * - mb_strrpos              - Find position of last occurrence of a string in a string
038   * - mb_str_split            - Convert a string to an array
039   * - mb_strtolower           - Make a string lowercase
040   * - mb_strtoupper           - Make a string uppercase
041   * - mb_substitute_character - Set/Get substitution character
042   * - mb_substr               - Get part of string
043   * - mb_stripos              - Finds position of first occurrence of a string within another, case insensitive
044   * - mb_stristr              - Finds first occurrence of a string within another, case insensitive
045   * - mb_strrchr              - Finds the last occurrence of a character in a string within another
046   * - mb_strrichr             - Finds the last occurrence of a character in a string within another, case insensitive
047   * - mb_strripos             - Finds position of last occurrence of a string within another, case insensitive
048   * - mb_strstr               - Finds first occurrence of a string within another
049   * - mb_strwidth             - Return width of string
050   * - mb_substr_count         - Count the number of substring occurrences
051   *
052   * Not implemented:
053   * - mb_convert_kana         - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
054   * - mb_ereg_*               - Regular expression with multibyte support
055   * - mb_parse_str            - Parse GET/POST/COOKIE data and set global variable
056   * - mb_preferred_mime_name  - Get MIME charset string
057   * - mb_regex_encoding       - Returns current encoding for multibyte regex as string
058   * - mb_regex_set_options    - Set/Get the default options for mbregex functions
059   * - mb_send_mail            - Send encoded mail
060   * - mb_split                - Split multibyte string using regular expression
061   * - mb_strcut               - Get part of string
062   * - mb_strimwidth           - Get truncated string with specified width
063   *
064   * @author Nicolas Grekas <p@tchwork.com>
065   *
066   * @internal
067   */
068  final class Mbstring
069  {
070      public const MB_CASE_FOLD = \PHP_INT_MAX;
071   
072      private const SIMPLE_CASE_FOLD = [
073          ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
074          ['μ', 's', 'ι',        'σ', 'β',        'θ',        'φ',        'π',        'κ',        'ρ',        'ε',        "\xE1\xB9\xA1", 'ι'],
075      ];
076   
077      private static $encodingList = ['ASCII', 'UTF-8'];
078      private static $language = 'neutral';
079      private static $internalEncoding = 'UTF-8';
080   
081      public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
082      {
083          if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) {
084              $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
085          } else {
086              $fromEncoding = self::getEncoding($fromEncoding);
087          }
088   
089          $toEncoding = self::getEncoding($toEncoding);
090   
091          if ('BASE64' === $fromEncoding) {
092              $s = base64_decode($s);
093              $fromEncoding = $toEncoding;
094          }
095   
096          if ('BASE64' === $toEncoding) {
097              return base64_encode($s);
098          }
099   
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                      static $caseFolding = null;
305                      if (null === $caseFolding) {
306                          $caseFolding = self::getData('caseFolding');
307                      }
308                      $s = strtr($s, $caseFolding);
309                  }
310   
311                  static $lower = null;
312                  if (null === $lower) {
313                      $lower = self::getData('lowerCase');
314                  }
315                  $map = $lower;
316              }
317   
318              static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
319   
320              $i = 0;
321              $len = \strlen($s);
322   
323              while ($i < $len) {
324                  $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
325                  $uchr = substr($s, $i, $ulen);
326                  $i += $ulen;
327   
328                  if (isset($map[$uchr])) {
329                      $uchr = $map[$uchr];
330                      $nlen = \strlen($uchr);
331   
332                      if ($nlen == $ulen) {
333                          $nlen = $i;
334                          do {
335                              $s[--$nlen] = $uchr[--$ulen];
336                          } while ($ulen);
337                      } else {
338                          $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
339                          $len += $nlen - $ulen;
340                          $i += $nlen - $ulen;
341                      }
342                  }
343              }
344          }
345   
346          if (null === $encoding) {
347              return $s;
348          }
349   
350          return iconv('UTF-8', $encoding.'//IGNORE', $s);
351      }
352   
353      public static function mb_internal_encoding($encoding = null)
354      {
355          if (null === $encoding) {
356              return self::$internalEncoding;
357          }
358   
359          $normalizedEncoding = self::getEncoding($encoding);
360   
361          if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
362              self::$internalEncoding = $normalizedEncoding;
363   
364              return true;
365          }
366   
367          if (80000 > \PHP_VERSION_ID) {
368              return false;
369          }
370   
371          throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
372      }
373   
374      public static function mb_language($lang = null)
375      {
376          if (null === $lang) {
377              return self::$language;
378          }
379   
380          switch ($normalizedLang = strtolower($lang)) {
381              case 'uni':
382              case 'neutral':
383                  self::$language = $normalizedLang;
384   
385                  return true;
386          }
387   
388          if (80000 > \PHP_VERSION_ID) {
389              return false;
390          }
391   
392          throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
393      }
394   
395      public static function mb_list_encodings()
396      {
397          return ['UTF-8'];
398      }
399   
400      public static function mb_encoding_aliases($encoding)
401      {
402          switch (strtoupper($encoding)) {
403              case 'UTF8':
404              case 'UTF-8':
405                  return ['utf8'];
406          }
407   
408          return false;
409      }
410   
411      public static function mb_check_encoding($var = null, $encoding = null)
412      {
413          if (PHP_VERSION_ID < 70200 && \is_array($var)) {
414              trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING);
415   
416              return null;
417          }
418   
419          if (null === $encoding) {
420              if (null === $var) {
421                  return false;
422              }
423              $encoding = self::$internalEncoding;
424          }
425   
426          if (!\is_array($var)) {
427              return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var);
428          }
429   
430          foreach ($var as $key => $value) {
431              if (!self::mb_check_encoding($key, $encoding)) {
432                  return false;
433              }
434              if (!self::mb_check_encoding($value, $encoding)) {
435                  return false;
436              }
437          }
438   
439          return true;
440   
441      }
442   
443      public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
444      {
445          if (null === $encodingList) {
446              $encodingList = self::$encodingList;
447          } else {
448              if (!\is_array($encodingList)) {
449                  $encodingList = array_map('trim', explode(',', $encodingList));
450              }
451              $encodingList = array_map('strtoupper', $encodingList);
452          }
453   
454          foreach ($encodingList as $enc) {
455              switch ($enc) {
456                  case 'ASCII':
457                      if (!preg_match('/[\x80-\xFF]/', $str)) {
458                          return $enc;
459                      }
460                      break;
461   
462                  case 'UTF8':
463                  case 'UTF-8':
464                      if (preg_match('//u', $str)) {
465                          return 'UTF-8';
466                      }
467                      break;
468   
469                  default:
470                      if (0 === strncmp($enc, 'ISO-8859-', 9)) {
471                          return $enc;
472                      }
473              }
474          }
475   
476          return false;
477      }
478   
479      public static function mb_detect_order($encodingList = null)
480      {
481          if (null === $encodingList) {
482              return self::$encodingList;
483          }
484   
485          if (!\is_array($encodingList)) {
486              $encodingList = array_map('trim', explode(',', $encodingList));
487          }
488          $encodingList = array_map('strtoupper', $encodingList);
489   
490          foreach ($encodingList as $enc) {
491              switch ($enc) {
492                  default:
493                      if (strncmp($enc, 'ISO-8859-', 9)) {
494                          return false;
495                      }
496                      // no break
497                  case 'ASCII':
498                  case 'UTF8':
499                  case 'UTF-8':
500              }
501          }
502   
503          self::$encodingList = $encodingList;
504   
505          return true;
506      }
507   
508      public static function mb_strlen($s, $encoding = null)
509      {
510          $encoding = self::getEncoding($encoding);
511          if ('CP850' === $encoding || 'ASCII' === $encoding) {
512              return \strlen($s);
513          }
514   
515          return @iconv_strlen($s, $encoding);
516      }
517   
518      public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
519      {
520          $encoding = self::getEncoding($encoding);
521          if ('CP850' === $encoding || 'ASCII' === $encoding) {
522              return strpos($haystack, $needle, $offset);
523          }
524   
525          $needle = (string) $needle;
526          if ('' === $needle) {
527              if (80000 > \PHP_VERSION_ID) {
528                  trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
529   
530                  return false;
531              }
532   
533              return 0;
534          }
535   
536          return iconv_strpos($haystack, $needle, $offset, $encoding);
537      }
538   
539      public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
540      {
541          $encoding = self::getEncoding($encoding);
542          if ('CP850' === $encoding || 'ASCII' === $encoding) {
543              return strrpos($haystack, $needle, $offset);
544          }
545   
546          if ($offset != (int) $offset) {
547              $offset = 0;
548          } elseif ($offset = (int) $offset) {
549              if ($offset < 0) {
550                  if (0 > $offset += self::mb_strlen($needle)) {
551                      $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
552                  }
553                  $offset = 0;
554              } else {
555                  $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
556              }
557          }
558   
559          $pos = '' !== $needle || 80000 > \PHP_VERSION_ID
560              ? iconv_strrpos($haystack, $needle, $encoding)
561              : self::mb_strlen($haystack, $encoding);
562   
563          return false !== $pos ? $offset + $pos : false;
564      }
565   
566      public static function mb_str_split($string, $split_length = 1, $encoding = null)
567      {
568          if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
569              trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
570   
571              return null;
572          }
573   
574          if (1 > $split_length = (int) $split_length) {
575              if (80000 > \PHP_VERSION_ID) {
576                  trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
577   
578                  return false;
579              }
580   
581              throw new \ValueError('Argument #2 ($length) must be greater than 0');
582          }
583   
584          if (null === $encoding) {
585              $encoding = mb_internal_encoding();
586          }
587   
588          if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
589              $rx = '/(';
590              while (65535 < $split_length) {
591                  $rx .= '.{65535}';
592                  $split_length -= 65535;
593              }
594              $rx .= '.{'.$split_length.'})/us';
595   
596              return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
597          }
598   
599          $result = [];
600          $length = mb_strlen($string, $encoding);
601   
602          for ($i = 0; $i < $length; $i += $split_length) {
603              $result[] = mb_substr($string, $i, $split_length, $encoding);
604          }
605   
606          return $result;
607      }
608   
609      public static function mb_strtolower($s, $encoding = null)
610      {
611          return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
612      }
613   
614      public static function mb_strtoupper($s, $encoding = null)
615      {
616          return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
617      }
618   
619      public static function mb_substitute_character($c = null)
620      {
621          if (null === $c) {
622              return 'none';
623          }
624          if (0 === strcasecmp($c, 'none')) {
625              return true;
626          }
627          if (80000 > \PHP_VERSION_ID) {
628              return false;
629          }
630          if (\is_int($c) || 'long' === $c || 'entity' === $c) {
631              return false;
632          }
633   
634          throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
635      }
636   
637      public static function mb_substr($s, $start, $length = null, $encoding = null)
638      {
639          $encoding = self::getEncoding($encoding);
640          if ('CP850' === $encoding || 'ASCII' === $encoding) {
641              return (string) substr($s, $start, null === $length ? 2147483647 : $length);
642          }
643   
644          if ($start < 0) {
645              $start = iconv_strlen($s, $encoding) + $start;
646              if ($start < 0) {
647                  $start = 0;
648              }
649          }
650   
651          if (null === $length) {
652              $length = 2147483647;
653          } elseif ($length < 0) {
654              $length = iconv_strlen($s, $encoding) + $length - $start;
655              if ($length < 0) {
656                  return '';
657              }
658          }
659   
660          return (string) iconv_substr($s, $start, $length, $encoding);
661      }
662   
663      public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
664      {
665          [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [
666              self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding),
667              self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding),
668          ]);
669   
670          return self::mb_strpos($haystack, $needle, $offset, $encoding);
671      }
672   
673      public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
674      {
675          $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
676   
677          return self::getSubpart($pos, $part, $haystack, $encoding);
678      }
679   
680      public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
681      {
682          $encoding = self::getEncoding($encoding);
683          if ('CP850' === $encoding || 'ASCII' === $encoding) {
684              $pos = strrpos($haystack, $needle);
685          } else {
686              $needle = self::mb_substr($needle, 0, 1, $encoding);
687              $pos = iconv_strrpos($haystack, $needle, $encoding);
688          }
689   
690          return self::getSubpart($pos, $part, $haystack, $encoding);
691      }
692   
693      public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
694      {
695          $needle = self::mb_substr($needle, 0, 1, $encoding);
696          $pos = self::mb_strripos($haystack, $needle, $encoding);
697   
698          return self::getSubpart($pos, $part, $haystack, $encoding);
699      }
700   
701      public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
702      {
703          $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding);
704          $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding);
705   
706          $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack);
707          $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle);
708   
709          return self::mb_strrpos($haystack, $needle, $offset, $encoding);
710      }
711   
712      public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
713      {
714          $pos = strpos($haystack, $needle);
715          if (false === $pos) {
716              return false;
717          }
718          if ($part) {
719              return substr($haystack, 0, $pos);
720          }
721   
722          return substr($haystack, $pos);
723      }
724   
725      public static function mb_get_info($type = 'all')
726      {
727          $info = [
728              'internal_encoding' => self::$internalEncoding,
729              'http_output' => 'pass',
730              'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
731              'func_overload' => 0,
732              'func_overload_list' => 'no overload',
733              'mail_charset' => 'UTF-8',
734              'mail_header_encoding' => 'BASE64',
735              'mail_body_encoding' => 'BASE64',
736              'illegal_chars' => 0,
737              'encoding_translation' => 'Off',
738              'language' => self::$language,
739              'detect_order' => self::$encodingList,
740              'substitute_character' => 'none',
741              'strict_detection' => 'Off',
742          ];
743   
744          if ('all' === $type) {
745              return $info;
746          }
747          if (isset($info[$type])) {
748              return $info[$type];
749          }
750   
751          return false;
752      }
753   
754      public static function mb_http_input($type = '')
755      {
756          return false;
757      }
758   
759      public static function mb_http_output($encoding = null)
760      {
761          return null !== $encoding ? 'pass' === $encoding : 'pass';
762      }
763   
764      public static function mb_strwidth($s, $encoding = null)
765      {
766          $encoding = self::getEncoding($encoding);
767   
768          if ('UTF-8' !== $encoding) {
769              $s = iconv($encoding, 'UTF-8//IGNORE', $s);
770          }
771   
772          $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);
773   
774          return ($wide << 1) + iconv_strlen($s, 'UTF-8');
775      }
776   
777      public static function mb_substr_count($haystack, $needle, $encoding = null)
778      {
779          return substr_count($haystack, $needle);
780      }
781   
782      public static function mb_output_handler($contents, $status)
783      {
784          return $contents;
785      }
786   
787      public static function mb_chr($code, $encoding = null)
788      {
789          if (0x80 > $code %= 0x200000) {
790              $s = \chr($code);
791          } elseif (0x800 > $code) {
792              $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
793          } elseif (0x10000 > $code) {
794              $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
795          } else {
796              $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
797          }
798   
799          if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
800              $s = mb_convert_encoding($s, $encoding, 'UTF-8');
801          }
802   
803          return $s;
804      }
805   
806      public static function mb_ord($s, $encoding = null)
807      {
808          if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
809              $s = mb_convert_encoding($s, 'UTF-8', $encoding);
810          }
811   
812          if (1 === \strlen($s)) {
813              return \ord($s);
814          }
815   
816          $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
817          if (0xF0 <= $code) {
818              return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
819          }
820          if (0xE0 <= $code) {
821              return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
822          }
823          if (0xC0 <= $code) {
824              return (($code - 0xC0) << 6) + $s[2] - 0x80;
825          }
826   
827          return $code;
828      }
829   
830      public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string
831      {
832          if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) {
833              throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH');
834          }
835   
836          if (null === $encoding) {
837              $encoding = self::mb_internal_encoding();
838          }
839   
840          try {
841              $validEncoding = @self::mb_check_encoding('', $encoding);
842          } catch (\ValueError $e) {
843              throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
844          }
845   
846          // BC for PHP 7.3 and lower
847          if (!$validEncoding) {
848              throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding));
849          }
850   
851          if (self::mb_strlen($pad_string, $encoding) <= 0) {
852              throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string');
853          }
854   
855          $paddingRequired = $length - self::mb_strlen($string, $encoding);
856   
857          if ($paddingRequired < 1) {
858              return $string;
859          }
860   
861          switch ($pad_type) {
862              case \STR_PAD_LEFT:
863                  return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
864              case \STR_PAD_RIGHT:
865                  return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
866              default:
867                  $leftPaddingLength = floor($paddingRequired / 2);
868                  $rightPaddingLength = $paddingRequired - $leftPaddingLength;
869   
870                  return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
871          }
872      }
873   
874      private static function getSubpart($pos, $part, $haystack, $encoding)
875      {
876          if (false === $pos) {
877              return false;
878          }
879          if ($part) {
880              return self::mb_substr($haystack, 0, $pos, $encoding);
881          }
882   
883          return self::mb_substr($haystack, $pos, null, $encoding);
884      }
885   
886      private static function html_encoding_callback(array $m)
887      {
888          $i = 1;
889          $entities = '';
890          $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
891   
892          while (isset($m[$i])) {
893              if (0x80 > $m[$i]) {
894                  $entities .= \chr($m[$i++]);
895                  continue;
896              }
897              if (0xF0 <= $m[$i]) {
898                  $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
899              } elseif (0xE0 <= $m[$i]) {
900                  $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
901              } else {
902                  $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
903              }
904   
905              $entities .= '&#'.$c.';';
906          }
907   
908          return $entities;
909      }
910   
911      private static function title_case(array $s)
912      {
913          return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
914      }
915   
916      private static function getData($file)
917      {
918          if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
919              return require $file;
920          }
921   
922          return false;
923      }
924   
925      private static function getEncoding($encoding)
926      {
927          if (null === $encoding) {
928              return self::$internalEncoding;
929          }
930   
931          if ('UTF-8' === $encoding) {
932              return 'UTF-8';
933          }
934   
935          $encoding = strtoupper($encoding);
936   
937          if ('8BIT' === $encoding || 'BINARY' === $encoding) {
938              return 'CP850';
939          }
940   
941          if ('UTF8' === $encoding) {
942              return 'UTF-8';
943          }
944   
945          return $encoding;
946      }
947  }
948