Completed
Push — master ( 302154...8eae75 )
by Lars
04:23
created

Mbstring::mb_encode_mimeheader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1.037

Importance

Changes 2
Bugs 0 Features 1
Metric Value
dl 0
loc 5
c 2
b 0
f 1
ccs 2
cts 3
cp 0.6667
rs 9.4286
cc 1
eloc 3
nc 1
nop 5
crap 1.037
1
<?php
2
3
/*
4
 * Copyright (C) 2013 Nicolas Grekas - [email protected]
5
 *
6
 * This library is free software; you can redistribute it and/or modify it
7
 * under the terms of the (at your option):
8
 * Apache License v2.0 (http://apache.org/licenses/LICENSE-2.0.txt), or
9
 * GNU General Public License v2.0 (http://gnu.org/licenses/gpl-2.0.txt).
10
 */
11
12
namespace voku\helper\shim;
13
14
/**
15
 * Partial mbstring implementation in PHP, iconv based, UTF-8 centric.
16
 *
17
 * Implemented:
18
 * - mb_convert_encoding     - Convert character encoding
19
 * - mb_decode_mimeheader    - Decode string in MIME header field
20
 * - mb_encode_mimeheader    - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED
21
 * - mb_convert_case         - Perform case folding on a string
22
 * - mb_get_info             - Get internal settings of mbstring
23
 * - mb_http_input           - Detect HTTP input character encoding
24
 * - mb_http_output          - Set/Get HTTP output character encoding
25
 * - mb_internal_encoding    - Set/Get internal character encoding
26
 * - mb_list_encodings       - Returns an array of all supported encodings
27
 * - mb_output_handler       - Callback function converts character encoding in output buffer
28
 * - mb_strlen               - Get string length
29
 * - mb_strpos               - Find position of first occurrence of string in a string
30
 * - mb_strrpos              - Find position of last occurrence of a string in a string
31
 * - mb_strtolower           - Make a string lowercase
32
 * - mb_strtoupper           - Make a string uppercase
33
 * - mb_substitute_character - Set/Get substitution character
34
 * - mb_substr               - Get part of string
35
 * - mb_stripos              - Finds position of first occurrence of a string within another, case insensitive
36
 * - mb_stristr              - Finds first occurrence of a string within another, case insensitive
37
 * - mb_strrchr              - Finds the last occurrence of a character in a string within another
38
 * - mb_strrichr             - Finds the last occurrence of a character in a string within another, case insensitive
39
 * - mb_strripos             - Finds position of last occurrence of a string within another, case insensitive
40
 * - mb_strstr               - Finds first occurrence of a string within anothers
41
 * - mb_strwidth             - Return width of string
42
 * - mb_substr_count         - Count the number of substring occurrences
43
 *
44
 * Not implemented:
45
 * - mb_convert_kana         - Convert "kana" one from another ("zen-kaku", "han-kaku" and more)
46
 * - mb_convert_variables    - Convert character code in variable(s)
47
 * - mb_decode_numericentity - Decode HTML numeric string reference to character
48
 * - mb_encode_numericentity - Encode character to HTML numeric string reference
49
 * - mb_ereg_*               - Regular expression with multibyte support
50
 * - mb_parse_str            - Parse GET/POST/COOKIE data and set global variable
51
 * - mb_preferred_mime_name  - Get MIME charset string
52
 * - mb_regex_encoding       - Returns current encoding for multibyte regex as string
53
 * - mb_regex_set_options    - Set/Get the default options for mbregex functions
54
 * - mb_send_mail            - Send encoded mail
55
 * - mb_split                - Split multibyte string using regular expression
56
 * - mb_strcut               - Get part of string
57
 * - mb_strimwidth           - Get truncated string with specified width
58
 *
59
 * @package voku\helper\shim
60
 */
