GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 5cefd1...492078 )
by Anton
04:08
created

Mbstring::mb_internal_trim()   B

Complexity

Conditions 11
Paths 52

Size

Total Lines 41
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 24
nc 52
nop 5
dl 0
loc 41
c 1
b 0
f 0
cc 11
rs 7.3166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the Symfony package.
5
 *
6
 * (c) Fabien Potencier <[email protected]>
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 <[email protected]>
65
 *
66
 * @internal
67
 */
68
final class Mbstring
69
{
70
    public const MB_CASE_FOLD = \PHP_INT_MAX;
71
72
    private const CASE_FOLD = [
73
        ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"],
74
        ['μ', 's', 'ι',        'σ', 'β',        'θ',        'φ',        'π',        'κ',        'ρ',        'ε',        "\xE1\xB9\xA1", 'ι'],
75
    ];
76
77
    private static $encodingList = ['ASCII', 'UTF-8'];
78
    private static $language = 'neutral';
79
    private static $internalEncoding = 'UTF-8';
80
81
    public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
82
    {
83
        if (\is_array($fromEncoding) || ($fromEncoding !== null && false !== strpos($fromEncoding, ','))) {
84
            $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
85
        } else {
86
            $fromEncoding = self::getEncoding($fromEncoding);
87
        }
88
89
        $toEncoding = self::getEncoding($toEncoding);
90
91
        if ('BASE64' === $fromEncoding) {
92
            $s = base64_decode($s);
93
            $fromEncoding = $toEncoding;
94
        }
95
96
        if ('BASE64' === $toEncoding) {
97
            return base64_encode($s);
98
        }
99
100
        if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
101
            if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
102
                $fromEncoding = 'Windows-1252';
103
            }
104
            if ('UTF-8' !== $fromEncoding) {
105
                $s = \iconv($fromEncoding, 'UTF-8//IGNORE', $s);
106
            }
107
108
            return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s);
109
        }
110
111
        if ('HTML-ENTITIES' === $fromEncoding) {
112
            $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8');
113
            $fromEncoding = 'UTF-8';
114
        }
115
116
        return \iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
117
    }
118
119
    public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars)
120
    {
121
        $ok = true;
122
        array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
123
            if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
0 ignored issues
show
introduced by
The condition false === $v = self::mb_...ncoding, $fromEncoding) is always false.
Loading history...
124
                $ok = false;
125
            }
126
        });
127
128
        return $ok ? $fromEncoding : false;
129
    }
130
131
    public static function mb_decode_mimeheader($s)
132
    {
133
        return \iconv_mime_decode($s, 2, self::$internalEncoding);
134
    }
135
136
    public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
0 ignored issues
show
Unused Code introduced by
The parameter $indent is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

136
    public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, /** @scrutinizer ignore-unused */ $indent = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $s is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

136
    public static function mb_encode_mimeheader(/** @scrutinizer ignore-unused */ $s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $linefeed is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

136
    public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, /** @scrutinizer ignore-unused */ $linefeed = null, $indent = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $transferEncoding is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

136
    public static function mb_encode_mimeheader($s, $charset = null, /** @scrutinizer ignore-unused */ $transferEncoding = null, $linefeed = null, $indent = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $charset is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

136
    public static function mb_encode_mimeheader($s, /** @scrutinizer ignore-unused */ $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
137
    {
138
        trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING);
139
    }
140
141
    public static function mb_decode_numericentity($s, $convmap, $encoding = null)
142
    {
143
        if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
144
            trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
145
146
            return null;
147
        }
148
149
        if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $convmap of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
150
            return false;
151
        }
152
153
        if (null !== $encoding && !is_scalar($encoding)) {
154
            trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
155
156
            return '';  // Instead of null (cf. mb_encode_numericentity).
157
        }
158
159
        $s = (string) $s;
160
        if ('' === $s) {
161
            return '';
162
        }
163
164
        $encoding = self::getEncoding($encoding);
165
166
        if ('UTF-8' === $encoding) {
167
            $encoding = null;
168
            if (!preg_match('//u', $s)) {
169
                $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
170
            }
171
        } else {
172
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
173
        }
174
175
        $cnt = floor(\count($convmap) / 4) * 4;
176
177
        for ($i = 0; $i < $cnt; $i += 4) {
178
            // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
179
            $convmap[$i] += $convmap[$i + 2];
180
            $convmap[$i + 1] += $convmap[$i + 2];
181
        }
182
183
        $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
184
            $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
185
            for ($i = 0; $i < $cnt; $i += 4) {
186
                if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
187
                    return self::mb_chr($c - $convmap[$i + 2]);
188
                }
189
            }
