PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.1.4
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.1.4
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
acymailing / vendor / javanile / php-imap2 / src / Roundcube / Charset.php

Charset.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 10.1.4, at vendor/javanile/php-imap2/src/Roundcube/Charset.php

761 lines 26.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 namespace Javanile\Imap2\Roundcube;
5
6 use Javanile\Imap2\ErrorException;
7 use Javanile\Imap2\rcube;
8
9 class Charset
10 {
11 static public $aliases = array(
12 'USASCII' => 'WINDOWS-1252',
13 'ANSIX31101983' => 'WINDOWS-1252',
14 'ANSIX341968' => 'WINDOWS-1252',
15 'UNKNOWN8BIT' => 'ISO-8859-15',
16 'UNKNOWN' => 'ISO-8859-15',
17 'USERDEFINED' => 'ISO-8859-15',
18 'KSC56011987' => 'EUC-KR',
19 'GB2312' => 'GBK',
20 'GB231280' => 'GBK',
21 'UNICODE' => 'UTF-8',
22 'UTF7IMAP' => 'UTF7-IMAP',
23 'TIS620' => 'WINDOWS-874',
24 'ISO88599' => 'WINDOWS-1254',
25 'ISO885911' => 'WINDOWS-874',
26 'MACROMAN' => 'MACINTOSH',
27 '77' => 'MAC',
28 '128' => 'SHIFT-JIS',
29 '129' => 'CP949',
30 '130' => 'CP1361',
31 '134' => 'GBK',
32 '136' => 'BIG5',
33 '161' => 'WINDOWS-1253',
34 '162' => 'WINDOWS-1254',
35 '163' => 'WINDOWS-1258',
36 '177' => 'WINDOWS-1255',
37 '178' => 'WINDOWS-1256',
38 '186' => 'WINDOWS-1257',
39 '204' => 'WINDOWS-1251',
40 '222' => 'WINDOWS-874',
41 '238' => 'WINDOWS-1250',
42 'MS950' => 'CP950',
43 'WINDOWS949' => 'UHC',
44 );
45
46 static public $windows_codepages = array(
47 37 => 'IBM037', // IBM EBCDIC US-Canada
48 437 => 'IBM437', // OEM United States
49 500 => 'IBM500', // IBM EBCDIC International
50 708 => 'ASMO-708', // Arabic (ASMO 708)
51 720 => 'DOS-720', // Arabic (Transparent ASMO); Arabic (DOS)
52 737 => 'IBM737', // OEM Greek (formerly 437G); Greek (DOS)
53 775 => 'IBM775', // OEM Baltic; Baltic (DOS)
54 850 => 'IBM850', // OEM Multilingual Latin 1; Western European (DOS)
55 852 => 'IBM852', // OEM Latin 2; Central European (DOS)
56 855 => 'IBM855', // OEM Cyrillic (primarily Russian)
57 857 => 'IBM857', // OEM Turkish; Turkish (DOS)
58 858 => 'IBM00858', // OEM Multilingual Latin 1 + Euro symbol
59 860 => 'IBM860', // OEM Portuguese; Portuguese (DOS)
60 861 => 'IBM861', // OEM Icelandic; Icelandic (DOS)
61 862 => 'DOS-862', // OEM Hebrew; Hebrew (DOS)
62 863 => 'IBM863', // OEM French Canadian; French Canadian (DOS)
63 864 => 'IBM864', // OEM Arabic; Arabic (864)
64 865 => 'IBM865', // OEM Nordic; Nordic (DOS)
65 866 => 'cp866', // OEM Russian; Cyrillic (DOS)
66 869 => 'IBM869', // OEM Modern Greek; Greek, Modern (DOS)
67 870 => 'IBM870', // IBM EBCDIC Multilingual/ROECE (Latin 2); IBM EBCDIC Multilingual Latin 2
68 874 => 'windows-874', // ANSI/OEM Thai (ISO 8859-11); Thai (Windows)
69 875 => 'cp875', // IBM EBCDIC Greek Modern
70 932 => 'shift_jis', // ANSI/OEM Japanese; Japanese (Shift-JIS)
71 936 => 'gb2312', // ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
72 950 => 'big5', // ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
73 1026 => 'IBM1026', // IBM EBCDIC Turkish (Latin 5)
74 1047 => 'IBM01047', // IBM EBCDIC Latin 1/Open System
75 1140 => 'IBM01140', // IBM EBCDIC US-Canada (037 + Euro symbol); IBM EBCDIC (US-Canada-Euro)
76 1141 => 'IBM01141', // IBM EBCDIC Germany (20273 + Euro symbol); IBM EBCDIC (Germany-Euro)
77 1142 => 'IBM01142', // IBM EBCDIC Denmark-Norway (20277 + Euro symbol); IBM EBCDIC (Denmark-Norway-Euro)
78 1143 => 'IBM01143', // IBM EBCDIC Finland-Sweden (20278 + Euro symbol); IBM EBCDIC (Finland-Sweden-Euro)
79 1144 => 'IBM01144', // IBM EBCDIC Italy (20280 + Euro symbol); IBM EBCDIC (Italy-Euro)
80 1145 => 'IBM01145', // IBM EBCDIC Latin America-Spain (20284 + Euro symbol); IBM EBCDIC (Spain-Euro)
81 1146 => 'IBM01146', // IBM EBCDIC United Kingdom (20285 + Euro symbol); IBM EBCDIC (UK-Euro)
82 1147 => 'IBM01147', // IBM EBCDIC France (20297 + Euro symbol); IBM EBCDIC (France-Euro)
83 1148 => 'IBM01148', // IBM EBCDIC International (500 + Euro symbol); IBM EBCDIC (International-Euro)
84 1149 => 'IBM01149', // IBM EBCDIC Icelandic (20871 + Euro symbol); IBM EBCDIC (Icelandic-Euro)
85 1200 => 'UTF-16', // Unicode UTF-16, little endian byte order (BMP of ISO 10646); available only to managed applications
86 1201 => 'UTF-16BE', // Unicode UTF-16, big endian byte order; available only to managed applications
87 1250 => 'windows-1250', // ANSI Central European; Central European (Windows)
88 1251 => 'windows-1251', // ANSI Cyrillic; Cyrillic (Windows)
89 1252 => 'windows-1252', // ANSI Latin 1; Western European (Windows)
90 1253 => 'windows-1253', // ANSI Greek; Greek (Windows)
91 1254 => 'windows-1254', // ANSI Turkish; Turkish (Windows)
92 1255 => 'windows-1255', // ANSI Hebrew; Hebrew (Windows)
93 1256 => 'windows-1256', // ANSI Arabic; Arabic (Windows)
94 1257 => 'windows-1257', // ANSI Baltic; Baltic (Windows)
95 1258 => 'windows-1258', // ANSI/OEM Vietnamese; Vietnamese (Windows)
96 10000 => 'macintosh', // MAC Roman; Western European (Mac)
97 12000 => 'UTF-32', // Unicode UTF-32, little endian byte order; available only to managed applications
98 12001 => 'UTF-32BE', // Unicode UTF-32, big endian byte order; available only to managed applications
99 20127 => 'US-ASCII', // US-ASCII (7-bit)
100 20273 => 'IBM273', // IBM EBCDIC Germany
101 20277 => 'IBM277', // IBM EBCDIC Denmark-Norway
102 20278 => 'IBM278', // IBM EBCDIC Finland-Sweden
103 20280 => 'IBM280', // IBM EBCDIC Italy
104 20284 => 'IBM284', // IBM EBCDIC Latin America-Spain
105 20285 => 'IBM285', // IBM EBCDIC United Kingdom
106 20290 => 'IBM290', // IBM EBCDIC Japanese Katakana Extended
107 20297 => 'IBM297', // IBM EBCDIC France
108 20420 => 'IBM420', // IBM EBCDIC Arabic
109 20423 => 'IBM423', // IBM EBCDIC Greek
110 20424 => 'IBM424', // IBM EBCDIC Hebrew
111 20838 => 'IBM-Thai', // IBM EBCDIC Thai
112 20866 => 'koi8-r', // Russian (KOI8-R); Cyrillic (KOI8-R)
113 20871 => 'IBM871', // IBM EBCDIC Icelandic
114 20880 => 'IBM880', // IBM EBCDIC Cyrillic Russian
115 20905 => 'IBM905', // IBM EBCDIC Turkish
116 20924 => 'IBM00924', // IBM EBCDIC Latin 1/Open System (1047 + Euro symbol)
117 20932 => 'EUC-JP', // Japanese (JIS 0208-1990 and 0212-1990)
118 20936 => 'cp20936', // Simplified Chinese (GB2312); Chinese Simplified (GB2312-80)
119 20949 => 'cp20949', // Korean Wansung
120 21025 => 'cp1025', // IBM EBCDIC Cyrillic Serbian-Bulgarian
121 21866 => 'koi8-u', // Ukrainian (KOI8-U); Cyrillic (KOI8-U)
122 28591 => 'iso-8859-1', // ISO 8859-1 Latin 1; Western European (ISO)
123 28592 => 'iso-8859-2', // ISO 8859-2 Central European; Central European (ISO)
124 28593 => 'iso-8859-3', // ISO 8859-3 Latin 3
125 28594 => 'iso-8859-4', // ISO 8859-4 Baltic
126 28595 => 'iso-8859-5', // ISO 8859-5 Cyrillic
127 28596 => 'iso-8859-6', // ISO 8859-6 Arabic
128 28597 => 'iso-8859-7', // ISO 8859-7 Greek
129 28598 => 'iso-8859-8', // ISO 8859-8 Hebrew; Hebrew (ISO-Visual)
130 28599 => 'iso-8859-9', // ISO 8859-9 Turkish
131 28603 => 'iso-8859-13', // ISO 8859-13 Estonian
132 28605 => 'iso-8859-15', // ISO 8859-15 Latin 9
133 38598 => 'iso-8859-8-i', // ISO 8859-8 Hebrew; Hebrew (ISO-Logical)
134 50220 => 'iso-2022-jp', // ISO 2022 Japanese with no halfwidth Katakana; Japanese (JIS)
135 50221 => 'csISO2022JP', // ISO 2022 Japanese with halfwidth Katakana; Japanese (JIS-Allow 1 byte Kana)
136 50222 => 'iso-2022-jp', // ISO 2022 Japanese JIS X 0201-1989; Japanese (JIS-Allow 1 byte Kana - SO/SI)
137 50225 => 'iso-2022-kr', // ISO 2022 Korean
138 51932 => 'EUC-JP', // EUC Japanese
139 51936 => 'EUC-CN', // EUC Simplified Chinese; Chinese Simplified (EUC)
140 51949 => 'EUC-KR', // EUC Korean
141 52936 => 'hz-gb-2312', // HZ-GB2312 Simplified Chinese; Chinese Simplified (HZ)
142 54936 => 'GB18030', // Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
143 65000 => 'UTF-7',
144 65001 => 'UTF-8',
145 );
146
147 public static function error_handler($errno, $errstr)
148 {
149 throw new ErrorException($errstr, 0, $errno);
150 }
151
152 public static function parse_charset($input)
153 {
154 static $charsets = array();
155 $charset = strtoupper($input);
156
157 if (isset($charsets[$input])) {
158 return $charsets[$input];
159 }
160
161 $charset = preg_replace(array(
162 '/^[^0-9A-Z]+/', // e.g. _ISO-8859-JP$SIO
163 '/\$.*$/', // e.g. _ISO-8859-JP$SIO
164 '/UNICODE-1-1-*/', // RFC1641/1642
165 '/^X-/', // X- prefix (e.g. X-ROMAN8 => ROMAN8)
166 '/\*.*$/' // lang code according to RFC 2231.5
167 ), '', $charset);
168
169 if ($charset == 'BINARY') {
170 return $charsets[$input] = null;
171 }
172
173 $str = preg_replace('/[^A-Z0-9]/', '', $charset);
174
175 if (isset(self::$aliases[$str])) {
176 $result = self::$aliases[$str];
177 }
178 else if (preg_match('/U[A-Z][A-Z](7|8|16|32)(BE|LE)*/', $str, $m)) {
179 $result = 'UTF-' . $m[1] . @$m[2];
180 }
181 else if (preg_match('/ISO8859([0-9]{0,2})/', $str, $m)) {
182 $iso = 'ISO-8859-' . ($m[1] ?: 1);
183 $result = $iso == 'ISO-8859-1' ? 'WINDOWS-1252' : $iso;
184 }
185 else if (preg_match('/(WIN|WINDOWS)([0-9]+)/', $str, $m)) {
186 $result = 'WINDOWS-' . $m[2];
187 }
188 else if (preg_match('/LATIN(.*)/', $str, $m)) {
189 $aliases = array('2' => 2, '3' => 3, '4' => 4, '5' => 9, '6' => 10,
190 '7' => 13, '8' => 14, '9' => 15, '10' => 16,
191 'ARABIC' => 6, 'CYRILLIC' => 5, 'GREEK' => 7, 'GREEK1' => 7, 'HEBREW' => 8
192 );
193
194 if ($m[1] == 1) {
195 $result = 'WINDOWS-1252';
196 }
197 else if (!empty($aliases[$m[1]])) {
198 $result = 'ISO-8859-'.$aliases[$m[1]];
199 }
200 else {
201 $result = $str;
202 }
203 }
204 else {
205 $result = $charset;
206 }
207
208 $charsets[$input] = $result;
209
210 return $result;
211 }
212
213 public static function convert($str, $from, $to = null)
214 {
215 static $iconv_options = null;
216 static $mbstring_sc = null;
217
218 $to = empty($to) ? IMAP2_CHARSET : strtoupper($to);
219 $from = self::parse_charset($from);
220
221 if ($from == 'UTF-16' && !preg_match('/[^\x00-\x7F]/', $str)) {
222 $from = 'UTF-8';
223 }
224
225 if ($from == $to || empty($str) || empty($from)) {
226 return $str;
227 }
228
229 if ($iconv_options === null) {
230 if (function_exists('iconv')) {
231 $iconv_options = '//IGNORE';
232 if (iconv('', $iconv_options, '') === false) {
233 $iconv_options = '';
234 }
235 }
236 else {
237 $iconv_options = false;
238 }
239 }
240
241 if ($iconv_options !== false && $from != 'UTF7-IMAP' && $to != 'UTF7-IMAP'
242 && $from !== 'ISO-2022-JP'
243 ) {
244 #set_error_handler(array('rcube_charset', 'error_handler'), E_NOTICE);
245 try {
246 $out = iconv($from, $to . $iconv_options, $str);
247 }
248 catch (ErrorException $e) {
249 $out = false;
250 }
251 #restore_error_handler();
252
253 if ($out !== false) {
254 return $out;
255 }
256 }
257
258 if ($mbstring_sc === null) {
259 $mbstring_sc = extension_loaded('mbstring') ? mb_substitute_character() : false;
260 }
261
262 if ($mbstring_sc !== false) {
263 $aliases = array(
264 'WINDOWS-1257' => 'ISO-8859-13',
265 'US-ASCII' => 'ASCII',
266 'ISO-2022-JP' => 'ISO-2022-JP-MS',
267 );
268
269 $mb_from = $aliases[$from] ?: $from;
270 $mb_to = $aliases[$to] ?: $to;
271
272 mb_substitute_character('none');
273
274 #set_error_handler(array('rcube_charset', 'error_handler'), E_WARNING);
275 try {
276 $out = mb_convert_encoding($str, $mb_to, $mb_from);
277 }
278 catch (ErrorException $e) {
279 $out = false;
280 }
281 #restore_error_handler();
282
283 mb_substitute_character($mbstring_sc);
284
285 if ($out !== false) {
286 return $out;
287 }
288 }
289
290 if ($to == 'UTF-8') {
291 if ($from == 'UTF7-IMAP') {
292 if ($out = self::utf7imap_to_utf8($str)) {
293 return $out;
294 }
295 }
296 else if ($from == 'UTF-7') {
297 if ($out = self::utf7_to_utf8($str)) {
298 return $out;
299 }
300 }
301 }
302
303 if ($from == 'UTF-8') {
304 if ($to == 'UTF7-IMAP' || $to == 'UTF-7') {
305 if ($out = self::utf8_to_utf7imap($str)) {
306 return $out;
307 }
308 }
309 }
310
311 if (!isset($out)) {
312 trigger_error("No suitable function found for '$from' to '$to' conversion");
313 }
314
315 return $str;
316 }
317
318 public static function utf7_to_utf8($str)
319 {
320 $Index_64 = array(
321 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
322 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
323 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0,
324 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
325 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
326 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
327 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
328 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
329 );
330
331 $u7len = strlen($str);
332 $str = strval($str);
333 $res = '';
334
335 for ($i=0; $u7len > 0; $i++, $u7len--) {
336 $u7 = $str[$i];
337 if ($u7 == '+') {
338 $i++;
339 $u7len--;
340 $ch = '';
341
342 for (; $u7len > 0; $i++, $u7len--) {
343 $u7 = $str[$i];
344
345 if (!$Index_64[ord($u7)]) {
346 break;
347 }
348
349 $ch .= $u7;
350 }
351
352 if ($ch == '') {
353 if ($u7 == '-') {
354 $res .= '+';
355 }
356
357 continue;
358 }
359
360 $res .= self::utf16_to_utf8(base64_decode($ch));
361 }
362 else {
363 $res .= $u7;
364 }
365 }
366
367 return $res;
368 }
369
370 public static function utf16_to_utf8($str)
371 {
372 $len = strlen($str);
373 $dec = '';
374
375 for ($i = 0; $i < $len; $i += 2) {
376 $c = ord($str[$i]) << 8 | ord($str[$i + 1]);
377 if ($c >= 0x0001 && $c <= 0x007F) {
378 $dec .= chr($c);
379 }
380 else if ($c > 0x07FF) {
381 $dec .= chr(0xE0 | (($c >> 12) & 0x0F));
382 $dec .= chr(0x80 | (($c >> 6) & 0x3F));
383 $dec .= chr(0x80 | (($c >> 0) & 0x3F));
384 }
385 else {
386 $dec .= chr(0xC0 | (($c >> 6) & 0x1F));
387 $dec .= chr(0x80 | (($c >> 0) & 0x3F));
388 }
389 }
390
391 return $dec;
392 }
393
394 public static function utf7imap_to_utf8($str)
395 {
396 $Index_64 = array(
397 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
398 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
399 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, 63,-1,-1,-1,
400 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
401 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
402 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
403 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
404 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
405 );
406
407 $u7len = strlen($str);
408 $str = strval($str);
409 $p = '';
410 $err = '';
411
412 for ($i=0; $u7len > 0; $i++, $u7len--) {
413 $u7 = $str[$i];
414 if ($u7 == '&') {
415 $i++;
416 $u7len--;
417 $u7 = $str[$i];
418
419 if ($u7len && $u7 == '-') {
420 $p .= '&';
421 continue;
422 }
423
424 $ch = 0;
425 $k = 10;
426 for (; $u7len > 0; $i++, $u7len--) {
427 $u7 = $str[$i];
428
429 if ((ord($u7) & 0x80) || ($b = $Index_64[ord($u7)]) == -1) {
430 break;
431 }
432
433 if ($k > 0) {
434 $ch |= $b << $k;
435 $k -= 6;
436 }
437 else {
438 $ch |= $b >> (-$k);
439 if ($ch < 0x80) {
440 if (0x20 <= $ch && $ch < 0x7f) {
441 return $err;
442 }
443 $p .= chr($ch);
444 }
445 else if ($ch < 0x800) {
446 $p .= chr(0xc0 | ($ch >> 6));
447 $p .= chr(0x80 | ($ch & 0x3f));
448 }
449 else {
450 $p .= chr(0xe0 | ($ch >> 12));
451 $p .= chr(0x80 | (($ch >> 6) & 0x3f));
452 $p .= chr(0x80 | ($ch & 0x3f));
453 }
454
455 $ch = ($b << (16 + $k)) & 0xffff;
456 $k += 10;
457 }
458 }
459
460 if ($ch || $k < 6) {
461 return $err;
462 }
463
464 if (!$u7len || $u7 != '-') {
465 return $err;
466 }
467
468 if ($u7len > 2 && $str[$i+1] == '&' && $str[$i+2] != '-') {
469 return $err;
470 }
471 }
472 else if (ord($u7) < 0x20 || ord($u7) >= 0x7f) {
473 return $err;
474 }
475 else {
476 $p .= $u7;
477 }
478 }
479
480 return $p;
481 }
482
483 public static function utf8_to_utf7imap($str)
484 {
485 $B64Chars = array(
486 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
487 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
488 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
489 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
490 '8', '9', '+', ','
491 );
492
493 $u8len = strlen($str);
494 $base64 = 0;
495 $i = 0;
496 $p = '';
497 $err = '';
498
499 while ($u8len) {
500 $u8 = $str[$i];
501 $c = ord($u8);
502
503 if ($c < 0x80) {
504 $ch = $c;
505 $n = 0;
506 }
507 else if ($c < 0xc2) {
508 return $err;
509 }
510 else if ($c < 0xe0) {
511 $ch = $c & 0x1f;
512 $n = 1;
513 }
514 else if ($c < 0xf0) {
515 $ch = $c & 0x0f;
516 $n = 2;
517 }
518 else if ($c < 0xf8) {
519 $ch = $c & 0x07;
520 $n = 3;
521 }
522 else if ($c < 0xfc) {
523 $ch = $c & 0x03;
524 $n = 4;
525 }
526 else if ($c < 0xfe) {
527 $ch = $c & 0x01;
528 $n = 5;
529 }
530 else {
531 return $err;
532 }
533
534 $i++;
535 $u8len--;
536
537 if ($n > $u8len) {
538 return $err;
539 }
540
541 for ($j=0; $j < $n; $j++) {
542 $o = ord($str[$i+$j]);
543 if (($o & 0xc0) != 0x80) {
544 return $err;
545 }
546 $ch = ($ch << 6) | ($o & 0x3f);
547 }
548
549 if ($n > 1 && !($ch >> ($n * 5 + 1))) {
550 return $err;
551 }
552
553 $i += $n;
554 $u8len -= $n;
555
556 if ($ch < 0x20 || $ch >= 0x7f) {
557 if (!$base64) {
558 $p .= '&';
559 $base64 = 1;
560 $b = 0;
561 $k = 10;
562 }
563 if ($ch & ~0xffff) {
564 $ch = 0xfffe;
565 }
566
567 $p .= $B64Chars[($b | $ch >> $k)];
568 $k -= 6;
569 for (; $k >= 0; $k -= 6) {
570 $p .= $B64Chars[(($ch >> $k) & 0x3f)];
571 }
572
573 $b = ($ch << (-$k)) & 0x3f;
574 $k += 16;
575 }
576 else {
577 if ($base64) {
578 if ($k > 10) {
579 $p .= $B64Chars[$b];
580 }
581 $p .= '-';
582 $base64 = 0;
583 }
584
585 $p .= chr($ch);
586 if (chr($ch) == '&') {
587 $p .= '-';
588 }
589 }
590 }
591
592 if ($base64) {
593 if ($k > 10) {
594 $p .= $B64Chars[$b];
595 }
596 $p .= '-';
597 }
598
599 return $p;
600 }
601
602 public static function detect($string, $failover = null, $language = null)
603 {
604 if (substr($string, 0, 4) == "\0\0\xFE\xFF") return 'UTF-32BE'; // Big Endian
605 if (substr($string, 0, 4) == "\xFF\xFE\0\0") return 'UTF-32LE'; // Little Endian
606 if (substr($string, 0, 2) == "\xFE\xFF") return 'UTF-16BE'; // Big Endian
607 if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian
608 if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8';
609
610 if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE';
611 if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE';
612 if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE';
613 if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE';
614
615 if (empty($language)) {
616 $rcube = rcube::get_instance();
617 $language = $rcube->get_user_language();
618 }
619
620 switch ($language) {
621 case 'ja_JP':
622 $prio = array('ISO-2022-JP', 'JIS', 'UTF-8', 'EUC-JP', 'eucJP-win', 'SJIS', 'SJIS-win');
623 break;
624
625 case 'zh_CN':
626 case 'zh_TW':
627 $prio = array('UTF-8', 'BIG-5', 'GB2312', 'EUC-TW');
628 break;
629
630 case 'ko_KR':
631 $prio = array('UTF-8', 'EUC-KR', 'ISO-2022-KR');
632 break;
633
634 case 'ru_RU':
635 $prio = array('UTF-8', 'WINDOWS-1251', 'KOI8-R');
636 break;
637
638 case 'tr_TR':
639 $prio = array('UTF-8', 'ISO-8859-9', 'WINDOWS-1254');
640 break;
641 }
642
643 if ($prio && function_exists('mb_check_encoding')) {
644 foreach ($prio as $encoding) {
645 if (mb_check_encoding($string, $encoding)) {
646 return $encoding;
647 }
648 }
649 }
650
651 if (function_exists('mb_detect_encoding')) {
652 if (!$prio) {
653 $prio = array('UTF-8', 'SJIS', 'GB2312',
654 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
655 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
656 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
657 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', 'BIG-5',
658 'ISO-2022-KR', 'ISO-2022-JP',
659 );
660 }
661
662 $encodings = array_unique(array_merge($prio, mb_list_encodings()));
663
664 if ($encoding = mb_detect_encoding($string, $encodings)) {
665 return $encoding;
666 }
667 }
668
669 if (preg_match('/\A(
670 [\x09\x0A\x0D\x20-\x7E]
671 | [\xC2-\xDF][\x80-\xBF]
672 | \xE0[\xA0-\xBF][\x80-\xBF]
673 | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}
674 | \xED[\x80-\x9F][\x80-\xBF]
675 | \xF0[\x90-\xBF][\x80-\xBF]{2}
676 | [\xF1-\xF3][\x80-\xBF]{3}
677 | \xF4[\x80-\x8F][\x80-\xBF]{2}
678 )*\z/xs', substr($string, 0, 2048))
679 ) {
680 return 'UTF-8';
681 }
682
683 return $failover;
684 }
685
686 public static function clean($input)
687 {
688 if (is_array($input)) {
689 foreach ($input as $idx => $val) {
690 $input[$idx] = self::clean($val);
691 }
692 return $input;
693 }
694
695 if (!is_string($input) || $input == '') {
696 return $input;
697 }
698
699 if (function_exists('mb_convert_encoding')) {
700 $msch = mb_substitute_character();
701 mb_substitute_character('none');
702 $res = mb_convert_encoding($input, 'UTF-8', 'UTF-8');
703 mb_substitute_character($msch);
704
705 if ($res !== false) {
706 return $res;
707 }
708 }
709
710 if (function_exists('iconv')) {
711 if (($res = @iconv('UTF-8', 'UTF-8//IGNORE', $input)) !== false) {
712 return $res;
713 }
714 }
715
716 $seq = '';
717 $out = '';
718 $regexp = '/^('.
719 '|[\xC2-\xDF][\x80-\xBF]'. // UTF8-2
720 '|\xE0[\xA0-\xBF][\x80-\xBF]'. // UTF8-3
721 '|[\xE1-\xEC][\x80-\xBF][\x80-\xBF]'. // UTF8-3
722 '|\xED[\x80-\x9F][\x80-\xBF]'. // UTF8-3
723 '|[\xEE-\xEF][\x80-\xBF][\x80-\xBF]'. // UTF8-3
724 '|\xF0[\x90-\xBF][\x80-\xBF][\x80-\xBF]'. // UTF8-4
725 '|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.// UTF8-4
726 '|\xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]'. // UTF8-4
727 ')$/';
728
729 for ($i = 0, $len = strlen($input); $i < $len; $i++) {
730 $chr = $input[$i];
731 $ord = ord($chr);
732
733 if ($ord <= 0x7F) {
734 if ($seq !== '') {
735 $out .= preg_match($regexp, $seq) ? $seq : '';
736 $seq = '';
737 }
738
739 $out .= $chr;
740 }
741 else if ($ord >= 0xC0) {
742 if ($seq !== '') {
743 $out .= preg_match($regexp, $seq) ? $seq : '';
744 $seq = '';
745 }
746
747 $seq = $chr;
748 }
749 else if ($seq !== '') {
750 $seq .= $chr;
751 }
752 }
753
754 if ($seq !== '') {
755 $out .= preg_match($regexp, $seq) ? $seq : '';
756 }
757
758 return $out;
759 }
760 }
761