61
class Mbstring
62
{
63
  const MB_CASE_FOLD = PHP_INT_MAX;
64
65
  protected static $encoding_list = array(
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
66
      'ASCII',
67
      'UTF-8',
68
  ),
69
70
    /**
71
     * @var string
72
     */
73
      $language = 'neutral',
74
75
    /**
76
     * @var string
77
     */
78
      $internal_encoding = 'UTF-8',
79
80
    /**
81
     * @var array
82
     */
83
      $caseFold = array(
84
      array(
85
          'µ',
86
          'ſ',
87
          "\xCD\x85",
88
          'ς',
89
          "\xCF\x90",
90
          "\xCF\x91",
91
          "\xCF\x95",
92
          "\xCF\x96",
93
          "\xCF\xB0",
94
          "\xCF\xB1",
95
          "\xCF\xB5",
96
          "\xE1\xBA\x9B",
97
          "\xE1\xBE\xBE",
98
      ),
99
      array(
100
          'μ',
101
          's',
102
          'ι',
103
          'σ',
104
          'β',
105
          'θ',
106
          'φ',
107
          'π',
108
          'κ',
109
          'ρ',
110
          'ε',
111
          "\xE1\xB9\xA1",
112
          'ι',
113
      ),
114
  );
115
116
  /**
117
   * @param string $str
118
   * @param string $to_encoding
119
   * @param string $from_encoding
120
   *
121
   * @return string|false
122
   */
123 1
  public static function mb_convert_encoding($str, $to_encoding, $from_encoding = INF)
124
  {
125 1
    INF === $from_encoding && $from_encoding = self::$internal_encoding;
126
127
    if (
128 1
        is_array($from_encoding)
129
        ||
130 1
        false !== strpos($from_encoding, ',')
131
    ) {
132 1
      $from_encoding = self::mb_detect_encoding($str, $from_encoding);
133
    }
134
135 1
    $from_encoding = strtolower($from_encoding);
136 1
    $to_encoding = strtolower($to_encoding);
137
138 1
    if ('base64' === $from_encoding) {
139 1
      $str = base64_decode($str);
140 1
      $from_encoding = $to_encoding;
141
    }
142
143 1
    if ('base64' === $to_encoding) {
144 1
      return base64_encode($str);
145
    }
146
147 1
    if ('html-entities' === $to_encoding) {
148 1
      'html-entities' === $from_encoding && $from_encoding = 'Windows-1252';
149
150 1
      'utf-8' === $from_encoding
151
      ||
152
      'utf8' === $from_encoding
153
      ||
154
      $str = iconv($from_encoding, 'UTF-8//IGNORE', $str);
155
156 1
      return preg_replace_callback(
157 1
          '/[\x80-\xFF]+/',
158
          array(
159 1
              __CLASS__,
160
              'html_encoding_callback',
161
          ),
162
          $str
163
      );
164
    }
165
166 1
    if ('html-entities' === $from_encoding) {
167 1
      $str = html_entity_decode($str, ENT_COMPAT, 'UTF-8');
168 1
      $from_encoding = 'UTF-8';
169
    }
170
171 1
    return iconv($from_encoding, $to_encoding . '//IGNORE', $str);
172
  }
173
174
  /**
175
   * @param string $str
176
   *
177
   * @return bool|string
178
   */
179
  public static function mb_decode_mimeheader($str)
180
  {
181
    return iconv_mime_decode($str, 2, self::$internal_encoding . '//IGNORE');
182
  }
183
184
  /**
185
   * @param $str
186
   * @param $charset
187
   * @param $transfer_encoding
188
   * @param $linefeed
189
   * @param $indent
190
   */
191 1
  public static function mb_encode_mimeheader(/** @noinspection PhpUnusedParameterInspection */
192
      $str, $charset = INF, $transfer_encoding = INF, $linefeed = INF, $indent = INF)
0 ignored issues
show
Unused Code introduced by
The parameter $str 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 $transfer_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...
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...
193
  {
194 1
    user_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', E_USER_WARNING);
195
  }
196
197
  /**
198
   * @param string $encoding
199
   *
200
   * @return bool|string
201
   */
202 1
  public static function mb_internal_encoding($encoding = INF)
203
  {
204 1
    if (INF === $encoding) {
205 1
      return self::$internal_encoding;
206
    } else {
207 1
      $encoding = strtoupper($encoding);
208
    }
209
210
    /** @noinspection PhpUsageOfSilenceOperatorInspection */
211
    if (
212 1
        'UTF-8' === $encoding
213
        ||
214 1
        'UTF8' === $encoding
215
        ||
216 1
        false !== @iconv($encoding, $encoding, ' ')
217
    ) {
218
219 1
      if ('UTF8' === $encoding) {
220 1
        self::$internal_encoding = 'UTF-8';
221
      } else {
222
        self::$internal_encoding = $encoding;
223
      }
224
225 1
      return true;
226
    }
227
228 1
    return false;
229
  }
230
231
  /**
232
   * @param string $lang
233
   *
234
   * @return bool|string
235
   */
236 1
  public static function mb_language($lang = INF)
237
  {
238 1
    if (INF === $lang) {
239 1
      return self::$language;
240
    }
241
242 1
    switch ($lang = strtolower($lang)) {
243
      case 'uni':
244 1
      case 'neutral':
245 1
        self::$language = $lang;
246
247 1
        return true;
248
    }
249
250 1
    return false;
251
  }
252
253
  /**
254
   * @return string[]
255
   */
256 1
  public static function mb_list_encodings()
257
  {
258 1
    return array('UTF-8');
259
  }
260
261
  /**
262
   * @param string $encoding
263
   *
264
   * @return array|bool
265
   */
266 1
  public static function mb_encoding_aliases($encoding)
267
  {
268 1
    switch (strtolower($encoding)) {
269
      case 'utf8':
270 1
      case 'utf-8':
271 1
        return array('utf8');
272
    }
273
274 1
    return false;
275
  }
276
277
  /**
278
   * @param string $var
279
   * @param string $encoding
280
   *
281
   * @return bool
282
   */
283 1
  public static function mb_check_encoding($var = INF, $encoding = INF)
284
  {
285 1
    if (INF === $encoding) {
286 1
      if (INF === $var) {
287 1
        return false;
288
      }
289
      $encoding = self::$internal_encoding;
290
    }
291
292 1
    return false !== mb_detect_encoding($var, array($encoding), true);
293
  }
294
295
  /**
296
   * @param string       $str
297
   * @param string|array $encoding_list
298
   * @param bool         $strict
299
   *
300
   * @return bool
301
   */
302 2
  public static function mb_detect_encoding($str, $encoding_list = INF, /** @noinspection PhpUnusedParameterInspection */
303
                                            $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...
304
  {
305 2
    if (INF === $encoding_list) {
306 1
      $encoding_list = self::$encoding_list;
307
    } else {
308 2
      if (!is_array($encoding_list)) {
309 2
        $encoding_list = array_map('trim', explode(',', $encoding_list));
310
      }
311 2
      $encoding_list = array_map('strtoupper', $encoding_list);
312
    }
313
314 2
    foreach ($encoding_list as $enc) {
315
      switch ($enc) {
316 2
        case 'ASCII':
317 2
          if (!preg_match('/[\x80-\xFF]/', $str)) {
318 1
            return $enc;
319
          }
320 2
          break;
321
322
        case 'UTF8':
323 2
        case 'UTF-8':
324 2
          if (preg_match('//u', $str)) {
325 1
            return $enc;
326
          }
327 2
          break;
328
329
        default:
330 2
          if (0 === strncmp($enc, 'ISO-8859-', 9)) {
331 2
            return $enc;
332
          }
333
      }
334
    }
335
336
    return false;
337
  }
338
339
  /**
340
   * @param string|array $encoding_list
341
   *
342
   * @return array|bool
343
   */
344 1
  public static function mb_detect_order($encoding_list = INF)
345
  {
346 1
    if (INF === $encoding_list) {
347 1
      return self::$encoding_list;
348
    }
349
350 1
    if (!is_array($encoding_list)) {
351 1
      $encoding_list = array_map('trim', explode(',', $encoding_list));
352
    }
353 1
    $encoding_list = array_map('strtoupper', $encoding_list);
354
355 1
    foreach ($encoding_list as $enc) {
356
      switch ($enc) {
357
        default:
358
          if (strncmp($enc, 'ISO-8859-', 9)) {
359
            return false;
360
          }
361 1
        case 'ASCII':
362
        case 'UTF8':
363 1
        case 'UTF-8':
364
      }
365
    }
366
367 1
    self::$encoding_list = $encoding_list;
368
369 1
    return true;
370
  }
371
372
  /**
373
   * @param string $str
374
   * @param string $encoding
375
   *
376
   * @return bool|int
377
   */
378 1
  public static function mb_strlen($str, $encoding = INF)
379
  {
380 1
    INF === $encoding && $encoding = self::$internal_encoding;
381
382 1
    return iconv_strlen($str, $encoding . '//IGNORE');
383
  }
384
385
  /**
386
   * @param string $str
387
   * @param string $encoding
388
   *
389
   * @return bool|mixed|string
390
   */
391 1
  public static function mb_strtolower($str, $encoding = INF)
392
  {
393 1
    return self::mb_convert_case($str, MB_CASE_LOWER, $encoding);
394
  }
395
396
  /**
397
   * @param string $str
398
   * @param int    $mode
399
   * @param string $encoding
400
   *
401
   * @return bool|mixed|string
402
   */
403 3
  public static function mb_convert_case($str, $mode, $encoding = INF)
404
  {
405 3
    if ('' === $str .= '') {
406
      return '';
407
    }
408
409 3
    if (INF === $encoding) {
410 1
      $encoding = self::$internal_encoding;
411
    } else {
412 3
      $encoding = strtoupper($encoding);
413
    }
414
415 3
    if ('UTF-8' === $encoding || 'UTF8' === $encoding) {
416 3
      $encoding = INF;
417
    } else {
418
      $str = iconv($encoding, 'UTF-8//IGNORE', $str);
419
    }
420
421 3
    if (MB_CASE_TITLE == $mode) {
422 1
      $str = preg_replace_callback(
423 1
          '/\b\p{Ll}/u',
424
          array(
425 1
              __CLASS__,
426
              'title_case_upper',
427
          ),
428
          $str
429
      );
430 1
      $str = preg_replace_callback(
431 1
          '/\B[\p{Lu}\p{Lt}]+/u',
432
          array(
433 1
              __CLASS__,
434
              'title_case_lower',
435
          ),
436
          $str
437
      );
438
    } else {
439 3
      if (MB_CASE_UPPER == $mode) {
440 1
        static $upper;
441 1
        isset($upper) || $upper = static::getData('upperCase');
442 1
        $map = $upper;
443
      } else {
444 3
        if (self::MB_CASE_FOLD === $mode) {
445 2
          $str = str_replace(self::$caseFold[0], self::$caseFold[1], $str);
446
        }
447
448 3
        static $lower;
449 3
        isset($lower) || $lower = static::getData('lowerCase');
450 3
        $map = $lower;
451
      }
452
453 3
      static $ulen_mask = array(
454
          "\xC0" => 2,
455
          "\xD0" => 2,
456
          "\xE0" => 3,
457
          "\xF0" => 4,
458
      );
459
460 3
      $i = 0;
461 3
      $len = strlen($str);
462
463 3
      while ($i < $len) {
464
465 3
        if ($str[$i] < "\x80") {
466 3
          $ulen = 1;
467
        } else {
468 3
          $ulen = $ulen_mask[$str[$i] & "\xF0"];
469
        }
470
471 3
        $uchr = substr($str, $i, $ulen);
472 3
        $i += $ulen;
473
474 3
        if (isset($map[$uchr])) {
475 3
          $uchr = $map[$uchr];
476 3
          $nlen = strlen($uchr);
477
478 3
          if ($nlen == $ulen) {
479 3
            $nlen = $i;
480
            do {
481 3
              $str[--$nlen] = $uchr[--$ulen];
482 3
            } while ($ulen);
483
          } else {
484 1
            $str = substr_replace($str, $uchr, $i - $ulen, $ulen);
485 1
            $len += $nlen - $ulen;
486 1
            $i += $nlen - $ulen;
487
          }
488
        }
489
      }
490
    }
491
492 3
    if (INF === $encoding) {
493 3
      return $str;
494
    } else {
495
      return iconv('UTF-8', $encoding, $str);
496
    }
497
  }
498
499
  /**
500
   * get data
501
   *
502
   * @param string $file
503
   *
504
   * @return bool|mixed
505
   */
506 1 View Code Duplication
  protected 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...
507
  {
508 1
    $file = __DIR__ . '/unidata/' . $file . '.ser';
509 1
    if (file_exists($file)) {
510 1
      return unserialize(file_get_contents($file));
511
    } else {
512
      return false;
513
    }
514
  }
515
516
  /**
517
   * @param string $str
518
   * @param string $encoding
519
   *
520
   * @return bool|mixed|string
521
   */
522 1
  public static function mb_strtoupper($str, $encoding = INF)
523
  {
524 1
    return self::mb_convert_case($str, MB_CASE_UPPER, $encoding);
525
  }
526
527
  /**
528
   * @param string $char
529
   *
530
   * @return false|string
531
   */
532 1
  public static function mb_substitute_character($char = INF)
533
  {
534 1
    if (INF !== $char) {
535 1
      return false;
536
    } else {
537 1
      return 'none';
538
    }
539
  }
540
541
  /**
542
   * @param string $haystack
543
   * @param string $needle
544
   * @param bool   $part
545
   * @param string $encoding
546
   *
547
   * @return false|string
548
   */
549 1
  public static function mb_stristr($haystack, $needle, $part = false, $encoding = INF)
550
  {
551 1
    $pos = self::mb_stripos($haystack, $needle, 0, $encoding);
552
553 1
    return self::getSubpart($pos, $part, $haystack, $encoding);
0 ignored issues
show
Bug introduced by
It seems like $pos defined by self::mb_stripos($haystack, $needle, 0, $encoding) on line 551 can also be of type boolean; however, voku\helper\shim\Mbstring::getSubpart() does only seem to accept false|integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
554
  }
555
556
  /**
557
   * @param string $haystack
558
   * @param string $needle
559
   * @param int    $offset
560
   * @param string $encoding
561
   *
562
   * @return bool|int
563
   */
564 2 View Code Duplication
  public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = INF)
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...
565
  {
566 2
    INF === $encoding && $encoding = self::$internal_encoding;
567 2
    $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
568 2
    $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
569
570 2
    return self::mb_strpos($haystack, $needle, $offset, $encoding);
571
  }
572
573
  /**
574
   * @param string $haystack
575
   * @param string $needle
576
   * @param int    $offset
577
   * @param string $encoding
578
   *
579
   * @return bool|int
580
   */
581 4
  public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = INF)
