Completed
Push — develop ( f11ef2...d41b65 )
by David
06:01 queued 11s
created

Mbstring::mb_strripos()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 7
Ratio 100 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 4
dl 7
loc 7
rs 10
c 0
b 0
f 0
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 $s is not used and could be removed.

This check looks from 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.

This check looks from 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.

This check looks from 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.

This check looks from 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.

This check looks from 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 View Code Duplication
        if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if (null !== $encoding && !\is_scalar($encoding)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if ('UTF-8' === $encoding) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if (null !== $s && !\is_scalar($s) && !(\is_object($s) && \method_exists($s, '__toString'))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if (null !== $encoding && !\is_scalar($encoding)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if (null !== $is_hex && !\is_scalar($is_hex)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if ('UTF-8' === $encoding) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
        if ('UTF-8' === $encoding) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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.

This check looks from 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 View Code Duplication
        if (null !== $string && !\is_scalar($string) && !(\is_object($string) && \method_exists($string, '__toString'))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
            $rx = '/(';
549
            while (65535 < $split_length) {
550
                $rx .= '.{65535}';
551
                $split_length -= 65535;
552
            }
553
            $rx .= '.{'.$split_length.'})/us';
554
555
            return preg_split($rx, $string, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
556
        }
557
558
        $result = array();
559
        $length = mb_strlen($string, $encoding);
560
561
        for ($i = 0; $i < $length; $i += $split_length) {
562
            $result[] = mb_substr($string, $i, $split_length, $encoding);
563
        }
564
565
        return $result;
566
    }
567
568
    public static function mb_strtolower($s, $encoding = null)
569
    {
570
        return self::mb_convert_case($s, MB_CASE_LOWER, $encoding);
571
    }
572
573
    public static function mb_strtoupper($s, $encoding = null)
574
    {
575
        return self::mb_convert_case($s, MB_CASE_UPPER, $encoding);
576
    }
577
578
    public static function mb_substitute_character($c = null)
579
    {
580
        if (0 === strcasecmp($c, 'none')) {
581
            return true;
582
        }
583
584
        return null !== $c ? false : 'none';
585
    }
586
587
    public static function mb_substr($s, $start, $length = null, $encoding = null)
588
    {
589
        $encoding = self::getEncoding($encoding);
590
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
591
            return (string) substr($s, $start, null === $length ? 2147483647 : $length);
592
        }
593
594 View Code Duplication
        if ($start < 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
595
            $start = iconv_strlen($s, $encoding) + $start;
596
            if ($start < 0) {
597
                $start = 0;
598
            }
599
        }
600
601
        if (null === $length) {
602
            $length = 2147483647;
603 View Code Duplication
        } elseif ($length < 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
604
            $length = iconv_strlen($s, $encoding) + $length - $start;
605
            if ($length < 0) {
606
                return '';
607
            }
608
        }
609
610
        return (string) iconv_substr($s, $start, $length, $encoding);
611
    }
612
613 View Code Duplication
    public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
614
    {
615
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
616
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
617
618
        return self::mb_strpos($haystack, $needle, $offset, $encoding);
619
    }
620
621
    public static function mb_stristr($haystack, $needle, $part = false, $encoding = null)
622
    {
623
        $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
624
625
        return self::getSubpart($pos, $part, $haystack, $encoding);
626
    }
627
628
    public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null)
629
    {
630
        $encoding = self::getEncoding($encoding);
631
        if ('CP850' === $encoding || 'ASCII' === $encoding) {
632
            return strrchr($haystack, $needle, $part);
633
        }
634
        $needle = self::mb_substr($needle, 0, 1, $encoding);
635
        $pos = iconv_strrpos($haystack, $needle, $encoding);
636
637
        return self::getSubpart($pos, $part, $haystack, $encoding);
638
    }
639
640
    public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null)
641
    {
642
        $needle = self::mb_substr($needle, 0, 1, $encoding);
643
        $pos = self::mb_strripos($haystack, $needle, $encoding);
644
645
        return self::getSubpart($pos, $part, $haystack, $encoding);
646
    }
647
648 View Code Duplication
    public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
649
    {
650
        $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
651
        $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
652
653
        return self::mb_strrpos($haystack, $needle, $offset, $encoding);
654
    }
655
656
    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.

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

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

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

Loading history...
699
    {
700
        return false;
701
    }
702
703
    public static function mb_http_output($encoding = null)
704
    {
705
        return null !== $encoding ? 'pass' === $encoding : 'pass';
706
    }
707
708
    public static function mb_strwidth($s, $encoding = null)
709
    {
710
        $encoding = self::getEncoding($encoding);
711
712
        if ('UTF-8' !== $encoding) {
713
            $s = iconv($encoding, 'UTF-8//IGNORE', $s);
714
        }
715
716
        $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);
717
718
        return ($wide << 1) + iconv_strlen($s, 'UTF-8');
719
    }
