add: full multi-tenancy control
This commit is contained in:
108
packages/Webkul/Email/src/Helpers/Attachment.php
Normal file
108
packages/Webkul/Email/src/Helpers/Attachment.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Email\Helpers;
|
||||
|
||||
class Attachment
|
||||
{
|
||||
/**
|
||||
* Content.
|
||||
*
|
||||
* @var File Content
|
||||
*/
|
||||
private $content = null;
|
||||
|
||||
/**
|
||||
* Create an helper instance
|
||||
*/
|
||||
public function __construct(
|
||||
public $filename,
|
||||
public $contentType,
|
||||
public $stream,
|
||||
public $contentDisposition = 'attachment',
|
||||
public $contentId = '',
|
||||
public $headers = []
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieve the attachment filename.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFilename()
|
||||
{
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the attachment content type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContentType()
|
||||
{
|
||||
return $this->contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the attachment content disposition.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContentDisposition()
|
||||
{
|
||||
return $this->contentDisposition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the attachment content ID.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContentID()
|
||||
{
|
||||
return $this->contentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the attachment headers.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the contents a few bytes at a time until completed.
|
||||
*
|
||||
* Once read to completion, it always returns false.
|
||||
*
|
||||
* @param int $bytes
|
||||
* @return string
|
||||
*/
|
||||
public function read($bytes = 2082)
|
||||
{
|
||||
return feof($this->stream) ? false : fread($this->stream, $bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the file content in one go.
|
||||
*
|
||||
* Once you retrieve the content you cannot use MimeMailParser_attachment::read().
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
if ($this->content === null) {
|
||||
fseek($this->stream, 0);
|
||||
|
||||
while (($buf = $this->read()) !== false) {
|
||||
$this->content .= $buf;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
}
|
||||
}
|
||||
353
packages/Webkul/Email/src/Helpers/Charset.php
Normal file
353
packages/Webkul/Email/src/Helpers/Charset.php
Normal file
@@ -0,0 +1,353 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Email\Helpers;
|
||||
|
||||
use Webkul\Email\Helpers\Contracts\CharsetManager;
|
||||
|
||||
class Charset implements CharsetManager
|
||||
{
|
||||
/**
|
||||
* Charset aliases.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $charsetAlias = [
|
||||
'ascii' => 'us-ascii',
|
||||
'us-ascii' => 'us-ascii',
|
||||
'ansi_x3.4-1968' => 'us-ascii',
|
||||
'646' => 'us-ascii',
|
||||
'iso-8859-1' => 'ISO-8859-1',
|
||||
'iso-8859-2' => 'ISO-8859-2',
|
||||
'iso-8859-3' => 'ISO-8859-3',
|
||||
'iso-8859-4' => 'ISO-8859-4',
|
||||
'iso-8859-5' => 'ISO-8859-5',
|
||||
'iso-8859-6' => 'ISO-8859-6',
|
||||
'iso-8859-6-i' => 'ISO-8859-6-I',
|
||||
'iso-8859-6-e' => 'ISO-8859-6-E',
|
||||
'iso-8859-7' => 'ISO-8859-7',
|
||||
'iso-8859-8' => 'ISO-8859-8',
|
||||
'iso-8859-8-i' => 'ISO-8859-8-I',
|
||||
'iso-8859-8-e' => 'ISO-8859-8-E',
|
||||
'iso-8859-9' => 'ISO-8859-9',
|
||||
'iso-8859-10' => 'ISO-8859-10',
|
||||
'iso-8859-11' => 'ISO-8859-11',
|
||||
'iso-8859-13' => 'ISO-8859-13',
|
||||
'iso-8859-14' => 'ISO-8859-14',
|
||||
'iso-8859-15' => 'ISO-8859-15',
|
||||
'iso-8859-16' => 'ISO-8859-16',
|
||||
'iso-ir-111' => 'ISO-IR-111',
|
||||
'iso-2022-cn' => 'ISO-2022-CN',
|
||||
'iso-2022-cn-ext' => 'ISO-2022-CN',
|
||||
'iso-2022-kr' => 'ISO-2022-KR',
|
||||
'iso-2022-jp' => 'ISO-2022-JP',
|
||||
'utf-16be' => 'UTF-16BE',
|
||||
'utf-16le' => 'UTF-16LE',
|
||||
'utf-16' => 'UTF-16',
|
||||
'windows-1250' => 'windows-1250',
|
||||
'windows-1251' => 'windows-1251',
|
||||
'windows-1252' => 'windows-1252',
|
||||
'windows-1253' => 'windows-1253',
|
||||
'windows-1254' => 'windows-1254',
|
||||
'windows-1255' => 'windows-1255',
|
||||
'windows-1256' => 'windows-1256',
|
||||
'windows-1257' => 'windows-1257',
|
||||
'windows-1258' => 'windows-1258',
|
||||
'ibm866' => 'IBM866',
|
||||
'ibm850' => 'IBM850',
|
||||
'ibm852' => 'IBM852',
|
||||
'ibm855' => 'IBM855',
|
||||
'ibm857' => 'IBM857',
|
||||
'ibm862' => 'IBM862',
|
||||
'ibm864' => 'IBM864',
|
||||
'utf-8' => 'UTF-8',
|
||||
'utf-7' => 'UTF-7',
|
||||
'shift_jis' => 'Shift_JIS',
|
||||
'big5' => 'Big5',
|
||||
'euc-jp' => 'EUC-JP',
|
||||
'euc-kr' => 'EUC-KR',
|
||||
'gb2312' => 'GB2312',
|
||||
'gb18030' => 'gb18030',
|
||||
'viscii' => 'VISCII',
|
||||
'koi8-r' => 'KOI8-R',
|
||||
'koi8_r' => 'KOI8-R',
|
||||
'cskoi8r' => 'KOI8-R',
|
||||
'koi' => 'KOI8-R',
|
||||
'koi8' => 'KOI8-R',
|
||||
'koi8-u' => 'KOI8-U',
|
||||
'tis-620' => 'TIS-620',
|
||||
't.61-8bit' => 'T.61-8bit',
|
||||
'hz-gb-2312' => 'HZ-GB-2312',
|
||||
'big5-hkscs' => 'Big5-HKSCS',
|
||||
'gbk' => 'gbk',
|
||||
'cns11643' => 'x-euc-tw',
|
||||
'x-imap4-modified-utf7' => 'x-imap4-modified-utf7',
|
||||
'x-euc-tw' => 'x-euc-tw',
|
||||
'x-mac-ce' => 'x-mac-ce',
|
||||
'x-mac-turkish' => 'x-mac-turkish',
|
||||
'x-mac-greek' => 'x-mac-greek',
|
||||
'x-mac-icelandic' => 'x-mac-icelandic',
|
||||
'x-mac-croatian' => 'x-mac-croatian',
|
||||
'x-mac-romanian' => 'x-mac-romanian',
|
||||
'x-mac-cyrillic' => 'x-mac-cyrillic',
|
||||
'x-mac-ukrainian' => 'x-mac-cyrillic',
|
||||
'x-mac-hebrew' => 'x-mac-hebrew',
|
||||
'x-mac-arabic' => 'x-mac-arabic',
|
||||
'x-mac-farsi' => 'x-mac-farsi',
|
||||
'x-mac-devanagari' => 'x-mac-devanagari',
|
||||
'x-mac-gujarati' => 'x-mac-gujarati',
|
||||
'x-mac-gurmukhi' => 'x-mac-gurmukhi',
|
||||
'armscii-8' => 'armscii-8',
|
||||
'x-viet-tcvn5712' => 'x-viet-tcvn5712',
|
||||
'x-viet-vps' => 'x-viet-vps',
|
||||
'iso-10646-ucs-2' => 'UTF-16BE',
|
||||
'x-iso-10646-ucs-2-be' => 'UTF-16BE',
|
||||
'x-iso-10646-ucs-2-le' => 'UTF-16LE',
|
||||
'x-user-defined' => 'x-user-defined',
|
||||
'x-johab' => 'x-johab',
|
||||
'latin1' => 'ISO-8859-1',
|
||||
'iso_8859-1' => 'ISO-8859-1',
|
||||
'iso8859-1' => 'ISO-8859-1',
|
||||
'iso8859-2' => 'ISO-8859-2',
|
||||
'iso8859-3' => 'ISO-8859-3',
|
||||
'iso8859-4' => 'ISO-8859-4',
|
||||
'iso8859-5' => 'ISO-8859-5',
|
||||
'iso8859-6' => 'ISO-8859-6',
|
||||
'iso8859-7' => 'ISO-8859-7',
|
||||
'iso8859-8' => 'ISO-8859-8',
|
||||
'iso8859-9' => 'ISO-8859-9',
|
||||
'iso8859-10' => 'ISO-8859-10',
|
||||
'iso8859-11' => 'ISO-8859-11',
|
||||
'iso8859-13' => 'ISO-8859-13',
|
||||
'iso8859-14' => 'ISO-8859-14',
|
||||
'iso8859-15' => 'ISO-8859-15',
|
||||
'iso_8859-1:1987' => 'ISO-8859-1',
|
||||
'iso-ir-100' => 'ISO-8859-1',
|
||||
'l1' => 'ISO-8859-1',
|
||||
'ibm819' => 'ISO-8859-1',
|
||||
'cp819' => 'ISO-8859-1',
|
||||
'csisolatin1' => 'ISO-8859-1',
|
||||
'latin2' => 'ISO-8859-2',
|
||||
'iso_8859-2' => 'ISO-8859-2',
|
||||
'iso_8859-2:1987' => 'ISO-8859-2',
|
||||
'iso-ir-101' => 'ISO-8859-2',
|
||||
'l2' => 'ISO-8859-2',
|
||||
'csisolatin2' => 'ISO-8859-2',
|
||||
'latin3' => 'ISO-8859-3',
|
||||
'iso_8859-3' => 'ISO-8859-3',
|
||||
'iso_8859-3:1988' => 'ISO-8859-3',
|
||||
'iso-ir-109' => 'ISO-8859-3',
|
||||
'l3' => 'ISO-8859-3',
|
||||
'csisolatin3' => 'ISO-8859-3',
|
||||
'latin4' => 'ISO-8859-4',
|
||||
'iso_8859-4' => 'ISO-8859-4',
|
||||
'iso_8859-4:1988' => 'ISO-8859-4',
|
||||
'iso-ir-110' => 'ISO-8859-4',
|
||||
'l4' => 'ISO-8859-4',
|
||||
'csisolatin4' => 'ISO-8859-4',
|
||||
'cyrillic' => 'ISO-8859-5',
|
||||
'iso_8859-5' => 'ISO-8859-5',
|
||||
'iso_8859-5:1988' => 'ISO-8859-5',
|
||||
'iso-ir-144' => 'ISO-8859-5',
|
||||
'csisolatincyrillic' => 'ISO-8859-5',
|
||||
'arabic' => 'ISO-8859-6',
|
||||
'iso_8859-6' => 'ISO-8859-6',
|
||||
'iso_8859-6:1987' => 'ISO-8859-6',
|
||||
'iso-ir-127' => 'ISO-8859-6',
|
||||
'ecma-114' => 'ISO-8859-6',
|
||||
'asmo-708' => 'ISO-8859-6',
|
||||
'csisolatinarabic' => 'ISO-8859-6',
|
||||
'csiso88596i' => 'ISO-8859-6-I',
|
||||
'csiso88596e' => 'ISO-8859-6-E',
|
||||
'greek' => 'ISO-8859-7',
|
||||
'greek8' => 'ISO-8859-7',
|
||||
'sun_eu_greek' => 'ISO-8859-7',
|
||||
'iso_8859-7' => 'ISO-8859-7',
|
||||
'iso_8859-7:1987' => 'ISO-8859-7',
|
||||
'iso-ir-126' => 'ISO-8859-7',
|
||||
'elot_928' => 'ISO-8859-7',
|
||||
'ecma-118' => 'ISO-8859-7',
|
||||
'csisolatingreek' => 'ISO-8859-7',
|
||||
'hebrew' => 'ISO-8859-8',
|
||||
'iso_8859-8' => 'ISO-8859-8',
|
||||
'visual' => 'ISO-8859-8',
|
||||
'iso_8859-8:1988' => 'ISO-8859-8',
|
||||
'iso-ir-138' => 'ISO-8859-8',
|
||||
'csisolatinhebrew' => 'ISO-8859-8',
|
||||
'csiso88598i' => 'ISO-8859-8-I',
|
||||
'iso-8859-8i' => 'ISO-8859-8-I',
|
||||
'logical' => 'ISO-8859-8-I',
|
||||
'csiso88598e' => 'ISO-8859-8-E',
|
||||
'latin5' => 'ISO-8859-9',
|
||||
'iso_8859-9' => 'ISO-8859-9',
|
||||
'iso_8859-9:1989' => 'ISO-8859-9',
|
||||
'iso-ir-148' => 'ISO-8859-9',
|
||||
'l5' => 'ISO-8859-9',
|
||||
'csisolatin5' => 'ISO-8859-9',
|
||||
'unicode-1-1-utf-8' => 'UTF-8',
|
||||
'utf8' => 'UTF-8',
|
||||
'x-sjis' => 'Shift_JIS',
|
||||
'shift-jis' => 'Shift_JIS',
|
||||
'ms_kanji' => 'Shift_JIS',
|
||||
'csshiftjis' => 'Shift_JIS',
|
||||
'windows-31j' => 'Shift_JIS',
|
||||
'cp932' => 'Shift_JIS',
|
||||
'sjis' => 'Shift_JIS',
|
||||
'cseucpkdfmtjapanese' => 'EUC-JP',
|
||||
'x-euc-jp' => 'EUC-JP',
|
||||
'csiso2022jp' => 'ISO-2022-JP',
|
||||
'iso-2022-jp-2' => 'ISO-2022-JP',
|
||||
'csiso2022jp2' => 'ISO-2022-JP',
|
||||
'csbig5' => 'Big5',
|
||||
'cn-big5' => 'Big5',
|
||||
'x-x-big5' => 'Big5',
|
||||
'zh_tw-big5' => 'Big5',
|
||||
'cseuckr' => 'EUC-KR',
|
||||
'ks_c_5601-1987' => 'EUC-KR',
|
||||
'iso-ir-149' => 'EUC-KR',
|
||||
'ks_c_5601-1989' => 'EUC-KR',
|
||||
'ksc_5601' => 'EUC-KR',
|
||||
'ksc5601' => 'EUC-KR',
|
||||
'korean' => 'EUC-KR',
|
||||
'csksc56011987' => 'EUC-KR',
|
||||
'5601' => 'EUC-KR',
|
||||
'windows-949' => 'EUC-KR',
|
||||
'gb_2312-80' => 'GB2312',
|
||||
'iso-ir-58' => 'GB2312',
|
||||
'chinese' => 'GB2312',
|
||||
'csiso58gb231280' => 'GB2312',
|
||||
'csgb2312' => 'GB2312',
|
||||
'zh_cn.euc' => 'GB2312',
|
||||
'gb_2312' => 'GB2312',
|
||||
'x-cp1250' => 'windows-1250',
|
||||
'x-cp1251' => 'windows-1251',
|
||||
'x-cp1252' => 'windows-1252',
|
||||
'x-cp1253' => 'windows-1253',
|
||||
'x-cp1254' => 'windows-1254',
|
||||
'x-cp1255' => 'windows-1255',
|
||||
'x-cp1256' => 'windows-1256',
|
||||
'x-cp1257' => 'windows-1257',
|
||||
'x-cp1258' => 'windows-1258',
|
||||
'windows-874' => 'windows-874',
|
||||
'ibm874' => 'windows-874',
|
||||
'dos-874' => 'windows-874',
|
||||
'macintosh' => 'macintosh',
|
||||
'x-mac-roman' => 'macintosh',
|
||||
'mac' => 'macintosh',
|
||||
'csmacintosh' => 'macintosh',
|
||||
'cp866' => 'IBM866',
|
||||
'cp-866' => 'IBM866',
|
||||
'866' => 'IBM866',
|
||||
'csibm866' => 'IBM866',
|
||||
'cp850' => 'IBM850',
|
||||
'850' => 'IBM850',
|
||||
'csibm850' => 'IBM850',
|
||||
'cp852' => 'IBM852',
|
||||
'852' => 'IBM852',
|
||||
'csibm852' => 'IBM852',
|
||||
'cp855' => 'IBM855',
|
||||
'855' => 'IBM855',
|
||||
'csibm855' => 'IBM855',
|
||||
'cp857' => 'IBM857',
|
||||
'857' => 'IBM857',
|
||||
'csibm857' => 'IBM857',
|
||||
'cp862' => 'IBM862',
|
||||
'862' => 'IBM862',
|
||||
'csibm862' => 'IBM862',
|
||||
'cp864' => 'IBM864',
|
||||
'864' => 'IBM864',
|
||||
'csibm864' => 'IBM864',
|
||||
'ibm-864' => 'IBM864',
|
||||
't.61' => 'T.61-8bit',
|
||||
'iso-ir-103' => 'T.61-8bit',
|
||||
'csiso103t618bit' => 'T.61-8bit',
|
||||
'x-unicode-2-0-utf-7' => 'UTF-7',
|
||||
'unicode-2-0-utf-7' => 'UTF-7',
|
||||
'unicode-1-1-utf-7' => 'UTF-7',
|
||||
'csunicode11utf7' => 'UTF-7',
|
||||
'csunicode' => 'UTF-16BE',
|
||||
'csunicode11' => 'UTF-16BE',
|
||||
'iso-10646-ucs-basic' => 'UTF-16BE',
|
||||
'csunicodeascii' => 'UTF-16BE',
|
||||
'iso-10646-unicode-latin1' => 'UTF-16BE',
|
||||
'csunicodelatin1' => 'UTF-16BE',
|
||||
'iso-10646' => 'UTF-16BE',
|
||||
'iso-10646-j-1' => 'UTF-16BE',
|
||||
'latin6' => 'ISO-8859-10',
|
||||
'iso-ir-157' => 'ISO-8859-10',
|
||||
'l6' => 'ISO-8859-10',
|
||||
'csisolatin6' => 'ISO-8859-10',
|
||||
'iso_8859-15' => 'ISO-8859-15',
|
||||
'csisolatin9' => 'ISO-8859-15',
|
||||
'l9' => 'ISO-8859-15',
|
||||
'ecma-cyrillic' => 'ISO-IR-111',
|
||||
'csiso111ecmacyrillic' => 'ISO-IR-111',
|
||||
'csiso2022kr' => 'ISO-2022-KR',
|
||||
'csviscii' => 'VISCII',
|
||||
'zh_tw-euc' => 'x-euc-tw',
|
||||
'iso88591' => 'ISO-8859-1',
|
||||
'iso88592' => 'ISO-8859-2',
|
||||
'iso88593' => 'ISO-8859-3',
|
||||
'iso88594' => 'ISO-8859-4',
|
||||
'iso88595' => 'ISO-8859-5',
|
||||
'iso88596' => 'ISO-8859-6',
|
||||
'iso88597' => 'ISO-8859-7',
|
||||
'iso88598' => 'ISO-8859-8',
|
||||
'iso88599' => 'ISO-8859-9',
|
||||
'iso885910' => 'ISO-8859-10',
|
||||
'iso885911' => 'ISO-8859-11',
|
||||
'iso885912' => 'ISO-8859-12',
|
||||
'iso885913' => 'ISO-8859-13',
|
||||
'iso885914' => 'ISO-8859-14',
|
||||
'iso885915' => 'ISO-8859-15',
|
||||
'tis620' => 'TIS-620',
|
||||
'cp1250' => 'windows-1250',
|
||||
'cp1251' => 'windows-1251',
|
||||
'cp1252' => 'windows-1252',
|
||||
'cp1253' => 'windows-1253',
|
||||
'cp1254' => 'windows-1254',
|
||||
'cp1255' => 'windows-1255',
|
||||
'cp1256' => 'windows-1256',
|
||||
'cp1257' => 'windows-1257',
|
||||
'cp1258' => 'windows-1258',
|
||||
'x-gbk' => 'gbk',
|
||||
'windows-936' => 'gbk',
|
||||
'ansi-1251' => 'windows-1251',
|
||||
];
|
||||
|
||||
/**
|
||||
* Decode the string from charset.
|
||||
*
|
||||
* @param string $encodedString
|
||||
* @param string $charset
|
||||
* @return string
|
||||
*/
|
||||
public function decodeCharset($encodedString, $charset)
|
||||
{
|
||||
if (strtolower($charset) == 'utf-8' || strtolower($charset) == 'us-ascii') {
|
||||
return $encodedString;
|
||||
}
|
||||
|
||||
try {
|
||||
return iconv($this->getCharsetAlias($charset), 'UTF-8//TRANSLIT', $encodedString);
|
||||
} catch (\Exception $e) {
|
||||
return iconv($this->getCharsetAlias($charset), 'UTF-8//IGNORE', $encodedString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get charset alias.
|
||||
*
|
||||
* @param string $charset.
|
||||
* @return string
|
||||
*/
|
||||
public function getCharsetAlias($charset)
|
||||
{
|
||||
$charset = strtolower($charset);
|
||||
|
||||
if (array_key_exists($charset, $this->charsetAlias)) {
|
||||
return $this->charsetAlias[$charset];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Email\Helpers\Contracts;
|
||||
|
||||
interface CharsetManager
|
||||
{
|
||||
/**
|
||||
* Decode the string from Charset.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function decodeCharset($encodedString, $charset);
|
||||
|
||||
/**
|
||||
* Get charset alias.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCharsetAlias($charset);
|
||||
}
|
||||
1207
packages/Webkul/Email/src/Helpers/HtmlFilter.php
Normal file
1207
packages/Webkul/Email/src/Helpers/HtmlFilter.php
Normal file
File diff suppressed because it is too large
Load Diff
888
packages/Webkul/Email/src/Helpers/Parser.php
Normal file
888
packages/Webkul/Email/src/Helpers/Parser.php
Normal file
@@ -0,0 +1,888 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Email\Helpers;
|
||||
|
||||
use Webkul\Email\Helpers\Contracts\CharsetManager;
|
||||
|
||||
class Parser
|
||||
{
|
||||
/**
|
||||
* Resource.
|
||||
*/
|
||||
public $resource;
|
||||
|
||||
/**
|
||||
* A file pointer to email.
|
||||
*/
|
||||
public $stream;
|
||||
|
||||
/**
|
||||
* Data.
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Container.
|
||||
*/
|
||||
public $container;
|
||||
|
||||
/**
|
||||
* Entity.
|
||||
*/
|
||||
public $entity;
|
||||
|
||||
/**
|
||||
* Files.
|
||||
*/
|
||||
public $files;
|
||||
|
||||
/**
|
||||
* Parts of an email.
|
||||
*/
|
||||
public $parts;
|
||||
|
||||
/**
|
||||
* Charset manager object.
|
||||
*/
|
||||
public $charset;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(?CharsetManager $charset = null)
|
||||
{
|
||||
if (is_null($charset)) {
|
||||
$charset = new Charset;
|
||||
}
|
||||
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the held resouces.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// clear the email file resource
|
||||
if (is_resource($this->stream)) {
|
||||
fclose($this->stream);
|
||||
}
|
||||
|
||||
// clear the mail parse resource
|
||||
if (is_resource($this->resource)) {
|
||||
mailparse_msg_free($this->resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the file path we use to get the email text.
|
||||
*
|
||||
* @param string $path
|
||||
* @return object
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->resource = mailparse_msg_parse_file($path);
|
||||
|
||||
$this->stream = fopen($path, 'r');
|
||||
|
||||
$this->parse();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the stream resource we use to get the email text.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function setStream($stream)
|
||||
{
|
||||
// streams have to be cached to file first
|
||||
$meta = @stream_get_meta_data($stream);
|
||||
|
||||
if (
|
||||
! $meta
|
||||
|| ! $meta['mode']
|
||||
|| $meta['mode'][0] != 'r'
|
||||
|| $meta['eof']
|
||||
) {
|
||||
throw new \Exception(
|
||||
'setStream() expects parameter stream to be readable stream resource.'
|
||||
);
|
||||
}
|
||||
|
||||
$tmp_fp = tmpfile();
|
||||
|
||||
if ($tmp_fp) {
|
||||
while (! feof($stream)) {
|
||||
fwrite($tmp_fp, fread($stream, 2028));
|
||||
}
|
||||
|
||||
fseek($tmp_fp, 0);
|
||||
|
||||
$this->stream = &$tmp_fp;
|
||||
} else {
|
||||
throw new \Exception(
|
||||
'Could not create temporary files for attachments. Your tmp directory may be un-writable by PHP.'
|
||||
);
|
||||
}
|
||||
|
||||
fclose($stream);
|
||||
|
||||
$this->resource = mailparse_msg_create();
|
||||
|
||||
// parses the message incrementally (low memory usage but slower)
|
||||
while (! feof($this->stream)) {
|
||||
mailparse_msg_parse($this->resource, fread($this->stream, 2082));
|
||||
}
|
||||
|
||||
$this->parse();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the email text.
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function setText($data)
|
||||
{
|
||||
$this->resource = \mailparse_msg_create();
|
||||
|
||||
// does not parse incrementally, fast memory hog might explode
|
||||
mailparse_msg_parse($this->resource, $data);
|
||||
|
||||
$this->data = $data;
|
||||
|
||||
$this->parse();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the message into parts.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function parse()
|
||||
{
|
||||
$structure = mailparse_msg_get_structure($this->resource);
|
||||
|
||||
$headerType = (stripos($this->data, 'Content-Language:') !== false) ? 'Content-Language:' : 'Content-Type:';
|
||||
|
||||
if (count($structure) == 1) {
|
||||
$tempParts = explode(PHP_EOL, $this->data);
|
||||
|
||||
foreach ($tempParts as $key => $part) {
|
||||
if (stripos($part, $headerType) !== false) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (trim($part) == '') {
|
||||
unset($tempParts[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$data = implode(PHP_EOL, $tempParts);
|
||||
|
||||
$this->resource = \mailparse_msg_create();
|
||||
|
||||
mailparse_msg_parse($this->resource, $data);
|
||||
|
||||
$this->data = $data;
|
||||
|
||||
$structure = mailparse_msg_get_structure($this->resource);
|
||||
}
|
||||
|
||||
$this->parts = [];
|
||||
|
||||
foreach ($structure as $part_id) {
|
||||
$part = mailparse_msg_get_part($this->resource, $part_id);
|
||||
|
||||
$this->parts[$part_id] = mailparse_msg_get_part_data($part);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse sender name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parseSenderName()
|
||||
{
|
||||
if (! $fromNameParts = mailparse_rfc822_parse_addresses($this->getHeader('from'))) {
|
||||
$fromNameParts = mailparse_rfc822_parse_addresses($this->getHeader('sender'));
|
||||
}
|
||||
|
||||
return $fromNameParts[0]['display'] == $fromNameParts[0]['address']
|
||||
? current(explode('@', $fromNameParts[0]['display']))
|
||||
: $fromNameParts[0]['display'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse email address.
|
||||
*
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
public function parseEmailAddress($type)
|
||||
{
|
||||
$emails = [];
|
||||
|
||||
$addresses = mailparse_rfc822_parse_addresses($this->getHeader($type));
|
||||
|
||||
if (count($addresses) > 1) {
|
||||
foreach ($addresses as $address) {
|
||||
if (filter_var($address['address'], FILTER_VALIDATE_EMAIL)) {
|
||||
$emails[] = $address['address'];
|
||||
}
|
||||
}
|
||||
} elseif ($addresses) {
|
||||
$emails[] = $addresses[0]['address'];
|
||||
}
|
||||
|
||||
return $emails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a specific email header, without charset conversion.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRawHeader($name)
|
||||
{
|
||||
if (isset($this->parts[1])) {
|
||||
$headers = $this->getPart('headers', $this->parts[1]);
|
||||
|
||||
return (isset($headers[$name])) ? $headers[$name] : false;
|
||||
} else {
|
||||
throw new \Exception(
|
||||
'setPath() or setText() or setStream() must be called before retrieving email headers.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a specific email header.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHeader($name)
|
||||
{
|
||||
$rawHeader = $this->getRawHeader($name);
|
||||
|
||||
if ($rawHeader === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->decodeHeader($rawHeader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all mail headers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders()
|
||||
{
|
||||
if (isset($this->parts[1])) {
|
||||
$headers = $this->getPart('headers', $this->parts[1]);
|
||||
|
||||
foreach ($headers as $name => &$value) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as &$v) {
|
||||
$v = $this->decodeSingleHeader($v);
|
||||
}
|
||||
} else {
|
||||
$value = $this->decodeSingleHeader($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $headers;
|
||||
} else {
|
||||
throw new \Exception(
|
||||
'setPath() or setText() or setStream() must be called before retrieving email headers.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get from name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFromName()
|
||||
{
|
||||
$headers = $this->getHeaders();
|
||||
|
||||
return $headers['from'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract multipart MIME text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function extractMultipartMIMEText($part, $source, $encodingType)
|
||||
{
|
||||
$boundary = trim($part['content-boundary']);
|
||||
$boundary = substr($boundary, strpos($boundary, '----=') + strlen('----='));
|
||||
|
||||
preg_match_all('/------=(3D_.*)\sContent-Type:\s(.*)\s*boundary=3D"----=(3D_.*)"/', $source, $matches);
|
||||
|
||||
$delimeter = array_shift($matches);
|
||||
$content_delimeter = end($delimeter);
|
||||
|
||||
[$relations, $content_types, $boundaries] = $matches;
|
||||
|
||||
$messageToProcess = substr($source, stripos($source, (string) $content_delimeter) + strlen($content_delimeter));
|
||||
|
||||
array_unshift($boundaries, $boundary);
|
||||
|
||||
// Extract the text
|
||||
foreach (array_reverse($boundaries) as $index => $boundary) {
|
||||
$processedEmailSegments = [];
|
||||
$emailSegments = explode('------='.$boundary, $messageToProcess);
|
||||
|
||||
// Remove empty parts
|
||||
foreach ($emailSegments as $emailSegment) {
|
||||
if (! empty(trim($emailSegment))) {
|
||||
$processedEmailSegments[] = trim($emailSegment);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove unrelated parts
|
||||
array_pop($processedEmailSegments);
|
||||
|
||||
for ($i = 0; $i < $index; $i++) {
|
||||
if (count($processedEmailSegments) > 1) {
|
||||
array_shift($processedEmailSegments);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse each parts for text|html content
|
||||
foreach ($processedEmailSegments as $emailSegment) {
|
||||
$emailSegment = quoted_printable_decode(quoted_printable_decode($emailSegment));
|
||||
|
||||
if (stripos($emailSegment, 'content-type: text/plain;') !== false
|
||||
|| stripos($emailSegment, 'content-type: text/html;') !== false
|
||||
) {
|
||||
$search = 'content-transfer-encoding: '.$encodingType;
|
||||
|
||||
return substr($emailSegment, stripos($emailSegment, $search) + strlen($search));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the email message body in the specified format.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getMessageBody($type = 'text')
|
||||
{
|
||||
$textBody = $htmlBody = $body = false;
|
||||
|
||||
$mime_types = [
|
||||
'text'=> 'text/plain',
|
||||
'text'=> 'text/plain; (error)',
|
||||
'html'=> 'text/html',
|
||||
];
|
||||
|
||||
if (in_array($type, array_keys($mime_types))) {
|
||||
foreach ($this->parts as $key => $part) {
|
||||
if (in_array($this->getPart('content-type', $part), $mime_types)
|
||||
&& $this->getPart('content-disposition', $part) != 'attachment'
|
||||
) {
|
||||
$headers = $this->getPart('headers', $part);
|
||||
$encodingType = array_key_exists('content-transfer-encoding', $headers) ? $headers['content-transfer-encoding'] : '';
|
||||
|
||||
if ($this->getPart('content-type', $part) == 'text/plain') {
|
||||
$textBody .= $this->decodeContentTransfer($this->getPartBody($part), $encodingType);
|
||||
$textBody = nl2br($this->charset->decodeCharset($textBody, $this->getPartCharset($part)));
|
||||
} elseif ($this->getPart('content-type', $part) == 'text/plain; (error)') {
|
||||
if (empty($part['headers']) || ! isset($part['headers']['from'])) {
|
||||
$parentKey = explode('.', $key)[0];
|
||||
if (isset($this->parts[$parentKey]) && isset($this->parts[$parentKey]['headers']['from'])) {
|
||||
$part_from_sender = is_array($this->parts[$parentKey]['headers']['from'])
|
||||
? $this->parts[$parentKey]['headers']['from'][0]
|
||||
: $this->parts[$parentKey]['headers']['from'];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$part_from_sender = is_array($part['headers']['from'])
|
||||
? $part['headers']['from'][0]
|
||||
: $part['headers']['from'];
|
||||
}
|
||||
$mail_part_addresses = mailparse_rfc822_parse_addresses($part_from_sender);
|
||||
|
||||
if (! empty($mail_part_addresses[0]['address'])
|
||||
&& strrpos($mail_part_addresses[0]['address'], 'pcsms.com') !== false
|
||||
) {
|
||||
$last_header = end($headers);
|
||||
$partMessage = substr($this->data, strrpos($this->data, $last_header) + strlen($last_header), $part['ending-pos-body']);
|
||||
$textBody .= $this->decodeContentTransfer($partMessage, $encodingType);
|
||||
$textBody = nl2br($this->charset->decodeCharset($textBody, $this->getPartCharset($part)));
|
||||
}
|
||||
} elseif ($this->getPart('content-type', $part) == 'multipart/mixed'
|
||||
|| $this->getPart('content-type', $part) == 'multipart/related'
|
||||
) {
|
||||
$emailContent = $this->extractMultipartMIMEText($part, $this->data, $encodingType);
|
||||
|
||||
$textBody .= $this->decodeContentTransfer($emailContent, $encodingType);
|
||||
$textBody = nl2br($this->charset->decodeCharset($textBody, $this->getPartCharset($part)));
|
||||
} else {
|
||||
$htmlBody .= $this->decodeContentTransfer($this->getPartBody($part), $encodingType);
|
||||
$htmlBody = $this->charset->decodeCharset($htmlBody, $this->getPartCharset($part));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$body = $htmlBody ?: $textBody;
|
||||
|
||||
if (is_array($this->files)) {
|
||||
foreach ($this->files as $file) {
|
||||
if ($file['contentId']) {
|
||||
$body = str_replace('cid:'.preg_replace('/[<>]/', '', $file['contentId']), $file['path'], $body);
|
||||
$path = $file['path'];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new \Exception('Invalid type specified for getMessageBody(). "type" can either be text or html.');
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get text message body.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTextMessageBody()
|
||||
{
|
||||
$textBody = null;
|
||||
|
||||
foreach ($this->parts as $key => $part) {
|
||||
if ($this->getPart('content-disposition', $part) != 'attachment') {
|
||||
$headers = $this->getPart('headers', $part);
|
||||
$encodingType = array_key_exists('content-transfer-encoding', $headers) ? $headers['content-transfer-encoding'] : '';
|
||||
|
||||
if ($this->getPart('content-type', $part) == 'text/plain') {
|
||||
$textBody .= $this->decodeContentTransfer($this->getPartBody($part), $encodingType);
|
||||
$textBody = nl2br($this->charset->decodeCharset($textBody, $this->getPartCharset($part)));
|
||||
} elseif ($this->getPart('content-type', $part) == 'text/plain; (error)') {
|
||||
$part_from_sender = is_array($part['headers']['from']) ? $part['headers']['from'][0] : $part['headers']['from'];
|
||||
$mail_part_addresses = mailparse_rfc822_parse_addresses($part_from_sender);
|
||||
|
||||
if (! empty($mail_part_addresses[0]['address'])
|
||||
&& strrpos($mail_part_addresses[0]['address'], 'pcsms.com') !== false
|
||||
) {
|
||||
$last_header = end($headers);
|
||||
$partMessage = substr($this->data, strrpos($this->data, $last_header) + strlen($last_header), $part['ending-pos-body']);
|
||||
$textBody .= $this->decodeContentTransfer($partMessage, $encodingType);
|
||||
$textBody = nl2br($this->charset->decodeCharset($textBody, $this->getPartCharset($part)));
|
||||
}
|
||||
} elseif ($this->getPart('content-type', $part) == 'multipart/mixed'
|
||||
|| $this->getPart('content-type', $part) == 'multipart/related'
|
||||
) {
|
||||
$emailContent = $this->extractMultipartMIMEText($part, $this->data, $encodingType);
|
||||
|
||||
$textBody .= $this->decodeContentTransfer($emailContent, $encodingType);
|
||||
$textBody = nl2br($this->charset->decodeCharset($textBody, $this->getPartCharset($part)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $textBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attachments contents in order of appearance.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAttachments()
|
||||
{
|
||||
$attachments = [];
|
||||
$dispositions = ['attachment', 'inline'];
|
||||
$non_attachment_types = ['text/plain', 'text/html', 'text/plain; (error)'];
|
||||
$nonameIter = 0;
|
||||
|
||||
foreach ($this->parts as $part) {
|
||||
$disposition = $this->getPart('content-disposition', $part);
|
||||
$filename = 'noname';
|
||||
|
||||
if (isset($part['disposition-filename'])) {
|
||||
$filename = $this->decodeHeader($part['disposition-filename']);
|
||||
} elseif (isset($part['content-name'])) {
|
||||
// if we have no disposition but we have a content-name, it's a valid attachment.
|
||||
// we simulate the presence of an attachment disposition with a disposition filename
|
||||
$filename = $this->decodeHeader($part['content-name']);
|
||||
$disposition = 'attachment';
|
||||
} elseif (! in_array($part['content-type'], $non_attachment_types, true)
|
||||
&& substr($part['content-type'], 0, 10) !== 'multipart/'
|
||||
) {
|
||||
// if we cannot get it by getMessageBody(), we assume it is an attachment
|
||||
$disposition = 'attachment';
|
||||
}
|
||||
|
||||
if (in_array($disposition, $dispositions) === true && isset($filename) === true) {
|
||||
if ($filename == 'noname') {
|
||||
$nonameIter++;
|
||||
$filename = 'noname'.$nonameIter;
|
||||
}
|
||||
|
||||
$headersAttachments = $this->getPart('headers', $part);
|
||||
$contentidAttachments = $this->getPart('content-id', $part);
|
||||
|
||||
if (! $contentidAttachments
|
||||
&& $disposition == 'inline'
|
||||
&& ! strpos($this->getPart('content-type', $part), 'image/')
|
||||
&& ! stripos($filename, 'noname') == false
|
||||
) {
|
||||
// skip
|
||||
} else {
|
||||
$attachments[] = new Attachment(
|
||||
$filename,
|
||||
$this->getPart('content-type', $part),
|
||||
$this->getAttachmentStream($part),
|
||||
$disposition,
|
||||
$contentidAttachments,
|
||||
$headersAttachments
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ! empty($attachments) ? $attachments : $this->extractMultipartMIMEAttachments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract attachments from multipart MIME.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function extractMultipartMIMEAttachments()
|
||||
{
|
||||
$attachmentCollection = $processedAttachmentCollection = [];
|
||||
|
||||
foreach ($this->parts as $part) {
|
||||
$boundary = isset($part['content-boundary']) ? trim($part['content-boundary']) : '';
|
||||
$boundary = substr($boundary, strpos($boundary, '----=') + strlen('----='));
|
||||
|
||||
preg_match_all('/------=(3D_.*)\sContent-Type:\s(.*)\s*boundary=3D"----=(3D_.*)"/', $this->data, $matches);
|
||||
|
||||
$delimeter = array_shift($matches);
|
||||
$content_delimeter = end($delimeter);
|
||||
|
||||
[$relations, $content_types, $boundaries] = $matches;
|
||||
$messageToProcess = substr($this->data, stripos($this->data, (string) $content_delimeter) + strlen($content_delimeter));
|
||||
|
||||
array_unshift($boundaries, $boundary);
|
||||
|
||||
// Extract the text
|
||||
foreach (array_reverse($boundaries) as $index => $boundary) {
|
||||
$processedEmailSegments = [];
|
||||
$emailSegments = explode('------='.$boundary, $messageToProcess);
|
||||
|
||||
// Remove empty parts
|
||||
foreach ($emailSegments as $emailSegment) {
|
||||
if (! empty(trim($emailSegment))) {
|
||||
$processedEmailSegments[] = trim($emailSegment);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove unrelated parts
|
||||
array_pop($processedEmailSegments);
|
||||
|
||||
for ($i = 0; $i < $index; $i++) {
|
||||
if (count($processedEmailSegments) > 1) {
|
||||
array_shift($processedEmailSegments);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse each parts for text|html content
|
||||
foreach ($processedEmailSegments as $emailSegment) {
|
||||
$emailSegment = quoted_printable_decode(quoted_printable_decode($emailSegment));
|
||||
|
||||
if (stripos($emailSegment, 'content-type: text/plain;') === false
|
||||
&& stripos($emailSegment, 'content-type: text/html;') === false
|
||||
) {
|
||||
$attachmentParts = explode("\n\n", $emailSegment);
|
||||
|
||||
if (! empty($attachmentParts) && count($attachmentParts) == 2) {
|
||||
$attachmentDetails = explode("\n", $attachmentParts[0]);
|
||||
|
||||
$attachmentDetails = array_map(function ($item) {
|
||||
return trim($item);
|
||||
}, $attachmentDetails);
|
||||
|
||||
$attachmentData = trim($attachmentParts[1]);
|
||||
|
||||
$attachmentCollection[] = [
|
||||
'details' => $attachmentDetails,
|
||||
'data' => $attachmentData,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($attachmentCollection as $attachmentDetails) {
|
||||
$stream = '';
|
||||
|
||||
$resourceDetails = [
|
||||
'name' => '',
|
||||
'fileName' => '',
|
||||
'contentType' => '',
|
||||
'encodingType' => 'base64',
|
||||
'contentDisposition' => 'inline',
|
||||
'contentId' => '',
|
||||
];
|
||||
|
||||
foreach ($attachmentDetails['details'] as $attachmentDetail) {
|
||||
if (stripos($attachmentDetail, 'Content-Type: ') === 0) {
|
||||
$resourceDetails['contentType'] = substr($attachmentDetail, strlen('Content-Type: '));
|
||||
} elseif (stripos($attachmentDetail, 'name="') === 0) {
|
||||
$resourceDetails['name'] = substr($attachmentDetail, strlen('name="'), -1);
|
||||
} elseif (stripos($attachmentDetail, 'Content-Transfer-Encoding: ') === 0) {
|
||||
$resourceDetails['encodingType'] = substr($attachmentDetail, strlen('Content-Transfer-Encoding: '));
|
||||
} elseif (stripos($attachmentDetail, 'Content-ID: ') === 0) {
|
||||
$resourceDetails['contentId'] = substr($attachmentDetail, strlen('Content-ID: '));
|
||||
} elseif (stripos($attachmentDetail, 'filename="') === 0) {
|
||||
$resourceDetails['fileName'] = substr($attachmentDetail, strlen('filename="'), -1);
|
||||
} elseif (stripos($attachmentDetail, 'Content-Disposition: ') === 0) {
|
||||
$resourceDetails['contentDisposition'] = substr($attachmentDetail, strlen('Content-Disposition: '), -1);
|
||||
}
|
||||
}
|
||||
|
||||
$resourceDetails['name'] = empty($resourceDetails['name']) ? $resourceDetails['fileName'] : $resourceDetails['name'];
|
||||
$resourceDetails['fileName'] = empty($resourceDetails['fileName']) ? $resourceDetails['name'] : $resourceDetails['fileName'];
|
||||
|
||||
$temp_fp = tmpfile();
|
||||
|
||||
fwrite($temp_fp, base64_decode($attachmentDetails['data']), strlen($attachmentDetails['data']));
|
||||
fseek($temp_fp, 0, SEEK_SET);
|
||||
|
||||
$processedAttachmentCollection[] = new Attachment(
|
||||
$resourceDetails['fileName'],
|
||||
$resourceDetails['contentType'],
|
||||
$temp_fp,
|
||||
$resourceDetails['contentDisposition'],
|
||||
$resourceDetails['contentId'], []
|
||||
);
|
||||
}
|
||||
|
||||
return $processedAttachmentCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the attachment body and save temporary file resource.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getAttachmentStream(&$part)
|
||||
{
|
||||
$temp_fp = tmpfile();
|
||||
|
||||
$headers = $this->getPart('headers', $part);
|
||||
$encodingType = array_key_exists('content-transfer-encoding', $headers)
|
||||
? $headers['content-transfer-encoding']
|
||||
: '';
|
||||
|
||||
if ($temp_fp) {
|
||||
if ($this->stream) {
|
||||
$start = $part['starting-pos-body'];
|
||||
$end = $part['ending-pos-body'];
|
||||
|
||||
fseek($this->stream, $start, SEEK_SET);
|
||||
|
||||
$len = $end - $start;
|
||||
$written = 0;
|
||||
|
||||
while ($written < $len) {
|
||||
$write = $len;
|
||||
$part = fread($this->stream, $write);
|
||||
|
||||
fwrite($temp_fp, $this->decodeContentTransfer($part, $encodingType));
|
||||
|
||||
$written += $write;
|
||||
}
|
||||
} elseif ($this->data) {
|
||||
$attachment = $this->decodeContentTransfer($this->getPartBodyFromText($part), $encodingType);
|
||||
|
||||
fwrite($temp_fp, $attachment, strlen($attachment));
|
||||
}
|
||||
|
||||
fseek($temp_fp, 0, SEEK_SET);
|
||||
} else {
|
||||
throw new \Exception(
|
||||
'Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'
|
||||
);
|
||||
}
|
||||
|
||||
return $temp_fp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the string from Content-Transfer-Encoding.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function decodeContentTransfer($encodedString, $encodingType)
|
||||
{
|
||||
$encodingType = strtolower($encodingType);
|
||||
|
||||
if ($encodingType == 'base64') {
|
||||
return base64_decode($encodedString);
|
||||
} elseif ($encodingType == 'quoted-printable') {
|
||||
return quoted_printable_decode($encodedString);
|
||||
} else {
|
||||
return $encodedString; // 8bit, 7bit, binary
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode header.
|
||||
*
|
||||
* @param string|array $input
|
||||
* @return string
|
||||
*/
|
||||
private function decodeHeader($input)
|
||||
{
|
||||
// sometimes we have 2 label From so we take only the first
|
||||
if (is_array($input)) {
|
||||
return $this->decodeSingleHeader($input[0]);
|
||||
}
|
||||
|
||||
return $this->decodeSingleHeader($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a single header (= string).
|
||||
*
|
||||
* @param string
|
||||
* @return string
|
||||
*/
|
||||
private function decodeSingleHeader($input)
|
||||
{
|
||||
// Remove white space between encoded-words
|
||||
$input = preg_replace('/(=\?[^?]+\?(q|b)\?[^?]*\?=)(\s)+=\?/i', '\1=?', $input);
|
||||
|
||||
// For each encoded-word...
|
||||
while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)/i', $input, $matches)) {
|
||||
$encoded = $matches[1];
|
||||
$charset = $matches[2];
|
||||
$encoding = $matches[3];
|
||||
$text = $matches[4];
|
||||
|
||||
switch (strtolower($encoding)) {
|
||||
case 'b':
|
||||
$text = $this->decodeContentTransfer($text, 'base64');
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
$text = str_replace('_', ' ', $text);
|
||||
|
||||
preg_match_all('/=([a-f0-9]{2})/i', $text, $matches);
|
||||
|
||||
foreach ($matches[1] as $value) {
|
||||
$text = str_replace('='.$value, chr(hexdec($value)), $text);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$text = $this->charset->decodeCharset($text, $this->charset->getCharsetAlias($charset));
|
||||
|
||||
$input = str_replace($encoded, $text, $input);
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the charset of the MIME part.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
private function getPartCharset($part)
|
||||
{
|
||||
if (isset($part['charset'])) {
|
||||
return $charset = $this->charset->getCharsetAlias($part['charset']);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a specified MIME part.
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
private function getPart($type, $parts)
|
||||
{
|
||||
return (isset($parts[$type])) ? $parts[$type] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Body of a MIME part.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getPartBody(&$part)
|
||||
{
|
||||
$body = '';
|
||||
|
||||
if ($this->stream) {
|
||||
$body = $this->getPartBodyFromFile($part);
|
||||
} elseif ($this->data) {
|
||||
$body = $this->getPartBodyFromText($part);
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Body from a MIME part from file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getPartBodyFromFile(&$part)
|
||||
{
|
||||
$start = $part['starting-pos-body'];
|
||||
|
||||
$end = $part['ending-pos-body'];
|
||||
|
||||
fseek($this->stream, $start, SEEK_SET);
|
||||
|
||||
return fread($this->stream, $end - $start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Body from a MIME part from text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getPartBodyFromText(&$part)
|
||||
{
|
||||
$start = $part['starting-pos-body'];
|
||||
|
||||
$end = $part['ending-pos-body'];
|
||||
|
||||
return substr($this->data, $start, $end - $start);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user