Merge branch '5.3' into 5.4
authorTim Düsterhus <duesterhus@woltlab.com>
Wed, 19 Jan 2022 12:31:58 +0000 (13:31 +0100)
committerTim Düsterhus <duesterhus@woltlab.com>
Wed, 19 Jan 2022 12:31:58 +0000 (13:31 +0100)
1  2 
wcfsetup/install/files/lib/util/StringUtil.class.php

index d266e0d427d53301f501854f9006a5c69f72d934,151b4bbd15c9df21960bb29b8b7a344c66f75ab3..76b16f01fbdfc5322ec60943aa445aec460d2fa1
@@@ -21,497 -17,450 +21,497 @@@ final class StringUti
                        (?:\s*[a-z\-]+\s*(=\s*(?:
                        "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'|[^\s>]
                        ))?)*\s*/?>~ix';
 -      const HTML_COMMENT_PATTERN = '~<!--(.*?)-->~';
 -      
 -      /**
 -       * utf8 bytes of the HORIZONTAL ELLIPSIS (U+2026)
 -       * @var string
 -       */
 -      const HELLIP = "\u{2026}";
 -      
 -      /**
 -       * utf8 bytes of the MINUS SIGN (U+2212)
 -       * @var string
 -       */
 -      const MINUS = "\u{2212}";
 -      
 -      /**
 -       * Alias to php sha1() function.
 -       * 
 -       * @param       string          $value
 -       * @return      string
 -       */
 -      public static function getHash($value) {
 -              return sha1($value);
 -      }
 -      
 -      /**
 -       * Returns a 40 character hexadecimal string generated using a CSPRNG.
 -       * 
 -       * @return      string
 -       */
 -      public static function getRandomID() {
 -              return \bin2hex(\random_bytes(20));
 -      }
 -      
 -      /**
 -       * Creates an UUID.
 -       * 
 -       * @return      string
 -       */
 -      public static function getUUID() {
 -              return sprintf(
 -                      '%04x%04x-%04x-%04x-%02x%02x-%04x%04x%04x',
 -                      // time_low
 -                      \random_int(0, 0xffff), \random_int(0, 0xffff),
 -                      // time_mid
 -                      \random_int(0, 0xffff), 
 -                      // time_hi_and_version
 -                      \random_int(0, 0x0fff) | 0x4000,
 -                      // clock_seq_hi_and_res
 -                      \random_int(0, 0x3f) | 0x80,
 -                      // clock_seq_low
 -                      \random_int(0, 0xff),
 -                      // node
 -                      \random_int(0, 0xffff), \random_int(0, 0xffff), \random_int(0, 0xffff)
 -              );
 -      }
 -      
 -      /**
 -       * Converts dos to unix newlines.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function unifyNewlines($string) {
 -              return preg_replace("%(\r\n)|(\r)%", "\n", $string);
 -      }
 -      
 -      /**
 -       * Removes Unicode whitespace characters from the beginning
 -       * and ending of the given string.
 -       * 
 -       * @param       string          $text
 -       * @return      string
 -       */
 -      public static function trim($text) {
 -              // These regular expressions use character properties
 -              // to find characters defined as space in the unicode
 -              // specification.
 -              // Do not merge the expressions, they are separated for
 -              // performance reasons.
 -              $text = preg_replace('/^[\p{Zs}\s\x{202E}]+/u', '', $text);
 -              $text = preg_replace('/[\p{Zs}\s\x{202E}]+$/u', '', $text);
 -              
 -              return $text;
 -      }
 -      
 -      /**
 -       * Converts html special characters.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function encodeHTML($string) {
 -              return @htmlspecialchars((string) $string, ENT_COMPAT, 'UTF-8');
 -      }
 -      
 -      /**
 -       * Converts javascript special characters.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function encodeJS($string) {
 -              $string = self::unifyNewlines($string);
 -              $string = str_replace(["\\", "'", '"', "\n", "/"], ["\\\\", "\'", '\"', '\n', '\/'], $string);
 -              
 -              return $string;
 -      }
 -      
 -      /**
 -       * Encodes JSON strings. This is not the same as PHP's json_encode()!
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function encodeJSON($string) {
 -              $string = self::encodeJS($string);
 -              
 -              $string = self::encodeHTML($string);
 -              
 -              // single quotes must be encoded as HTML entity
 -              $string = str_replace("\'", "&#39;", $string);
 -              
 -              return $string;
 -      }
 -      
 -      /**
 -       * Decodes html entities.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function decodeHTML($string) {
 -              $string = str_ireplace('&nbsp;', ' ', $string); // convert non-breaking spaces to ascii 32; not ascii 160
 -              return @html_entity_decode($string, ENT_COMPAT, 'UTF-8');
 -      }
 -      
 -      /**
 -       * Formats a numeric.
 -       * 
 -       * @param       number          $numeric
 -       * @return      string
 -       */
 -      public static function formatNumeric($numeric) {
 -              if (is_int($numeric)) {
 -                      return self::formatInteger($numeric);
 -              }
 -              else if (is_float($numeric)) {
 -                      return self::formatDouble($numeric);
 -              }
 -              else {
 -                      if (floatval($numeric) - (float) intval($numeric)) {
 -                              return self::formatDouble($numeric);
 -                      }
 -                      else {
 -                              return self::formatInteger(intval($numeric));
 -                      }
 -              }
 -      }
 -      
 -      /**
 -       * Formats an integer.
 -       * 
 -       * @param       integer         $integer
 -       * @return      string
 -       */
 -      public static function formatInteger($integer) {
 -              $integer = self::addThousandsSeparator($integer);
 -              
 -              // format minus
 -              $integer = self::formatNegative($integer);
 -              
 -              return $integer;
 -      }
 -      
 -      /**
 -       * Formats a double.
 -       * 
 -       * @param       double          $double
 -       * @param       integer         $maxDecimals
 -       * @return      string
 -       */
 -      public static function formatDouble($double, $maxDecimals = 0) {
 -              // round
 -              $double = (string) round($double, ($maxDecimals > 0 ? $maxDecimals : 2));
 -              
 -              // consider as integer, if no decimal places found
 -              if (!$maxDecimals && preg_match('~^(-?\d+)(?:\.(?:0*|00[0-4]\d*))?$~', $double, $match)) {
 -                      return self::formatInteger($match[1]);
 -              }
 -              
 -              // remove last 0
 -              if ($maxDecimals < 2 && substr($double, -1) == '0') $double = substr($double, 0, -1);
 -              
 -              // replace decimal point
 -              $double = str_replace('.', WCF::getLanguage()->get('wcf.global.decimalPoint'), $double);
 -              
 -              // add thousands separator
 -              $double = self::addThousandsSeparator($double);
 -              
 -              // format minus
 -              $double = self::formatNegative($double);
 -              
 -              return $double;
 -      }
 -      
 -      /**
 -       * Adds thousands separators to a given number.
 -       * 
 -       * @param       mixed           $number
 -       * @return      string
 -       */
 -      public static function addThousandsSeparator($number) {
 -              if ($number >= 1000 || $number <= -1000) {
 -                      $number = preg_replace('~(?<=\d)(?=(\d{3})+(?!\d))~', WCF::getLanguage()->get('wcf.global.thousandsSeparator'), $number);
 -              }
 -              
 -              return $number;
 -      }
 -      
 -      /**
 -       * Replaces the MINUS-HYPHEN with the MINUS SIGN.
 -       * 
 -       * @param       mixed           $number
 -       * @return      string
 -       */
 -      public static function formatNegative($number) {
 -              return str_replace('-', self::MINUS, $number);
 -      }
 -      
 -      /**
 -       * Alias to php ucfirst() function with multibyte support.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function firstCharToUpperCase($string) {
 -              return mb_strtoupper(mb_substr($string, 0, 1)).mb_substr($string, 1);
 -      }
 -      
 -      /**
 -       * Alias to php lcfirst() function with multibyte support.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function firstCharToLowerCase($string) {
 -              return mb_strtolower(mb_substr($string, 0, 1)).mb_substr($string, 1);
 -      }
 -      
 -      /**
 -       * Alias to php mb_convert_case() function.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function wordsToUpperCase($string) {
 -              return mb_convert_case($string, MB_CASE_TITLE);
 -      }
 -      
 -      /**
 -       * Alias to php str_ireplace() function with UTF-8 support.
 -       * 
 -       * This function is considered to be slow, if $search contains
 -       * only ASCII characters, please use str_ireplace() instead.
 -       * 
 -       * @param       string          $search
 -       * @param       string          $replace
 -       * @param       string          $subject
 -       * @param       integer         $count
 -       * @return      string
 -       */
 -      public static function replaceIgnoreCase($search, $replace, $subject, &$count = 0) {
 -              $startPos = mb_strpos(mb_strtolower($subject), mb_strtolower($search));
 -              if ($startPos === false) return $subject;
 -              else {
 -                      $endPos = $startPos + mb_strlen($search);
 -                      $count++;
 -                      return mb_substr($subject, 0, $startPos) . $replace . self::replaceIgnoreCase($search, $replace, mb_substr($subject, $endPos), $count);
 -              }
 -      }
 -      
 -      /**
 -       * Alias to php str_split() function with multibyte support.
 -       * 
 -       * @param       string          $string
 -       * @param       integer         $length
 -       * @return      string[]
 -       */
 -      public static function split($string, $length = 1) {
 -              $result = [];
 -              for ($i = 0, $max = mb_strlen($string); $i < $max; $i += $length) {
 -                      $result[] = mb_substr($string, $i, $length);
 -              }
 -              return $result;
 -      }
 -      
 -      /**
 -       * Checks whether $haystack starts with $needle, or not.
 -       * 
 -       * @param       string          $haystack       The string to be checked for starting with $needle
 -       * @param       string          $needle         The string to be found at the start of $haystack
 -       * @param       boolean         $ci             Case insensitive or not. Default = false.
 -       * 
 -       * @return      boolean                         True, if $haystack starts with $needle, false otherwise.
 -       */
 -      public static function startsWith($haystack, $needle, $ci = false) {
 -              if ($ci) {
 -                      $haystack = mb_strtolower($haystack);
 -                      $needle = mb_strtolower($needle);
 -              }
 -              // using mb_substr and === is MUCH faster for long strings then using indexOf.
 -              return mb_substr($haystack, 0, mb_strlen($needle)) === $needle;
 -      }
 -      
 -      /**
 -       * Returns true if $haystack ends with $needle or if the length of $needle is 0.
 -       * 
 -       * @param       string          $haystack
 -       * @param       string          $needle
 -       * @param       boolean         $ci             case insensitive
 -       * @return      boolean
 -       */
 -      public static function endsWith($haystack, $needle, $ci = false) {
 -              if ($ci) {
 -                      $haystack = mb_strtolower($haystack);
 -                      $needle = mb_strtolower($needle);
 -              }
 -              $length = mb_strlen($needle);
 -              if ($length === 0) return true;
 -              return (mb_substr($haystack, $length * -1) === $needle);
 -      }
 -      
 -      /**
 -       * Alias to php str_pad function with multibyte support.
 -       * 
 -       * @param       string          $input
 -       * @param       integer         $padLength
 -       * @param       string          $padString
 -       * @param       integer         $padType
 -       * @return      string
 -       */
 -      public static function pad($input, $padLength, $padString = ' ', $padType = STR_PAD_RIGHT) {
 -              $additionalPadding = strlen($input) - mb_strlen($input);
 -              return str_pad($input, $padLength + $additionalPadding, $padString, $padType);
 -      }
 -      
 -      /**
 -       * Unescapes escaped characters in a string.
 -       * 
 -       * @param       string          $string
 -       * @param       string          $chars
 -       * @return      string
 -       */
 -      public static function unescape($string, $chars = '"') {
 -              for ($i = 0, $j = strlen($chars); $i < $j; $i++) {
 -                      $string = str_replace('\\'.$chars[$i], $chars[$i], $string);
 -              }
 -              
 -              return $string;
 -      }
 -      
 -      /**
 -       * Takes a numeric HTML entity value and returns the appropriate UTF-8 bytes.
 -       * 
 -       * @param       integer         $dec            html entity value
 -       * @return      string                          utf-8 bytes
 -       */
 -      public static function getCharacter($dec) {
 -              if ($dec < 128) {
 -                      $utf = chr($dec);
 -              }
 -              else if ($dec < 2048) {
 -                      $utf = chr(192 + (($dec - ($dec % 64)) / 64));
 -                      $utf .= chr(128 + ($dec % 64));
 -              }
 -              else {
 -                      $utf = chr(224 + (($dec - ($dec % 4096)) / 4096));
 -                      $utf .= chr(128 + ((($dec % 4096) - ($dec % 64)) / 64));
 -                      $utf .= chr(128 + ($dec % 64));
 -              }
 -              return $utf;
 -      }
 -      
 -      /**
 -       * Converts UTF-8 to Unicode
 -       * @see         http://www1.tip.nl/~t876506/utf8tbl.html
 -       * 
 -       * @param       string          $c
 -       * @return      integer
 -       */
 -      public static function getCharValue($c) {
 -              $ud = 0;
 -              if (ord($c[0]) >= 0 && ord($c[0]) <= 127) 
 -                      $ud = ord($c[0]);
 -              if (ord($c[0]) >= 192 && ord($c[0]) <= 223) 
 -                      $ud = (ord($c[0]) - 192) * 64 + (ord($c[1]) - 128);
 -              if (ord($c[0]) >= 224 && ord($c[0]) <= 239) 
 -                      $ud = (ord($c[0]) - 224) * 4096 + (ord($c[1]) - 128) * 64 + (ord($c[2]) - 128);
 -              if (ord($c[0]) >= 240 && ord($c[0]) <= 247) 
 -                      $ud = (ord($c[0]) - 240) * 262144 + (ord($c[1]) - 128) * 4096 + (ord($c[2]) - 128) * 64 + (ord($c[3]) - 128);
 -              if (ord($c[0]) >= 248 && ord($c[0]) <= 251) 
 -                      $ud = (ord($c[0]) - 248) * 16777216 + (ord($c[1]) - 128) * 262144 + (ord($c[2]) - 128) * 4096 + (ord($c[3]) - 128) * 64 + (ord($c[4]) - 128);
 -              if (ord($c[0]) >= 252 && ord($c[0]) <= 253) 
 -                      $ud = (ord($c[0]) - 252) * 1073741824 + (ord($c[1]) - 128) * 16777216 + (ord($c[2]) - 128) * 262144 + (ord($c[3]) - 128) * 4096 + (ord($c[4]) - 128) * 64 + (ord($c[5]) - 128);
 -              if (ord($c[0]) >= 254 && ord($c[0]) <= 255) 
 -                      $ud = false; // error
 -              return $ud;
 -      }
 -      
 -      /**
 -       * Returns html entities of all characters in the given string.
 -       * 
 -       * @param       string          $string
 -       * @return      string
 -       */
 -      public static function encodeAllChars($string) {
 -              $result = '';
 -              for ($i = 0, $j = mb_strlen($string); $i < $j; $i++) {
 -                      $char = mb_substr($string, $i, 1);
 -                      $result .= '&#'.self::getCharValue($char).';';
 -              }
 -              
 -              return $result;
 -      }
 -      
 -      /**
 -       * Returns true if the given string contains only ASCII characters.
 -       * 
 -       * @param       string          $string
 -       * @return      boolean
 -       */
 -      public static function isASCII($string) {
 -              return preg_match('/^[\x00-\x7F]*$/', $string);
 -      }
 -      
 -      /**
 -       * Returns true if the given string is utf-8 encoded.
 -       * @see         http://www.w3.org/International/questions/qa-forms-utf-8
 -       * 
 -       * @param       string          $string
 -       * @return      boolean
 -       */
 -      public static function isUTF8($string) {
 -              return preg_match('/^(
 +
 +    const HTML_COMMENT_PATTERN = '~<!--(.*?)-->~';
 +
 +    /**
 +     * utf8 bytes of the HORIZONTAL ELLIPSIS (U+2026)
 +     * @var string
 +     */
 +    const HELLIP = "\u{2026}";
 +
 +    /**
 +     * utf8 bytes of the MINUS SIGN (U+2212)
 +     * @var string
 +     */
 +    const MINUS = "\u{2212}";
 +
 +    /**
 +     * Alias to php sha1() function.
 +     *
 +     * @param string $value
 +     * @return  string
 +     */
 +    public static function getHash($value)
 +    {
 +        return \sha1($value);
 +    }
 +
 +    /**
 +     * Returns a 40 character hexadecimal string generated using a CSPRNG.
 +     *
 +     * @return  string
 +     */
 +    public static function getRandomID()
 +    {
 +        return Hex::encode(\random_bytes(20));
 +    }
 +
 +    /**
 +     * Creates an UUID.
 +     *
 +     * @return  string
 +     */
 +    public static function getUUID()
 +    {
 +        return \sprintf(
 +            '%04x%04x-%04x-%04x-%02x%02x-%04x%04x%04x',
 +            // time_low
 +            \random_int(0, 0xffff),
 +            \random_int(0, 0xffff),
 +            // time_mid
 +            \random_int(0, 0xffff),
 +            // time_hi_and_version
 +            \random_int(0, 0x0fff) | 0x4000,
 +            // clock_seq_hi_and_res
 +            \random_int(0, 0x3f) | 0x80,
 +            // clock_seq_low
 +            \random_int(0, 0xff),
 +            // node
 +            \random_int(0, 0xffff),
 +            \random_int(0, 0xffff),
 +            \random_int(0, 0xffff)
 +        );
 +    }
 +
 +    /**
 +     * Converts dos to unix newlines.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function unifyNewlines($string)
 +    {
 +        return \preg_replace("%(\r\n)|(\r)%", "\n", $string);
 +    }
 +
 +    /**
 +     * Removes Unicode whitespace characters from the beginning
 +     * and ending of the given string.
 +     *
 +     * @param string $text
 +     * @return  string
 +     */
 +    public static function trim($text)
 +    {
 +        // These regular expressions use character properties
 +        // to find characters defined as space in the unicode
 +        // specification.
 +        // Do not merge the expressions, they are separated for
 +        // performance reasons.
 +        $text = \preg_replace('/^[\p{Zs}\s\x{202E}\x{200B}]+/u', '', $text);
 +
 +        return \preg_replace('/[\p{Zs}\s\x{202E}\x{200B}]+$/u', '', $text);
 +    }
 +
 +    /**
 +     * Converts html special characters.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function encodeHTML($string)
 +    {
 +        return @\htmlspecialchars((string)$string, \ENT_COMPAT, 'UTF-8');
 +    }
 +
 +    /**
 +     * Converts javascript special characters.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function encodeJS($string)
 +    {
 +        $string = self::unifyNewlines($string);
 +
-         return \str_replace(["\\", "'", "\n", "/"], ["\\\\", "\\'", '\n', '\/'], $string);
++        return \str_replace(["\\", "'", '"', "\n", "/"], ["\\\\", "\\'", '\\"', '\n', '\/'], $string);
 +    }
 +
 +    /**
 +     * Encodes JSON strings. This is not the same as PHP's json_encode()!
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function encodeJSON($string)
 +    {
 +        $string = self::encodeJS($string);
 +
 +        $string = self::encodeHTML($string);
 +
 +        // single quotes must be encoded as HTML entity
 +        return \str_replace("\\'", "&#39;", $string);
 +    }
 +
 +    /**
 +     * Decodes html entities.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function decodeHTML($string)
 +    {
 +        $string = \str_ireplace('&nbsp;', ' ', $string); // convert non-breaking spaces to ascii 32; not ascii 160
 +
 +        return @\html_entity_decode($string, \ENT_COMPAT, 'UTF-8');
 +    }
 +
 +    /**
 +     * Formats a numeric.
 +     *
 +     * @param number $numeric
 +     * @return  string
 +     */
 +    public static function formatNumeric($numeric)
 +    {
 +        if (\is_int($numeric)) {
 +            return self::formatInteger($numeric);
 +        } elseif (\is_float($numeric)) {
 +            return self::formatDouble($numeric);
 +        } else {
 +            if (\floatval($numeric) - (float)\intval($numeric)) {
 +                return self::formatDouble($numeric);
 +            } else {
 +                return self::formatInteger(\intval($numeric));
 +            }
 +        }
 +    }
 +
 +    /**
 +     * Formats an integer.
 +     *
 +     * @param int $integer
 +     * @return  string
 +     */
 +    public static function formatInteger($integer)
 +    {
 +        $integer = self::addThousandsSeparator($integer);
 +
 +        // format minus
 +        return self::formatNegative($integer);
 +    }
 +
 +    /**
 +     * Formats a double.
 +     *
 +     * @param double $double
 +     * @param int $maxDecimals
 +     * @return  string
 +     */
 +    public static function formatDouble($double, $maxDecimals = 0)
 +    {
 +        // round
 +        $double = (string)\round($double, ($maxDecimals > 0 ? $maxDecimals : 2));
 +
 +        // consider as integer, if no decimal places found
 +        if (!$maxDecimals && \preg_match('~^(-?\d+)(?:\.(?:0*|00[0-4]\d*))?$~', $double, $match)) {
 +            return self::formatInteger($match[1]);
 +        }
 +
 +        // remove last 0
 +        if ($maxDecimals < 2 && \substr($double, -1) == '0') {
 +            $double = \substr($double, 0, -1);
 +        }
 +
 +        // replace decimal point
 +        $double = \str_replace('.', WCF::getLanguage()->get('wcf.global.decimalPoint'), $double);
 +
 +        // add thousands separator
 +        $double = self::addThousandsSeparator($double);
 +
 +        // format minus
 +        return self::formatNegative($double);
 +    }
 +
 +    /**
 +     * Adds thousands separators to a given number.
 +     *
 +     * @param mixed $number
 +     * @return  string
 +     */
 +    public static function addThousandsSeparator($number)
 +    {
 +        if ($number >= 1000 || $number <= -1000) {
 +            $number = \preg_replace(
 +                '~(?<=\d)(?=(\d{3})+(?!\d))~',
 +                WCF::getLanguage()->get('wcf.global.thousandsSeparator'),
 +                $number
 +            );
 +        }
 +
 +        return $number;
 +    }
 +
 +    /**
 +     * Replaces the MINUS-HYPHEN with the MINUS SIGN.
 +     *
 +     * @param mixed $number
 +     * @return  string
 +     */
 +    public static function formatNegative($number)
 +    {
 +        return \str_replace('-', self::MINUS, $number);
 +    }
 +
 +    /**
 +     * Alias to php ucfirst() function with multibyte support.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function firstCharToUpperCase($string)
 +    {
 +        return \mb_strtoupper(\mb_substr($string, 0, 1)) . \mb_substr($string, 1);
 +    }
 +
 +    /**
 +     * Alias to php lcfirst() function with multibyte support.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function firstCharToLowerCase($string)
 +    {
 +        return \mb_strtolower(\mb_substr($string, 0, 1)) . \mb_substr($string, 1);
 +    }
 +
 +    /**
 +     * Alias to php mb_convert_case() function.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function wordsToUpperCase($string)
 +    {
 +        return \mb_convert_case($string, \MB_CASE_TITLE);
 +    }
 +
 +    /**
 +     * Alias to php str_ireplace() function with UTF-8 support.
 +     *
 +     * This function is considered to be slow, if $search contains
 +     * only ASCII characters, please use str_ireplace() instead.
 +     *
 +     * @param string $search
 +     * @param string $replace
 +     * @param string $subject
 +     * @param int $count
 +     * @return  string
 +     */
 +    public static function replaceIgnoreCase($search, $replace, $subject, &$count = 0)
 +    {
 +        $startPos = \mb_strpos(\mb_strtolower($subject), \mb_strtolower($search));
 +        if ($startPos === false) {
 +            return $subject;
 +        } else {
 +            $endPos = $startPos + \mb_strlen($search);
 +            $count++;
 +
 +            return \mb_substr($subject, 0, $startPos) . $replace . self::replaceIgnoreCase(
 +                $search,
 +                $replace,
 +                \mb_substr($subject, $endPos),
 +                $count
 +            );
 +        }
 +    }
 +
 +    /**
 +     * Alias to php str_split() function with multibyte support.
 +     *
 +     * @param string $string
 +     * @param int $length
 +     * @return  string[]
 +     */
 +    public static function split($string, $length = 1)
 +    {
 +        $result = [];
 +        for ($i = 0, $max = \mb_strlen($string); $i < $max; $i += $length) {
 +            $result[] = \mb_substr($string, $i, $length);
 +        }
 +
 +        return $result;
 +    }
 +
 +    /**
 +     * Checks whether $haystack starts with $needle, or not.
 +     *
 +     * @param string $haystack The string to be checked for starting with $needle
 +     * @param string $needle The string to be found at the start of $haystack
 +     * @param bool $ci Case insensitive or not. Default = false.
 +     *
 +     * @return  bool                True, if $haystack starts with $needle, false otherwise.
 +     */
 +    public static function startsWith($haystack, $needle, $ci = false)
 +    {
 +        if ($ci) {
 +            $haystack = \mb_strtolower($haystack);
 +            $needle = \mb_strtolower($needle);
 +        }
 +        // using mb_substr and === is MUCH faster for long strings then using indexOf.
 +        return \mb_substr($haystack, 0, \mb_strlen($needle)) === $needle;
 +    }
 +
 +    /**
 +     * Returns true if $haystack ends with $needle or if the length of $needle is 0.
 +     *
 +     * @param string $haystack
 +     * @param string $needle
 +     * @param bool $ci case insensitive
 +     * @return  bool
 +     */
 +    public static function endsWith($haystack, $needle, $ci = false)
 +    {
 +        if ($ci) {
 +            $haystack = \mb_strtolower($haystack);
 +            $needle = \mb_strtolower($needle);
 +        }
 +        $length = \mb_strlen($needle);
 +        if ($length === 0) {
 +            return true;
 +        }
 +
 +        return \mb_substr($haystack, $length * -1) === $needle;
 +    }
 +
 +    /**
 +     * Alias to php str_pad function with multibyte support.
 +     *
 +     * @param string $input
 +     * @param int $padLength
 +     * @param string $padString
 +     * @param int $padType
 +     * @return  string
 +     */
 +    public static function pad($input, $padLength, $padString = ' ', $padType = \STR_PAD_RIGHT)
 +    {
 +        $additionalPadding = \strlen($input) - \mb_strlen($input);
 +
 +        return \str_pad($input, $padLength + $additionalPadding, $padString, $padType);
 +    }
 +
 +    /**
 +     * Unescapes escaped characters in a string.
 +     *
 +     * @param string $string
 +     * @param string $chars
 +     * @return  string
 +     */
 +    public static function unescape($string, $chars = '"')
 +    {
 +        for ($i = 0, $j = \strlen($chars); $i < $j; $i++) {
 +            $string = \str_replace('\\' . $chars[$i], $chars[$i], $string);
 +        }
 +
 +        return $string;
 +    }
 +
 +    /**
 +     * Takes a numeric HTML entity value and returns the appropriate UTF-8 bytes.
 +     *
 +     * @param int $dec html entity value
 +     * @return  string              utf-8 bytes
 +     */
 +    public static function getCharacter($dec)
 +    {
 +        if ($dec < 128) {
 +            $utf = \chr($dec);
 +        } elseif ($dec < 2048) {
 +            $utf = \chr(192 + (($dec - ($dec % 64)) / 64));
 +            $utf .= \chr(128 + ($dec % 64));
 +        } else {
 +            $utf = \chr(224 + (($dec - ($dec % 4096)) / 4096));
 +            $utf .= \chr(128 + ((($dec % 4096) - ($dec % 64)) / 64));
 +            $utf .= \chr(128 + ($dec % 64));
 +        }
 +
 +        return $utf;
 +    }
 +
 +    /**
 +     * Converts UTF-8 to Unicode
 +     * @see     http://www1.tip.nl/~t876506/utf8tbl.html
 +     *
 +     * @param string $c
 +     * @return  int
 +     */
 +    public static function getCharValue($c)
 +    {
 +        $ud = 0;
 +        if (\ord($c[0]) >= 0 && \ord($c[0]) <= 127) {
 +            $ud = \ord($c[0]);
 +        }
 +        if (\ord($c[0]) >= 192 && \ord($c[0]) <= 223) {
 +            $ud = (\ord($c[0]) - 192) * 64 + (\ord($c[1]) - 128);
 +        }
 +        if (\ord($c[0]) >= 224 && \ord($c[0]) <= 239) {
 +            $ud = (\ord($c[0]) - 224) * 4096 + (\ord($c[1]) - 128) * 64 + (\ord($c[2]) - 128);
 +        }
 +        if (\ord($c[0]) >= 240 && \ord($c[0]) <= 247) {
 +            $ud = (\ord($c[0]) - 240) * 262144 + (\ord($c[1]) - 128) * 4096 + (\ord($c[2]) - 128) * 64 + (\ord($c[3]) - 128);
 +        }
 +        if (\ord($c[0]) >= 248 && \ord($c[0]) <= 251) {
 +            $ud = (\ord($c[0]) - 248) * 16777216 + (\ord($c[1]) - 128) * 262144 + (\ord($c[2]) - 128) * 4096 + (\ord($c[3]) - 128) * 64 + (\ord($c[4]) - 128);
 +        }
 +        if (\ord($c[0]) >= 252 && \ord($c[0]) <= 253) {
 +            $ud = (\ord($c[0]) - 252) * 1073741824 + (\ord($c[1]) - 128) * 16777216 + (\ord($c[2]) - 128) * 262144 + (\ord($c[3]) - 128) * 4096 + (\ord($c[4]) - 128) * 64 + (\ord($c[5]) - 128);
 +        }
 +        if (\ord($c[0]) >= 254 && \ord($c[0]) <= 255) {
 +            $ud = false; // error
 +        }
 +
 +        return $ud;
 +    }
 +
 +    /**
 +     * Returns html entities of all characters in the given string.
 +     *
 +     * @param string $string
 +     * @return  string
 +     */
 +    public static function encodeAllChars($string)
 +    {
 +        $result = '';
 +        for ($i = 0, $j = \mb_strlen($string); $i < $j; $i++) {
 +            $char = \mb_substr($string, $i, 1);
 +            $result .= '&#' . self::getCharValue($char) . ';';
 +        }
 +
 +        return $result;
 +    }
 +
 +    /**
 +     * Returns true if the given string contains only ASCII characters.
 +     *
 +     * @param string $string
 +     * @return  bool
 +     */
 +    public static function isASCII($string)
 +    {
 +        return \preg_match('/^[\x00-\x7F]*$/', $string);
 +    }
 +
 +    /**
 +     * Returns true if the given string is utf-8 encoded.
 +     * @see     http://www.w3.org/International/questions/qa-forms-utf-8
 +     *
 +     * @param string $string
 +     * @return  bool
 +     */
 +    public static function isUTF8($string)
 +    {
 +        return \preg_match('/^(
                                [\x09\x0A\x0D\x20-\x7E]*                # ASCII
                        |       [\xC2-\xDF][\x80-\xBF]                  # non-overlong 2-byte
                        |       \xE0[\xA0-\xBF][\x80-\xBF]              # excluding overlongs