720
721
    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.

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

Loading history...
722
    {
723
        return substr_count($haystack, $needle);
724
    }
725
726
    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.

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

Loading history...
727
    {
728
        return $contents;
729
    }
730
731
    public static function mb_chr($code, $encoding = null)
732
    {
733
        if (0x80 > $code %= 0x200000) {
734
            $s = \chr($code);
735
        } elseif (0x800 > $code) {
736
            $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F);
737
        } elseif (0x10000 > $code) {
738
            $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
739
        } else {
740
            $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F);
741
        }
742
743
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
744
            $s = mb_convert_encoding($s, $encoding, 'UTF-8');
745
        }
746
747
        return $s;
748
    }
749
750
    public static function mb_ord($s, $encoding = null)
751
    {
752
        if ('UTF-8' !== $encoding = self::getEncoding($encoding)) {
753
            $s = mb_convert_encoding($s, 'UTF-8', $encoding);
754
        }
755
756
        if (1 === \strlen($s)) {
757
            return \ord($s);
758
        }
759
760
        $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0;
761
        if (0xF0 <= $code) {
762
            return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80;
763
        }
764
        if (0xE0 <= $code) {
765
            return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80;
766
        }
767
        if (0xC0 <= $code) {
768
            return (($code - 0xC0) << 6) + $s[2] - 0x80;
769
        }
770
771
        return $code;
772
    }
773
774
    private static function getSubpart($pos, $part, $haystack, $encoding)
775
    {
776
        if (false === $pos) {
777
            return false;
778
        }
779
        if ($part) {
780
            return self::mb_substr($haystack, 0, $pos, $encoding);
781
        }
782
783
        return self::mb_substr($haystack, $pos, null, $encoding);
784
    }
785
786
    private static function html_encoding_callback(array $m)
787
    {
788
        $i = 1;
789
        $entities = '';
790
        $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
791
792
        while (isset($m[$i])) {
793
            if (0x80 > $m[$i]) {
794
                $entities .= \chr($m[$i++]);
795
                continue;
796
            }
797
            if (0xF0 <= $m[$i]) {
798
                $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
799
            } elseif (0xE0 <= $m[$i]) {
800
                $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
801
            } else {
802
                $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
803
            }
804
805
            $entities .= '&#'.$c.';';
806
        }
807
808
        return $entities;
809
    }
810
811
    private static function title_case(array $s)
812
    {
813
        return self::mb_convert_case($s[1], MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], MB_CASE_LOWER, 'UTF-8');
814
    }
815
816 View Code Duplication
    private static function getData($file)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
817
    {
818
        if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) {
819
            return require $file;
820
        }
821
822
        return false;
823
    }
824
825
    private static function getEncoding($encoding)
826
    {
827
        if (null === $encoding) {
828
            return self::$internalEncoding;
829
        }
830
831
        if ('UTF-8' === $encoding) {
832
            return 'UTF-8';
833
        }
834
835
        $encoding = strtoupper($encoding);
836
837
        if ('8BIT' === $encoding || 'BINARY' === $encoding) {
838
            return 'CP850';
839
        }
840
841
        if ('UTF8' === $encoding) {
842
            return 'UTF-8';
843
        }
844
845
        return $encoding;
846
    }
847
}
848