Completed
Push — master ( 534dd4...28e496 )
by Michael
46s queued 22s
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_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
    const MB_CASE_FOLD = PHP_INT_MAX;
71
72
    private static $encodingList = array('ASCII', 'UTF-8');
73
    private static $language = 'neutral';
74
    private static $internalEncoding = 'UTF-8';
75
    private static $caseFold = array(
76
        array('µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"),
77
        array('μ', 's', 'ι',        'σ', 'β',        'θ',        'φ',        'π',        'κ',        'ρ',        'ε',        "\xE1\xB9\xA1", 'ι'),
78
    );
79
80
    public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null)
81
    {
82
        if (\is_array($fromEncoding) || false !== strpos($fromEncoding, ',')) {
83
            $fromEncoding = self::mb_detect_encoding($s, $fromEncoding);
84
        } else {
85
            $fromEncoding = self::getEncoding($fromEncoding);
86
        }
87
88
        $toEncoding = self::getEncoding($toEncoding);
89
90
        if ('BASE64' === $fromEncoding) {
91
            $s = base64_decode($s);
92
            $fromEncoding = $toEncoding;
93
        }
94
95
        if ('BASE64' === $toEncoding) {
96
            return base64_encode($s);
97
        }
98
99
        if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) {
100
            if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) {
101
                $fromEncoding = 'Windows-1252';
102
            }
103
            if ('UTF-8' !== $fromEncoding) {
104
                $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s);
105
            }
106
107
            return preg_replace_callback('/[\x80-\xFF]+/', array(__CLASS__, 'html_encoding_callback'), $s);
108
        }
109
110
        if ('HTML-ENTITIES' === $fromEncoding) {
111
            $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8');
112
            $fromEncoding = 'UTF-8';
113
        }
114
115
        return iconv($fromEncoding, $toEncoding.'//IGNORE', $s);
116
    }
117
118
    public static function mb_convert_variables($toEncoding, $fromEncoding, &$a = null, &$b = null, &$c = null, &$d = null, &$e = null, &$f = null)
119
    {
120
        $vars = array(&$a, &$b, &$c, &$d, &$e, &$f);
121
122
        $ok = true;
123
        array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) {
124
            if (false === $v = Mbstring::mb_convert_encoding($v, $toEncoding, $fromEncoding)) {
125
                $ok = false;
126
            }
127
        });
128
129
        return $ok ? $fromEncoding : false;
130
    }
131
132
    public static function mb_decode_mimeheader($s)
133
    {
134
        return iconv_mime_decode($s, 2, self::$internalEncoding);
135
    }
136
137
    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 $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

137
    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

137
    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 $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

137
    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 $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

137
    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 $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

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

412
    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...
413
    {
414
        if (null === $encodingList) {
415
            $encodingList = self::$encodingList;
416
        } else {
417
            if (!\is_array($encodingList)) {
418
                $encodingList = array_map('trim', explode(',', $encodingList));
419
            }
420
            $encodingList = array_map('strtoupper', $encodingList);
421
        }
422
423
        foreach ($encodingList as $enc) {
424
            switch ($enc) {
425
                case 'ASCII':
426
                    if (!preg_match('/[\x80-\xFF]/', $str)) {
427
                        return $enc;
428
                    }
429
                    break;
430
431
                case 'UTF8':
432
                case 'UTF-8':
433
                    if (preg_match('//u', $str)) {
434
                        return 'UTF-8';
435
                    }
436
                    break;
437
438
                default:
439
                    if (0 === strncmp($enc, 'ISO-8859-', 9)) {
440
                        return $enc;
441
                    }
442
            }
443
        }
444
445
        return false;
446
    }
447
448
    public static function mb_detect_order($encodingList = null)
449
    {
450
        if (null === $encodingList) {
451
            return self::$encodingList;
452
        }
453
454
        if (!\is_array($encodingList)) {
455
            $encodingList = array_map('trim', explode(',', $encodingList));
456
        }
457
        $encodingList = array_map('strtoupper', $encodingList);
458
459
        foreach ($encodingList as $enc) {
460
            switch ($enc) {
461
                default:
462
                    if (strncmp($enc, 'ISO-8859-', 9)) {
463
                        return false;
464
                    }
465
                    // no break
466
                case 'ASCII':
467
                case 'UTF8':
468
                case 'UTF-8':
469
            }
470
        }
471
472
        self::$encodingList = $encodingList;
473
474
        return true;
475
    }
476
477
    public static function mb_strlen($s, $encoding = null)
478
    {
479
        $encoding = self::getEncoding($encoding);
480
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
481
            return \strlen($s);
482
        }