582
  {
583 4
    INF === $encoding && $encoding = self::$internal_encoding;
584 4
    if ('' === $needle .= '') {
585 2
      user_error(__METHOD__ . ': Empty delimiter', E_USER_WARNING);
586
587 1
      return false;
588
    } else {
589 3
      return iconv_strpos($haystack, $needle, $offset, $encoding . '//IGNORE');
590
    }
591
  }
592
593
  /**
594
   * @param false|int $pos
595
   * @param bool      $part
596
   * @param string    $haystack
597
   * @param string    $encoding
598
   *
599
   * @return false|string
600
   */
601 1
  protected static function getSubpart($pos, $part, $haystack, $encoding)
602
  {
603 1
    INF === $encoding && $encoding = self::$internal_encoding;
604
605 1
    if (false === $pos) {
606
      return false;
607
    }
608 1
    if ($part) {
609 1
      return self::mb_substr($haystack, 0, $pos, $encoding);
610
    } else {
611 1
      return self::mb_substr($haystack, $pos, null, $encoding);
612
    }
613
  }
614
615
  /**
616
   * @param string   $str
617
   * @param int      $start
618
   * @param null|int $length
619
   * @param string   $encoding
620
   *
621
   * @return string
622
   */
623 3
  public static function mb_substr($str, $start, $length = null, $encoding = INF)
