"Fossies" - the Fresh Open Source Software Archive

Member "grav/vendor/symfony/polyfill-mbstring/Mbstring.php" (1 Sep 2020, 28145 Bytes) of package /linux/www/grav-v1.6.27.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Mbstring.php" see the Fossies "Dox" file reference documentation.

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