483
484
        return @iconv_strlen($s, $encoding);
485
    }
486
487
    public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null)
488
    {
489
        $encoding = self::getEncoding($encoding);
490
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
491
            return strpos($haystack, $needle, $offset);
492
        }
493
494
        $needle = (string) $needle;
495
        if ('' === $needle) {
496
            trigger_error(__METHOD__.': Empty delimiter', E_USER_WARNING);
497
498
            return false;
499
        }
500
501
        return iconv_strpos($haystack, $needle, $offset, $encoding);
502
    }
503
504
    public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null)
505
    {
506
        $encoding = self::getEncoding($encoding);
507
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
508
            return strrpos($haystack, $needle, $offset);
509
        }
510
511
        if ($offset != (int) $offset) {
512
            $offset = 0;
513
        } elseif ($offset = (int) $offset) {
514
            if ($offset < 0) {
515
                if (0 > $offset += self::mb_strlen($needle)) {
516
                    $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
517
                }
518
                $offset = 0;
519
            } else {
520
                $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
521
            }
522
        }
523
524
        $pos = iconv_strrpos($haystack, $needle, $encoding);
525
526
        return false !== $pos ? $offset + $pos : false;
527
    }
528
529
    public static function mb_str_split($string, $split_length = 1, $encoding = null)
530
    {
531
        if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) {
532
            trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', E_USER_WARNING);
533
534
            return null;
535
        }
536
537
        if (1 > $split_length = (int) $split_length) {
538
            trigger_error('The length of each segment must be greater than zero', E_USER_WARNING);
539
540
            return false;
541
        }
542
543
        if (null === $encoding) {
544
            $encoding = mb_internal_encoding();
545
        }
546
547
        if ('UTF-8' === $encoding = self::getEncoding($encoding)) {
548
            return preg_split("/(.{{$split_length}})/u", $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
549
        }
550
551
        $result = array();
552
        $length = mb_strlen($string, $encoding);
553
554
        for ($i = 0; $i < $length; $i += $split_length) {
555
            $result[] = mb_substr($string, $i, $split_length, $encoding);
556
        }
557
558
        return $result;
559
    }
560
561
    public static function mb_strtolower($s, $encoding = null)
562
    {
563
        return self::mb_convert_case($s, MB_CASE_LOWER, $encoding);
564
    }
565
566
    public static function mb_strtoupper($s, $encoding = null)
567
    {
568
        return self::mb_convert_case($s, MB_CASE_UPPER, $encoding);
569
    }
570
571
    public static function mb_substitute_character($c = null)
572
    {
573
        if (0 === strcasecmp($c, 'none')) {
574
            return true;
575
        }
576
577
        return null !== $c ? false : 'none';
578
    }
579
580
    public static function mb_substr($s, $start, $length = null, $encoding = null)
581
    {
582
        $encoding = self::getEncoding($encoding);
583
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
584
            return (string) substr($s, $start, null === $length ? 2147483647 : $length);
585
        }
586
587
        if ($start < 0) {
588
            $start = iconv_strlen($s, $encoding) + $start;
589
            if ($start < 0) {
590
                $start = 0;
591
            }
592
        }
593
594
        if (null === $length) {
595
            $length = 2147483647;
596
        } elseif ($length < 0) {
597
            $length = iconv_strlen($s, $encoding) + $length - $start;
598
            if ($length < 0) {
599
                return '';
600
            }
601
        }
602
603
        return (string) iconv_substr($s, $start, $length, $encoding);
604
    }
605
606
    public static function mb_stripos($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_strpos($haystack, $needle, $offset, $encoding);
612
    }
613
614
    public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
615
    {
616
        $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
617
618
        return self::getSubpart($pos, $part, $haystack, $encoding);
619
    }
620
621
    public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
622
    {
623
        $encoding = self::getEncoding($encoding);
624
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
625
            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

625
            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...
626
        }
627
        $needle = self::mb_substr($needle, 0, 1, $encoding);
628
        $pos = iconv_strrpos($haystack, $needle, $encoding);
629
630
        return self::getSubpart($pos, $part, $haystack, $encoding);
631
    }
632
633
    public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
634
    {
635
        $needle = self::mb_substr($needle, 0, 1, $encoding);
636
        $pos = self::mb_strripos($haystack, $needle, $encoding);
637
638
        return self::getSubpart($pos, $part, $haystack, $encoding);
639
    }
640
641
    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
642
    {
643
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
644
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
645
646
        return self::mb_strrpos($haystack, $needle, $offset, $encoding);
647
    }
648
649
    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

649
    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...