190
191
            return $m[0];
192
        }, $s);
193
194
        if (null === $encoding) {
195
            return $s;
196
        }
197
198
        return \iconv('UTF-8', $encoding.'//IGNORE', $s);
199
    }
200
201
    public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
202
    {
203
        if (null !== $s && !is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) {
204
            trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING);
205
206
            return null;
207
        }
208
209
        if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $convmap of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
210
            return false;
211
        }
212
213
        if (null !== $encoding && !is_scalar($encoding)) {
214
            trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING);
215
216
            return null;  // Instead of '' (cf. mb_decode_numericentity).
217
        }
218
219
        if (null !== $is_hex && !is_scalar($is_hex)) {
220
            trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING);
221
222
            return null;
223
        }
224
225
        $s = (string) $s;
226
        if ('' === $s) {
227
            return '';
228
        }
229
230
        $encoding = self::getEncoding($encoding);
231
232
        if ('UTF-8' === $encoding) {
233
            $encoding = null;
234
            if (!preg_match('//u', $s)) {
235
                $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
236
            }
237
        } else {
238
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
239
        }
240
241
        static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
242
243
        $cnt = floor(\count($convmap) / 4) * 4;
244
        $i = 0;
245
        $len = \strlen($s);
0 ignored issues
show
Bug introduced by
It seems like $s can also be of type false; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

245
        $len = \strlen(/** @scrutinizer ignore-type */ $s);
Loading history...
246
        $result = '';
247
248
        while ($i < $len) {
249
            $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
250
            $uchr = substr($s, $i, $ulen);
0 ignored issues
show
Bug introduced by
It seems like $s can also be of type false; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

250
            $uchr = substr(/** @scrutinizer ignore-type */ $s, $i, $ulen);
Loading history...
251
            $i += $ulen;
252
            $c = self::mb_ord($uchr);
253
254
            for ($j = 0; $j < $cnt; $j += 4) {
255
                if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
256
                    $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
257
                    $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
258
                    continue 2;
259
                }
260
            }
261
            $result .= $uchr;
262
        }
263
264
        if (null === $encoding) {
265
            return $result;
266
        }
267
268
        return \iconv('UTF-8', $encoding.'//IGNORE', $result);
269
    }
270
271
    public static function mb_convert_case($s, $mode, $encoding = null)
272
    {
273
        $s = (string) $s;
274
        if ('' === $s) {
275
            return '';
276
        }
277
278
        $encoding = self::getEncoding($encoding);
279
280
        if ('UTF-8' === $encoding) {
281
            $encoding = null;
282
            if (!preg_match('//u', $s)) {
283
                $s = @\iconv('UTF-8', 'UTF-8//IGNORE', $s);
284
            }
285
        } else {
286
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
287
        }
288
289
        if (\MB_CASE_TITLE == $mode) {
290
            static $titleRegexp = null;
291
            if (null === $titleRegexp) {
292
                $titleRegexp = self::getData('titleCaseRegexp');
293
            }
294
            $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s);
295
        } else {
296
            if (\MB_CASE_UPPER == $mode) {
297
                static $upper = null;
298
                if (null === $upper) {
299
                    $upper = self::getData('upperCase');
300
                }
301
                $map = $upper;
302
            } else {
303
                if (self::MB_CASE_FOLD === $mode) {
304
                    $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s);
0 ignored issues
show
Bug introduced by
The constant Symfony\Polyfill\Mbstring\Mbstring::CASE_FOLD was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
305
                }
306
307
                static $lower = null;
308
                if (null === $lower) {
309
                    $lower = self::getData('lowerCase');
310
                }
311
                $map = $lower;
312
            }
313
314
            static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4];