624
  {
625 3
    INF === $encoding && $encoding = self::$internal_encoding;
626
627 3 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...
628 1
      $start = iconv_strlen($str, $encoding . '//IGNORE') + $start;
629 1
      if ($start < 0) {
630 1
        $start = 0;
631
      }
632
    }
633
634 3
    if (null === $length) {
635 2
      $length = 2147483647;
636 3 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...
637 2
      $length = iconv_strlen($str, $encoding . '//IGNORE') + $length - $start;
638 2
      if ($length < 0) {
639 1
        return '';
640
      }
641
    }
642
643 3
    return iconv_substr($str, $start, $length, $encoding . '//IGNORE') . '';
644
  }
645
646
  /**
647
   * @param string $type
648
   *
649
   * @return array|bool
650
   */
651
  public static function mb_get_info($type = 'all')
652
  {
653
    $info = array(
654
        'internal_encoding'          => self::$internal_encoding,
655
        'http_output'                => 'pass',
656
        'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)',
657
        'func_overload'              => 0,
658
        'func_overload_list'         => 'no overload',
659
        'mail_charset'               => 'UTF-8',
660
        'mail_header_encoding'       => 'BASE64',
661
        'mail_body_encoding'         => 'BASE64',
662
        'illegal_chars'              => 0,
663
        'encoding_translation'       => 'Off',
664
        'language'                   => self::$language,
665
        'detect_order'               => self::$encoding_list,
666
        'substitute_character'       => 'none',
667
        'strict_detection'           => 'Off',
668
    );
669
670
    if ('all' === $type) {
671
      return $info;
672
    } elseif (isset($info[$type])) {
673
      return $info[$type];
674
    } else {
675
      return false;
676
    }
677
  }
