Passed
Push — master ( 9542e6...b5fb3e )
by Richard
09:04
created

Mbstring::mb_convert_variables()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 12
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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_strtolower           - Make a string lowercase
39
 * - mb_strtoupper           - Make a string uppercase
40
 * - mb_substitute_character - Set/Get substitution character
41
 * - mb_substr               - Get part of string
42
 * - mb_stripos              - Finds position of first occurrence of a string within another, case insensitive
43
 * - mb_stristr              - Finds first occurrence of a string within another, case insensitive
44
 * - mb_strrchr              - Finds the last occurrence of a character in a string within another
45
 * - mb_strrichr             - Finds the last occurrence of a character in a string within another, case insensitive
46
 * - mb_strripos             - Finds position of last occurrence of a string within another, case insensitive
47
 * - mb_strstr               - Finds first occurrence of a string within another
48
 * - mb_strwidth             - Return width of string
49
 * - mb_substr_count         - Count the number of substring occurrences
50
 *
51
 * Not implemented:
52
 * - mb_convert_kana         - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
53
 * - mb_ereg_*               - Regular expression with multibyte support
54
 * - mb_parse_str            - Parse GET/POST/COOKIE data and set global variable
55
 * - mb_preferred_mime_name  - Get MIME charset string
56
 * - mb_regex_encoding       - Returns current encoding for multibyte regex as string
57
 * - mb_regex_set_options    - Set/Get the default options for mbregex functions
58
 * - mb_send_mail            - Send encoded mail
59
 * - mb_split                - Split multibyte string using regular expression
60
 * - mb_strcut               - Get part of string
61
 * - mb_strimwidth           - Get truncated string with specified width
62
 *
63
 * @author Nicolas Grekas <[email protected]>
64
 *
65
 * @internal
66
 */
67
final class Mbstring
68
{
69
    const MB_CASE_FOLD = PHP_INT_MAX;
70
71
    private static $encodingList = array('ASCII', 'UTF-8');
72
    private static $language = 'neutral';
73
    private static $internalEncoding = 'UTF-8';
74
    private static $caseFold = array(
75
        array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"),
76
        array('μ', 's', 'ι',        'σ', 'β',        'θ',        'φ',        'π',        'κ',        'ρ',        'ε',        "\xE1\xB9\xA1", 'ι'),
77
    );
78
79
    public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
80
    {
81
        if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
82
            $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
83
        } else {
84
            $fromEncoding = self::getEncoding($fromEncoding);
85
        }
86
87
        $toEncoding = self::getEncoding($toEncoding);
88
89
        if ('BASE64' === $fromEncoding) {
90
            $s = base64_decode($s);
91
            $fromEncoding = $toEncoding;
92
        }
93
94
        if ('BASE64' === $toEncoding) {
95
            return base64_encode($s);
96
        }
97
98
        if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
99
            if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
100
                $fromEncoding = 'Windows-1252';
101
            }
102
            if ('UTF-8' !== $fromEncoding) {
103
                $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
104
            }
105
106
            return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s);
107
        }
108
109
        if ('HTML-ENTITIES' === $fromEncoding) {
110
            $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
111
            $fromEncoding = 'UTF-8';
112
        }
113
114
        return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
115
    }
116
117
    public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null)
118
    {
119
        $vars = array(&$a, &$b, &$c, &$d, &$e, &$f);
120
121
        $ok = true;
122
        array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
123
            if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
124
                $ok = false;
125
            }
126
        });
127
128
        return $ok ? $fromEncoding : false;
129
    }
130
131
    public static function mb_decode_mimeheader($s)
132
    {
133
        return iconv_mime_decode($s, 2, self::$internalEncoding);
134
    }
135
136
    public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null)
0 ignored issues
show
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...
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...
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) || !$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 Mbstring::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) || !$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 = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
242
243
        $cnt = floor(\count($convmap) / 4) * 4;
244
        $i = 0;
245
        $len = \strlen($s);
246
        $result = '';
247
248
        while ($i < $len) {
249
            $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
250
            $uchr = substr($s, $i, $ulen);
251
            $i += $ulen;
252
            $c = self::mb_ord($uchr);
253
254
            for ($j = 0; $j < $cnt; $j += 4) {
255
                if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
256
                    $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
257
                    $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
258
                    continue 2;
259
                }
260
            }