315
316
            $i = 0;
317
            $len = \strlen($s);
0 ignored issues
show
Bug introduced by
It seems like $s can also be of type false; however, parameter $string of strlen() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

317
            $len = \strlen(/** @scrutinizer ignore-type */ $s);
Loading history...
318
319
            while ($i < $len) {
320
                $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
321
                $uchr = substr($s, $i, $ulen);
0 ignored issues
show
Bug introduced by
It seems like $s can also be of type false; however, parameter $string of substr() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

321
                $uchr = substr(/** @scrutinizer ignore-type */ $s, $i, $ulen);
Loading history...
322
                $i += $ulen;
323
324
                if (isset($map[$uchr])) {
325
                    $uchr = $map[$uchr];
326
                    $nlen = \strlen($uchr);
327
328
                    if ($nlen == $ulen) {
329
                        $nlen = $i;
330
                        do {
331
                            $s[--$nlen] = $uchr[--$ulen];
332
                        } while ($ulen);
333
                    } else {
334
                        $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
0 ignored issues
show
Bug introduced by
It seems like $s can also be of type false; however, parameter $string of substr_replace() does only seem to accept array|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

334
                        $s = substr_replace(/** @scrutinizer ignore-type */ $s, $uchr, $i - $ulen, $ulen);
Loading history...
335
                        $len += $nlen - $ulen;
336
                        $i += $nlen - $ulen;
337
                    }
338
                }
339
            }
340
        }
341
342
        if (null === $encoding) {
343
            return $s;
344
        }
345
346
        return \iconv('UTF-8', $encoding.'//IGNORE', $s);
347
    }
348
349
    public static function mb_internal_encoding($encoding = null)
350
    {
351
        if (null === $encoding) {
352
            return self::$internalEncoding;
353
        }
354
355
        $normalizedEncoding = self::getEncoding($encoding);
356
357
        if ('UTF-8' === $normalizedEncoding || false !== @\iconv($normalizedEncoding, $normalizedEncoding, ' ')) {
358
            self::$internalEncoding = $normalizedEncoding;
359
360
            return true;
361
        }
362
363
        if (80000 > \PHP_VERSION_ID) {
364
            return false;
365
        }
366
367
        throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding));
368
    }
369
370
    public static function mb_language($lang = null)
371
    {
372
        if (null === $lang) {
373
            return self::$language;
374
        }
375
376
        switch ($normalizedLang = strtolower($lang)) {
377
            case 'uni':
378
            case 'neutral':
379
                self::$language = $normalizedLang;
380
381
                return true;
382
        }
383
384
        if (80000 > \PHP_VERSION_ID) {
385
            return false;
386
        }
387
388
        throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang));
389
    }
390
391
    public static function mb_list_encodings()
392
    {
393
        return ['UTF-8'];
394
    }
395
396
    public static function mb_encoding_aliases($encoding)
397
    {
398
        switch (strtoupper($encoding)) {
399
            case 'UTF8':
400
            case 'UTF-8':
401
                return ['utf8'];
402
        }
403
404
        return false;
405
    }
406
407
    public static function mb_check_encoding($var = null, $encoding = null)
408
    {
409
        if (null === $encoding) {
410
            if (null === $var) {
411
                return false;
412
            }
413
            $encoding = self::$internalEncoding;
414
        }
415
416
        return self::mb_detect_encoding($var, [$encoding]) || false !== @\iconv($encoding, $encoding, $var);
417
    }
418
419
    public static function mb_detect_encoding($str, $encodingList = null, $strict = false)
0 ignored issues
show
Unused Code introduced by
The parameter $strict is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