678
679
  /**
680
   * @param string $type
681
   *
682
   * @return bool
683
   */
684
  public static function mb_http_input(/** @noinspection PhpUnusedParameterInspection */
685
      $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...
686
  {
687
    return false;
688
  }
689
690
  /**
691
   * @param string $encoding
692
   *
693
   * @return bool|string
694
   */
695
  public static function mb_http_output($encoding = INF)
696
  {
697
    if (INF !== $encoding) {
698
      return 'pass' === $encoding;
699
    } else {
700
      return 'pass';
701
    }
702
  }
703
704
  /**
705
   * @param string $str
706
   * @param string $encoding
707
   *
708
   * @return int
709
   */
710 1
  public static function mb_strwidth($str, $encoding = INF)
711
  {
712 1
    if (INF === $encoding) {
713 1
      $encoding = self::$internal_encoding;
714
    } else {
715 1
      $encoding = strtoupper($encoding);
716
    }
717
718 1
    if ('UTF-8' !== $encoding && 'UTF8' !== $encoding) {
719 1
      $str = iconv($encoding, 'UTF-8//IGNORE', $str);
720
    }
721
722 1
    $str = preg_replace('/[\x00-\x19]/', '', $str);
723
724 1
    preg_replace('/[\x{0020}-\x{1FFF}\x{FF61}-\x{FF9F}]/u', '', $str, -1, $narrow);
725
726 1
    return (iconv_strlen($str, 'UTF-8') << 1) - $narrow;
727
  }
728
729
  /**
730
   * @param string $haystack
731
   * @param string $needle
732
   * @param string $encoding
733
   *
734
   * @return int
735
   */
736
  public static function mb_substr_count($haystack, $needle, /** @noinspection PhpUnusedParameterInspection */
737
                                          $encoding = INF)
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...
738
  {
739
    return substr_count($haystack, $needle);
740
  }
741
742
  /**
743
   * @param $contents
744
   * @param $status
745
   *
746
   * @return mixed
747
   */
748
  public static function mb_output_handler($contents, /** @noinspection PhpUnusedParameterInspection */
749
                                            $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...
750
  {
751
    return $contents;
752
  }
753
754
  /**
755
   * @param string $haystack
756
   * @param string $needle
757
   * @param bool   $part
758
   * @param string $encoding
759
   *
760
   * @return false|string
761
   */
762 1
  public static function mb_strrchr($haystack, $needle, $part = false, $encoding = INF)
763
  {
764 1
    INF === $encoding && $encoding = self::$internal_encoding;
765
766 1
    $needle = self::mb_substr($needle, 0, 1, $encoding);
767 1
    $pos = iconv_strrpos($haystack, $needle, $encoding);
768
769 1
    return self::getSubpart($pos, $part, $haystack, $encoding);
0 ignored issues
show
Bug introduced by
It seems like $pos defined by iconv_strrpos($haystack, $needle, $encoding) on line 767 can also be of type double; however, voku\helper\shim\Mbstring::getSubpart() does only seem to accept false|integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
770
  }
771
772
  /**
773
   * @param string $haystack
774
   * @param string $needle
775
   * @param bool   $part
776
   * @param string $encoding
777
   *
778
   * @return false|string
779
   */
780 1
  public static function mb_strrichr($haystack, $needle, $part = false, $encoding = INF)
781
  {
782 1
    $needle = self::mb_substr($needle, 0, 1, $encoding);
783 1
    $pos = self::mb_strripos($haystack, $needle, $encoding);
784
785 1
    return self::getSubpart($pos, $part, $haystack, $encoding);
0 ignored issues
show
Bug introduced by
It seems like $pos defined by self::mb_strripos($haystack, $needle, $encoding) on line 783 can also be of type double; however, voku\helper\shim\Mbstring::getSubpart() does only seem to accept false|integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
786
  }
787
788
  /**
789
   * @param string $haystack
790
   * @param string $needle
791
   * @param int    $offset
792
   * @param string $encoding
793
   *
794
   * @return bool|int
795
   */
796 2 View Code Duplication
  public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = INF)
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...
797
  {
798 2
    INF === $encoding && $encoding = self::$internal_encoding;
799
800 2
    $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding);
801 2
    $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding);
