1 | <?php |
||
5 | class HeaderDecoder |
||
6 | { |
||
7 | private $decodeWindows1252 = false; |
||
8 | |||
9 | 7 | public function __construct(bool $decodeWindows1252 = false) |
|
13 | |||
14 | 7 | public function decode(string $string): string |
|
15 | { |
||
16 | /* Take out any spaces between multiple encoded words. */ |
||
17 | 7 | $string = preg_replace('|\?=\s+=\?|', '?==?', $string); |
|
18 | |||
19 | 7 | $out = ''; |
|
20 | 7 | $old_pos = 0; |
|
21 | |||
22 | 7 | while (($pos = strpos($string, '=?', $old_pos)) !== false) { |
|
23 | /* Save any preceding text. */ |
||
24 | 4 | $out .= substr($string, $old_pos, $pos - $old_pos); |
|
25 | |||
26 | /* Search for first delimiting question mark (charset). */ |
||
27 | 4 | if (($d1 = strpos($string, '?', $pos + 2)) === false) { |
|
28 | break; |
||
29 | } |
||
30 | |||
31 | 4 | $orig_charset = substr($string, $pos + 2, $d1 - $pos - 2); |
|
32 | 4 | if ($this->decodeWindows1252 && mb_strtolower($orig_charset) == 'iso-8859-1') { |
|
33 | $orig_charset = 'windows-1252'; |
||
34 | } |
||
35 | |||
36 | /* Search for second delimiting question mark (encoding). */ |
||
37 | 4 | if (($d2 = strpos($string, '?', $d1 + 1)) === false) { |
|
38 | break; |
||
39 | } |
||
40 | |||
41 | 4 | $encoding = substr($string, $d1 + 1, $d2 - $d1 - 1); |
|
42 | |||
43 | /* Search for end of encoded data. */ |
||
44 | 4 | if (($end = strpos($string, '?=', $d2 + 1)) === false) { |
|
45 | break; |
||
46 | } |
||
47 | |||
48 | 4 | $encoded_text = substr($string, $d2 + 1, $end - $d2 - 1); |
|
49 | |||
50 | switch ($encoding) { |
||
51 | 4 | case 'Q': |
|
52 | 3 | case 'q': |
|
53 | 1 | $out .= self::convertCharset(preg_replace_callback('/=([0-9a-f]{2})/i', function ($ord) { |
|
54 | 1 | return chr(hexdec($ord [1])); |
|
55 | 1 | }, str_replace('_', ' ', $encoded_text)), $orig_charset, mb_internal_encoding()); |
|
56 | 1 | break; |
|
57 | |||
58 | 3 | case 'B': |
|
59 | case 'b': |
||
60 | 3 | $out .= self::convertCharset(base64_decode($encoded_text), $orig_charset, mb_internal_encoding()); |
|
61 | 3 | break; |
|
62 | |||
63 | default: |
||
64 | // Ignore unknown encoding. |
||
65 | break; |
||
66 | } |
||
67 | |||
68 | 4 | $old_pos = $end + 2; |
|
69 | } |
||
70 | |||
71 | 7 | return $out . substr($string, $old_pos); |
|
72 | } |
||
73 | |||
74 | 4 | private static function convertCharset(string $str, string $orig, string $to) |
|
78 | } |
||
79 |