261
            $result .= $uchr;
262
        }
263
264
        if (null === $encoding) {
265
            return $result;
266
        }
267
268
        return iconv('UTF-8', $encoding.'//IGNORE', $result);
269
    }
270
271
    public static function mb_convert_case($s, $mode, $encoding = null)
272
    {
273
        $s = (string) $s;
274
        if ('' === $s) {
275
            return '';
276
        }
277
278
        $encoding = self::getEncoding($encoding);
279
280
        if ('UTF-8' === $encoding) {
281
            $encoding = null;
282
            if (!preg_match('//u', $s)) {
283
                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
284
            }
285
        } else {
286
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
287
        }
288
289
        if (MB_CASE_TITLE == $mode) {
290
            static $titleRegexp = null;
291
            if (null === $titleRegexp) {
292
                $titleRegexp = self::getData('titleCaseRegexp');
293
            }
294
            $s = preg_replace_callback($titleRegexp, array(__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::$caseFold[0], self::$caseFold[1], $s);
305
                }
306
307
                static $lower = null;
308
                if (null === $lower) {
309
                    $lower = self::getData('lowerCase');
310
                }
311
                $map = $lower;
312
            }
313
314
            static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
315
316
            $i = 0;
317
            $len = \strlen($s);
318
319
            while ($i < $len) {
320
                $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
321
                $uchr = substr($s, $i, $ulen);
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);
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
        $encoding = self::getEncoding($encoding);
356
357
        if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) {
358
            self::$internalEncoding = $encoding;
359
360
            return true;
361
        }
362
363
        return false;
364
    }
365
366
    public static function mb_language($lang = null)
367
    {
368
        if (null === $lang) {
369
            return self::$language;
370
        }
371
372
        switch ($lang = strtolower($lang)) {
373
            case 'uni':
374
            case 'neutral':
375
                self::$language = $lang;
376
377
                return true;
378
        }
379
380
        return false;
381
    }
382
383
    public static function mb_list_encodings()
384
    {
385
        return array('UTF-8');
386
    }
387
388
    public static function mb_encoding_aliases($encoding)
389
    {
390
        switch (strtoupper($encoding)) {
391
            case 'UTF8':
392
            case 'UTF-8':
393
                return array('utf8');
394
        }
395
396
        return false;
397
    }
398
399
    public static function mb_check_encoding($var = null, $encoding = null)
400
    {
401
        if (null === $encoding) {
402
            if (null === $var) {
403
                return false;
404
            }
405
            $encoding = self::$internalEncoding;
406
        }
407
408
        return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var);
409
    }
410
411
    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

411
    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...
412
    {
413
        if (null === $encodingList) {
414
            $encodingList = self::$encodingList;
415
        } else {
416
            if (!\is_array($encodingList)) {
417
                $encodingList = array_map('trim', explode(',', $encodingList));
418
            }
419
            $encodingList = array_map('strtoupper', $encodingList);
420
        }
421
422
        foreach ($encodingList as $enc) {
423
            switch ($enc) {
424
                case 'ASCII':
425
                    if (!preg_match('/[\x80-\xFF]/', $str)) {
426
                        return $enc;
427
                    }
428
                    break;
429
430
                case 'UTF8':
431
                case 'UTF-8':
432
                    if (preg_match('//u', $str)) {
433
                        return 'UTF-8';
434
                    }
435
                    break;
436
437
                default:
438
                    if (0 === strncmp($enc, 'ISO-8859-', 9)) {
439
                        return $enc;
440
                    }
441
            }
442
        }
443
444
        return false;
445
    }
446
447
    public static function mb_detect_order($encodingList = null)
448
    {
449
        if (null === $encodingList) {
450
            return self::$encodingList;
451
        }
452
453
        if (!\is_array($encodingList)) {
454
            $encodingList = array_map('trim', explode(',', $encodingList));
455
        }
456
        $encodingList = array_map('strtoupper', $encodingList);
457
458
        foreach ($encodingList as $enc) {
459
            switch ($enc) {
460
                default:
461
                    if (strncmp($enc, 'ISO-8859-', 9)) {
462
                        return false;
463
                    }
464
                    // no break
465
                case 'ASCII':
466
                case 'UTF8':
467
                case 'UTF-8':
468
            }
469
        }
470
471
        self::$encodingList = $encodingList;
472
473
        return true;
474
    }
