Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.88% covered (warning)
73.88%
645 / 873
37.04% covered (danger)
37.04%
10 / 27
CRAP
n/a
0 / 0
utf8_strrpos
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
3.58
utf8_strpos
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
utf8_stripos
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
utf8_strtolower
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
utf8_strtoupper
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
utf8_substr
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
utf8_strlen
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
utf8_str_split
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
4.05
utf8_strspn
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
utf8_ucfirst
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
utf8_recode
0.00% covered (danger)
0.00%
0 / 102
0.00% covered (danger)
0.00%
0 / 1
4290
utf8_encode_ucr
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
utf8_encode_ncr
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
utf8_encode_ncr_callback
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
utf8_ord
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
42
utf8_chr
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
utf8_decode_ncr
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
utf8_decode_ncr_callback
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
utf8_case_fold
84.62% covered (warning)
84.62%
11 / 13
0.00% covered (danger)
0.00%
0 / 1
7.18
utf8_case_fold_nfkc
100.00% covered (success)
100.00%
571 / 571
100.00% covered (success)
100.00%
1 / 1
1
utf8_case_fold_nfc
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
2
utf8_normalize_nfc
31.25% covered (danger)
31.25%
5 / 16
0.00% covered (danger)
0.00%
0 / 1
35.32
utf8_clean_string
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
utf8_htmlspecialchars
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
utf8_convert_message
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
utf8_wordwrap
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
6
utf8_basename
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2/**
3*
4* This file is part of the phpBB Forum Software package.
5*
6* @copyright (c) phpBB Limited <https://www.phpbb.com>
7* @license GNU General Public License, version 2 (GPL-2.0)
8*
9* For full copyright and license information, please see
10* the docs/CREDITS.txt file.
11*
12*/
13
14/**
15*/
16if (!defined('IN_PHPBB'))
17{
18    exit;
19}
20
21// Enforce ASCII only string handling
22setlocale(LC_CTYPE, 'C');
23
24/**
25 * UTF-8 portability layer is provided by
26 * symfony/polyfill-mbstring, symfony/polyfill-intl-normalizer, symfony/polyfill-php72
27 */
28
29/**
30* UTF-8 tools
31*
32* Whenever possible, these functions will try to use PHP's built-in functions or
33* extensions, otherwise they will default to custom routines.
34*
35*/
36
37/**
38* UTF-8 aware alternative to strrpos
39* @ignore
40*/
41function utf8_strrpos($str,    $needle, $offset = null)
42{
43    // Emulate behaviour of strrpos rather than raising warning
44    if (empty($str))
45    {
46        return false;
47    }
48
49    if (is_null($offset))
50    {
51        return mb_strrpos($str, $needle);
52    }
53    else
54    {
55        return mb_strrpos($str, $needle, $offset);
56    }
57}
58
59/**
60* UTF-8 aware alternative to strpos
61* @ignore
62*/
63function utf8_strpos($str, $needle, $offset = null)
64{
65    if (is_null($offset))
66    {
67        return mb_strpos($str, $needle);
68    }
69    else
70    {
71        return mb_strpos($str, $needle, $offset);
72    }
73}
74
75/**
76* UTF-8 aware alternative to stripos
77* @ignore
78*/
79function utf8_stripos($str, $needle, $offset = null)
80{
81    if (is_null($offset))
82    {
83        return mb_stripos($str, $needle);
84    }
85    else
86    {
87        return mb_stripos($str, $needle, $offset);
88    }
89}
90
91/**
92* UTF-8 aware alternative to strtolower
93* @ignore
94*/
95function utf8_strtolower($str)
96{
97    return mb_strtolower($str);
98}
99
100/**
101* UTF-8 aware alternative to strtoupper
102* @ignore
103*/
104function utf8_strtoupper($str)
105{
106    return mb_strtoupper($str);
107}
108
109/**
110* UTF-8 aware alternative to substr
111* @ignore
112*/
113function utf8_substr($str, $offset, $length = null)
114{
115    if (is_null($length))
116    {
117        return mb_substr($str, $offset);
118    }
119    else
120    {
121        return mb_substr($str, $offset, $length);
122    }
123}
124
125/**
126* Return the length (in characters) of a UTF-8 string
127* @ignore
128*/
129function utf8_strlen($text)
130{
131    return mb_strlen($text, 'utf-8');
132}
133
134/**
135* UTF-8 aware alternative to str_split
136* Convert a string to an array
137*
138* @author Harry Fuecks
139* @param string $str UTF-8 encoded
140* @param int $split_len number to characters to split string by
141* @return array characters in string reverses
142*/
143function utf8_str_split($str, $split_len = 1)
144{
145    if (!is_int($split_len) || $split_len < 1)
146    {
147        return false;
148    }
149
150    $len = utf8_strlen($str);
151    if ($len <= $split_len)
152    {
153        return array($str);
154    }
155
156    preg_match_all('/.{' . $split_len . '}|[^\x00]{1,' . $split_len . '}$/us', $str, $ar);
157    return $ar[0];
158}
159
160/**
161* UTF-8 aware alternative to strspn
162* Find length of initial segment matching the mask
163*
164* @author Harry Fuecks
165*/
166function utf8_strspn($str, $mask, $start = null, $length = null)
167{
168    if ($start !== null || $length !== null)
169    {
170        $str = utf8_substr($str, $start, $length);
171    }
172
173    preg_match('/^[' . $mask . ']+/u', $str, $matches);
174
175    if (isset($matches[0]))
176    {
177        return utf8_strlen($matches[0]);
178    }
179
180    return 0;
181}
182
183/**
184* UTF-8 aware alternative to ucfirst
185* Make a string's first character uppercase
186*
187* @author Harry Fuecks
188* @param string $str
189* @return string with first character as upper case (if applicable)
190*/
191function utf8_ucfirst($str)
192{
193    switch (utf8_strlen($str))
194    {
195        case 0:
196            return '';
197        break;
198
199        case 1:
200            return utf8_strtoupper($str);
201        break;
202
203        default:
204            preg_match('/^(.{1})(.*)$/us', $str, $matches);
205            return utf8_strtoupper($matches[1]) . $matches[2];
206        break;
207    }
208}
209
210/**
211* Recode a string to UTF-8
212*
213* If the encoding is not supported, the string is returned as-is
214*
215* @param    string    $string        Original string
216* @param    string    $encoding    Original encoding (lowered)
217* @return    string                The string, encoded in UTF-8
218*/
219function utf8_recode($string, $encoding)
220{
221    $encoding = strtolower($encoding);
222
223    if ($encoding == 'utf-8' || !is_string($string) || empty($string))
224    {
225        return $string;
226    }
227
228    // we force iso-8859-1 to be cp1252
229    if ($encoding == 'iso-8859-1')
230    {
231        $encoding = 'cp1252';
232    }
233    // convert iso-8859-8-i to iso-8859-8
234    else if ($encoding == 'iso-8859-8-i')
235    {
236        $encoding = 'iso-8859-8';
237        $string = hebrev($string);
238    }
239
240    // First, try iconv()
241    if (function_exists('iconv'))
242    {
243        $ret = @iconv($encoding, 'utf-8', $string);
244
245        if (!empty($ret))
246        {
247            return $ret;
248        }
249    }
250
251    // Try the mb_string extension
252    if (function_exists('mb_convert_encoding'))
253    {
254        // mbstring is nasty on PHP4, we must make *sure* that we send a good encoding
255        switch ($encoding)
256        {
257            case 'iso-8859-1':
258            case 'iso-8859-2':
259            case 'iso-8859-4':
260            case 'iso-8859-7':
261            case 'iso-8859-9':
262            case 'iso-8859-15':
263            case 'windows-1251':
264            case 'windows-1252':
265            case 'cp1252':
266            case 'shift_jis':
267            case 'euc-kr':
268            case 'big5':
269            case 'gb2312':
270                $ret = @mb_convert_encoding($string, 'utf-8', $encoding);
271
272                if (!empty($ret))
273                {
274                    return $ret;
275                }
276        }
277    }
278
279    // Try the recode extension
280    if (function_exists('recode_string'))
281    {
282        $ret = @recode_string($encoding . '..utf-8', $string);
283
284        if (!empty($ret))
285        {
286            return $ret;
287        }
288    }
289
290    // If nothing works, check if we have a custom transcoder available
291    if (!preg_match('#^[a-z0-9_ \\-]+$#', $encoding))
292    {
293        // Make sure the encoding name is alphanumeric, we don't want it to be abused into loading arbitrary files
294        trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR);
295    }
296
297    global $phpbb_root_path, $phpEx;
298
299    // iso-8859-* character encoding
300    if (preg_match('/iso[_ -]?8859[_ -]?(\\d+)/', $encoding, $array))
301    {
302        switch ($array[1])
303        {
304            case '1':
305            case '2':
306            case '4':
307            case '7':
308            case '8':
309            case '9':
310            case '15':
311                if (!function_exists('iso_8859_' . $array[1]))
312                {
313                    if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx))
314                    {
315                        trigger_error('Basic reencoder file is missing', E_USER_ERROR);
316                    }
317                    include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx);
318                }
319                return call_user_func('iso_8859_' . $array[1], $string);
320            break;
321
322            default:
323                trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR);
324            break;
325        }
326    }
327
328    // CP/WIN character encoding
329    if (preg_match('/(?:cp|windows)[_\- ]?(\\d+)/', $encoding, $array))
330    {
331        switch ($array[1])
332        {
333            case '932':
334            break;
335            case '1250':
336            case '1251':
337            case '1252':
338            case '1254':
339            case '1255':
340            case '1256':
341            case '1257':
342            case '874':
343                if (!function_exists('cp' . $array[1]))
344                {
345                    if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx))
346                    {
347                        trigger_error('Basic reencoder file is missing', E_USER_ERROR);
348                    }
349                    include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx);
350                }
351                return call_user_func('cp' . $array[1], $string);
352            break;
353
354            default:
355                trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR);
356            break;
357        }
358    }
359
360    // TIS-620
361    if (preg_match('/tis[_ -]?620/', $encoding))
362    {
363        if (!function_exists('tis_620'))
364        {
365            if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx))
366            {
367                trigger_error('Basic reencoder file is missing', E_USER_ERROR);
368            }
369            include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx);
370        }
371        return tis_620($string);
372    }
373
374    // SJIS
375    if (preg_match('/sjis(?:[_ -]?win)?|(?:cp|ibm)[_ -]?932|shift[_ -]?jis/', $encoding))
376    {
377        if (!function_exists('sjis'))
378        {
379            if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx))
380            {
381                trigger_error('CJK reencoder file is missing', E_USER_ERROR);
382            }
383            include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx);
384        }
385        return sjis($string);
386    }
387
388    // EUC_KR
389    if (preg_match('/euc[_ -]?kr/', $encoding))
390    {
391        if (!function_exists('euc_kr'))
392        {
393            if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx))
394            {
395                trigger_error('CJK reencoder file is missing', E_USER_ERROR);
396            }
397            include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx);
398        }
399        return euc_kr($string);
400    }
401
402    // BIG-5
403    if (preg_match('/big[_ -]?5/', $encoding))
404    {
405        if (!function_exists('big5'))
406        {
407            if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx))
408            {
409                trigger_error('CJK reencoder file is missing', E_USER_ERROR);
410            }
411            include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx);
412        }
413        return big5($string);
414    }
415
416    // GB2312
417    if (preg_match('/gb[_ -]?2312/', $encoding))
418    {
419        if (!function_exists('gb2312'))
420        {
421            if (!file_exists($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx))
422            {
423                trigger_error('CJK reencoder file is missing', E_USER_ERROR);
424            }
425            include($phpbb_root_path . 'includes/utf/data/recode_cjk.' . $phpEx);
426        }
427        return gb2312($string);
428    }
429
430    // Trigger an error?! Fow now just give bad data :-(
431    trigger_error('Unknown encoding: ' . $encoding, E_USER_ERROR);
432}
433
434/**
435 * Replace some special UTF-8 chars that are not in ASCII with their UCR.
436 * using their Numeric Character Reference's Hexadecimal notation.
437 *
438 * Doesn't interfere with Japanese or Cyrillic etc.
439 * Unicode character visualization will depend on the character support
440 * of your web browser and the fonts installed on your system.
441 *
442 * @see https://en.wikibooks.org/wiki/Unicode/Character_reference/1F000-1FFFF
443 *
444 * @param    string    $text        UTF-8 string in NFC
445 * @return    string                ASCII string using NCR for non-ASCII chars
446 */
447function utf8_encode_ucr($text)
448{
449    return preg_replace_callback('/[\\xF0-\\xF4].../', 'utf8_encode_ncr_callback', $text);
450}
451
452/**
453 * Replace all UTF-8 chars that are not in ASCII with their NCR
454 * using their Numeric Character Reference's Hexadecimal notation.
455 *
456 * @param    string    $text        UTF-8 string in NFC
457 * @return    string                ASCII string using NCRs for non-ASCII chars
458 */
459function utf8_encode_ncr($text)
460{
461    return preg_replace_callback('#[\\xC2-\\xF4][\\x80-\\xBF]{1,3}#', 'utf8_encode_ncr_callback', $text);
462}
463
464/**
465 * Callback used in utf8_encode_ncr() and utf8_encode_ucr()
466 *
467 * Takes a UTF-8 char and replaces it with its NCR. Attention, $m is an array
468 *
469 * @param    array    $m            0-based numerically indexed array passed by preg_replace_callback()
470 * @return    string                A HTML NCR if the character is valid, or the original string otherwise
471 */
472function utf8_encode_ncr_callback($m)
473{
474    return '&#' . utf8_ord($m[0]) . ';';
475}
476
477/**
478* Converts a UTF-8 char to an NCR
479*
480* @param string $chr UTF-8 char
481* @return integer UNICODE code point
482*/
483function utf8_ord($chr)
484{
485    switch (strlen($chr))
486    {
487        case 1:
488            return ord($chr);
489        break;
490
491        case 2:
492            return ((ord($chr[0]) & 0x1F) << 6) | (ord($chr[1]) & 0x3F);
493        break;
494
495        case 3:
496            return ((ord($chr[0]) & 0x0F) << 12) | ((ord($chr[1]) & 0x3F) << 6) | (ord($chr[2]) & 0x3F);
497        break;
498
499        case 4:
500            return ((ord($chr[0]) & 0x07) << 18) | ((ord($chr[1]) & 0x3F) << 12) | ((ord($chr[2]) & 0x3F) << 6) | (ord($chr[3]) & 0x3F);
501        break;
502
503        default:
504            return $chr;
505    }
506}
507
508/**
509* Converts an NCR to a UTF-8 char
510*
511* @param    int        $cp    UNICODE code point
512* @return    string        UTF-8 char
513*/
514function utf8_chr($cp)
515{
516    if ($cp > 0xFFFF)
517    {
518        return chr(0xF0 | ($cp >> 18)) . chr(0x80 | (($cp >> 12) & 0x3F)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
519    }
520    else if ($cp > 0x7FF)
521    {
522        return chr(0xE0 | ($cp >> 12)) . chr(0x80 | (($cp >> 6) & 0x3F)) . chr(0x80 | ($cp & 0x3F));
523    }
524    else if ($cp > 0x7F)
525    {
526        return chr(0xC0 | ($cp >> 6)) . chr(0x80 | ($cp & 0x3F));
527    }
528    else
529    {
530        return chr($cp);
531    }
532}
533
534/**
535* Convert Numeric Character References to UTF-8 chars
536*
537* Notes:
538*    - we do not convert NCRs recursively, if you pass &#38;#38; it will return &#38;
539*    - we DO NOT check for the existence of the Unicode characters, therefore an entity may be converted to an inexistent codepoint
540*
541* @param    string    $text        String to convert, encoded in UTF-8 (no normal form required)
542* @return    string                UTF-8 string where NCRs have been replaced with the actual chars
543*/
544function utf8_decode_ncr($text)
545{
546    return preg_replace_callback('/&#([0-9]{1,6}|x[0-9A-F]{1,5});/i', 'utf8_decode_ncr_callback', $text);
547}
548
549/**
550* Callback used in decode_ncr()
551*
552* Takes a NCR (in decimal or hexadecimal) and returns a UTF-8 char. Attention, $m is an array.
553* It will ignore most of invalid NCRs, but not all!
554*
555* @param    array    $m            0-based numerically indexed array passed by preg_replace_callback()
556* @return    string                UTF-8 char
557*/
558function utf8_decode_ncr_callback($m)
559{
560    $cp = (strncasecmp($m[1], 'x', 1)) ? $m[1] : hexdec(substr($m[1], 1));
561
562    return utf8_chr($cp);
563}
564
565/**
566* Case folds a unicode string as per Unicode 5.0, section 3.13
567*
568* @param    string    $text    text to be case folded
569* @param    string    $option    determines how we will fold the cases
570* @return    string            case folded text
571*/
572function utf8_case_fold($text, $option = 'full')
573{
574    static $uniarray = array();
575    global $phpbb_root_path, $phpEx;
576
577    // common is always set
578    if (!isset($uniarray['c']))
579    {
580        $uniarray['c'] = include($phpbb_root_path . 'includes/utf/data/case_fold_c.' . $phpEx);
581    }
582
583    // only set full if we need to
584    if ($option === 'full' && !isset($uniarray['f']))
585    {
586        $uniarray['f'] = include($phpbb_root_path . 'includes/utf/data/case_fold_f.' . $phpEx);
587    }
588
589    // only set simple if we need to
590    if ($option !== 'full' && !isset($uniarray['s']))
591    {
592        $uniarray['s'] = include($phpbb_root_path . 'includes/utf/data/case_fold_s.' . $phpEx);
593    }
594
595    // common is always replaced
596    $text = strtr($text, $uniarray['c']);
597
598    if ($option === 'full')
599    {
600        // full replaces a character with multiple characters
601        $text = strtr($text, $uniarray['f']);
602    }
603    else
604    {
605        // simple replaces a character with another character
606        $text = strtr($text, $uniarray['s']);
607    }
608
609    return $text;
610}
611
612/**
613* Takes the input and does a "special" case fold. It does minor normalization
614* and returns NFKC compatable text
615*
616* @param    string    $text    text to be case folded
617* @param    string    $option    determines how we will fold the cases
618* @return    string            case folded text
619*/
620function utf8_case_fold_nfkc($text, $option = 'full')
621{
622    static $fc_nfkc_closure = array(
623        "\xCD\xBA"    => "\x20\xCE\xB9",
624        "\xCF\x92"    => "\xCF\x85",
625        "\xCF\x93"    => "\xCF\x8D",
626        "\xCF\x94"    => "\xCF\x8B",
627        "\xCF\xB2"    => "\xCF\x83",
628        "\xCF\xB9"    => "\xCF\x83",
629        "\xE1\xB4\xAC"    => "\x61",
630        "\xE1\xB4\xAD"    => "\xC3\xA6",
631        "\xE1\xB4\xAE"    => "\x62",
632        "\xE1\xB4\xB0"    => "\x64",
633        "\xE1\xB4\xB1"    => "\x65",
634        "\xE1\xB4\xB2"    => "\xC7\x9D",
635        "\xE1\xB4\xB3"    => "\x67",
636        "\xE1\xB4\xB4"    => "\x68",
637        "\xE1\xB4\xB5"    => "\x69",
638        "\xE1\xB4\xB6"    => "\x6A",
639        "\xE1\xB4\xB7"    => "\x6B",
640        "\xE1\xB4\xB8"    => "\x6C",
641        "\xE1\xB4\xB9"    => "\x6D",
642        "\xE1\xB4\xBA"    => "\x6E",
643        "\xE1\xB4\xBC"    => "\x6F",
644        "\xE1\xB4\xBD"    => "\xC8\xA3",
645        "\xE1\xB4\xBE"    => "\x70",
646        "\xE1\xB4\xBF"    => "\x72",
647        "\xE1\xB5\x80"    => "\x74",
648        "\xE1\xB5\x81"    => "\x75",
649        "\xE1\xB5\x82"    => "\x77",
650        "\xE2\x82\xA8"    => "\x72\x73",
651        "\xE2\x84\x82"    => "\x63",
652        "\xE2\x84\x83"    => "\xC2\xB0\x63",
653        "\xE2\x84\x87"    => "\xC9\x9B",
654        "\xE2\x84\x89"    => "\xC2\xB0\x66",
655        "\xE2\x84\x8B"    => "\x68",
656        "\xE2\x84\x8C"    => "\x68",
657        "\xE2\x84\x8D"    => "\x68",
658        "\xE2\x84\x90"    => "\x69",
659        "\xE2\x84\x91"    => "\x69",
660        "\xE2\x84\x92"    => "\x6C",
661        "\xE2\x84\x95"    => "\x6E",
662        "\xE2\x84\x96"    => "\x6E\x6F",
663        "\xE2\x84\x99"    => "\x70",
664        "\xE2\x84\x9A"    => "\x71",
665        "\xE2\x84\x9B"    => "\x72",
666        "\xE2\x84\x9C"    => "\x72",
667        "\xE2\x84\x9D"    => "\x72",
668        "\xE2\x84\xA0"    => "\x73\x6D",
669        "\xE2\x84\xA1"    => "\x74\x65\x6C",
670        "\xE2\x84\xA2"    => "\x74\x6D",
671        "\xE2\x84\xA4"    => "\x7A",
672        "\xE2\x84\xA8"    => "\x7A",
673        "\xE2\x84\xAC"    => "\x62",
674        "\xE2\x84\xAD"    => "\x63",
675        "\xE2\x84\xB0"    => "\x65",
676        "\xE2\x84\xB1"    => "\x66",
677        "\xE2\x84\xB3"    => "\x6D",
678        "\xE2\x84\xBB"    => "\x66\x61\x78",
679        "\xE2\x84\xBE"    => "\xCE\xB3",
680        "\xE2\x84\xBF"    => "\xCF\x80",
681        "\xE2\x85\x85"    => "\x64",
682        "\xE3\x89\x90"    => "\x70\x74\x65",
683        "\xE3\x8B\x8C"    => "\x68\x67",
684        "\xE3\x8B\x8E"    => "\x65\x76",
685        "\xE3\x8B\x8F"    => "\x6C\x74\x64",
686        "\xE3\x8D\xB1"    => "\x68\x70\x61",
687        "\xE3\x8D\xB3"    => "\x61\x75",
688        "\xE3\x8D\xB5"    => "\x6F\x76",
689        "\xE3\x8D\xBA"    => "\x69\x75",
690        "\xE3\x8E\x80"    => "\x70\x61",
691        "\xE3\x8E\x81"    => "\x6E\x61",
692        "\xE3\x8E\x82"    => "\xCE\xBC\x61",
693        "\xE3\x8E\x83"    => "\x6D\x61",
694        "\xE3\x8E\x84"    => "\x6B\x61",
695        "\xE3\x8E\x85"    => "\x6B\x62",
696        "\xE3\x8E\x86"    => "\x6D\x62",
697        "\xE3\x8E\x87"    => "\x67\x62",
698        "\xE3\x8E\x8A"    => "\x70\x66",
699        "\xE3\x8E\x8B"    => "\x6E\x66",
700        "\xE3\x8E\x8C"    => "\xCE\xBC\x66",
701        "\xE3\x8E\x90"    => "\x68\x7A",
702        "\xE3\x8E\x91"    => "\x6B\x68\x7A",
703        "\xE3\x8E\x92"    => "\x6D\x68\x7A",
704        "\xE3\x8E\x93"    => "\x67\x68\x7A",
705        "\xE3\x8E\x94"    => "\x74\x68\x7A",
706        "\xE3\x8E\xA9"    => "\x70\x61",
707        "\xE3\x8E\xAA"    => "\x6B\x70\x61",
708        "\xE3\x8E\xAB"    => "\x6D\x70\x61",
709        "\xE3\x8E\xAC"    => "\x67\x70\x61",
710        "\xE3\x8E\xB4"    => "\x70\x76",
711        "\xE3\x8E\xB5"    => "\x6E\x76",
712        "\xE3\x8E\xB6"    => "\xCE\xBC\x76",
713        "\xE3\x8E\xB7"    => "\x6D\x76",
714        "\xE3\x8E\xB8"    => "\x6B\x76",
715        "\xE3\x8E\xB9"    => "\x6D\x76",
716        "\xE3\x8E\xBA"    => "\x70\x77",
717        "\xE3\x8E\xBB"    => "\x6E\x77",
718        "\xE3\x8E\xBC"    => "\xCE\xBC\x77",
719        "\xE3\x8E\xBD"    => "\x6D\x77",
720        "\xE3\x8E\xBE"    => "\x6B\x77",
721        "\xE3\x8E\xBF"    => "\x6D\x77",
722        "\xE3\x8F\x80"    => "\x6B\xCF\x89",
723        "\xE3\x8F\x81"    => "\x6D\xCF\x89",
724        "\xE3\x8F\x83"    => "\x62\x71",
725        "\xE3\x8F\x86"    => "\x63\xE2\x88\x95\x6B\x67",
726        "\xE3\x8F\x87"    => "\x63\x6F\x2E",
727        "\xE3\x8F\x88"    => "\x64\x62",
728        "\xE3\x8F\x89"    => "\x67\x79",
729        "\xE3\x8F\x8B"    => "\x68\x70",
730        "\xE3\x8F\x8D"    => "\x6B\x6B",
731        "\xE3\x8F\x8E"    => "\x6B\x6D",
732        "\xE3\x8F\x97"    => "\x70\x68",
733        "\xE3\x8F\x99"    => "\x70\x70\x6D",
734        "\xE3\x8F\x9A"    => "\x70\x72",
735        "\xE3\x8F\x9C"    => "\x73\x76",
736        "\xE3\x8F\x9D"    => "\x77\x62",
737        "\xE3\x8F\x9E"    => "\x76\xE2\x88\x95\x6D",
738        "\xE3\x8F\x9F"    => "\x61\xE2\x88\x95\x6D",
739        "\xF0\x9D\x90\x80"    => "\x61",
740        "\xF0\x9D\x90\x81"    => "\x62",
741        "\xF0\x9D\x90\x82"    => "\x63",
742        "\xF0\x9D\x90\x83"    => "\x64",
743        "\xF0\x9D\x90\x84"    => "\x65",
744        "\xF0\x9D\x90\x85"    => "\x66",
745        "\xF0\x9D\x90\x86"    => "\x67",
746        "\xF0\x9D\x90\x87"    => "\x68",
747        "\xF0\x9D\x90\x88"    => "\x69",
748        "\xF0\x9D\x90\x89"    => "\x6A",
749        "\xF0\x9D\x90\x8A"    => "\x6B",
750        "\xF0\x9D\x90\x8B"    => "\x6C",
751        "\xF0\x9D\x90\x8C"    => "\x6D",
752        "\xF0\x9D\x90\x8D"    => "\x6E",
753        "\xF0\x9D\x90\x8E"    => "\x6F",
754        "\xF0\x9D\x90\x8F"    => "\x70",
755        "\xF0\x9D\x90\x90"    => "\x71",
756        "\xF0\x9D\x90\x91"    => "\x72",
757        "\xF0\x9D\x90\x92"    => "\x73",
758        "\xF0\x9D\x90\x93"    => "\x74",
759        "\xF0\x9D\x90\x94"    => "\x75",
760        "\xF0\x9D\x90\x95"    => "\x76",
761        "\xF0\x9D\x90\x96"    => "\x77",
762        "\xF0\x9D\x90\x97"    => "\x78",
763        "\xF0\x9D\x90\x98"    => "\x79",
764        "\xF0\x9D\x90\x99"    => "\x7A",
765        "\xF0\x9D\x90\xB4"    => "\x61",
766        "\xF0\x9D\x90\xB5"    => "\x62",
767        "\xF0\x9D\x90\xB6"    => "\x63",
768        "\xF0\x9D\x90\xB7"    => "\x64",
769        "\xF0\x9D\x90\xB8"    => "\x65",
770        "\xF0\x9D\x90\xB9"    => "\x66",
771        "\xF0\x9D\x90\xBA"    => "\x67",
772        "\xF0\x9D\x90\xBB"    => "\x68",
773        "\xF0\x9D\x90\xBC"    => "\x69",
774        "\xF0\x9D\x90\xBD"    => "\x6A",
775        "\xF0\x9D\x90\xBE"    => "\x6B",
776        "\xF0\x9D\x90\xBF"    => "\x6C",
777        "\xF0\x9D\x91\x80"    => "\x6D",
778        "\xF0\x9D\x91\x81"    => "\x6E",
779        "\xF0\x9D\x91\x82"    => "\x6F",
780        "\xF0\x9D\x91\x83"    => "\x70",
781        "\xF0\x9D\x91\x84"    => "\x71",
782        "\xF0\x9D\x91\x85"    => "\x72",
783        "\xF0\x9D\x91\x86"    => "\x73",
784        "\xF0\x9D\x91\x87"    => "\x74",
785        "\xF0\x9D\x91\x88"    => "\x75",
786        "\xF0\x9D\x91\x89"    => "\x76",
787        "\xF0\x9D\x91\x8A"    => "\x77",
788        "\xF0\x9D\x91\x8B"    => "\x78",
789        "\xF0\x9D\x91\x8C"    => "\x79",
790        "\xF0\x9D\x91\x8D"    => "\x7A",
791        "\xF0\x9D\x91\xA8"    => "\x61",
792        "\xF0\x9D\x91\xA9"    => "\x62",
793        "\xF0\x9D\x91\xAA"    => "\x63",
794        "\xF0\x9D\x91\xAB"    => "\x64",
795        "\xF0\x9D\x91\xAC"    => "\x65",
796        "\xF0\x9D\x91\xAD"    => "\x66",
797        "\xF0\x9D\x91\xAE"    => "\x67",
798        "\xF0\x9D\x91\xAF"    => "\x68",
799        "\xF0\x9D\x91\xB0"    => "\x69",
800        "\xF0\x9D\x91\xB1"    => "\x6A",
801        "\xF0\x9D\x91\xB2"    => "\x6B",
802        "\xF0\x9D\x91\xB3"    => "\x6C",
803        "\xF0\x9D\x91\xB4"    => "\x6D",
804        "\xF0\x9D\x91\xB5"    => "\x6E",
805        "\xF0\x9D\x91\xB6"    => "\x6F",
806        "\xF0\x9D\x91\xB7"    => "\x70",
807        "\xF0\x9D\x91\xB8"    => "\x71",
808        "\xF0\x9D\x91\xB9"    => "\x72",
809        "\xF0\x9D\x91\xBA"    => "\x73",
810        "\xF0\x9D\x91\xBB"    => "\x74",
811        "\xF0\x9D\x91\xBC"    => "\x75",
812        "\xF0\x9D\x91\xBD"    => "\x76",
813        "\xF0\x9D\x91\xBE"    => "\x77",
814        "\xF0\x9D\x91\xBF"    => "\x78",
815        "\xF0\x9D\x92\x80"    => "\x79",
816        "\xF0\x9D\x92\x81"    => "\x7A",
817        "\xF0\x9D\x92\x9C"    => "\x61",
818        "\xF0\x9D\x92\x9E"    => "\x63",
819        "\xF0\x9D\x92\x9F"    => "\x64",
820        "\xF0\x9D\x92\xA2"    => "\x67",
821        "\xF0\x9D\x92\xA5"    => "\x6A",
822        "\xF0\x9D\x92\xA6"    => "\x6B",
823        "\xF0\x9D\x92\xA9"    => "\x6E",
824        "\xF0\x9D\x92\xAA"    => "\x6F",
825        "\xF0\x9D\x92\xAB"    => "\x70",
826        "\xF0\x9D\x92\xAC"    => "\x71",
827        "\xF0\x9D\x92\xAE"    => "\x73",
828        "\xF0\x9D\x92\xAF"    => "\x74",
829        "\xF0\x9D\x92\xB0"    => "\x75",
830        "\xF0\x9D\x92\xB1"    => "\x76",
831        "\xF0\x9D\x92\xB2"    => "\x77",
832        "\xF0\x9D\x92\xB3"    => "\x78",
833        "\xF0\x9D\x92\xB4"    => "\x79",
834        "\xF0\x9D\x92\xB5"    => "\x7A",
835        "\xF0\x9D\x93\x90"    => "\x61",
836        "\xF0\x9D\x93\x91"    => "\x62",
837        "\xF0\x9D\x93\x92"    => "\x63",
838        "\xF0\x9D\x93\x93"    => "\x64",
839        "\xF0\x9D\x93\x94"    => "\x65",
840        "\xF0\x9D\x93\x95"    => "\x66",
841        "\xF0\x9D\x93\x96"    => "\x67",
842        "\xF0\x9D\x93\x97"    => "\x68",
843        "\xF0\x9D\x93\x98"    => "\x69",
844        "\xF0\x9D\x93\x99"    => "\x6A",
845        "\xF0\x9D\x93\x9A"    => "\x6B",
846        "\xF0\x9D\x93\x9B"    => "\x6C",
847        "\xF0\x9D\x93\x9C"    => "\x6D",
848        "\xF0\x9D\x93\x9D"    => "\x6E",
849        "\xF0\x9D\x93\x9E"    => "\x6F",
850        "\xF0\x9D\x93\x9F"    => "\x70",
851        "\xF0\x9D\x93\xA0"    => "\x71",
852        "\xF0\x9D\x93\xA1"    => "\x72",
853        "\xF0\x9D\x93\xA2"    => "\x73",
854        "\xF0\x9D\x93\xA3"    => "\x74",
855        "\xF0\x9D\x93\xA4"    => "\x75",
856        "\xF0\x9D\x93\xA5"    => "\x76",
857        "\xF0\x9D\x93\xA6"    => "\x77",
858        "\xF0\x9D\x93\xA7"    => "\x78",
859        "\xF0\x9D\x93\xA8"    => "\x79",
860        "\xF0\x9D\x93\xA9"    => "\x7A",
861        "\xF0\x9D\x94\x84"    => "\x61",
862        "\xF0\x9D\x94\x85"    => "\x62",
863        "\xF0\x9D\x94\x87"    => "\x64",
864        "\xF0\x9D\x94\x88"    => "\x65",
865        "\xF0\x9D\x94\x89"    => "\x66",
866        "\xF0\x9D\x94\x8A"    => "\x67",
867        "\xF0\x9D\x94\x8D"    => "\x6A",
868        "\xF0\x9D\x94\x8E"    => "\x6B",
869        "\xF0\x9D\x94\x8F"    => "\x6C",
870        "\xF0\x9D\x94\x90"    => "\x6D",
871        "\xF0\x9D\x94\x91"    => "\x6E",
872        "\xF0\x9D\x94\x92"    => "\x6F",
873        "\xF0\x9D\x94\x93"    => "\x70",
874        "\xF0\x9D\x94\x94"    => "\x71",
875        "\xF0\x9D\x94\x96"    => "\x73",
876        "\xF0\x9D\x94\x97"    => "\x74",
877        "\xF0\x9D\x94\x98"    => "\x75",
878        "\xF0\x9D\x94\x99"    => "\x76",
879        "\xF0\x9D\x94\x9A"    => "\x77",
880        "\xF0\x9D\x94\x9B"    => "\x78",
881        "\xF0\x9D\x94\x9C"    => "\x79",
882        "\xF0\x9D\x94\xB8"    => "\x61",
883        "\xF0\x9D\x94\xB9"    => "\x62",
884        "\xF0\x9D\x94\xBB"    => "\x64",
885        "\xF0\x9D\x94\xBC"    => "\x65",
886        "\xF0\x9D\x94\xBD"    => "\x66",
887        "\xF0\x9D\x94\xBE"    => "\x67",
888        "\xF0\x9D\x95\x80"    => "\x69",
889        "\xF0\x9D\x95\x81"    => "\x6A",
890        "\xF0\x9D\x95\x82"    => "\x6B",
891        "\xF0\x9D\x95\x83"    => "\x6C",
892        "\xF0\x9D\x95\x84"    => "\x6D",
893        "\xF0\x9D\x95\x86"    => "\x6F",
894        "\xF0\x9D\x95\x8A"    => "\x73",
895        "\xF0\x9D\x95\x8B"    => "\x74",
896        "\xF0\x9D\x95\x8C"    => "\x75",
897        "\xF0\x9D\x95\x8D"    => "\x76",
898        "\xF0\x9D\x95\x8E"    => "\x77",
899        "\xF0\x9D\x95\x8F"    => "\x78",
900        "\xF0\x9D\x95\x90"    => "\x79",
901        "\xF0\x9D\x95\xAC"    => "\x61",
902        "\xF0\x9D\x95\xAD"    => "\x62",
903        "\xF0\x9D\x95\xAE"    => "\x63",
904        "\xF0\x9D\x95\xAF"    => "\x64",
905        "\xF0\x9D\x95\xB0"    => "\x65",
906        "\xF0\x9D\x95\xB1"    => "\x66",
907        "\xF0\x9D\x95\xB2"    => "\x67",
908        "\xF0\x9D\x95\xB3"    => "\x68",
909        "\xF0\x9D\x95\xB4"    => "\x69",
910        "\xF0\x9D\x95\xB5"    => "\x6A",
911        "\xF0\x9D\x95\xB6"    => "\x6B",
912        "\xF0\x9D\x95\xB7"    => "\x6C",
913        "\xF0\x9D\x95\xB8"    => "\x6D",
914        "\xF0\x9D\x95\xB9"    => "\x6E",
915        "\xF0\x9D\x95\xBA"    => "\x6F",
916        "\xF0\x9D\x95\xBB"    => "\x70",
917        "\xF0\x9D\x95\xBC"    => "\x71",
918        "\xF0\x9D\x95\xBD"    => "\x72",
919        "\xF0\x9D\x95\xBE"    => "\x73",
920        "\xF0\x9D\x95\xBF"    => "\x74",
921        "\xF0\x9D\x96\x80"    => "\x75",
922        "\xF0\x9D\x96\x81"    => "\x76",
923        "\xF0\x9D\x96\x82"    => "\x77",
924        "\xF0\x9D\x96\x83"    => "\x78",
925        "\xF0\x9D\x96\x84"    => "\x79",
926        "\xF0\x9D\x96\x85"    => "\x7A",
927        "\xF0\x9D\x96\xA0"    => "\x61",
928        "\xF0\x9D\x96\xA1"    => "\x62",
929        "\xF0\x9D\x96\xA2"    => "\x63",
930        "\xF0\x9D\x96\xA3"    => "\x64",
931        "\xF0\x9D\x96\xA4"    => "\x65",
932        "\xF0\x9D\x96\xA5"    => "\x66",
933        "\xF0\x9D\x96\xA6"    => "\x67",
934        "\xF0\x9D\x96\xA7"    => "\x68",
935        "\xF0\x9D\x96\xA8"    => "\x69",
936        "\xF0\x9D\x96\xA9"    => "\x6A",
937        "\xF0\x9D\x96\xAA"    => "\x6B",
938        "\xF0\x9D\x96\xAB"    => "\x6C",
939        "\xF0\x9D\x96\xAC"    => "\x6D",
940        "\xF0\x9D\x96\xAD"    => "\x6E",
941        "\xF0\x9D\x96\xAE"    => "\x6F",
942        "\xF0\x9D\x96\xAF"    => "\x70",
943        "\xF0\x9D\x96\xB0"    => "\x71",
944        "\xF0\x9D\x96\xB1"    => "\x72",
945        "\xF0\x9D\x96\xB2"    => "\x73",
946        "\xF0\x9D\x96\xB3"    => "\x74",
947        "\xF0\x9D\x96\xB4"    => "\x75",
948        "\xF0\x9D\x96\xB5"    => "\x76",
949        "\xF0\x9D\x96\xB6"    => "\x77",
950        "\xF0\x9D\x96\xB7"    => "\x78",
951        "\xF0\x9D\x96\xB8"    => "\x79",
952        "\xF0\x9D\x96\xB9"    => "\x7A",
953        "\xF0\x9D\x97\x94"    => "\x61",
954        "\xF0\x9D\x97\x95"    => "\x62",
955        "\xF0\x9D\x97\x96"    => "\x63",
956        "\xF0\x9D\x97\x97"    => "\x64",
957        "\xF0\x9D\x97\x98"    => "\x65",
958        "\xF0\x9D\x97\x99"    => "\x66",
959        "\xF0\x9D\x97\x9A"    => "\x67",
960        "\xF0\x9D\x97\x9B"    => "\x68",
961        "\xF0\x9D\x97\x9C"    => "\x69",
962        "\xF0\x9D\x97\x9D"    => "\x6A",
963        "\xF0\x9D\x97\x9E"    => "\x6B",
964        "\xF0\x9D\x97\x9F"    => "\x6C",
965        "\xF0\x9D\x97\xA0"    => "\x6D",
966        "\xF0\x9D\x97\xA1"    => "\x6E",
967        "\xF0\x9D\x97\xA2"    => "\x6F",
968        "\xF0\x9D\x97\xA3"    => "\x70",
969        "\xF0\x9D\x97\xA4"    => "\x71",
970        "\xF0\x9D\x97\xA5"    => "\x72",
971        "\xF0\x9D\x97\xA6"    => "\x73",
972        "\xF0\x9D\x97\xA7"    => "\x74",
973        "\xF0\x9D\x97\xA8"    => "\x75",
974        "\xF0\x9D\x97\xA9"    => "\x76",
975        "\xF0\x9D\x97\xAA"    => "\x77",
976        "\xF0\x9D\x97\xAB"    => "\x78",
977        "\xF0\x9D\x97\xAC"    => "\x79",
978        "\xF0\x9D\x97\xAD"    => "\x7A",
979        "\xF0\x9D\x98\x88"    => "\x61",
980        "\xF0\x9D\x98\x89"    => "\x62",
981        "\xF0\x9D\x98\x8A"    => "\x63",
982        "\xF0\x9D\x98\x8B"    => "\x64",
983        "\xF0\x9D\x98\x8C"    => "\x65",
984        "\xF0\x9D\x98\x8D"    => "\x66",
985        "\xF0\x9D\x98\x8E"    => "\x67",
986        "\xF0\x9D\x98\x8F"    => "\x68",
987        "\xF0\x9D\x98\x90"    => "\x69",
988        "\xF0\x9D\x98\x91"    => "\x6A",
989        "\xF0\x9D\x98\x92"    => "\x6B",
990        "\xF0\x9D\x98\x93"    => "\x6C",
991        "\xF0\x9D\x98\x94"    => "\x6D",
992        "\xF0\x9D\x98\x95"    => "\x6E",
993        "\xF0\x9D\x98\x96"    => "\x6F",
994        "\xF0\x9D\x98\x97"    => "\x70",
995        "\xF0\x9D\x98\x98"    => "\x71",
996        "\xF0\x9D\x98\x99"    => "\x72",
997        "\xF0\x9D\x98\x9A"    => "\x73",
998        "\xF0\x9D\x98\x9B"    => "\x74",
999        "\xF0\x9D\x98\x9C"    => "\x75",
1000        "\xF0\x9D\x98\x9D"    => "\x76",
1001        "\xF0\x9D\x98\x9E"    => "\x77",
1002        "\xF0\x9D\x98\x9F"    => "\x78",
1003        "\xF0\x9D\x98\xA0"    => "\x79",
1004        "\xF0\x9D\x98\xA1"    => "\x7A",
1005        "\xF0\x9D\x98\xBC"    => "\x61",
1006        "\xF0\x9D\x98\xBD"    => "\x62",
1007        "\xF0\x9D\x98\xBE"    => "\x63",
1008        "\xF0\x9D\x98\xBF"    => "\x64",
1009        "\xF0\x9D\x99\x80"    => "\x65",
1010        "\xF0\x9D\x99\x81"    => "\x66",
1011        "\xF0\x9D\x99\x82"    => "\x67",
1012        "\xF0\x9D\x99\x83"    => "\x68",
1013        "\xF0\x9D\x99\x84"    => "\x69",
1014        "\xF0\x9D\x99\x85"    => "\x6A",
1015        "\xF0\x9D\x99\x86"    => "\x6B",
1016        "\xF0\x9D\x99\x87"    => "\x6C",
1017        "\xF0\x9D\x99\x88"    => "\x6D",
1018        "\xF0\x9D\x99\x89"    => "\x6E",
1019        "\xF0\x9D\x99\x8A"    => "\x6F",
1020        "\xF0\x9D\x99\x8B"    => "\x70",
1021        "\xF0\x9D\x99\x8C"    => "\x71",
1022        "\xF0\x9D\x99\x8D"    => "\x72",
1023        "\xF0\x9D\x99\x8E"    => "\x73",
1024        "\xF0\x9D\x99\x8F"    => "\x74",
1025        "\xF0\x9D\x99\x90"    => "\x75",
1026        "\xF0\x9D\x99\x91"    => "\x76",
1027        "\xF0\x9D\x99\x92"    => "\x77",
1028        "\xF0\x9D\x99\x93"    => "\x78",
1029        "\xF0\x9D\x99\x94"    => "\x79",
1030        "\xF0\x9D\x99\x95"    => "\x7A",
1031        "\xF0\x9D\x99\xB0"    => "\x61",
1032        "\xF0\x9D\x99\xB1"    => "\x62",
1033        "\xF0\x9D\x99\xB2"    => "\x63",
1034        "\xF0\x9D\x99\xB3"    => "\x64",
1035        "\xF0\x9D\x99\xB4"    => "\x65",
1036        "\xF0\x9D\x99\xB5"    => "\x66",
1037        "\xF0\x9D\x99\xB6"    => "\x67",
1038        "\xF0\x9D\x99\xB7"    => "\x68",
1039        "\xF0\x9D\x99\xB8"    => "\x69",
1040        "\xF0\x9D\x99\xB9"    => "\x6A",
1041        "\xF0\x9D\x99\xBA"    => "\x6B",
1042        "\xF0\x9D\x99\xBB"    => "\x6C",
1043        "\xF0\x9D\x99\xBC"    => "\x6D",
1044        "\xF0\x9D\x99\xBD"    => "\x6E",
1045        "\xF0\x9D\x99\xBE"    => "\x6F",
1046        "\xF0\x9D\x99\xBF"    => "\x70",
1047        "\xF0\x9D\x9A\x80"    => "\x71",
1048        "\xF0\x9D\x9A\x81"    => "\x72",
1049        "\xF0\x9D\x9A\x82"    => "\x73",
1050        "\xF0\x9D\x9A\x83"    => "\x74",
1051        "\xF0\x9D\x9A\x84"    => "\x75",
1052        "\xF0\x9D\x9A\x85"    => "\x76",
1053        "\xF0\x9D\x9A\x86"    => "\x77",
1054        "\xF0\x9D\x9A\x87"    => "\x78",
1055        "\xF0\x9D\x9A\x88"    => "\x79",
1056        "\xF0\x9D\x9A\x89"    => "\x7A",
1057        "\xF0\x9D\x9A\xA8"    => "\xCE\xB1",
1058        "\xF0\x9D\x9A\xA9"    => "\xCE\xB2",
1059        "\xF0\x9D\x9A\xAA"    => "\xCE\xB3",
1060        "\xF0\x9D\x9A\xAB"    => "\xCE\xB4",
1061        "\xF0\x9D\x9A\xAC"    => "\xCE\xB5",
1062        "\xF0\x9D\x9A\xAD"    => "\xCE\xB6",
1063        "\xF0\x9D\x9A\xAE"    => "\xCE\xB7",
1064        "\xF0\x9D\x9A\xAF"    => "\xCE\xB8",
1065        "\xF0\x9D\x9A\xB0"    => "\xCE\xB9",
1066        "\xF0\x9D\x9A\xB1"    => "\xCE\xBA",
1067        "\xF0\x9D\x9A\xB2"    => "\xCE\xBB",
1068        "\xF0\x9D\x9A\xB3"    => "\xCE\xBC",
1069        "\xF0\x9D\x9A\xB4"    => "\xCE\xBD",
1070        "\xF0\x9D\x9A\xB5"    => "\xCE\xBE",
1071        "\xF0\x9D\x9A\xB6"    => "\xCE\xBF",
1072        "\xF0\x9D\x9A\xB7"    => "\xCF\x80",
1073        "\xF0\x9D\x9A\xB8"    => "\xCF\x81",
1074        "\xF0\x9D\x9A\xB9"    => "\xCE\xB8",
1075        "\xF0\x9D\x9A\xBA"    => "\xCF\x83",
1076        "\xF0\x9D\x9A\xBB"    => "\xCF\x84",
1077        "\xF0\x9D\x9A\xBC"    => "\xCF\x85",
1078        "\xF0\x9D\x9A\xBD"    => "\xCF\x86",
1079        "\xF0\x9D\x9A\xBE"    => "\xCF\x87",
1080        "\xF0\x9D\x9A\xBF"    => "\xCF\x88",
1081        "\xF0\x9D\x9B\x80"    => "\xCF\x89",
1082        "\xF0\x9D\x9B\x93"    => "\xCF\x83",
1083        "\xF0\x9D\x9B\xA2"    => "\xCE\xB1",
1084        "\xF0\x9D\x9B\xA3"    => "\xCE\xB2",
1085        "\xF0\x9D\x9B\xA4"    => "\xCE\xB3",
1086        "\xF0\x9D\x9B\xA5"    => "\xCE\xB4",
1087        "\xF0\x9D\x9B\xA6"    => "\xCE\xB5",
1088        "\xF0\x9D\x9B\xA7"    => "\xCE\xB6",
1089        "\xF0\x9D\x9B\xA8"    => "\xCE\xB7",
1090        "\xF0\x9D\x9B\xA9"    => "\xCE\xB8",
1091        "\xF0\x9D\x9B\xAA"    => "\xCE\xB9",
1092        "\xF0\x9D\x9B\xAB"    => "\xCE\xBA",
1093        "\xF0\x9D\x9B\xAC"    => "\xCE\xBB",
1094        "\xF0\x9D\x9B\xAD"    => "\xCE\xBC",
1095        "\xF0\x9D\x9B\xAE"    => "\xCE\xBD",
1096        "\xF0\x9D\x9B\xAF"    => "\xCE\xBE",
1097        "\xF0\x9D\x9B\xB0"    => "\xCE\xBF",
1098        "\xF0\x9D\x9B\xB1"    => "\xCF\x80",
1099        "\xF0\x9D\x9B\xB2"    => "\xCF\x81",
1100        "\xF0\x9D\x9B\xB3"    => "\xCE\xB8",
1101        "\xF0\x9D\x9B\xB4"    => "\xCF\x83",
1102        "\xF0\x9D\x9B\xB5"    => "\xCF\x84",
1103        "\xF0\x9D\x9B\xB6"    => "\xCF\x85",
1104        "\xF0\x9D\x9B\xB7"    => "\xCF\x86",
1105        "\xF0\x9D\x9B\xB8"    => "\xCF\x87",
1106        "\xF0\x9D\x9B\xB9"    => "\xCF\x88",
1107        "\xF0\x9D\x9B\xBA"    => "\xCF\x89",
1108        "\xF0\x9D\x9C\x8D"    => "\xCF\x83",
1109        "\xF0\x9D\x9C\x9C"    => "\xCE\xB1",
1110        "\xF0\x9D\x9C\x9D"    => "\xCE\xB2",
1111        "\xF0\x9D\x9C\x9E"    => "\xCE\xB3",
1112        "\xF0\x9D\x9C\x9F"    => "\xCE\xB4",
1113        "\xF0\x9D\x9C\xA0"    => "\xCE\xB5",
1114        "\xF0\x9D\x9C\xA1"    => "\xCE\xB6",
1115        "\xF0\x9D\x9C\xA2"    => "\xCE\xB7",
1116        "\xF0\x9D\x9C\xA3"    => "\xCE\xB8",
1117        "\xF0\x9D\x9C\xA4"    => "\xCE\xB9",
1118        "\xF0\x9D\x9C\xA5"    => "\xCE\xBA",
1119        "\xF0\x9D\x9C\xA6"    => "\xCE\xBB",
1120        "\xF0\x9D\x9C\xA7"    => "\xCE\xBC",
1121        "\xF0\x9D\x9C\xA8"    => "\xCE\xBD",
1122        "\xF0\x9D\x9C\xA9"    => "\xCE\xBE",
1123        "\xF0\x9D\x9C\xAA"    => "\xCE\xBF",
1124        "\xF0\x9D\x9C\xAB"    => "\xCF\x80",
1125        "\xF0\x9D\x9C\xAC"    => "\xCF\x81",
1126        "\xF0\x9D\x9C\xAD"    => "\xCE\xB8",
1127        "\xF0\x9D\x9C\xAE"    => "\xCF\x83",
1128        "\xF0\x9D\x9C\xAF"    => "\xCF\x84",
1129        "\xF0\x9D\x9C\xB0"    => "\xCF\x85",
1130        "\xF0\x9D\x9C\xB1"    => "\xCF\x86",
1131        "\xF0\x9D\x9C\xB2"    => "\xCF\x87",
1132        "\xF0\x9D\x9C\xB3"    => "\xCF\x88",
1133        "\xF0\x9D\x9C\xB4"    => "\xCF\x89",
1134        "\xF0\x9D\x9D\x87"    => "\xCF\x83",
1135        "\xF0\x9D\x9D\x96"    => "\xCE\xB1",
1136        "\xF0\x9D\x9D\x97"    => "\xCE\xB2",
1137        "\xF0\x9D\x9D\x98"    => "\xCE\xB3",
1138        "\xF0\x9D\x9D\x99"    => "\xCE\xB4",
1139        "\xF0\x9D\x9D\x9A"    => "\xCE\xB5",
1140        "\xF0\x9D\x9D\x9B"    => "\xCE\xB6",
1141        "\xF0\x9D\x9D\x9C"    => "\xCE\xB7",
1142        "\xF0\x9D\x9D\x9D"    => "\xCE\xB8",
1143        "\xF0\x9D\x9D\x9E"    => "\xCE\xB9",
1144        "\xF0\x9D\x9D\x9F"    => "\xCE\xBA",
1145        "\xF0\x9D\x9D\xA0"    => "\xCE\xBB",
1146        "\xF0\x9D\x9D\xA1"    => "\xCE\xBC",
1147        "\xF0\x9D\x9D\xA2"    => "\xCE\xBD",
1148        "\xF0\x9D\x9D\xA3"    => "\xCE\xBE",
1149        "\xF0\x9D\x9D\xA4"    => "\xCE\xBF",
1150        "\xF0\x9D\x9D\xA5"    => "\xCF\x80",
1151        "\xF0\x9D\x9D\xA6"    => "\xCF\x81",
1152        "\xF0\x9D\x9D\xA7"    => "\xCE\xB8",
1153        "\xF0\x9D\x9D\xA8"    => "\xCF\x83",
1154        "\xF0\x9D\x9D\xA9"    => "\xCF\x84",
1155        "\xF0\x9D\x9D\xAA"    => "\xCF\x85",
1156        "\xF0\x9D\x9D\xAB"    => "\xCF\x86",
1157        "\xF0\x9D\x9D\xAC"    => "\xCF\x87",
1158        "\xF0\x9D\x9D\xAD"    => "\xCF\x88",
1159        "\xF0\x9D\x9D\xAE"    => "\xCF\x89",
1160        "\xF0\x9D\x9E\x81"    => "\xCF\x83",
1161        "\xF0\x9D\x9E\x90"    => "\xCE\xB1",
1162        "\xF0\x9D\x9E\x91"    => "\xCE\xB2",
1163        "\xF0\x9D\x9E\x92"    => "\xCE\xB3",
1164        "\xF0\x9D\x9E\x93"    => "\xCE\xB4",
1165        "\xF0\x9D\x9E\x94"    => "\xCE\xB5",
1166        "\xF0\x9D\x9E\x95"    => "\xCE\xB6",
1167        "\xF0\x9D\x9E\x96"    => "\xCE\xB7",
1168        "\xF0\x9D\x9E\x97"    => "\xCE\xB8",
1169        "\xF0\x9D\x9E\x98"    => "\xCE\xB9",
1170        "\xF0\x9D\x9E\x99"    => "\xCE\xBA",
1171        "\xF0\x9D\x9E\x9A"    => "\xCE\xBB",
1172        "\xF0\x9D\x9E\x9B"    => "\xCE\xBC",
1173        "\xF0\x9D\x9E\x9C"    => "\xCE\xBD",
1174        "\xF0\x9D\x9E\x9D"    => "\xCE\xBE",
1175        "\xF0\x9D\x9E\x9E"    => "\xCE\xBF",
1176        "\xF0\x9D\x9E\x9F"    => "\xCF\x80",
1177        "\xF0\x9D\x9E\xA0"    => "\xCF\x81",
1178        "\xF0\x9D\x9E\xA1"    => "\xCE\xB8",
1179        "\xF0\x9D\x9E\xA2"    => "\xCF\x83",
1180        "\xF0\x9D\x9E\xA3"    => "\xCF\x84",
1181        "\xF0\x9D\x9E\xA4"    => "\xCF\x85",
1182        "\xF0\x9D\x9E\xA5"    => "\xCF\x86",
1183        "\xF0\x9D\x9E\xA6"    => "\xCF\x87",
1184        "\xF0\x9D\x9E\xA7"    => "\xCF\x88",
1185        "\xF0\x9D\x9E\xA8"    => "\xCF\x89",
1186        "\xF0\x9D\x9E\xBB"    => "\xCF\x83",
1187        "\xF0\x9D\x9F\x8A"    => "\xCF\x9D",
1188    );
1189
1190    // do the case fold
1191    $text = utf8_case_fold($text, $option);
1192
1193    // convert to NFKC
1194    Normalizer::normalize($text, Normalizer::NFKC);
1195
1196    // FC_NFKC_Closure, http://www.unicode.org/Public/5.0.0/ucd/DerivedNormalizationProps.txt
1197    $text = strtr($text, $fc_nfkc_closure);
1198
1199    return $text;
1200}
1201
1202/**
1203* Assume the input is NFC:
1204* Takes the input and does a "special" case fold. It does minor normalization as well.
1205*
1206* @param    string    $text    text to be case folded
1207* @param    string    $option    determines how we will fold the cases
1208* @return    string            case folded text
1209*/
1210function utf8_case_fold_nfc($text, $option = 'full')
1211{
1212    static $uniarray = array();
1213    static $ypogegrammeni = array(
1214        "\xCD\xBA"        => "\x20\xCD\x85",
1215        "\xE1\xBE\x80"    => "\xE1\xBC\x80\xCD\x85",
1216        "\xE1\xBE\x81"    => "\xE1\xBC\x81\xCD\x85",
1217        "\xE1\xBE\x82"    => "\xE1\xBC\x82\xCD\x85",
1218        "\xE1\xBE\x83"    => "\xE1\xBC\x83\xCD\x85",
1219        "\xE1\xBE\x84"    => "\xE1\xBC\x84\xCD\x85",
1220        "\xE1\xBE\x85"    => "\xE1\xBC\x85\xCD\x85",
1221        "\xE1\xBE\x86"    => "\xE1\xBC\x86\xCD\x85",
1222        "\xE1\xBE\x87"    => "\xE1\xBC\x87\xCD\x85",
1223        "\xE1\xBE\x88"    => "\xE1\xBC\x88\xCD\x85",
1224        "\xE1\xBE\x89"    => "\xE1\xBC\x89\xCD\x85",
1225        "\xE1\xBE\x8A"    => "\xE1\xBC\x8A\xCD\x85",
1226        "\xE1\xBE\x8B"    => "\xE1\xBC\x8B\xCD\x85",
1227        "\xE1\xBE\x8C"    => "\xE1\xBC\x8C\xCD\x85",
1228        "\xE1\xBE\x8D"    => "\xE1\xBC\x8D\xCD\x85",
1229        "\xE1\xBE\x8E"    => "\xE1\xBC\x8E\xCD\x85",
1230        "\xE1\xBE\x8F"    => "\xE1\xBC\x8F\xCD\x85",
1231        "\xE1\xBE\x90"    => "\xE1\xBC\xA0\xCD\x85",
1232        "\xE1\xBE\x91"    => "\xE1\xBC\xA1\xCD\x85",
1233        "\xE1\xBE\x92"    => "\xE1\xBC\xA2\xCD\x85",
1234        "\xE1\xBE\x93"    => "\xE1\xBC\xA3\xCD\x85",
1235        "\xE1\xBE\x94"    => "\xE1\xBC\xA4\xCD\x85",
1236        "\xE1\xBE\x95"    => "\xE1\xBC\xA5\xCD\x85",
1237        "\xE1\xBE\x96"    => "\xE1\xBC\xA6\xCD\x85",
1238        "\xE1\xBE\x97"    => "\xE1\xBC\xA7\xCD\x85",
1239        "\xE1\xBE\x98"    => "\xE1\xBC\xA8\xCD\x85",
1240        "\xE1\xBE\x99"    => "\xE1\xBC\xA9\xCD\x85",
1241        "\xE1\xBE\x9A"    => "\xE1\xBC\xAA\xCD\x85",
1242        "\xE1\xBE\x9B"    => "\xE1\xBC\xAB\xCD\x85",
1243        "\xE1\xBE\x9C"    => "\xE1\xBC\xAC\xCD\x85",
1244        "\xE1\xBE\x9D"    => "\xE1\xBC\xAD\xCD\x85",
1245        "\xE1\xBE\x9E"    => "\xE1\xBC\xAE\xCD\x85",
1246        "\xE1\xBE\x9F"    => "\xE1\xBC\xAF\xCD\x85",
1247        "\xE1\xBE\xA0"    => "\xE1\xBD\xA0\xCD\x85",
1248        "\xE1\xBE\xA1"    => "\xE1\xBD\xA1\xCD\x85",
1249        "\xE1\xBE\xA2"    => "\xE1\xBD\xA2\xCD\x85",
1250        "\xE1\xBE\xA3"    => "\xE1\xBD\xA3\xCD\x85",
1251        "\xE1\xBE\xA4"    => "\xE1\xBD\xA4\xCD\x85",
1252        "\xE1\xBE\xA5"    => "\xE1\xBD\xA5\xCD\x85",
1253        "\xE1\xBE\xA6"    => "\xE1\xBD\xA6\xCD\x85",
1254        "\xE1\xBE\xA7"    => "\xE1\xBD\xA7\xCD\x85",
1255        "\xE1\xBE\xA8"    => "\xE1\xBD\xA8\xCD\x85",
1256        "\xE1\xBE\xA9"    => "\xE1\xBD\xA9\xCD\x85",
1257        "\xE1\xBE\xAA"    => "\xE1\xBD\xAA\xCD\x85",
1258        "\xE1\xBE\xAB"    => "\xE1\xBD\xAB\xCD\x85",
1259        "\xE1\xBE\xAC"    => "\xE1\xBD\xAC\xCD\x85",
1260        "\xE1\xBE\xAD"    => "\xE1\xBD\xAD\xCD\x85",
1261        "\xE1\xBE\xAE"    => "\xE1\xBD\xAE\xCD\x85",
1262        "\xE1\xBE\xAF"    => "\xE1\xBD\xAF\xCD\x85",
1263        "\xE1\xBE\xB2"    => "\xE1\xBD\xB0\xCD\x85",
1264        "\xE1\xBE\xB3"    => "\xCE\xB1\xCD\x85",
1265        "\xE1\xBE\xB4"    => "\xCE\xAC\xCD\x85",
1266        "\xE1\xBE\xB7"    => "\xE1\xBE\xB6\xCD\x85",
1267        "\xE1\xBE\xBC"    => "\xCE\x91\xCD\x85",
1268        "\xE1\xBF\x82"    => "\xE1\xBD\xB4\xCD\x85",
1269        "\xE1\xBF\x83"    => "\xCE\xB7\xCD\x85",
1270        "\xE1\xBF\x84"    => "\xCE\xAE\xCD\x85",
1271        "\xE1\xBF\x87"    => "\xE1\xBF\x86\xCD\x85",
1272        "\xE1\xBF\x8C"    => "\xCE\x97\xCD\x85",
1273        "\xE1\xBF\xB2"    => "\xE1\xBD\xBC\xCD\x85",
1274        "\xE1\xBF\xB3"    => "\xCF\x89\xCD\x85",
1275        "\xE1\xBF\xB4"    => "\xCF\x8E\xCD\x85",
1276        "\xE1\xBF\xB7"    => "\xE1\xBF\xB6\xCD\x85",
1277        "\xE1\xBF\xBC"    => "\xCE\xA9\xCD\x85",
1278    );
1279
1280    // perform a small trick, avoid further normalization on composed points that contain U+0345 in their decomposition
1281    $text = strtr($text, $ypogegrammeni);
1282
1283    // do the case fold
1284    $text = utf8_case_fold($text, $option);
1285
1286    return $text;
1287}
1288
1289/**
1290* wrapper around PHP's native normalizer from intl
1291* previously a PECL extension, included in the core since PHP 5.3.0
1292* http://php.net/manual/en/normalizer.normalize.php
1293*
1294* @param    mixed    $strings    a string or an array of strings to normalize
1295* @return    mixed                the normalized content, preserving array keys if array given.
1296*/
1297function utf8_normalize_nfc($strings)
1298{
1299    if (empty($strings))
1300    {
1301        return $strings;
1302    }
1303
1304    if (!is_array($strings))
1305    {
1306        if (Normalizer::isNormalized($strings))
1307        {
1308            return $strings;
1309        }
1310        return (string) Normalizer::normalize($strings);
1311    }
1312    else
1313    {
1314        foreach ($strings as $key => $string)
1315        {
1316            if (is_array($string))
1317            {
1318                foreach ($string as $_key => $_string)
1319                {
1320                    if (Normalizer::isNormalized($strings[$key][$_key]))
1321                    {
1322                        continue;
1323                    }
1324                    $strings[$key][$_key] = (string) Normalizer::normalize($strings[$key][$_key]);
1325                }
1326            }
1327            else
1328            {
1329                if (Normalizer::isNormalized($strings[$key]))
1330                {
1331                    continue;
1332                }
1333                $strings[$key] = (string) Normalizer::normalize($strings[$key]);
1334            }
1335        }
1336    }
1337
1338    return $strings;
1339}
1340
1341/**
1342* This function is used to generate a "clean" version of a string.
1343* Clean means that it is a case insensitive form (case folding) and that it is normalized (NFC).
1344* Additionally a homographs of one character are transformed into one specific character (preferably ASCII
1345* if it is an ASCII character).
1346*
1347* Please be aware that if you change something within this function or within
1348* functions used here you need to rebuild/update the username_clean column in the users table. And all other
1349* columns that store a clean string otherwise you will break this functionality.
1350*
1351* @param    string    $text    An unclean string, mabye user input (has to be valid UTF-8!)
1352* @return    string            Cleaned up version of the input string
1353*/
1354function utf8_clean_string($text)
1355{
1356    global $phpbb_root_path, $phpEx;
1357
1358    static $homographs = array();
1359    if (empty($homographs))
1360    {
1361        $homographs = include($phpbb_root_path . 'includes/utf/data/confusables.' . $phpEx);
1362    }
1363
1364    $text = utf8_case_fold_nfkc($text);
1365    $text = strtr($text, $homographs);
1366    // Other control characters
1367    $text = preg_replace('#(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)#', '', $text);
1368
1369    // we need to reduce multiple spaces to a single one
1370    $text = preg_replace('# {2,}#', ' ', $text);
1371
1372    // we can use trim here as all the other space characters should have been turned
1373    // into normal ASCII spaces by now
1374    return trim($text);
1375}
1376
1377/**
1378* A wrapper for htmlspecialchars($value, ENT_COMPAT, 'UTF-8')
1379*/
1380function utf8_htmlspecialchars($value)
1381{
1382    return htmlspecialchars($value, ENT_COMPAT, 'UTF-8');
1383}
1384
1385/**
1386* Trying to convert returned system message to utf8
1387*
1388* PHP assumes such messages are ISO-8859-1 so we'll do that too
1389* and if it breaks messages we'll blame it on them ;-)
1390*/
1391function utf8_convert_message($message)
1392{
1393    // First of all check if conversion is neded at all, as there is no point
1394    // in converting ASCII messages from ISO-8859-1 to UTF-8
1395    if (!preg_match('/[\x80-\xFF]/', $message))
1396    {
1397        return utf8_htmlspecialchars($message);
1398    }
1399
1400    // else we need to convert some part of the message
1401    return utf8_htmlspecialchars(utf8_recode($message, 'ISO-8859-1'));
1402}
1403
1404/**
1405* UTF8-compatible wordwrap replacement
1406*
1407* @param    string    $string    The input string
1408* @param    int        $width    The column width. Defaults to 75.
1409* @param    string    $break    The line is broken using the optional break parameter. Defaults to '\n'.
1410* @param    bool    $cut    If the cut is set to TRUE, the string is always wrapped at the specified width. So if you have a word that is larger than the given width, it is broken apart.
1411*
1412* @return    string            the given string wrapped at the specified column.
1413*
1414*/
1415function utf8_wordwrap($string, $width = 75, $break = "\n", $cut = false)
1416{
1417    // We first need to explode on $break, not destroying existing (intended) breaks
1418    $lines = explode($break, $string);
1419    $new_lines = array(0 => '');
1420    $index = 0;
1421
1422    foreach ($lines as $line)
1423    {
1424        $words = explode(' ', $line);
1425
1426        for ($i = 0, $size = count($words); $i < $size; $i++)
1427        {
1428            $word = $words[$i];
1429
1430            // If cut is true we need to cut the word if it is > width chars
1431            if ($cut && utf8_strlen($word) > $width)
1432            {
1433                $words[$i] = utf8_substr($word, $width);
1434                $word = utf8_substr($word, 0, $width);
1435                $i--;
1436            }
1437
1438            if (utf8_strlen($new_lines[$index] . $word) > $width)
1439            {
1440                $new_lines[$index] = substr($new_lines[$index], 0, -1);
1441                $index++;
1442                $new_lines[$index] = '';
1443            }
1444
1445            $new_lines[$index] .= $word . ' ';
1446        }
1447
1448        $new_lines[$index] = substr($new_lines[$index], 0, -1);
1449        $index++;
1450        $new_lines[$index] = '';
1451    }
1452
1453    unset($new_lines[$index]);
1454    return implode($break, $new_lines);
1455}
1456
1457/**
1458* UTF8-safe basename() function
1459*
1460* basename() has some limitations and is dependent on the locale setting
1461* according to the PHP manual. Therefore we provide our own locale independent
1462* basename function.
1463*
1464* @param string $filename The filename basename() should be applied to
1465* @return string The basenamed filename
1466*/
1467function utf8_basename($filename): string
1468{
1469    if (!$filename)
1470    {
1471        return '';
1472    }
1473
1474    // We always check for forward slash AND backward slash
1475    // because they could be mixed or "sneaked" in. ;)
1476    // You know, never trust user input...
1477    if (str_contains($filename, '/'))
1478    {
1479        $filename = utf8_substr($filename, utf8_strrpos($filename, '/') + 1);
1480    }
1481
1482    if (str_contains($filename, '\\'))
1483    {
1484        $filename = utf8_substr($filename, utf8_strrpos($filename, '\\') + 1);
1485    }
1486
1487    return $filename;
1488}