650
    {
651
        $pos = strpos($haystack, $needle);
652
        if (false === $pos) {
653
            return false;
654
        }
655
        if ($part) {
656
            return substr($haystack, 0, $pos);
657
        }
658
659
        return substr($haystack, $pos);
660
    }
661
662
    public static function mb_get_info($type = 'all')
663
    {
664
        $info = array(
665
            'internal_encoding' => self::$internalEncoding,
666
            'http_output' => 'pass',
667
            'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
668
            'func_overload' => 0,
669
            'func_overload_list' => 'no overload',
670
            'mail_charset' => 'UTF-8',
671
            'mail_header_encoding' => 'BASE64',
672
            'mail_body_encoding' => 'BASE64',
673
            'illegal_chars' => 0,
674
            'encoding_translation' => 'Off',
675
            'language' => self::$language,
676
            'detect_order' => self::$encodingList,
677
            'substitute_character' => 'none',
678
            'strict_detection' => 'Off',
679
        );
680
681
        if ('all' === $type) {
682
            return $info;
683
        }
684
        if (isset($info[$type])) {
685
            return $info[$type];
686
        }
687
688
        return false;
689
    }
690
691
    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

691
    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...
692
    {
693
        return false;
694
    }
695
696
    public static function mb_http_output($encoding = null)
697
    {
698
        return null !== $encoding ? 'pass' === $encoding : 'pass';
699
    }
700
701
    public static function mb_strwidth($s, $encoding = null)
702
    {
703
        $encoding = self::getEncoding($encoding);
704
705
        if ('UTF-8' !== $encoding) {
706
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
707
        }
708
709
        $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);
710
711
        return ($wide << 1) + iconv_strlen($s, 'UTF-8');
712
    }
713
714
    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

714
    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...
715
    {
716
        return substr_count($haystack, $needle);
717
    }
718
719
    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

719
    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...
720
    {
721
        return $contents;
722
    }
723
724
    public static function mb_chr($code, $encoding = null)
725
    {
726
        if (0x80 > $code %= 0x200000) {
727
            $s = \chr($code);
728
        } elseif (0x800 > $code) {
729
            $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
730
        } elseif (0x10000 > $code) {
731
            $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
732
        } else {
733
            $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
734
        }
735
736
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
737
            $s = mb_convert_encoding($s, $encoding, 'UTF-8');
738
        }
739
740
        return $s;
741
    }
742
743
    public static function mb_ord($s, $encoding = null)
744
    {
745
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
746
            $s = mb_convert_encoding($s, 'UTF-8', $encoding);
747
        }
748
749
        if (1 === \strlen($s)) {
750
            return \ord($s);
751
        }
752
753
        $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
754
        if (0xF0 <= $code) {
755
            return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
756
        }
757
        if (0xE0 <= $code) {
758
            return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
759
        }
760
        if (0xC0 <= $code) {
761
            return (($code - 0xC0) << 6) + $s[2] - 0x80;
762
        }
763
764
        return $code;
765
    }
766
767
    private static function getSubpart($pos, $part, $haystack, $encoding)
768
    {
769
        if (false === $pos) {
770
            return false;
771
        }
772
        if ($part) {
773
            return self::mb_substr($haystack, 0, $pos, $encoding);
774
        }
775
776
        return self::mb_substr($haystack, $pos, null, $encoding);
777
    }
778
779
    private static function html_encoding_callback(array $m)
780
    {
781
        $i = 1;
782
        $entities = '';
783
        $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
784
785
        while (isset($m[$i])) {
786
            if (0x80 > $m[$i]) {
787
                $entities .= \chr($m[$i++]);
788
                continue;
789
            }
790
            if (0xF0 <= $m[$i]) {
791
                $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
792
            } elseif (0xE0 <= $m[$i]) {
793
                $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
794
            } else {
795
                $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
796
            }
797
798
            $entities .= '&#'.$c.';';
799
        }
800
801
        return $entities;
802
    }
803
804
    private static function title_case(array $s)
805
    {
806
        return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8');
807
    }
808
809
    private static function getData($file)
810
    {
811
        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
812
            return require $file;
813
        }
814
815
        return false;
816
    }
817
818
    private static function getEncoding($encoding)
819
    {
820
        if (null === $encoding) {
821
            return self::$internalEncoding;
822
        }
823
824
        if ('UTF-8' === $encoding) {
825
            return 'UTF-8';
826
        }
827
828
        $encoding = strtoupper($encoding);
829
830
        if ('8BIT' === $encoding || 'BINARY' === $encoding) {
831
            return 'CP850';
832
        }
833
834
        if ('UTF8' === $encoding) {
835
            return 'UTF-8';
836
        }
837
838
        return $encoding;
839
    }
840
}
841