475
476
    public static function mb_strlen($s, $encoding = null)
477
    {
478
        $encoding = self::getEncoding($encoding);
479
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
480
            return \strlen($s);
481
        }
482
483
        return @iconv_strlen($s, $encoding);
484
    }
485
486
    public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
487
    {
488
        $encoding = self::getEncoding($encoding);
489
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
490
            return strpos($haystack, $needle, $offset);
491
        }
492
493
        $needle = (string) $needle;
494
        if ('' === $needle) {
495
            trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
496
497
            return false;
498
        }
499
500
        return iconv_strpos($haystack, $needle, $offset, $encoding);
501
    }
502
503
    public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
504
    {
505
        $encoding = self::getEncoding($encoding);
506
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
507
            return strrpos($haystack, $needle, $offset);
508
        }
509
510
        if ($offset != (int) $offset) {
511
            $offset = 0;
512
        } elseif ($offset = (int) $offset) {
513
            if ($offset < 0) {
514
                $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
515
                $offset = 0;
516
            } else {
517
                $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
518
            }
519
        }
520
521
        $pos = iconv_strrpos($haystack, $needle, $encoding);
522
523
        return false !== $pos ? $offset + $pos : false;
524
    }
525
526
    public static function mb_strtolower($s, $encoding = null)
527
    {
528
        return self::mb_convert_case($s, MB_CASE_LOWER, $encoding);
529
    }
530
531
    public static function mb_strtoupper($s, $encoding = null)
532
    {
533
        return self::mb_convert_case($s, MB_CASE_UPPER, $encoding);
534
    }
535
536
    public static function mb_substitute_character($c = null)
537
    {
538
        if (0 === strcasecmp($c, 'none')) {
539
            return true;
540
        }
541
542
        return null !== $c ? false : 'none';
543
    }
544
545
    public static function mb_substr($s, $start, $length = null, $encoding = null)
546
    {
547
        $encoding = self::getEncoding($encoding);
548
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
549
            return substr($s, $start, null === $length ? 2147483647 : $length);
550
        }
551
552
        if ($start < 0) {
553
            $start = iconv_strlen($s, $encoding) + $start;
554
            if ($start < 0) {
555
                $start = 0;
556
            }
557
        }
558
559
        if (null === $length) {
560
            $length = 2147483647;
561
        } elseif ($length < 0) {
562
            $length = iconv_strlen($s, $encoding) + $length - $start;
563
            if ($length < 0) {
564
                return '';
565
            }
566
        }
567
568
        return (string) iconv_substr($s, $start, $length, $encoding);
569
    }
570
571
    public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
572
    {
573
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
574
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
575
576
        return self::mb_strpos($haystack, $needle, $offset, $encoding);
577
    }
578
579
    public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
580
    {
581
        $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
582
583
        return self::getSubpart($pos, $part, $haystack, $encoding);
584
    }
585
586
    public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
587
    {
588
        $encoding = self::getEncoding($encoding);
589
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
590
            return strrchr($haystack, $needle, $part);
0 ignored issues
show
Unused Code introduced by
The call to strrchr() has too many arguments starting with $part. ( Ignorable by Annotation )

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

590
            return /** @scrutinizer ignore-call */ strrchr($haystack, $needle, $part);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
591
        }
592
        $needle = self::mb_substr($needle, 0, 1, $encoding);
593
        $pos = iconv_strrpos($haystack, $needle, $encoding);
594
595
        return self::getSubpart($pos, $part, $haystack, $encoding);
596
    }
597
598
    public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
599
    {
600
        $needle = self::mb_substr($needle, 0, 1, $encoding);
601
        $pos = self::mb_strripos($haystack, $needle, $encoding);
602
603
        return self::getSubpart($pos, $part, $haystack, $encoding);
604
    }
605
606
    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
607
    {
608
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
609
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
610
611
        return self::mb_strrpos($haystack, $needle, $offset, $encoding);
612
    }
613
614
    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

614
    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...
615
    {
616
        $pos = strpos($haystack, $needle);
617
        if (false === $pos) {
618
            return false;
619
        }
620
        if ($part) {
621
            return substr($haystack, 0, $pos);
622
        }
623
624
        return substr($haystack, $pos);
625
    }
626
627
    public static function mb_get_info($type = 'all')
