PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.0.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.0.1
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 / Mime.php

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

677 lines 21.2 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\rcube;
7 use Javanile\Imap2\rcube_mime_decode;
8
9 class Mime
10 {
11 private static $default_charset;
12
13
14 function __construct($default_charset = null)
15 {
16 self::$default_charset = $default_charset;
17 }
18
19 public static function get_charset()
20 {
21 if (self::$default_charset) {
22 return self::$default_charset;
23 }
24
25 if ($charset = IMAP2_CHARSET) {
26 return $charset;
27 }
28
29 return IMAP2_CHARSET;
30 }
31
32 public static function parse_message($raw_body)
33 {
34 $conf = array(
35 'include_bodies' => true,
36 'decode_bodies' => true,
37 'decode_headers' => false,
38 'default_charset' => self::get_charset(),
39 );
40
41 $mime = new rcube_mime_decode($conf);
42
43 return $mime->decode($raw_body);
44 }
45
46 static function decode_address_list($input, $max = null, $decode = true, $fallback = null, $addronly = false)
47 {
48 if (is_array($input)) {
49 $input = implode(', ', $input);
50 }
51
52 $a = self::parse_address_list($input, $decode, $fallback);
53 $out = array();
54 $j = 0;
55
56 $special_chars = '[\(\)\<\>\\\.\[\]@,;:"]';
57
58 if (!is_array($a)) {
59 return $out;
60 }
61
62 foreach ($a as $val) {
63 $j++;
64 $address = trim($val['address']);
65
66 if ($addronly) {
67 $out[$j] = $address;
68 }
69 else {
70 $name = trim($val['name']);
71 if ($name && $address && $name != $address)
72 $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address);
73 else if ($address)
74 $string = $address;
75 else if ($name)
76 $string = $name;
77
78 $out[$j] = array('name' => $name, 'mailto' => $address, 'string' => $string);
79 }
80
81 if ($max && $j==$max)
82 break;
83 }
84
85 return $out;
86 }
87
88 public static function decode_header($input, $fallback = null)
89 {
90 $str = self::decode_mime_string((string)$input, $fallback);
91
92 return $str;
93 }
94
95 public static function decode_mime_string($input, $fallback = null)
96 {
97 $default_charset = $fallback ?: self::get_charset();
98
99 $input = preg_replace("/\?=\s+=\?/", '?==?', $input);
100
101 $re = '/=\?([^?]+)\?([BbQq])\?([^\n]*?)\?=/';
102
103 if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
104 $tmp = array();
105 $out = '';
106 $start = 0;
107
108 foreach ($matches as $idx => $m) {
109 $pos = $m[0][1];
110 $charset = $m[1][0];
111 $encoding = $m[2][0];
112 $text = $m[3][0];
113 $length = strlen($m[0][0]);
114
115 if ($start != $pos) {
116 $substr = substr($input, $start, $pos-$start);
117 $out .= Charset::convert($substr, $default_charset);
118 $start = $pos;
119 }
120 $start += $length;
121
122
123 $tmp[] = $text;
124 if ($next_match = $matches[$idx+1]) {
125 if ($next_match[0][1] == $start
126 && $next_match[1][0] == $charset
127 && $next_match[2][0] == $encoding
128 ) {
129 continue;
130 }
131 }
132
133 $count = count($tmp);
134 $text = '';
135
136 if ($encoding == 'B' || $encoding == 'b') {
137 $rest = '';
138 for ($i=0; $i<$count; $i++) {
139 $chunk = $rest . $tmp[$i];
140 $length = strlen($chunk);
141 if ($length % 4) {
142 $length = floor($length / 4) * 4;
143 $rest = substr($chunk, $length);
144 $chunk = substr($chunk, 0, $length);
145 }
146
147 $text .= base64_decode($chunk);
148 }
149 }
150 else { //if ($encoding == 'Q' || $encoding == 'q') {
151 for ($i=0; $i<$count; $i++)
152 $text .= $tmp[$i];
153
154 $text = str_replace('_', ' ', $text);
155 $text = quoted_printable_decode($text);
156 }
157
158 $out .= Charset::convert($text, $charset);
159 $tmp = array();
160 }
161
162 if ($start != strlen($input)) {
163 $out .= Charset::convert(substr($input, $start), $default_charset);
164 }
165
166 return $out;
167 }
168
169 return Charset::convert($input, $default_charset);
170 }
171
172 public static function decode($input, $encoding = '7bit')
173 {
174 switch (strtolower($encoding)) {
175 case 'quoted-printable':
176 return quoted_printable_decode($input);
177 case 'base64':
178 return base64_decode($input);
179 case 'x-uuencode':
180 case 'x-uue':
181 case 'uue':
182 case 'uuencode':
183 return convert_uudecode($input);
184 case '7bit':
185 default:
186 return $input;
187 }
188 }
189
190 public static function parse_headers($headers)
191 {
192 $a_headers = array();
193 $headers = preg_replace('/\r?\n(\t| )+/', ' ', $headers);
194 $lines = explode("\n", $headers);
195 $count = count($lines);
196
197 for ($i=0; $i<$count; $i++) {
198 if ($p = strpos($lines[$i], ': ')) {
199 $field = strtolower(substr($lines[$i], 0, $p));
200 $value = trim(substr($lines[$i], $p+1));
201 if (!empty($value)) {
202 $a_headers[$field] = $value;
203 }
204 }
205 }
206
207 return $a_headers;
208 }
209
210 private static function parse_address_list($str, $decode = true, $fallback = null)
211 {
212 $str = preg_replace('/\r?\n(\s|\t)?/', ' ', $str);
213
214 $str = self::explode_header_string(',;', $str, true);
215 $result = array();
216
217 $email_rx = '(\S+|("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+"))@\S+';
218
219 foreach ($str as $key => $val) {
220 $name = '';
221 $address = '';
222 $val = trim($val);
223
224 if (preg_match('/(.*)<('.$email_rx.')>$/', $val, $m)) {
225 $address = $m[2];
226 $name = trim($m[1]);
227 }
228 else if (preg_match('/^('.$email_rx.')$/', $val, $m)) {
229 $address = $m[1];
230 $name = '';
231 }
232 else if (preg_match('/(\s*<MAILER-DAEMON>)$/', $val, $m)) {
233 $address = 'MAILER-DAEMON';
234 $name = substr($val, 0, -strlen($m[1]));
235 }
236 else if (preg_match('/('.$email_rx.')/', $val, $m)) {
237 $name = $m[1];
238 }
239 else {
240 $name = $val;
241 }
242
243 if ($name) {
244 if ($name[0] == '"' && $name[strlen($name)-1] == '"') {
245 $name = substr($name, 1, -1);
246 $name = stripslashes($name);
247 }
248 if ($decode) {
249 $name = self::decode_header($name, $fallback);
250 if ($name[0] == '"' && $name[strlen($name)-1] == '"') {
251 $name = substr($name, 1, -1);
252 }
253 }
254 }
255
256 if (!$address && $name) {
257 $address = $name;
258 $name = '';
259 }
260
261 if ($address) {
262 $address = self::fix_email($address);
263 $result[$key] = array('name' => $name, 'address' => $address);
264 }
265 }
266
267 return $result;
268 }
269
270 public static function explode_header_string($separator, $str, $remove_comments = false)
271 {
272 $length = strlen($str);
273 $result = array();
274 $quoted = false;
275 $comment = 0;
276 $out = '';
277
278 for ($i=0; $i<$length; $i++) {
279 if ($quoted) {
280 if ($str[$i] == '"') {
281 $quoted = false;
282 }
283 else if ($str[$i] == "\\") {
284 if ($comment <= 0) {
285 $out .= "\\";
286 }
287 $i++;
288 }
289 }
290 else if ($comment > 0) {
291 if ($str[$i] == ')') {
292 $comment--;
293 }
294 else if ($str[$i] == '(') {
295 $comment++;
296 }
297 else if ($str[$i] == "\\") {
298 $i++;
299 }
300 continue;
301 }
302 else if (strpos($separator, $str[$i]) !== false) {
303 if ($out) {
304 $result[] = $out;
305 }
306 $out = '';
307 continue;
308 }
309 else if ($str[$i] == '"') {
310 $quoted = true;
311 }
312 else if ($remove_comments && $str[$i] == '(') {
313 $comment++;
314 }
315
316 if ($comment <= 0) {
317 $out .= $str[$i];
318 }
319 }
320
321 if ($out && $comment <= 0) {
322 $result[] = $out;
323 }
324
325 return $result;
326 }
327
328 public static function unfold_flowed($text, $mark = null, $delsp = false)
329 {
330 $text = preg_split('/\r?\n/', $text);
331 $last = -1;
332 $q_level = 0;
333 $marks = array();
334
335 foreach ($text as $idx => $line) {
336 if ($q = strspn($line, '>')) {
337 $line = substr($line, $q);
338 if ($line[0] === ' ') $line = substr($line, 1);
339
340 if ($q == $q_level
341 && isset($text[$last]) && $text[$last][strlen($text[$last])-1] == ' '
342 && !preg_match('/^>+ {0,1}$/', $text[$last])
343 ) {
344 if ($delsp) {
345 $text[$last] = substr($text[$last], 0, -1);
346 }
347 $text[$last] .= $line;
348 unset($text[$idx]);
349
350 if ($mark) {
351 $marks[$last] = true;
352 }
353 }
354 else {
355 $last = $idx;
356 }
357 }
358 else {
359 if ($line == '-- ') {
360 $last = $idx;
361 }
362 else {
363 if ($line[0] === ' ') $line = substr($line, 1);
364
365 if (isset($text[$last]) && $line && !$q_level
366 && $text[$last] != '-- '
367 && $text[$last][strlen($text[$last])-1] == ' '
368 ) {
369 if ($delsp) {
370 $text[$last] = substr($text[$last], 0, -1);
371 }
372 $text[$last] .= $line;
373 unset($text[$idx]);
374
375 if ($mark) {
376 $marks[$last] = true;
377 }
378 }
379 else {
380 $text[$idx] = $line;
381 $last = $idx;
382 }
383 }
384 }
385 $q_level = $q;
386 }
387
388 if (!empty($marks)) {
389 foreach (array_keys($marks) as $mk) {
390 $text[$mk] = $mark . $text[$mk];
391 }
392 }
393
394 return implode("\r\n", $text);
395 }
396
397 public static function format_flowed($text, $length = 72, $charset=null)
398 {
399 $text = preg_split('/\r?\n/', $text);
400
401 foreach ($text as $idx => $line) {
402 if ($line != '-- ') {
403 if ($level = strspn($line, '>')) {
404 $line = substr($line, $level);
405 $line = rtrim($line, ' ');
406 if ($line[0] === ' ') $line = substr($line, 1);
407
408 $prefix = str_repeat('>', $level) . ' ';
409 $line = $prefix . self::wordwrap($line, $length - $level - 2, " \r\n$prefix", false, $charset);
410 }
411 else if ($line) {
412 $line = self::wordwrap(rtrim($line), $length - 2, " \r\n", false, $charset);
413 $line = preg_replace('/(^|\r\n)(From| |>)/', '\\1 \\2', $line);
414 }
415
416 $text[$idx] = $line;
417 }
418 }
419
420 return implode("\r\n", $text);
421 }
422
423 public static function wordwrap($string, $width=75, $break="\n", $cut=false, $charset=null, $wrap_quoted=true)
424 {
425
426 if ($charset && $charset != IMAP2_CHARSET) {
427 mb_internal_encoding($charset);
428 }
429
430 $string = str_replace("\r\n", "\n", $string);
431 $separator = "\n"; // must be 1 character length
432 $result = array();
433
434 while (($stringLength = mb_strlen($string)) > 0) {
435 $breakPos = mb_strpos($string, $separator, 0);
436
437 if ($wrap_quoted && $string[0] == '>') {
438 if ($breakPos === $stringLength - 1 || $breakPos === false) {
439 $subString = $string;
440 $cutLength = null;
441 }
442 else {
443 $subString = mb_substr($string, 0, $breakPos);
444 $cutLength = $breakPos + 1;
445 }
446 }
447 else if ($breakPos !== false && $breakPos < $width) {
448 if ($breakPos === $stringLength - 1) {
449 $subString = $string;
450 $cutLength = null;
451 }
452 else {
453 $subString = mb_substr($string, 0, $breakPos);
454 $cutLength = $breakPos + 1;
455 }
456 }
457 else {
458 $subString = mb_substr($string, 0, $width);
459
460 if ($breakPos === false && $subString === $string) {
461 $cutLength = null;
462 }
463 else {
464 $nextChar = mb_substr($string, $width, 1);
465
466 if ($nextChar === ' ' || $nextChar === $separator) {
467 $afterNextChar = mb_substr($string, $width + 1, 1);
468
469 if ($afterNextChar === false || $afterNextChar === '') {
470 $subString .= $nextChar;
471 }
472
473 $cutLength = mb_strlen($subString) + 1;
474 }
475 else {
476 $spacePos = mb_strrpos($subString, ' ', 0);
477
478 if ($spacePos !== false) {
479 $subString = mb_substr($subString, 0, $spacePos);
480 $cutLength = $spacePos + 1;
481 }
482 else if ($cut === false) {
483 $spacePos = mb_strpos($string, ' ', 0);
484
485 if ($spacePos !== false && ($breakPos === false || $spacePos < $breakPos)) {
486 $subString = mb_substr($string, 0, $spacePos);
487 $cutLength = $spacePos + 1;
488 }
489 else if ($breakPos === false) {
490 $subString = $string;
491 $cutLength = null;
492 }
493 else {
494 $subString = mb_substr($string, 0, $breakPos);
495 $cutLength = $breakPos + 1;
496 }
497 }
498 else {
499 $cutLength = $width;
500 }
501 }
502 }
503 }
504
505 $result[] = $subString;
506
507 if ($cutLength !== null) {
508 $string = mb_substr($string, $cutLength, ($stringLength - $cutLength));
509 }
510 else {
511 break;
512 }
513 }
514
515 if ($charset && $charset != IMAP2_CHARSET) {
516 mb_internal_encoding(IMAP2_CHARSET);
517 }
518
519 return implode($break, $result);
520 }
521
522 public static function file_content_type($path, $name, $failover = 'application/octet-stream', $is_stream = false, $skip_suffix = false)
523 {
524 static $mime_ext = array();
525
526 $mime_type = null;
527 $config = rcube::get_instance()->config;
528
529 if (!$skip_suffix && empty($mime_ext)) {
530 foreach ($config->resolve_paths('mimetypes.php') as $fpath) {
531 $mime_ext = array_merge($mime_ext, (array) @include($fpath));
532 }
533 }
534
535 if (!$skip_suffix && is_array($mime_ext) && $name) {
536 if ($suffix = substr($name, strrpos($name, '.')+1)) {
537 $mime_type = $mime_ext[strtolower($suffix)];
538 }
539 }
540
541 if (!$mime_type && function_exists('finfo_open')) {
542 $mime_magic = $config->get('mime_magic');
543 if ($mime_magic) {
544 $finfo = finfo_open(FILEINFO_MIME, $mime_magic);
545 }
546 else {
547 $finfo = finfo_open(FILEINFO_MIME);
548 }
549
550 if ($finfo) {
551 $func = $is_stream ? 'finfo_buffer' : 'finfo_file';
552 $mime_type = $func($finfo, $path, FILEINFO_MIME_TYPE);
553 finfo_close($finfo);
554 }
555 }
556
557 if (!$mime_type && !$is_stream && function_exists('mime_content_type')) {
558 $mime_type = @mime_content_type($path);
559 }
560
561 if (!$mime_type) {
562 $mime_type = $failover;
563 }
564
565 return $mime_type;
566 }
567
568 public static function get_mime_extensions($mimetype = null)
569 {
570 static $mime_types, $mime_extensions;
571
572 if (is_array($mime_types)) {
573 return $mimetype ? $mime_types[$mimetype] : $mime_extensions;
574 }
575
576 $file_paths = array();
577
578 if ($mime_types = rcube::get_instance()->config->get('mime_types')) {
579 $file_paths[] = $mime_types;
580 }
581
582 if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
583 $file_paths[] = 'C:/xampp/apache/conf/mime.types.';
584 }
585 else {
586 $file_paths[] = '/etc/mime.types';
587 $file_paths[] = '/etc/httpd/mime.types';
588 $file_paths[] = '/etc/httpd2/mime.types';
589 $file_paths[] = '/etc/apache/mime.types';
590 $file_paths[] = '/etc/apache2/mime.types';
591 $file_paths[] = '/etc/nginx/mime.types';
592 $file_paths[] = '/usr/local/etc/httpd/conf/mime.types';
593 $file_paths[] = '/usr/local/etc/apache/conf/mime.types';
594 $file_paths[] = '/usr/local/etc/apache24/mime.types';
595 }
596
597 foreach ($file_paths as $fp) {
598 if (@is_readable($fp)) {
599 $lines = file($fp, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
600 break;
601 }
602 }
603
604 $mime_types = $mime_extensions = array();
605 $regex = "/([\w\+\-\.\/]+)\s+([\w\s]+)/i";
606 foreach ((array)$lines as $line) {
607 if ($line[0] == '#' || !preg_match($regex, $line, $matches))
608 continue;
609
610 $mime = $matches[1];
611 foreach (explode(' ', $matches[2]) as $ext) {
612 $ext = trim($ext);
613 $mime_types[$mime][] = $ext;
614 $mime_extensions[$ext] = $mime;
615 }
616 }
617
618 if (empty($mime_types)) {
619 foreach (rcube::get_instance()->config->resolve_paths('mimetypes.php') as $fpath) {
620 $mime_extensions = array_merge($mime_extensions, (array) @include($fpath));
621 }
622
623 foreach ($mime_extensions as $ext => $mime) {
624 $mime_types[$mime][] = $ext;
625 }
626 }
627
628 $aliases = array(
629 'image/gif' => array('gif'),
630 'image/png' => array('png'),
631 'image/x-png' => array('png'),
632 'image/jpeg' => array('jpg', 'jpeg', 'jpe'),
633 'image/jpg' => array('jpg', 'jpeg', 'jpe'),
634 'image/pjpeg' => array('jpg', 'jpeg', 'jpe'),
635 'image/tiff' => array('tif'),
636 'image/bmp' => array('bmp'),
637 'image/x-ms-bmp' => array('bmp'),
638 'message/rfc822' => array('eml'),
639 'text/x-mail' => array('eml'),
640 );
641
642 foreach ($aliases as $mime => $exts) {
643 $mime_types[$mime] = array_unique(array_merge((array) $mime_types[$mime], $exts));
644
645 foreach ($exts as $ext) {
646 if (!isset($mime_extensions[$ext])) {
647 $mime_extensions[$ext] = $mime;
648 }
649 }
650 }
651
652 return $mimetype ? $mime_types[$mimetype] : $mime_extensions;
653 }
654
655 public static function image_content_type($data)
656 {
657 $type = 'jpeg';
658 if (preg_match('/^\x89\x50\x4E\x47/', $data)) $type = 'png';
659 else if (preg_match('/^\x47\x49\x46\x38/', $data)) $type = 'gif';
660 else if (preg_match('/^\x00\x00\x01\x00/', $data)) $type = 'ico';
661
662 return 'image/' . $type;
663 }
664
665 public static function fix_email($email)
666 {
667 $parts = Utils::explode_quoted_string('@', $email);
668 foreach ($parts as $idx => $part) {
669 if ($part[0] == '"' && preg_match('/^"([a-zA-Z0-9._+=-]+)"$/', $part, $m)) {
670 $parts[$idx] = $m[1];
671 }
672 }
673
674 return implode('@', $parts);
675 }
676 }
677