419
    public static function mb_detect_encoding($str, $encodingList = null, /** @scrutinizer ignore-unused */ $strict = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
420
    {
421
        if (null === $encodingList) {
422
            $encodingList = self::$encodingList;
423
        } else {
424
            if (!\is_array($encodingList)) {
425
                $encodingList = array_map('trim', explode(',', $encodingList));
426
            }
427
            $encodingList = array_map('strtoupper', $encodingList);
428
        }
429
430
        foreach ($encodingList as $enc) {
431
            switch ($enc) {
432
                case 'ASCII':
433
                    if (!preg_match('/[\x80-\xFF]/', $str)) {
434
                        return $enc;
435
                    }
436
                    break;
437
438
                case 'UTF8':
439
                case 'UTF-8':
440
                    if (preg_match('//u', $str)) {
441
                        return 'UTF-8';
442
                    }
443
                    break;
444
445
                default:
446
                    if (0 === strncmp($enc, 'ISO-8859-', 9)) {
447
                        return $enc;
448
                    }
449
            }
450
        }
451
452
        return false;
453
    }
454
455
    public static function mb_detect_order($encodingList = null)
456
    {
457
        if (null === $encodingList) {
458
            return self::$encodingList;
459
        }
460
461
        if (!\is_array($encodingList)) {
462
            $encodingList = array_map('trim', explode(',', $encodingList));
463
        }
464
        $encodingList = array_map('strtoupper', $encodingList);
465
466
        foreach ($encodingList as $enc) {
467
            switch ($enc) {
468
                default:
469
                    if (strncmp($enc, 'ISO-8859-', 9)) {
470
                        return false;
471
                    }
472
                    // no break
473
                case 'ASCII':
474
                case 'UTF8':
475
                case 'UTF-8':
476
            }
477
        }
478
479
        self::$encodingList = $encodingList;
480
481
        return true;
482
    }
483
484
    public static function mb_strlen($s, $encoding = null)
485
    {
486
        $encoding = self::getEncoding($encoding);
487
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
488
            return \strlen($s);
489
        }
490
491
        return @\iconv_strlen($s, $encoding);
492
    }
493
494
    public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
495
    {
496
        $encoding = self::getEncoding($encoding);
497
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
498
            return strpos($haystack, $needle, $offset);
499
        }
500
501
        $needle = (string) $needle;
502
        if ('' === $needle) {
503
            if (80000 > \PHP_VERSION_ID) {
504
                trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING);
505
506
                return false;
507
            }
508
509
            return 0;
510
        }
511
512
        return \iconv_strpos($haystack, $needle, $offset, $encoding);
513
    }
514
515
    public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
516
    {
517
        $encoding = self::getEncoding($encoding);
518
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
519
            return strrpos($haystack, $needle, $offset);
520
        }
521
522
        if ($offset != (int) $offset) {
523
            $offset = 0;
524
        } elseif ($offset = (int) $offset) {
525
            if ($offset < 0) {
526
                if (0 > $offset += self::mb_strlen($needle)) {
527
                    $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
528
                }
529
                $offset = 0;
530
            } else {
531
                $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
532
            }
533
        }
534
535
        $pos = '' !== $needle || 80000 > \PHP_VERSION_ID
536
            ? \iconv_strrpos($haystack, $needle, $encoding)
537
            : self::mb_strlen($haystack, $encoding);
538
539
        return false !== $pos ? $offset + $pos : false;
540
    }
541
542
    public static function mb_str_split($string, $split_length = 1, $encoding = null)
543
    {
544
        if (null !== $string && !is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) {
545
            trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING);
546
547
            return null;
548
        }
549
550
        if (1 > $split_length = (int) $split_length) {
551
            if (80000 > \PHP_VERSION_ID) {
552
                trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING);
553
                return false;
554
            }
555
556
            throw new \ValueError('Argument #2 ($length) must be greater than 0');
557
        }
558
559
        if (null === $encoding) {
560
            $encoding = mb_internal_encoding();
561
        }
562
563
        if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
564
            $rx = '/(';
565
            while (65535 < $split_length) {
566
                $rx .= '.{65535}';
567
                $split_length -= 65535;
568
            }
569
            $rx .= '.{'.$split_length.'})/us';
570
571
            return preg_split($rx, $string, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY);
572
        }
573
574
        $result = [];
575
        $length = mb_strlen($string, $encoding);
576
577
        for ($i = 0; $i < $length; $i += $split_length) {
578
            $result[] = mb_substr($string, $i, $split_length, $encoding);
579
        }
580
581
        return $result;
582
    }
583
584
    public static function mb_strtolower($s, $encoding = null)
585
    {
586
        return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding);
587
    }
588
589
    public static function mb_strtoupper($s, $encoding = null)