802
803 2
    return self::mb_strrpos($haystack, $needle, $offset, $encoding);
804
  }
805
806
  /**
807
   * @param string $haystack
808
   * @param string $needle
809
   * @param int    $offset
810
   * @param string $encoding
811
   *
812
   * @return bool|int
813
   */
814 2
  public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = INF)
815
  {
816 2
    INF === $encoding && $encoding = self::$internal_encoding;
817
818 2
    $intOffset = (int)$offset;
819
820 2
    if ($offset != $intOffset) {
821 1
      $offset = 0;
822 1
    } elseif ($intOffset) {
823 1
      if ($offset < 0) {
824 1
        $haystack = self::mb_substr($haystack, 0, $offset, $encoding);
825 1
        $offset = 0;
826
      } else {
827
        $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding);
828
      }
829
    }
830
831 2
    $pos = iconv_strrpos($haystack, $needle, $encoding . '//IGNORE');
832
833 2
    if (false !== $pos) {
834 2
      return $offset + $pos;
835
    } else {
836 1
      return false;
837
    }
838
  }
839
840
  /**
841
   * @param string $haystack
842
   * @param string $needle
843
   * @param bool   $part
844
   * @param string $encoding
845
   *
846
   * @return false|string
847
   */
848 1
  public static function mb_strstr($haystack, $needle, $part = false, /** @noinspection PhpUnusedParameterInspection */
849
                                    $encoding = INF)
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...
850
  {
851 1
    $pos = strpos($haystack, $needle);
852 1
    if (false === $pos) {
853
      return false;
854
    }
855
856 1
    if ($part) {
857 1
      return substr($haystack, 0, $pos);
858
    } else {
859 1
      return substr($haystack, $pos);
860
    }
861
  }
