From 3ffef6df51e0ca58fc1d607b9c4d6d376ba480fe Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 28 Nov 2025 17:27:05 -0500 Subject: [PATCH] Remove library phpMimeParser as its no longer needed and php-imap webklex is not doing this function --- plugins/php-mime-mail-parser/Attachment.php | 276 ------ plugins/php-mime-mail-parser/Charset.php | 370 ------- .../Contracts/CharsetManager.php | 24 - .../Contracts/Middleware.php | 23 - plugins/php-mime-mail-parser/Exception.php | 8 - plugins/php-mime-mail-parser/Middleware.php | 29 - .../php-mime-mail-parser/MiddlewareStack.php | 89 -- plugins/php-mime-mail-parser/MimePart.php | 119 --- plugins/php-mime-mail-parser/Parser.php | 928 ------------------ 9 files changed, 1866 deletions(-) delete mode 100644 plugins/php-mime-mail-parser/Attachment.php delete mode 100644 plugins/php-mime-mail-parser/Charset.php delete mode 100644 plugins/php-mime-mail-parser/Contracts/CharsetManager.php delete mode 100644 plugins/php-mime-mail-parser/Contracts/Middleware.php delete mode 100644 plugins/php-mime-mail-parser/Exception.php delete mode 100644 plugins/php-mime-mail-parser/Middleware.php delete mode 100644 plugins/php-mime-mail-parser/MiddlewareStack.php delete mode 100644 plugins/php-mime-mail-parser/MimePart.php delete mode 100644 plugins/php-mime-mail-parser/Parser.php diff --git a/plugins/php-mime-mail-parser/Attachment.php b/plugins/php-mime-mail-parser/Attachment.php deleted file mode 100644 index 9b001a5b..00000000 --- a/plugins/php-mime-mail-parser/Attachment.php +++ /dev/null @@ -1,276 +0,0 @@ -filename = $filename; - $this->contentType = $contentType; - $this->stream = $stream; - $this->content = null; - $this->contentDisposition = $contentDisposition; - $this->contentId = $contentId; - $this->headers = $headers; - $this->mimePartStr = $mimePartStr; - } - - /** - * 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 array - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * Get a handle to the stream - * - * @return resource - */ - public function getStream() - { - return $this->stream; - } - - /** - * Rename a file if it already exists at its destination. - * Renaming is done by adding a duplicate number to the file name. E.g. existingFileName_1.ext. - * After a max duplicate number, renaming the file will switch over to generating a random suffix. - * - * @param string $fileName Complete path to the file. - * @return string The suffixed file name. - */ - protected function suffixFileName(string $fileName): string - { - $pathInfo = pathinfo($fileName); - $dirname = $pathInfo['dirname'].DIRECTORY_SEPARATOR; - $filename = $pathInfo['filename']; - $extension = empty($pathInfo['extension']) ? '' : '.'.$pathInfo['extension']; - - $i = 0; - do { - $i++; - - if ($i > $this->maxDuplicateNumber) { - $duplicateExtension = uniqid(); - } else { - $duplicateExtension = $i; - } - - $resultName = $dirname.$filename."_$duplicateExtension".$extension; - } while (file_exists($resultName)); - - return $resultName; - } - - /** - * Read the contents a few bytes at a time until completed - * Once read to completion, it always returns false - * - * @param int $bytes (default: 2082) - * - * @return string|bool - */ - 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; - } - - /** - * Get mime part string for this attachment - * - * @return string - */ - public function getMimePartStr() - { - return $this->mimePartStr; - } - - /** - * Save the attachment individually - * - * @param string $attach_dir - * @param string $filenameStrategy - * - * @return string - */ - public function save( - $attach_dir, - $filenameStrategy = Parser::ATTACHMENT_DUPLICATE_SUFFIX - ) { - $attach_dir = rtrim($attach_dir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; - if (!is_dir($attach_dir)) { - mkdir($attach_dir); - } - - // Determine filename - switch ($filenameStrategy) { - case Parser::ATTACHMENT_RANDOM_FILENAME: - $fileInfo = pathinfo($this->getFilename()); - $extension = empty($fileInfo['extension']) ? '' : '.'.$fileInfo['extension']; - $attachment_path = $attach_dir.bin2hex(random_bytes(16)).$extension; - break; - case Parser::ATTACHMENT_DUPLICATE_THROW: - case Parser::ATTACHMENT_DUPLICATE_SUFFIX: - $attachment_path = $attach_dir.$this->getFilename(); - break; - default: - throw new Exception('Invalid filename strategy argument provided.'); - } - - // Handle duplicate filename - if (file_exists($attachment_path)) { - switch ($filenameStrategy) { - case Parser::ATTACHMENT_DUPLICATE_THROW: - throw new Exception('Could not create file for attachment: duplicate filename.'); - case Parser::ATTACHMENT_DUPLICATE_SUFFIX: - $attachment_path = $this->suffixFileName($attachment_path); - break; - } - } - - /** @var resource $fp */ - if ($fp = fopen($attachment_path, 'w')) { - while ($bytes = $this->read()) { - fwrite($fp, $bytes); - } - fclose($fp); - return realpath($attachment_path); - } else { - throw new Exception('Could not write attachments. Your directory may be unwritable by PHP.'); - } - } -} diff --git a/plugins/php-mime-mail-parser/Charset.php b/plugins/php-mime-mail-parser/Charset.php deleted file mode 100644 index 0824f947..00000000 --- a/plugins/php-mime-mail-parser/Charset.php +++ /dev/null @@ -1,370 +0,0 @@ - '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', - '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' => 'macce', - 'x-mac-turkish' => 'macturkish', - 'x-mac-greek' => 'macgreek', - 'x-mac-icelandic' => 'macicelandic', - 'x-mac-croatian' => 'maccroatian', - 'x-mac-romanian' => 'macromanian', - 'x-mac-cyrillic' => 'maccyrillic', - 'x-mac-ukrainian' => 'macukrainian', - 'x-mac-hebrew' => 'machebrew', - 'x-mac-arabic' => 'macarabic', - 'x-mac-farsi' => 'macfarsi', - 'x-mac-devanagari' => 'macdevanagari', - 'x-mac-gujarati' => 'macgujarati', - 'x-mac-gurmukhi' => 'macgurmukhi', - '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', - 'iso-8859-8i' => 'iso-8859-8', - 'logical' => 'iso-8859-8', - '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', - ]; - - /** - * {@inheritdoc} - */ - public function decodeCharset($encodedString, $charset) - { - $charset = $this->getCharsetAlias($charset); - - if ($charset == 'utf-8' || $charset == 'us-ascii') { - return $encodedString; - } - - if (function_exists('mb_convert_encoding')) { - if ($charset == 'iso-2022-jp') { - return mb_convert_encoding($encodedString, 'utf-8', 'iso-2022-jp-ms'); - } - - if (array_search($charset, $this->getSupportedEncodings())) { - return mb_convert_encoding($encodedString, 'utf-8', $charset); - } - } - - return iconv($charset, 'utf-8//translit//ignore', $encodedString); - } - - /** - * {@inheritdoc} - */ - public function getCharsetAlias($charset) - { - $charset = strtolower($charset); - - if (array_key_exists($charset, $this->charsetAlias)) { - return $this->charsetAlias[$charset]; - } - - return 'us-ascii'; - } - - private function getSupportedEncodings() - { - return - array_map( - 'strtolower', - array_unique( - array_merge( - $enc = array_diff(mb_list_encodings(), ['BASE64', 'UUENCODE', 'HTML-ENTITIES', 'Quoted-Printable']), - call_user_func_array( - 'array_merge', - array_map( - "mb_encoding_aliases", - $enc - ) - ) - ) - ) - ); - } -} diff --git a/plugins/php-mime-mail-parser/Contracts/CharsetManager.php b/plugins/php-mime-mail-parser/Contracts/CharsetManager.php deleted file mode 100644 index 660ec00c..00000000 --- a/plugins/php-mime-mail-parser/Contracts/CharsetManager.php +++ /dev/null @@ -1,24 +0,0 @@ -parser = $fn; - } - - /** - * Process a mime part, optionally delegating parsing to the $next MiddlewareStack - */ - public function parse(MimePart $part, MiddlewareStack $next) - { - return call_user_func($this->parser, $part, $next); - } -} diff --git a/plugins/php-mime-mail-parser/MiddlewareStack.php b/plugins/php-mime-mail-parser/MiddlewareStack.php deleted file mode 100644 index ecab6445..00000000 --- a/plugins/php-mime-mail-parser/MiddlewareStack.php +++ /dev/null @@ -1,89 +0,0 @@ -add($Middleware) - * - * @param Middleware $middleware - */ - public function __construct(?MiddleWareContracts $middleware = null) - { - $this->middleware = $middleware; - } - - /** - * Creates a chained middleware in MiddlewareStack - * - * @param Middleware $middleware - * @return MiddlewareStack Immutable MiddlewareStack - */ - public function add(MiddleWareContracts $middleware) - { - $stack = new static($middleware); - $stack->next = $this; - return $stack; - } - - /** - * Parses the MimePart by passing it through the Middleware - * @param MimePart $part - * @return MimePart - */ - public function parse(MimePart $part) - { - if (!$this->middleware) { - return $part; - } - $part = call_user_func(array($this->middleware, 'parse'), $part, $this->next); - return $part; - } - - /** - * Creates a MiddlewareStack based on an array of middleware - * - * @param Middleware[] $middlewares - * @return MiddlewareStack - */ - public static function factory(array $middlewares = array()) - { - $stack = new static; - foreach ($middlewares as $middleware) { - $stack = $stack->add($middleware); - } - return $stack; - } - - /** - * Allow calling MiddlewareStack instance directly to invoke parse() - * - * @param MimePart $part - * @return MimePart - */ - public function __invoke(MimePart $part) - { - return $this->parse($part); - } -} diff --git a/plugins/php-mime-mail-parser/MimePart.php b/plugins/php-mime-mail-parser/MimePart.php deleted file mode 100644 index d2211b7c..00000000 --- a/plugins/php-mime-mail-parser/MimePart.php +++ /dev/null @@ -1,119 +0,0 @@ -getPart(); - * $part['headers']['from'] = 'modified@example.com'; - * $MimePart->setPart($part); - */ -class MimePart implements \ArrayAccess -{ - /** - * Internal mime part - * - * @var array - */ - protected $part = array(); - - /** - * Immutable Part Id - * - * @var string - */ - private $id; - - /** - * Create a mime part - * - * @param array $part - * @param string $id - */ - public function __construct($id, array $part) - { - $this->part = $part; - $this->id = $id; - } - - /** - * Retrieve the part Id - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Retrieve the part data - * - * @return array - */ - public function getPart() - { - return $this->part; - } - - /** - * Set the mime part data - * - * @param array $part - * @return void - */ - public function setPart(array $part) - { - $this->part = $part; - } - - /** - * ArrayAccess - */ - #[\ReturnTypeWillChange] - public function offsetSet($offset, $value) - { - if (is_null($offset)) { - $this->part[] = $value; - return; - } - $this->part[$offset] = $value; - } - - /** - * ArrayAccess - */ - #[\ReturnTypeWillChange] - public function offsetExists($offset) - { - return isset($this->part[$offset]); - } - - /** - * ArrayAccess - */ - #[\ReturnTypeWillChange] - public function offsetUnset($offset) - { - unset($this->part[$offset]); - } - - /** - * ArrayAccess - */ - #[\ReturnTypeWillChange] - public function offsetGet($offset) - { - return isset($this->part[$offset]) ? $this->part[$offset] : null; - } -} diff --git a/plugins/php-mime-mail-parser/Parser.php b/plugins/php-mime-mail-parser/Parser.php deleted file mode 100644 index fcc4d7c6..00000000 --- a/plugins/php-mime-mail-parser/Parser.php +++ /dev/null @@ -1,928 +0,0 @@ -saveAttachments(). - */ - const ATTACHMENT_DUPLICATE_THROW = 'DuplicateThrow'; - const ATTACHMENT_DUPLICATE_SUFFIX = 'DuplicateSuffix'; - const ATTACHMENT_RANDOM_FILENAME = 'RandomFilename'; - - /** - * PHP MimeParser Resource ID - * - * @var resource $resource - */ - protected $resource; - - /** - * A file pointer to email - * - * @var resource $stream - */ - protected $stream; - - /** - * A text of an email - * - * @var string $data - */ - protected $data; - - /** - * Parts of an email - * - * @var array $parts - */ - protected $parts; - - /** - * @var CharsetManager object - */ - protected $charset; - - /** - * Valid stream modes for reading - * - * @var array - */ - protected static $readableModes = [ - 'r', 'r+', 'w+', 'a+', 'x+', 'c+', 'rb', 'r+b', 'w+b', 'a+b', - 'x+b', 'c+b', 'rt', 'r+t', 'w+t', 'a+t', 'x+t', 'c+t' - ]; - - /** - * Stack of middleware registered to process data - * - * @var MiddlewareStack - */ - protected $middlewareStack; - - /** - * Parser constructor. - * - * @param CharsetManager|null $charset - */ - public function __construct(?CharsetManager $charset = null) - { - if ($charset == null) { - $charset = new Charset(); - } - - $this->charset = $charset; - $this->middlewareStack = new MiddlewareStack(); - } - - /** - * Free the held resources - * - * @return void - */ - public function __destruct() - { - // clear the email file resource - if (is_resource($this->stream)) { - fclose($this->stream); - } - // clear the MailParse 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 File path to the MIME mail - * - * @return Parser MimeMailParser Instance - */ - public function setPath($path) - { - if (is_writable($path)) { - $file = fopen($path, 'a+'); - fseek($file, -1, SEEK_END); - if (fread($file, 1) != "\n") { - fwrite($file, PHP_EOL); - } - fclose($file); - } - - // should parse message incrementally from file - $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 - * - * @param resource $stream - * - * @return Parser MimeMailParser Instance - * @throws Exception - */ - public function setStream($stream) - { - // streams have to be cached to file first - $meta = @stream_get_meta_data($stream); - if (!$meta || !$meta['mode'] || !in_array($meta['mode'], self::$readableModes, true)) { - throw new Exception( - 'setStream() expects parameter stream to be readable stream resource.' - ); - } - - /** @var resource $tmp_fp */ - $tmp_fp = tmpfile(); - if ($tmp_fp) { - while (!feof($stream)) { - fwrite($tmp_fp, fread($stream, 2028)); - } - - if (fread($tmp_fp, 1) != "\n") { - fwrite($tmp_fp, PHP_EOL); - } - - fseek($tmp_fp, 0); - $this->stream = &$tmp_fp; - } else { - throw new Exception( - 'Could not create temporary files for attachments. Your tmp directory may be unwritable 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 - * - * @param string $data - * - * @return Parser MimeMailParser Instance - */ - public function setText($data) - { - if (empty($data)) { - throw new Exception('You must not call MimeMailParser::setText with an empty string parameter'); - } - - if (substr($data, -1) != "\n") { - $data = $data.PHP_EOL; - } - - $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 - */ - protected function parse() - { - if (!$this->resource) { - throw new Exception( - 'MIME message cannot be parsed' - ); - } - $structure = mailparse_msg_get_structure($this->resource); - $this->parts = []; - foreach ($structure as $part_id) { - $part = mailparse_msg_get_part($this->resource, $part_id); - $part_data = mailparse_msg_get_part_data($part); - $mimePart = new MimePart($part_id, $part_data); - // let each middleware parse the part before saving - $this->parts[$part_id] = $this->middlewareStack->parse($mimePart)->getPart(); - } - } - - /** - * Retrieve a specific Email Header, without charset conversion. - * - * @param string $name Header name (case-insensitive) - * - * @return string|bool - * @throws Exception - */ - public function getRawHeader($name) - { - $name = strtolower($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 - * - * @param string $name Header name (case-insensitive) - * - * @return string|false - */ - public function getHeader($name) - { - $rawHeader = $this->getRawHeader($name); - if ($rawHeader === false) { - return false; - } - - return $this->decodeHeader($rawHeader); - } - - /** - * Retrieve all mail headers - * - * @return array - * @throws Exception - */ - public function getHeaders() - { - if (isset($this->parts[1])) { - $headers = $this->getPart('headers', $this->parts[1]); - foreach ($headers as &$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.' - ); - } - } - - /** - * Retrieve the raw mail headers as a string - * - * @return string - * @throws Exception - */ - public function getHeadersRaw() - { - if (isset($this->parts[1])) { - return $this->getPartHeader($this->parts[1]); - } else { - throw new Exception( - 'setPath() or setText() or setStream() must be called before retrieving email headers.' - ); - } - } - - /** - * Retrieve the raw Header of a MIME part - * - * @return String - * @param $part Object - * @throws Exception - */ - protected function getPartHeader(&$part) - { - $header = ''; - if ($this->stream) { - $header = $this->getPartHeaderFromFile($part); - } elseif ($this->data) { - $header = $this->getPartHeaderFromText($part); - } - return $header; - } - - /** - * Retrieve the Header from a MIME part from file - * - * @return String Mime Header Part - * @param $part Array - */ - protected function getPartHeaderFromFile(&$part) - { - $start = $part['starting-pos']; - $end = $part['starting-pos-body']; - fseek($this->stream, $start, SEEK_SET); - $header = fread($this->stream, $end - $start); - return $header; - } - - /** - * Retrieve the Header from a MIME part from text - * - * @return String Mime Header Part - * @param $part Array - */ - protected function getPartHeaderFromText(&$part) - { - $start = $part['starting-pos']; - $end = $part['starting-pos-body']; - $header = substr($this->data, $start, $end - $start); - return $header; - } - - /** - * Checks whether a given part ID is a child of another part - * eg. an RFC822 attachment may have one or more text parts - * - * @param string $partId - * @param string $parentPartId - * @return bool - */ - protected function partIdIsChildOfPart($partId, $parentPartId) - { - $parentPartId = $parentPartId.'.'; - return substr($partId, 0, strlen($parentPartId)) == $parentPartId; - } - - /** - * Whether the given part ID is a child of any attachment part in the message. - * - * @param string $checkPartId - * @return bool - */ - protected function partIdIsChildOfAnAttachment($checkPartId) - { - foreach ($this->parts as $partId => $part) { - if ($this->getPart('content-disposition', $part) == 'attachment') { - if ($this->partIdIsChildOfPart($checkPartId, $partId)) { - return true; - } - } - } - return false; - } - - /** - * Returns the email message body in the specified format - * - * @param string $type text, html or htmlEmbedded - * - * @return string Body - * @throws Exception - */ - public function getMessageBody($type = 'text') - { - $mime_types = [ - 'text' => 'text/plain', - 'html' => 'text/html', - 'htmlEmbedded' => 'text/html', - ]; - - if (in_array($type, array_keys($mime_types))) { - $part_type = $type === 'htmlEmbedded' ? 'html' : $type; - $inline_parts = $this->getInlineParts($part_type); - $body = empty($inline_parts) ? '' : $inline_parts[0]; - } else { - throw new Exception( - 'Invalid type specified for getMessageBody(). Expected: text, html or htmlEmbedded.' - ); - } - - if ($type == 'htmlEmbedded') { - $attachments = $this->getAttachments(); - foreach ($attachments as $attachment) { - if ($attachment->getContentID() != '') { - $body = str_replace( - '"cid:'.$attachment->getContentID().'"', - '"'.$this->getEmbeddedData($attachment->getContentID()).'"', - $body - ); - } - } - } - - return $body; - } - - /** - * Returns the embedded data structure - * - * @param string $contentId Content-Id - * - * @return string - */ - protected function getEmbeddedData($contentId) - { - foreach ($this->parts as $part) { - if ($this->getPart('content-id', $part) == $contentId) { - $embeddedData = 'data:'; - $embeddedData .= $this->getPart('content-type', $part); - $embeddedData .= ';'.$this->getPart('transfer-encoding', $part); - $embeddedData .= ','.$this->getPartBody($part); - return $embeddedData; - } - } - return ''; - } - - /** - * Return an array with the following keys display, address, is_group - * - * @param string $name Header name (case-insensitive) - * - * @return array - */ - public function getAddresses($name) - { - $value = $this->getRawHeader($name); - $value = (is_array($value)) ? $value[0] : $value; - $addresses = mailparse_rfc822_parse_addresses($value); - foreach ($addresses as $i => $item) { - $addresses[$i]['display'] = $this->decodeHeader($item['display']); - } - return $addresses; - } - - /** - * Returns the inline parts contents (text or HTML) - * - * @return string[] The decoded inline parts. - */ - public function getInlineParts($type = 'text') - { - $inline_parts = []; - $mime_types = [ - 'text' => 'text/plain', - 'html' => 'text/html', - ]; - - if (!in_array($type, array_keys($mime_types))) { - throw new Exception('Invalid type specified for getInlineParts(). "type" can either be text or html.'); - } - - foreach ($this->parts as $partId => $part) { - if ($this->getPart('content-type', $part) == $mime_types[$type] - && $this->getPart('content-disposition', $part) != 'attachment' - && !$this->partIdIsChildOfAnAttachment($partId) - ) { - $headers = $this->getPart('headers', $part); - $encodingType = array_key_exists('content-transfer-encoding', $headers) ? - $headers['content-transfer-encoding'] : ''; - $undecoded_body = $this->decodeContentTransfer($this->getPartBody($part), $encodingType); - $inline_parts[] = $this->charset->decodeCharset($undecoded_body, $this->getPartCharset($part)); - } - } - - return $inline_parts; - } - - /** - * Returns the attachments contents in order of appearance - * - * @return Attachment[] - */ - public function getAttachments($include_inline = true) - { - $attachments = []; - $dispositions = $include_inline ? ['attachment', 'inline'] : ['attachment']; - $non_attachment_types = ['text/plain', 'text/html']; - $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) - && $disposition !== 'attachment') { - // it is a message body, no attachment - continue; - } elseif (substr($part['content-type'], 0, 10) !== 'multipart/' - && $part['content-type'] !== 'text/plain; (error)' && $disposition != 'inline') { - // if we cannot get it by getMessageBody(), we assume it is an attachment - $disposition = 'attachment'; - } - if (in_array($disposition, ['attachment', 'inline']) === false && !empty($disposition)) { - $disposition = 'attachment'; - } - - if (in_array($disposition, $dispositions) === true) { - if ($filename == 'noname') { - $nonameIter++; - $filename = 'noname'.$nonameIter; - } else { - // Escape all potentially unsafe characters from the filename - $filename = preg_replace('((^\.)|\/|[\n|\r|\n\r]|(\.$))', '_', $filename); - } - - $headersAttachments = $this->getPart('headers', $part); - $contentidAttachments = $this->getPart('content-id', $part); - - $attachmentStream = $this->getAttachmentStream($part); - $mimePartStr = $this->getPartComplete($part); - - $attachments[] = new Attachment( - $filename, - $this->getPart('content-type', $part), - $attachmentStream, - $disposition, - $contentidAttachments, - $headersAttachments, - $mimePartStr - ); - } - } - - return $attachments; - } - - /** - * Save attachments in a folder - * - * @param string $attach_dir directory - * @param bool $include_inline - * @param string $filenameStrategy How to generate attachment filenames - * - * @return array Saved attachments paths - * @throws Exception - */ - public function saveAttachments( - $attach_dir, - $include_inline = true, - $filenameStrategy = self::ATTACHMENT_DUPLICATE_SUFFIX - ) { - $attachments = $this->getAttachments($include_inline); - - $attachments_paths = []; - foreach ($attachments as $attachment) { - $attachments_paths[] = $attachment->save($attach_dir, $filenameStrategy); - } - - return $attachments_paths; - } - - /** - * Read the attachment Body and save temporary file resource - * - * @param array $part - * - * @return resource Mime Body Part - * @throws Exception - */ - protected function getAttachmentStream(&$part) - { - /** @var resource $temp_fp */ - $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; - $data = fread($this->stream, $write); - fwrite($temp_fp, $this->decodeContentTransfer($data, $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 - * - * @param string $encodedString The string in its original encoded state - * @param string $encodingType The encoding type from the Content-Transfer-Encoding header of the part. - * - * @return string The decoded string - */ - protected function decodeContentTransfer($encodedString, $encodingType) - { - if (is_array($encodingType)) { - $encodingType = $encodingType[0]; - } - - $encodingType = strtolower($encodingType); - if ($encodingType == 'base64') { - return base64_decode($encodedString); - } elseif ($encodingType == 'quoted-printable') { - return quoted_printable_decode($encodedString); - } else { - return $encodedString; - } - } - - /** - * $input can be a string or array - * - * @param string|array $input - * - * @return string - */ - protected 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 $input - * - * @return string - */ - protected function decodeSingleHeader($input) - { - // For each encoded-word... - while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)((\s+)=\?)?/i', $input, $matches)) { - $encoded = $matches[1]; - $charset = $matches[2]; - $encoding = $matches[3]; - $text = $matches[4]; - $space = isset($matches[6]) ? $matches[6] : ''; - - 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.$space, $text, $input); - } - - return $input; - } - - /** - * Return the charset of the MIME part - * - * @param array $part - * - * @return string - */ - protected function getPartCharset($part) - { - if (isset($part['charset'])) { - return $this->charset->getCharsetAlias($part['charset']); - } else { - return 'us-ascii'; - } - } - - /** - * Retrieve a specified MIME part - * - * @param string $type - * @param array $parts - * - * @return string|array - */ - protected function getPart($type, $parts) - { - return (isset($parts[$type])) ? $parts[$type] : false; - } - - /** - * Retrieve the Body of a MIME part - * - * @param array $part - * - * @return string - */ - protected 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 - * - * @param array $part - * - * @return string Mime Body Part - */ - protected function getPartBodyFromFile(&$part) - { - $start = $part['starting-pos-body']; - $end = $part['ending-pos-body']; - $body = ''; - if ($end - $start > 0) { - fseek($this->stream, $start, SEEK_SET); - $body = fread($this->stream, $end - $start); - } - - return $body; - } - - /** - * Retrieve the Body from a MIME part from text - * - * @param array $part - * - * @return string Mime Body Part - */ - protected function getPartBodyFromText(&$part) - { - $start = $part['starting-pos-body']; - $end = $part['ending-pos-body']; - - return substr($this->data, $start, $end - $start); - } - - /** - * Retrieve the content of a MIME part - * - * @param array $part - * - * @return string - */ - protected function getPartComplete(&$part) - { - $body = ''; - if ($this->stream) { - $body = $this->getPartFromFile($part); - } elseif ($this->data) { - $body = $this->getPartFromText($part); - } - - return $body; - } - - /** - * Retrieve the content from a MIME part from file - * - * @param array $part - * - * @return string Mime Content - */ - protected function getPartFromFile(&$part) - { - $start = $part['starting-pos']; - $end = $part['ending-pos']; - $body = ''; - if ($end - $start > 0) { - fseek($this->stream, $start, SEEK_SET); - $body = fread($this->stream, $end - $start); - } - - return $body; - } - - /** - * Retrieve the content from a MIME part from text - * - * @param array $part - * - * @return string Mime Content - */ - protected function getPartFromText(&$part) - { - $start = $part['starting-pos']; - $end = $part['ending-pos']; - - return substr($this->data, $start, $end - $start); - } - - /** - * Retrieve the resource - * - * @return resource resource - */ - public function getResource() - { - return $this->resource; - } - - /** - * Retrieve the file pointer to email - * - * @return resource stream - */ - public function getStream() - { - return $this->stream; - } - - /** - * Retrieve the text of an email - * - * @return string data - */ - public function getData() - { - return $this->data; - } - - /** - * Retrieve the parts of an email - * - * @return array parts - */ - public function getParts() - { - return $this->parts; - } - - /** - * Retrieve the charset manager object - * - * @return CharsetManager charset - */ - public function getCharset() - { - return $this->charset; - } - - /** - * Add a middleware to the parser MiddlewareStack - * Each middleware is invoked when: - * a MimePart is retrieved by mailparse_msg_get_part_data() during $this->parse() - * The middleware will receive MimePart $part and the next MiddlewareStack $next - * - * Eg: - * - * $Parser->addMiddleware(function(MimePart $part, MiddlewareStack $next) { - * // do something with the $part - * return $next($part); - * }); - * - * @param callable $middleware Plain Function or Middleware Instance to execute - * @return void - */ - public function addMiddleware(callable $middleware) - { - if (!$middleware instanceof Middleware) { - $middleware = new Middleware($middleware); - } - $this->middlewareStack = $this->middlewareStack->add($middleware); - } -}