Test Failed
Push — master ( 398493...d4ef72 )
by Michael
11: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
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
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 anothers
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)) {
0 ignored issues
show
introduced by
The condition false === $v = Symfony\P...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
            return null;
146
        }
147
148
        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...
149
            return false;
150
        }
151
152
        if (null !== $encoding && !\is_scalar($encoding)) {
153
            trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
154
            return '';  // Instead of null (cf. mb_encode_numericentity).
155
        }
156
157
        $s = (string) $s;
158
        if ('' === $s) {
159
            return '';
160
        }
161
162
        $encoding = self::getEncoding($encoding);
163
164
        if ('UTF-8' === $encoding) {
165
            $encoding = null;
166
            if (!preg_match('//u', $s)) {
167
                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
168
            }
169
        } else {
170
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
171
        }
172
173
        $cnt = floor(\count($convmap) / 4) * 4;
174
175
        for ($i = 0; $i < $cnt; $i += 4) {
176
            // collector_decode_htmlnumericentity ignores $convmap[$i + 3]
177
            $convmap[$i] += $convmap[$i + 2];
178
            $convmap[$i + 1] += $convmap[$i + 2];
179
        }
180
181
        $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) {
182
            $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1];
183
            for ($i = 0; $i < $cnt; $i += 4) {
184
                if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) {
185
                    return Mbstring::mb_chr($c - $convmap[$i + 2]);
186
                }
187
            }
188
            return $m[0];
189
        }, $s);
190
191
        if (null === $encoding) {
192
            return $s;
193
        }
194
195
        return iconv('UTF-8', $encoding.'//IGNORE', $s);
196
    }
197
198
    public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false)
199
    {
200
        if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
201
            trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.gettype($s).' given', E_USER_WARNING);
202
            return null;
203
        }
204
205
        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...
206
            return false;
207
        }
208
209
        if (null !== $encoding && !\is_scalar($encoding)) {
210
            trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.gettype($s).' given', E_USER_WARNING);
211
            return null;  // Instead of '' (cf. mb_decode_numericentity).
212
        }
213
214
        if (null !== $is_hex && !\is_scalar($is_hex)) {
215
            trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.gettype($s).' given', E_USER_WARNING);
216
            return null;
217
        }
218
219
        $s = (string) $s;
220
        if ('' === $s) {
221
            return '';
222
        }
223
224
        $encoding = self::getEncoding($encoding);
225
226
        if ('UTF-8' === $encoding) {
227
            $encoding = null;
228
            if (!preg_match('//u', $s)) {
229
                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
230
            }
231
        } else {
232
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
233
        }
234
235
        static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
236
237
        $cnt = floor(\count($convmap) / 4) * 4;
238
        $i = 0;
239
        $len = \strlen($s);
240
        $result = '';
241
242
        while ($i < $len) {
243
            $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
244
            $uchr = substr($s, $i, $ulen);
245
            $i += $ulen;
246
            $c = self::mb_ord($uchr);
247
248
            for ($j = 0; $j < $cnt; $j += 4) {
249
                if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) {
250
                    $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3];
251
                    $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';';
252
                    continue 2;
253
                }
254
            }
255
            $result .= $uchr;
256
        }
257
258
        if (null === $encoding) {
259
            return $result;
260
        }
261
262
        return iconv('UTF-8', $encoding.'//IGNORE', $result);
263
    }
264
265
    public static function mb_convert_case($s, $mode, $encoding = null)
266
    {
267
        $s = (string) $s;
268
        if ('' === $s) {
269
            return '';
270
        }
271
272
        $encoding = self::getEncoding($encoding);
273
274
        if ('UTF-8' === $encoding) {
275
            $encoding = null;
276
            if (!preg_match('//u', $s)) {
277
                $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s);
278
            }
279
        } else {
280
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
281
        }
282
283
        if (MB_CASE_TITLE == $mode) {
284
            $s = preg_replace_callback('/\b\p{Ll}/u', array(__CLASS__, 'title_case_upper'), $s);
285
            $s = preg_replace_callback('/\B[\p{Lu}\p{Lt}]+/u', array(__CLASS__, 'title_case_lower'), $s);
286
        } else {
287
            if (MB_CASE_UPPER == $mode) {
288
                static $upper = null;
289
                if (null === $upper) {
290
                    $upper = self::getData('upperCase');
291
                }
292
                $map = $upper;
293
            } else {
294
                if (self::MB_CASE_FOLD === $mode) {
295
                    $s = str_replace(self::$caseFold[0], self::$caseFold[1], $s);
296
                }
297
298
                static $lower = null;
299
                if (null === $lower) {
300
                    $lower = self::getData('lowerCase');
301
                }
302
                $map = $lower;
303
            }
304
305
            static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4);