590
    {
591
        return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding);
592
    }
593
594
    public static function mb_substitute_character($c = null)
595
    {
596
        if (null === $c) {
597
            return 'none';
598
        }
599
        if (0 === strcasecmp($c, 'none')) {
600
            return true;
601
        }
602
        if (80000 > \PHP_VERSION_ID) {
603
            return false;
604
        }
605
        if (\is_int($c) || 'long' === $c || 'entity' === $c) {
606
            return false;
607
        }
608
609
        throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint');
610
    }
611
612
    public static function mb_substr($s, $start, $length = null, $encoding = null)
613
    {
614
        $encoding = self::getEncoding($encoding);
615
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
616
            return (string) substr($s, $start, null === $length ? 2147483647 : $length);
617
        }
618
619
        if ($start < 0) {
620
            $start = \iconv_strlen($s, $encoding) + $start;
621
            if ($start < 0) {
622
                $start = 0;
623
            }
624
        }
625
626
        if (null === $length) {
627
            $length = 2147483647;
628
        } elseif ($length < 0) {
629
            $length = \iconv_strlen($s, $encoding) + $length - $start;
630
            if ($length < 0) {
631
                return '';
632
            }
633
        }
634
635
        return (string) \iconv_substr($s, $start, $length, $encoding);
636
    }
637
638
    public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
639
    {
640
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
641
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
642
643
        return self::mb_strpos($haystack, $needle, $offset, $encoding);
644
    }
645
646
    public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
647
    {
648
        $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
649
650
        return self::getSubpart($pos, $part, $haystack, $encoding);
651
    }
652
653
    public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
654
    {
655
        $encoding = self::getEncoding($encoding);
656
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
657
            $pos = strrpos($haystack, $needle);
658
        } else {
659
            $needle = self::mb_substr($needle, 0, 1, $encoding);
660
            $pos = \iconv_strrpos($haystack, $needle, $encoding);
661
        }
662
663
        return self::getSubpart($pos, $part, $haystack, $encoding);
664
    }
665
666
    public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
667
    {
668
        $needle = self::mb_substr($needle, 0, 1, $encoding);
669
        $pos = self::mb_strripos($haystack, $needle, $encoding);
670
671
        return self::getSubpart($pos, $part, $haystack, $encoding);
672
    }
673
674
    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
675
    {
676
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
677
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
678
679
        return self::mb_strrpos($haystack, $needle, $offset, $encoding);
680
    }
681
682
    public static function mb_strstr($haystack, $needle, $part = false, $encoding = null)
0 ignored issues
show
Unused Code introduced by
The parameter $encoding is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