628
    {
629
        $info = array(
630
            'internal_encoding' => self::$internalEncoding,
631
            'http_output' => 'pass',
632
            'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
633
            'func_overload' => 0,
634
            'func_overload_list' => 'no overload',
635
            'mail_charset' => 'UTF-8',
636
            'mail_header_encoding' => 'BASE64',
637
            'mail_body_encoding' => 'BASE64',
638
            'illegal_chars' => 0,
639
            'encoding_translation' => 'Off',
640
            'language' => self::$language,
641
            'detect_order' => self::$encodingList,
642
            'substitute_character' => 'none',
643
            'strict_detection' => 'Off',
644
        );
645
646
        if ('all' === $type) {
647
            return $info;
648
        }
649
        if (isset($info[$type])) {
650
            return $info[$type];
651
        }
652
653
        return false;
654
    }
655
656
    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

656
    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...
657
    {
658
        return false;
659
    }
660
661
    public static function mb_http_output($encoding = null)
662
    {
663
        return null !== $encoding ? 'pass' === $encoding : 'pass';
664
    }
665
666
    public static function mb_strwidth($s, $encoding = null)
667
    {
668
        $encoding = self::getEncoding($encoding);
669
670
        if ('UTF-8' !== $encoding) {
671
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
672
        }
673
674
        $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);
675
676
        return ($wide << 1) + iconv_strlen($s, 'UTF-8');
677
    }
678
679
    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

679
    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...
680
    {
681
        return substr_count($haystack, $needle);
682
    }
683
684
    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

684
    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...
685
    {
686
        return $contents;
687
    }
688
689
    public static function mb_chr($code, $encoding = null)
690
    {
691
        if (0x80 > $code %= 0x200000) {
692
            $s = \chr($code);
693
        } elseif (0x800 > $code) {
694
            $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
695
        } elseif (0x10000 > $code) {
696
            $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
697
        } else {
698
            $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
699
        }
700
701
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
702
            $s = mb_convert_encoding($s, $encoding, 'UTF-8');
703
        }
704
705
        return $s;
706
    }
707
708
    public static function mb_ord($s, $encoding = null)
709
    {
710
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
711
            $s = mb_convert_encoding($s, 'UTF-8', $encoding);
712
        }
713
714
        if (1 === \strlen($s)) {
715
            return \ord($s);
716
        }
717
718
        $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
719
        if (0xF0 <= $code) {
720
            return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
721
        }
722
        if (0xE0 <= $code) {
723
            return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
724
        }
725
        if (0xC0 <= $code) {
726
            return (($code - 0xC0) << 6) + $s[2] - 0x80;
727
        }
728
729
        return $code;
730
    }
731
732
    private static function getSubpart($pos, $part, $haystack, $encoding)
733
    {
734
        if (false === $pos) {
735
            return false;
736
        }
737
        if ($part) {
738
            return self::mb_substr($haystack, 0, $pos, $encoding);
739
        }
740
741
        return self::mb_substr($haystack, $pos, null, $encoding);
742
    }
743
744
    private static function html_encoding_callback(array $m)
745
    {
746
        $i = 1;
747
        $entities = '';
748
        $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
749
750
        while (isset($m[$i])) {
751
            if (0x80 > $m[$i]) {
752
                $entities .= \chr($m[$i++]);
753
                continue;
754
            }
755
            if (0xF0 <= $m[$i]) {
756
                $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
757
            } elseif (0xE0 <= $m[$i]) {
758
                $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
759
            } else {
760
                $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
761
            }
762
763
            $entities .= '&#'.$c.';';
764
        }
765
766
        return $entities;
767
    }
768
769
    private static function title_case(array $s)
770
    {
771
        return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8');
772
    }
773
774
    private static function getData($file)
775
    {
776
        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
777
            return require $file;
778
        }
779
780
        return false;
781
    }
782
783
    private static function getEncoding($encoding)
784
    {
785
        if (null === $encoding) {
786
            return self::$internalEncoding;
787
        }
788
789
        $encoding = strtoupper($encoding);
790
791
        if ('8BIT' === $encoding || 'BINARY' === $encoding) {
792
            return 'CP850';
793
        }
794
        if ('UTF8' === $encoding) {
795
            return 'UTF-8';
796
        }
797
798
        return $encoding;
799
    }
800
}
801