306
307
            $i = 0;
308
            $len = \strlen($s);
309
310
            while ($i < $len) {
311
                $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"];
312
                $uchr = substr($s, $i, $ulen);
313
                $i += $ulen;
314
315
                if (isset($map[$uchr])) {
316
                    $uchr = $map[$uchr];
317
                    $nlen = \strlen($uchr);
318
319
                    if ($nlen == $ulen) {
320
                        $nlen = $i;
321
                        do {
322
                            $s[--$nlen] = $uchr[--$ulen];
323
                        } while ($ulen);
324
                    } else {
325
                        $s = substr_replace($s, $uchr, $i - $ulen, $ulen);
326
                        $len += $nlen - $ulen;
327
                        $i   += $nlen - $ulen;
328
                    }
329
                }
330
            }
331
        }
332
333
        if (null === $encoding) {
334
            return $s;
335
        }
336
337
        return iconv('UTF-8', $encoding.'//IGNORE', $s);
338
    }
339
340
    public static function mb_internal_encoding($encoding = null)
341
    {
342
        if (null === $encoding) {
343
            return self::$internalEncoding;
344
        }
345
346
        $encoding = self::getEncoding($encoding);
347
348
        if ('UTF-8' === $encoding || false !== @iconv($encoding, $encoding, ' ')) {
349
            self::$internalEncoding = $encoding;
350
351
            return true;
352
        }
353
354
        return false;
355
    }
356
357
    public static function mb_language($lang = null)
358
    {
359
        if (null === $lang) {
360
            return self::$language;
361
        }
362
363
        switch ($lang = strtolower($lang)) {
364
            case 'uni':
365
            case 'neutral':
366
                self::$language = $lang;
367
368
                return true;
369
        }
370
371
        return false;
372
    }
373
374
    public static function mb_list_encodings()
375
    {
376
        return array('UTF-8');
377
    }
378
379
    public static function mb_encoding_aliases($encoding)
380
    {
381
        switch (strtoupper($encoding)) {
382
            case 'UTF8':
383
            case 'UTF-8':
384
                return array('utf8');
385
        }
386
387
        return false;
388
    }
389
390
    public static function mb_check_encoding($var = null, $encoding = null)
391
    {
392
        if (null === $encoding) {
393
            if (null === $var) {
394
                return false;
395
            }
396
            $encoding = self::$internalEncoding;
397
        }
398
399
        return self::mb_detect_encoding($var, array($encoding)) || false !== @iconv($encoding, $encoding, $var);
400
    }
401
402
    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

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

580
            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...
581
        }
582
        $needle = self::mb_substr($needle, 0, 1, $encoding);
583
        $pos = iconv_strrpos($haystack, $needle, $encoding);
584
585
        return self::getSubpart($pos, $part, $haystack, $encoding);
586
    }
587
588
    public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
589
    {
590
        $needle = self::mb_substr($needle, 0, 1, $encoding);
591
        $pos = self::mb_strripos($haystack, $needle, $encoding);
592
593
        return self::getSubpart($pos, $part, $haystack, $encoding);
594
    }
595
596
    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
597
    {
598
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
599
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
600
601
        return self::mb_strrpos($haystack, $needle, $offset, $encoding);
602
    }
603
604
    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

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

646
    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...
647
    {
648
        return false;
649
    }
650
651
    public static function mb_http_output($encoding = null)
652
    {
653
        return null !== $encoding ? 'pass' === $encoding : 'pass';
654
    }
655
656
    public static function mb_strwidth($s, $encoding = null)
657
    {
658
        $encoding = self::getEncoding($encoding);
659
660
        if ('UTF-8' !== $encoding) {
661
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
662
        }
663
664
        $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);
665
666
        return ($wide << 1) + iconv_strlen($s, 'UTF-8');
667
    }
668
669
    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

669
    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...
670
    {
671
        return substr_count($haystack, $needle);
672
    }
673
674
    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

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