682
    public static function mb_strstr($haystack, $needle, $part = false, /** @scrutinizer ignore-unused */ $encoding = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
683
    {
684
        $pos = strpos($haystack, $needle);
685
        if (false === $pos) {
686
            return false;
687
        }
688
        if ($part) {
689
            return substr($haystack, 0, $pos);
690
        }
691
692
        return substr($haystack, $pos);
693
    }
694
695
    public static function mb_get_info($type = 'all')
696
    {
697
        $info = [
698
            'internal_encoding' => self::$internalEncoding,
699
            'http_output' => 'pass',
700
            'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
701
            'func_overload' => 0,
702
            'func_overload_list' => 'no overload',
703
            'mail_charset' => 'UTF-8',
704
            'mail_header_encoding' => 'BASE64',
705
            'mail_body_encoding' => 'BASE64',
706
            'illegal_chars' => 0,
707
            'encoding_translation' => 'Off',
708
            'language' => self::$language,
709
            'detect_order' => self::$encodingList,
710
            'substitute_character' => 'none',
711
            'strict_detection' => 'Off',
712
        ];
713
714
        if ('all' === $type) {
715
            return $info;
716
        }
717
        if (isset($info[$type])) {
718
            return $info[$type];
719
        }
720
721
        return false;
722
    }
723
724
    public static function mb_http_input($type = '')
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

724
    public static function mb_http_input(/** @scrutinizer ignore-unused */ $type = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
725
    {
726
        return false;
727
    }
728
729
    public static function mb_http_output($encoding = null)
730
    {
731
        return null !== $encoding ? 'pass' === $encoding : 'pass';
732
    }
733
734
    public static function mb_strwidth($s, $encoding = null)
735
    {
736
        $encoding = self::getEncoding($encoding);
737
738
        if ('UTF-8' !== $encoding) {
739
            $s = \iconv($encoding, 'UTF-8//IGNORE', $s);
740
        }
741
742
        $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);
743
744
        return ($wide << 1) + \iconv_strlen($s, 'UTF-8');
745
    }
746
747
    public static function mb_substr_count($haystack, $needle, $encoding = null)
0 ignored issues
show
Unused Code introduced by
The parameter $encoding is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

747
    public static function mb_substr_count($haystack, $needle, /** @scrutinizer ignore-unused */ $encoding = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
748
    {
749
        return substr_count($haystack, $needle);
750
    }
751
752
    public static function mb_output_handler($contents, $status)
0 ignored issues
show
Unused Code introduced by
The parameter $status is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

752
    public static function mb_output_handler($contents, /** @scrutinizer ignore-unused */ $status)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
753
    {
754
        return $contents;
755
    }
756
757
    public static function mb_chr($code, $encoding = null)
758
    {
759
        if (0x80 > $code %= 0x200000) {
760
            $s = \chr($code);
761
        } elseif (0x800 > $code) {
762
            $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
763
        } elseif (0x10000 > $code) {
764
            $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
765
        } else {
766
            $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
767
        }
768
769
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
770
            $s = mb_convert_encoding($s, $encoding, 'UTF-8');
771
        }
772
773
        return $s;
774
    }
775
776
    public static function mb_ord($s, $encoding = null)
777
    {
778
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
779
            $s = mb_convert_encoding($s, 'UTF-8', $encoding);
780
        }
781
782
        if (1 === \strlen($s)) {
783
            return \ord($s);
784
        }
785
786
        $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
787
        if (0xF0 <= $code) {
788
            return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
789
        }
790
        if (0xE0 <= $code) {
791
            return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
792
        }
793
        if (0xC0 <= $code) {
794
            return (($code - 0xC0) << 6) + $s[2] - 0x80;
795
        }
796
797
        return $code;
798
    }
799
800
    private static function getSubpart($pos, $part, $haystack, $encoding)
801
    {
802
        if (false === $pos) {
803
            return false;
804
        }
805
        if ($part) {
806
            return self::mb_substr($haystack, 0, $pos, $encoding);
807
        }
808
809
        return self::mb_substr($haystack, $pos, null, $encoding);
810
    }
811
812
    private static function html_encoding_callback(array $m)
813
    {
814
        $i = 1;
815
        $entities = '';
816
        $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8'));
817
818
        while (isset($m[$i])) {
819
            if (0x80 > $m[$i]) {
820
                $entities .= \chr($m[$i++]);
821
                continue;
822
            }
823
            if (0xF0 <= $m[$i]) {
824
                $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
825
            } elseif (0xE0 <= $m[$i]) {
826
                $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
827
            } else {
828
                $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
829
            }
830
831
            $entities .= '&#'.$c.';';
832
        }
833
834
        return $entities;
835
    }
836
837
    private static function title_case(array $s)
838
    {
839
        return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
0 ignored issues
show
Bug introduced by
Are you sure self::mb_convert_case($s...MB_CASE_UPPER, 'UTF-8') of type array|false|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

839
        return /** @scrutinizer ignore-type */ self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8');
Loading history...
840
    }
841
842
    private static function getData($file)
843
    {
844
        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
845
            return require $file;
846
        }
847
848
        return false;
849
    }
850
851
    private static function getEncoding($encoding)
852
    {
853
        if (null === $encoding) {
854
            return self::$internalEncoding;
855
        }
856
857
        if ('UTF-8' === $encoding) {
858
            return 'UTF-8';
859
        }
860
861
        $encoding = strtoupper($encoding);
862
863
        if ('8BIT' === $encoding || 'BINARY' === $encoding) {
864
            return 'CP850';
865
        }
866
867
        if ('UTF8' === $encoding) {
868
            return 'UTF-8';
869
        }
870
871
        return $encoding;
872
    }
873
}
874