11 require_once
'WSCMimeParser.php';
12 require_once
'WSCCharset.php';
13 require_once
'WSCMessagePart.php';
17 const WSC_CHARSET =
'UTF-8';
18 private static $default_charset;
27 self::$default_charset = self::WSC_CHARSET;
28 if (!empty($default_charset))
30 self::$default_charset = $default_charset;
42 if (self::$default_charset)
44 return self::$default_charset;
46 return self::WSC_CHARSET;
63 'include_bodies' =>
true,
64 'decode_bodies' =>
true,
65 'decode_headers' =>
false,
66 'default_charset' => self::get_charset(),
69 return $mime->decode($raw_body);
83 static function decode_address_list($input, $max = null, $decode =
true, $fallback = null, $addronly =
false)
85 $a = self::parse_address_list($input, $decode, $fallback);
89 $special_chars =
'[\(\)<>\\\.\[\]@,;:"]';
93 foreach ($a as $val) {
95 $address = trim($val[
'address']);
100 $name = trim($val[
'name']);
101 if ($name && $address && $name != $address)
102 $string = sprintf(
'%s <%s>', preg_match(
"/$special_chars/", $name) ?
'"'.addcslashes($name,
'"').
'"' : $name, $address);
107 $out[$j] = array(
'name' => $name,
'mailto' => $address,
'string' => $string);
109 if ($max && $j==$max)
125 $str = self::decode_mime_string((
string)$input, $fallback);
141 $default_charset = $fallback ?: self::get_charset();
146 $input = preg_replace(
"/\?=\s+=\?/",
'?==?', $input);
148 $re =
'/=\?([^?]+)\?([BbQq])\?([^\n]*?)\?=/';
150 if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER))
156 foreach ($matches as $idx => $m) {
159 $encoding = $m[2][0];
161 $length = strlen($m[0][0]);
163 if ($start != $pos) {
164 $substr = substr($input, $start, $pos-$start);
165 $out .= WSCCharset::convert($substr, $default_charset);
177 if ($next_match = $matches[$idx+1]) {
178 if ($next_match[0][1] == $start
179 && $next_match[1][0] == $charset
180 && $next_match[2][0] == $encoding
185 $count = count($tmp);
188 if ($encoding ==
'B' || $encoding ==
'b') {
190 for ($i=0; $i<$count; $i++)
191 $text .= base64_decode($tmp[$i]);
195 for ($i=0; $i<$count; $i++)
197 $text = str_replace(
'_',
' ', $text);
198 $text = quoted_printable_decode($text);
200 $out .= WSCCharset::convert($text, $charset);
204 if ($start != strlen($input)) {
205 $out .= WSCCharset::convert(substr($input, $start), $default_charset);
211 return WSCCharset::convert($input, $default_charset);
222 public static function decode($input, $encoding =
'7bit')
224 switch (strtolower($encoding)) {
225 case 'quoted-printable':
226 return quoted_printable_decode($input);
228 return base64_decode($input);
233 return convert_uudecode($input);
245 $a_headers = array();
246 $headers = preg_replace(
'/\r?\n(\t| )+/',
' ', $headers);
247 $lines = explode(
"\n", $headers);
248 $count = count($lines);
249 for ($i=0; $i<$count; $i++) {
250 if ($p = strpos($lines[$i],
': ')) {
251 $field = strtolower(substr($lines[$i], 0, $p));
252 $value = trim(substr($lines[$i], $p+1));
253 if (!empty($value)) {
254 $a_headers[$field] = $value;
264 private static function parse_address_list($str, $decode =
true, $fallback = null)
268 $str = preg_replace(
'/\r?\n(\s|\t)?/',
' ', $str);
270 $str = self::explode_header_string(
',;', $str,
true);
273 $email_rx =
'(\S+|("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+"))@\S+';
274 foreach ($str as $key => $val) {
278 if (preg_match(
'/(.*)<('.$email_rx.
')>$/', $val, $m)) {
282 else if (preg_match(
'/^('.$email_rx.
')$/', $val, $m)) {
287 else if (preg_match(
'/(\s*<MAILER-DAEMON>)$/', $val, $m)) {
288 $address =
'MAILER-DAEMON';
289 $name = substr($val, 0, -strlen($m[1]));
291 else if (preg_match(
'/('.$email_rx.
')/', $val, $m)) {
299 if ($name[0] ==
'"' && $name[strlen($name)-1] ==
'"') {
300 $name = substr($name, 1, -1);
301 $name = stripslashes($name);
304 $name = self::decode_header($name, $fallback);
306 if ($name[0] ==
'"' && $name[strlen($name)-1] ==
'"') {
307 $name = substr($name, 1, -1);
311 if (!$address && $name) {
316 $address = self::fix_email($address);
317 $result[$key] = array(
'name' => $name,
'address' => $address);
336 $length = strlen($str);
341 for ($i=0; $i<$length; $i++) {
344 if ($str[$i] ==
'"') {
347 else if ($str[$i] ==
"\\") {
355 else if ($comment > 0) {
356 if ($str[$i] ==
')') {
359 else if ($str[$i] ==
'(') {
362 else if ($str[$i] ==
"\\") {
368 else if (strpos($separator, $str[$i]) !==
false) {
376 else if ($str[$i] ==
'"') {
380 else if ($remove_comments && $str[$i] ==
'(') {
387 if ($out && $comment <= 0) {
403 $text = preg_split(
'/\r?\n/', $text);
407 foreach ($text as $idx => $line) {
408 if ($q = strspn($line,
'>')) {
410 $line = substr($line, $q);
412 if ($line[0] ===
' ') $line = substr($line, 1);
418 && isset($text[$last]) && $text[$last][strlen($text[$last])-1] ==
' ' 419 && !preg_match(
'/^>+ {0,1}$/', $text[$last])
421 $text[$last] .= $line;
424 $marks[$last] =
true;
432 if ($line ==
'-- ') {
437 if ($line[0] ===
' ') $line = substr($line, 1);
438 if (isset($text[$last]) && $line && !$q_level
439 && $text[$last] !=
'-- ' 440 && $text[$last][strlen($text[$last])-1] ==
' ' 442 $text[$last] .= $line;
445 $marks[$last] =
true;
456 if (!empty($marks)) {
457 foreach (array_keys($marks) as $mk) {
458 $text[$mk] = $mark . $text[$mk];
461 return implode(
"\r\n", $text);
475 $text = preg_split(
'/\r?\n/', $text);
476 foreach ($text as $idx => $line) {
477 if ($line !=
'-- ') {
478 if ($level = strspn($line,
'>')) {
480 $line = substr($line, $level);
482 $line = rtrim($line,
' ');
483 if ($line[0] ===
' ') $line = substr($line, 1);
484 $prefix = str_repeat(
'>', $level) .
' ';
485 $line = $prefix . self::wordwrap($line, $length - $level - 2,
" \r\n$prefix",
false, $charset);
488 $line = self::wordwrap(rtrim($line), $length - 2,
" \r\n",
false, $charset);
490 $line = preg_replace(
'/(^|\r\n)(From| |>)/',
'\\1 \\2', $line);
495 return implode(
"\r\n", $text);
511 public static function wordwrap($string, $width=75, $break=
"\n", $cut=
false, $charset=null, $wrap_quoted=
true)
515 if ($charset && $charset != WSC_CHARSET) {
516 mb_internal_encoding($charset);
519 $string = str_replace(
"\r\n",
"\n", $string);
522 while (($stringLength = mb_strlen($string)) > 0) {
523 $breakPos = mb_strpos($string, $separator, 0);
525 if ($wrap_quoted && $string[0] ==
'>') {
526 if ($breakPos === $stringLength - 1 || $breakPos ===
false) {
527 $subString = $string;
531 $subString = mb_substr($string, 0, $breakPos);
532 $cutLength = $breakPos + 1;
536 else if ($breakPos !==
false && $breakPos < $width) {
537 if ($breakPos === $stringLength - 1) {
538 $subString = $string;
542 $subString = mb_substr($string, 0, $breakPos);
543 $cutLength = $breakPos + 1;
547 $subString = mb_substr($string, 0, $width);
549 if ($breakPos ===
false && $subString === $string) {
553 $nextChar = mb_substr($string, $width, 1);
554 if ($nextChar ===
' ' || $nextChar === $separator) {
555 $afterNextChar = mb_substr($string, $width + 1, 1);
557 if ($afterNextChar ===
false || $afterNextChar ===
'') {
558 $subString .= $nextChar;
560 $cutLength = mb_strlen($subString) + 1;
563 $spacePos = mb_strrpos($subString,
' ', 0);
564 if ($spacePos !==
false) {
565 $subString = mb_substr($subString, 0, $spacePos);
566 $cutLength = $spacePos + 1;
568 else if ($cut ===
false) {
569 $spacePos = mb_strpos($string,
' ', 0);
570 if ($spacePos !==
false && ($breakPos ===
false || $spacePos < $breakPos)) {
571 $subString = mb_substr($string, 0, $spacePos);
572 $cutLength = $spacePos + 1;
574 else if ($breakPos ===
false) {
575 $subString = $string;
579 $subString = mb_substr($string, 0, $breakPos);
580 $cutLength = $breakPos + 1;
589 $result[] = $subString;
590 if ($cutLength !== null) {
591 $string = mb_substr($string, $cutLength, ($stringLength - $cutLength));
597 if ($charset && $charset != WSC_CHARSET) {
598 mb_internal_encoding(WSC_CHARSET);
600 return implode($break, $result);
617 public static function file_content_type($path, $name, $failover =
'application/octet-stream', $is_stream =
false, $skip_suffix =
false)
619 $tipoMime = $failover;
621 $realpath = realpath($path);
624 && function_exists(
'finfo_file' )
625 && function_exists(
'finfo_open' )
626 && defined(
'FILEINFO_MIME_TYPE' )
630 $tipoMime = finfo_file( finfo_open( FILEINFO_MIME_TYPE ), $realpath );
634 $fileExtension = pathinfo($path, PATHINFO_EXTENSION);
640 'txt' =>
'text/plain',
641 'htm' =>
'text/html',
642 'html' =>
'text/html',
643 'php' =>
'text/html',
645 'js' =>
'application/javascript',
646 'json' =>
'application/json',
647 'xml' =>
'application/xml',
651 'png' =>
'image/png',
652 'jpe' =>
'image/jpeg',
653 'jpeg' =>
'image/jpeg',
654 'jpg' =>
'image/jpeg',
655 'gif' =>
'image/gif',
656 'bmp' =>
'image/bmp',
657 'ico' =>
'image/vnd.microsoft.icon',
658 'tiff' =>
'image/tiff',
659 'tif' =>
'image/tiff',
660 'svg' =>
'image/svg+xml',
661 'svgz' =>
'image/svg+xml',
664 'zip' =>
'application/zip',
665 'rar' =>
'application/x-rar-compressed',
666 'exe' =>
'application/x-msdownload',
667 'msi' =>
'application/x-msdownload',
668 'cab' =>
'application/vnd.ms-cab-compressed',
669 'tgz' =>
'application/tar+gzip',
670 'tar.gz' =>
'application/tar+gzip',
671 'tar' =>
'application/tar',
672 'gz' =>
'application/gzip',
673 '7z' =>
'application/x-7z-compressed',
674 's7z' =>
'application/x-7z-compressed',
677 'mp3' =>
'audio/mpeg',
678 'qt' =>
'video/quicktime',
679 'mov' =>
'video/quicktime',
680 'mpeg' =>
'video/mpeg',
681 'avi' =>
'video/x-msvideo',
682 'swf' =>
'application/x-shockwave-flash',
683 'flv' =>
'video/x-flv',
686 'pdf' =>
'application/pdf',
687 'psd' =>
'image/vnd.adobe.photoshop',
688 'ai' =>
'application/postscript',
689 'eps' =>
'application/postscript',
690 'ps' =>
'application/postscript',
693 'doc' =>
'application/msword',
694 'dot' =>
'application/msword',
695 'docx' =>
'application/msword',
696 'rtf' =>
'application/rtf',
698 'xls' =>
'application/vnd.ms-excel',
699 'xlsx' =>
'application/vnd.ms-excel',
700 'xlm' =>
'application/vnd.ms-excel',
701 'xla' =>
'application/vnd.ms-excel',
702 'xlc' =>
'application/vnd.ms-excel',
703 'xlt' =>
'application/vnd.ms-excel',
704 'xlw' =>
'application/vnd.ms-excel',
706 'ppt' =>
'application/vnd.ms-powerpoint',
707 'pptx' =>
'application/vnd.ms-powerpoint',
708 'pps' =>
'application/vnd.ms-powerpoint',
709 'pot' =>
'application/vnd.ms-powerpoint',
712 'odc' =>
'application/vnd.oasis.opendocument.chart',
713 'otc' =>
'application/vnd.oasis.opendocument.chart-template',
714 'odf' =>
'application/vnd.oasis.opendocument.formula',
715 'otf' =>
'application/vnd.oasis.opendocument.formula-template',
716 'odg' =>
'application/vnd.oasis.opendocument.graphics',
717 'otg' =>
'application/vnd.oasis.opendocument.graphics-template',
718 'odi' =>
'application/vnd.oasis.opendocument.image',
719 'oti' =>
'application/vnd.oasis.opendocument.image-template',
720 'odp' =>
'application/vnd.oasis.opendocument.presentation',
721 'otp' =>
'application/vnd.oasis.opendocument.presentation-template',
722 'ods' =>
'application/vnd.oasis.opendocument.spreadsheet',
723 'ots' =>
'application/vnd.oasis.opendocument.spreadsheet-template',
724 'odt' =>
'application/vnd.oasis.opendocument.text',
725 'otm' =>
'application/vnd.oasis.opendocument.text-master',
726 'ott' =>
'application/vnd.oasis.opendocument.text-template',
727 'oth' =>
'application/vnd.oasis.opendocument.text-web',
730 'vcf' =>
'text/vcard',
731 'ics' =>
'text/calendar',
735 if (array_key_exists($fileExtension, $mime_types))
737 $tipoMime = $mime_types[$fileExtension];
755 if (preg_match(
'/^\x89\x50\x4E\x47/', $data)) $type =
'png';
756 else if (preg_match(
'/^\x47\x49\x46\x38/', $data)) $type =
'gif';
757 else if (preg_match(
'/^\x00\x00\x01\x00/', $data)) $type =
'ico';
759 return 'image/' . $type;
771 $strlen = strlen($email);
772 for ($q=$p=$i=0; $i < $strlen; $i++)
774 if ($email[$i] ==
"\"" && $email[$i-1] !=
"\\")
776 $q = $q ? false :
true;
778 else if (!$q && preg_match(
"/$delimiter/", $email[$i]))
780 $parts[] = substr($email, $p, $i - $p);
784 $parts[] = (string) substr($email, $p);
786 foreach ($parts as $idx => $part)
789 if ($part[0] ==
'"' && preg_match(
'/^"([a-zA-Z0-9._+=-]+)"$/', $part, $m)) {
790 $parts[$idx] = $m[1];
793 return implode(
'@', $parts);
static image_content_type($data)
static parse_headers($headers)
static decode_mime_string($input, $fallback=null)
static format_flowed($text, $length=72, $charset=null)
static decode_address_list($input, $max=null, $decode=true, $fallback=null, $addronly=false)
static unfold_flowed($text, $mark=null)
static decode($input, $encoding='7bit')
__construct($default_charset=null)
static decode_header($input, $fallback=null)
static file_content_type($path, $name, $failover='application/octet-stream', $is_stream=false, $skip_suffix=false)
static parse_message($raw_body)
static wordwrap($string, $width=75, $break="\, $cut=false, $charset=null, $wrap_quoted=true)
static explode_header_string($separator, $str, $remove_comments=false)