862
863
  /**
864
   * @param array $m
865
   *
866
   * @return string
867
   */
868 1
  protected static function html_encoding_callback($m)
869
  {
870 1
    $i = 1;
871 1
    $entities = '';
872 1
    $m = unpack('C*', htmlentities($m[0], ENT_COMPAT, 'UTF-8'));
873
874 1
    while (isset($m[$i])) {
875 1
      if (0x80 > $m[$i]) {
876 1
        $entities .= chr($m[$i++]);
877 1
        continue;
878
      }
879
880 1
      if (0xF0 <= $m[$i]) {
881
        $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
882 1
      } elseif (0xE0 <= $m[$i]) {
883 1
        $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80;
884
      } else {
885
        $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80;
886
      }
887
888 1
      $entities .= '&#' . $c . ';';
889
    }
890
891 1
    return $entities;
892
  }
893
894
  /**
895
   * @param string $str
896
   *
897
   * @return bool|mixed|string
898
   */
899 1
  protected static function title_case_lower($str)
900
  {
901 1
    return self::mb_convert_case($str[0], MB_CASE_LOWER, 'UTF-8');
902
  }
903
904
  /**
905
   * @param string $str
906
   *
907
   * @return bool|mixed|string
908
   */
909 1
  protected static function title_case_upper($str)
910
  {
911 1
    return self::mb_convert_case($str[0], MB_CASE_UPPER, 'UTF-8');
912
  }
913
}
914