@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update mimemailparser from May 2011 version to 8.0.4

Summary:
Bump to version 8.0.4 from 2024-09-11 per https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases before this ancient code copy falls apart.
`scripts/mail/mail_handler.php` (used for incoming (!) mail) is the only consumer.

Closes T15940

Test Plan: Feed `mail_handler.php` with various test emails (formats: plain text, HTML, multipart; encodings: UTF-8, ASCII, ISO-8859-something) by manually replacing `php://stdin` with corresponding text files and adding some `phlog`s for output checking as I don't have mail server glue handy. Get only expected errors for broken emails.

Reviewers: O1 Blessed Committers, 20after4

Reviewed By: O1 Blessed Committers, 20after4

Subscribers: 20after4, tobiaswiese, valerio.bozzolan, Matthew, Cigaryno

Maniphest Tasks: T15940

Differential Revision: https://we.phorge.it/D25829

+2130 -769
+276
externals/mimemailparser/Attachment.php
··· 1 + <?php 2 + 3 + namespace PhpMimeMailParser; 4 + 5 + use function var_dump; 6 + 7 + /** 8 + * Attachment of php-mime-mail-parser 9 + * 10 + * Fully Tested Mailparse Extension Wrapper for PHP 5.4+ 11 + * 12 + */ 13 + class Attachment 14 + { 15 + /** 16 + * @var string $filename Filename 17 + */ 18 + protected $filename; 19 + 20 + /** 21 + * @var string $contentType Mime Type 22 + */ 23 + protected $contentType; 24 + 25 + /** 26 + * @var string $content File Content 27 + */ 28 + protected $content; 29 + 30 + /** 31 + * @var string $contentDisposition Content-Disposition (attachment or inline) 32 + */ 33 + protected $contentDisposition; 34 + 35 + /** 36 + * @var string $contentId Content-ID 37 + */ 38 + protected $contentId; 39 + 40 + /** 41 + * @var array $headers An Array of the attachment headers 42 + */ 43 + protected $headers; 44 + 45 + /** 46 + * @var resource $stream 47 + */ 48 + protected $stream; 49 + 50 + /** 51 + * @var string $mimePartStr 52 + */ 53 + protected $mimePartStr; 54 + 55 + /** 56 + * @var integer $maxDuplicateNumber 57 + */ 58 + public $maxDuplicateNumber = 100; 59 + 60 + /** 61 + * Attachment constructor. 62 + * 63 + * @param string $filename 64 + * @param string $contentType 65 + * @param resource $stream 66 + * @param string $contentDisposition 67 + * @param string $contentId 68 + * @param array $headers 69 + * @param string $mimePartStr 70 + */ 71 + public function __construct( 72 + $filename, 73 + $contentType, 74 + $stream, 75 + $contentDisposition = 'attachment', 76 + $contentId = '', 77 + $headers = [], 78 + $mimePartStr = '' 79 + ) { 80 + $this->filename = $filename; 81 + $this->contentType = $contentType; 82 + $this->stream = $stream; 83 + $this->content = null; 84 + $this->contentDisposition = $contentDisposition; 85 + $this->contentId = $contentId; 86 + $this->headers = $headers; 87 + $this->mimePartStr = $mimePartStr; 88 + } 89 + 90 + /** 91 + * retrieve the attachment filename 92 + * 93 + * @return string 94 + */ 95 + public function getFilename() 96 + { 97 + return $this->filename; 98 + } 99 + 100 + /** 101 + * Retrieve the Attachment Content-Type 102 + * 103 + * @return string 104 + */ 105 + public function getContentType() 106 + { 107 + return $this->contentType; 108 + } 109 + 110 + /** 111 + * Retrieve the Attachment Content-Disposition 112 + * 113 + * @return string 114 + */ 115 + public function getContentDisposition() 116 + { 117 + return $this->contentDisposition; 118 + } 119 + 120 + /** 121 + * Retrieve the Attachment Content-ID 122 + * 123 + * @return string 124 + */ 125 + public function getContentID() 126 + { 127 + return $this->contentId; 128 + } 129 + 130 + /** 131 + * Retrieve the Attachment Headers 132 + * 133 + * @return array 134 + */ 135 + public function getHeaders() 136 + { 137 + return $this->headers; 138 + } 139 + 140 + /** 141 + * Get a handle to the stream 142 + * 143 + * @return resource 144 + */ 145 + public function getStream() 146 + { 147 + return $this->stream; 148 + } 149 + 150 + /** 151 + * Rename a file if it already exists at its destination. 152 + * Renaming is done by adding a duplicate number to the file name. E.g. existingFileName_1.ext. 153 + * After a max duplicate number, renaming the file will switch over to generating a random suffix. 154 + * 155 + * @param string $fileName Complete path to the file. 156 + * @return string The suffixed file name. 157 + */ 158 + protected function suffixFileName(string $fileName): string 159 + { 160 + $pathInfo = pathinfo($fileName); 161 + $dirname = $pathInfo['dirname'].DIRECTORY_SEPARATOR; 162 + $filename = $pathInfo['filename']; 163 + $extension = empty($pathInfo['extension']) ? '' : '.'.$pathInfo['extension']; 164 + 165 + $i = 0; 166 + do { 167 + $i++; 168 + 169 + if ($i > $this->maxDuplicateNumber) { 170 + $duplicateExtension = uniqid(); 171 + } else { 172 + $duplicateExtension = $i; 173 + } 174 + 175 + $resultName = $dirname.$filename."_$duplicateExtension".$extension; 176 + } while (file_exists($resultName)); 177 + 178 + return $resultName; 179 + } 180 + 181 + /** 182 + * Read the contents a few bytes at a time until completed 183 + * Once read to completion, it always returns false 184 + * 185 + * @param int $bytes (default: 2082) 186 + * 187 + * @return string|bool 188 + */ 189 + public function read($bytes = 2082) 190 + { 191 + return feof($this->stream) ? false : fread($this->stream, $bytes); 192 + } 193 + 194 + /** 195 + * Retrieve the file content in one go 196 + * Once you retrieve the content you cannot use MimeMailParser_attachment::read() 197 + * 198 + * @return string 199 + */ 200 + public function getContent() 201 + { 202 + if ($this->content === null) { 203 + fseek($this->stream, 0); 204 + while (($buf = $this->read()) !== false) { 205 + $this->content .= $buf; 206 + } 207 + } 208 + 209 + return $this->content; 210 + } 211 + 212 + /** 213 + * Get mime part string for this attachment 214 + * 215 + * @return string 216 + */ 217 + public function getMimePartStr() 218 + { 219 + return $this->mimePartStr; 220 + } 221 + 222 + /** 223 + * Save the attachment individually 224 + * 225 + * @param string $attach_dir 226 + * @param string $filenameStrategy 227 + * 228 + * @return string 229 + */ 230 + public function save( 231 + $attach_dir, 232 + $filenameStrategy = Parser::ATTACHMENT_DUPLICATE_SUFFIX 233 + ) { 234 + $attach_dir = rtrim($attach_dir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR; 235 + if (!is_dir($attach_dir)) { 236 + mkdir($attach_dir); 237 + } 238 + 239 + // Determine filename 240 + switch ($filenameStrategy) { 241 + case Parser::ATTACHMENT_RANDOM_FILENAME: 242 + $fileInfo = pathinfo($this->getFilename()); 243 + $extension = empty($fileInfo['extension']) ? '' : '.'.$fileInfo['extension']; 244 + $attachment_path = $attach_dir.uniqid().$extension; 245 + break; 246 + case Parser::ATTACHMENT_DUPLICATE_THROW: 247 + case Parser::ATTACHMENT_DUPLICATE_SUFFIX: 248 + $attachment_path = $attach_dir.$this->getFilename(); 249 + break; 250 + default: 251 + throw new Exception('Invalid filename strategy argument provided.'); 252 + } 253 + 254 + // Handle duplicate filename 255 + if (file_exists($attachment_path)) { 256 + switch ($filenameStrategy) { 257 + case Parser::ATTACHMENT_DUPLICATE_THROW: 258 + throw new Exception('Could not create file for attachment: duplicate filename.'); 259 + case Parser::ATTACHMENT_DUPLICATE_SUFFIX: 260 + $attachment_path = $this->suffixFileName($attachment_path); 261 + break; 262 + } 263 + } 264 + 265 + /** @var resource $fp */ 266 + if ($fp = fopen($attachment_path, 'w')) { 267 + while ($bytes = $this->read()) { 268 + fwrite($fp, $bytes); 269 + } 270 + fclose($fp); 271 + return realpath($attachment_path); 272 + } else { 273 + throw new Exception('Could not write attachments. Your directory may be unwritable by PHP.'); 274 + } 275 + } 276 + }
+338
externals/mimemailparser/Charset.php
··· 1 + <?php namespace PhpMimeMailParser; 2 + 3 + use PhpMimeMailParser\Contracts\CharsetManager; 4 + 5 + class Charset implements CharsetManager 6 + { 7 + /** 8 + * Charset Aliases 9 + */ 10 + private $charsetAlias = [ 11 + 'ascii' => 'us-ascii', 12 + 'us-ascii' => 'us-ascii', 13 + 'ansi_x3.4-1968' => 'us-ascii', 14 + '646' => 'us-ascii', 15 + 'iso-8859-1' => 'ISO-8859-1', 16 + 'iso-8859-2' => 'ISO-8859-2', 17 + 'iso-8859-3' => 'ISO-8859-3', 18 + 'iso-8859-4' => 'ISO-8859-4', 19 + 'iso-8859-5' => 'ISO-8859-5', 20 + 'iso-8859-6' => 'ISO-8859-6', 21 + 'iso-8859-6-i' => 'ISO-8859-6-I', 22 + 'iso-8859-6-e' => 'ISO-8859-6-E', 23 + 'iso-8859-7' => 'ISO-8859-7', 24 + 'iso-8859-8' => 'ISO-8859-8', 25 + 'iso-8859-8-i' => 'ISO-8859-8', 26 + 'iso-8859-8-e' => 'ISO-8859-8-E', 27 + 'iso-8859-9' => 'ISO-8859-9', 28 + 'iso-8859-10' => 'ISO-8859-10', 29 + 'iso-8859-11' => 'ISO-8859-11', 30 + 'iso-8859-13' => 'ISO-8859-13', 31 + 'iso-8859-14' => 'ISO-8859-14', 32 + 'iso-8859-15' => 'ISO-8859-15', 33 + 'iso-8859-16' => 'ISO-8859-16', 34 + 'iso-ir-111' => 'ISO-IR-111', 35 + 'iso-2022-cn' => 'ISO-2022-CN', 36 + 'iso-2022-cn-ext' => 'ISO-2022-CN', 37 + 'iso-2022-kr' => 'ISO-2022-KR', 38 + 'iso-2022-jp' => 'ISO-2022-JP', 39 + 'utf-16be' => 'UTF-16BE', 40 + 'utf-16le' => 'UTF-16LE', 41 + 'utf-16' => 'UTF-16', 42 + 'windows-1250' => 'windows-1250', 43 + 'windows-1251' => 'windows-1251', 44 + 'windows-1252' => 'windows-1252', 45 + 'windows-1253' => 'windows-1253', 46 + 'windows-1254' => 'windows-1254', 47 + 'windows-1255' => 'windows-1255', 48 + 'windows-1256' => 'windows-1256', 49 + 'windows-1257' => 'windows-1257', 50 + 'windows-1258' => 'windows-1258', 51 + 'ibm866' => 'IBM866', 52 + 'ibm850' => 'IBM850', 53 + 'ibm852' => 'IBM852', 54 + 'ibm855' => 'IBM855', 55 + 'ibm857' => 'IBM857', 56 + 'ibm862' => 'IBM862', 57 + 'ibm864' => 'IBM864', 58 + 'utf-8' => 'UTF-8', 59 + 'utf-7' => 'UTF-7', 60 + 'shift_jis' => 'Shift_JIS', 61 + 'big5' => 'Big5', 62 + 'euc-jp' => 'EUC-JP', 63 + 'euc-kr' => 'EUC-KR', 64 + 'gb2312' => 'GB2312', 65 + 'gb18030' => 'gb18030', 66 + 'viscii' => 'VISCII', 67 + 'koi8-r' => 'KOI8-R', 68 + 'koi8_r' => 'KOI8-R', 69 + 'cskoi8r' => 'KOI8-R', 70 + 'koi' => 'KOI8-R', 71 + 'koi8' => 'KOI8-R', 72 + 'koi8-u' => 'KOI8-U', 73 + 'tis-620' => 'TIS-620', 74 + 't.61-8bit' => 'T.61-8bit', 75 + 'hz-gb-2312' => 'HZ-GB-2312', 76 + 'big5-hkscs' => 'Big5-HKSCS', 77 + 'gbk' => 'gbk', 78 + 'cns11643' => 'x-euc-tw', 79 + 'x-imap4-modified-utf7' => 'x-imap4-modified-utf7', 80 + 'x-euc-tw' => 'x-euc-tw', 81 + 'x-mac-ce' => 'x-mac-ce', 82 + 'x-mac-turkish' => 'x-mac-turkish', 83 + 'x-mac-greek' => 'x-mac-greek', 84 + 'x-mac-icelandic' => 'x-mac-icelandic', 85 + 'x-mac-croatian' => 'x-mac-croatian', 86 + 'x-mac-romanian' => 'x-mac-romanian', 87 + 'x-mac-cyrillic' => 'x-mac-cyrillic', 88 + 'x-mac-ukrainian' => 'x-mac-cyrillic', 89 + 'x-mac-hebrew' => 'x-mac-hebrew', 90 + 'x-mac-arabic' => 'x-mac-arabic', 91 + 'x-mac-farsi' => 'x-mac-farsi', 92 + 'x-mac-devanagari' => 'x-mac-devanagari', 93 + 'x-mac-gujarati' => 'x-mac-gujarati', 94 + 'x-mac-gurmukhi' => 'x-mac-gurmukhi', 95 + 'armscii-8' => 'armscii-8', 96 + 'x-viet-tcvn5712' => 'x-viet-tcvn5712', 97 + 'x-viet-vps' => 'x-viet-vps', 98 + 'iso-10646-ucs-2' => 'UTF-16BE', 99 + 'x-iso-10646-ucs-2-be' => 'UTF-16BE', 100 + 'x-iso-10646-ucs-2-le' => 'UTF-16LE', 101 + 'x-user-defined' => 'x-user-defined', 102 + 'x-johab' => 'x-johab', 103 + 'latin1' => 'ISO-8859-1', 104 + 'iso_8859-1' => 'ISO-8859-1', 105 + 'iso8859-1' => 'ISO-8859-1', 106 + 'iso8859-2' => 'ISO-8859-2', 107 + 'iso8859-3' => 'ISO-8859-3', 108 + 'iso8859-4' => 'ISO-8859-4', 109 + 'iso8859-5' => 'ISO-8859-5', 110 + 'iso8859-6' => 'ISO-8859-6', 111 + 'iso8859-7' => 'ISO-8859-7', 112 + 'iso8859-8' => 'ISO-8859-8', 113 + 'iso8859-9' => 'ISO-8859-9', 114 + 'iso8859-10' => 'ISO-8859-10', 115 + 'iso8859-11' => 'ISO-8859-11', 116 + 'iso8859-13' => 'ISO-8859-13', 117 + 'iso8859-14' => 'ISO-8859-14', 118 + 'iso8859-15' => 'ISO-8859-15', 119 + 'iso_8859-1:1987' => 'ISO-8859-1', 120 + 'iso-ir-100' => 'ISO-8859-1', 121 + 'l1' => 'ISO-8859-1', 122 + 'ibm819' => 'ISO-8859-1', 123 + 'cp819' => 'ISO-8859-1', 124 + 'csisolatin1' => 'ISO-8859-1', 125 + 'latin2' => 'ISO-8859-2', 126 + 'iso_8859-2' => 'ISO-8859-2', 127 + 'iso_8859-2:1987' => 'ISO-8859-2', 128 + 'iso-ir-101' => 'ISO-8859-2', 129 + 'l2' => 'ISO-8859-2', 130 + 'csisolatin2' => 'ISO-8859-2', 131 + 'latin3' => 'ISO-8859-3', 132 + 'iso_8859-3' => 'ISO-8859-3', 133 + 'iso_8859-3:1988' => 'ISO-8859-3', 134 + 'iso-ir-109' => 'ISO-8859-3', 135 + 'l3' => 'ISO-8859-3', 136 + 'csisolatin3' => 'ISO-8859-3', 137 + 'latin4' => 'ISO-8859-4', 138 + 'iso_8859-4' => 'ISO-8859-4', 139 + 'iso_8859-4:1988' => 'ISO-8859-4', 140 + 'iso-ir-110' => 'ISO-8859-4', 141 + 'l4' => 'ISO-8859-4', 142 + 'csisolatin4' => 'ISO-8859-4', 143 + 'cyrillic' => 'ISO-8859-5', 144 + 'iso_8859-5' => 'ISO-8859-5', 145 + 'iso_8859-5:1988' => 'ISO-8859-5', 146 + 'iso-ir-144' => 'ISO-8859-5', 147 + 'csisolatincyrillic' => 'ISO-8859-5', 148 + 'arabic' => 'ISO-8859-6', 149 + 'iso_8859-6' => 'ISO-8859-6', 150 + 'iso_8859-6:1987' => 'ISO-8859-6', 151 + 'iso-ir-127' => 'ISO-8859-6', 152 + 'ecma-114' => 'ISO-8859-6', 153 + 'asmo-708' => 'ISO-8859-6', 154 + 'csisolatinarabic' => 'ISO-8859-6', 155 + 'csiso88596i' => 'ISO-8859-6-I', 156 + 'csiso88596e' => 'ISO-8859-6-E', 157 + 'greek' => 'ISO-8859-7', 158 + 'greek8' => 'ISO-8859-7', 159 + 'sun_eu_greek' => 'ISO-8859-7', 160 + 'iso_8859-7' => 'ISO-8859-7', 161 + 'iso_8859-7:1987' => 'ISO-8859-7', 162 + 'iso-ir-126' => 'ISO-8859-7', 163 + 'elot_928' => 'ISO-8859-7', 164 + 'ecma-118' => 'ISO-8859-7', 165 + 'csisolatingreek' => 'ISO-8859-7', 166 + 'hebrew' => 'ISO-8859-8', 167 + 'iso_8859-8' => 'ISO-8859-8', 168 + 'visual' => 'ISO-8859-8', 169 + 'iso_8859-8:1988' => 'ISO-8859-8', 170 + 'iso-ir-138' => 'ISO-8859-8', 171 + 'csisolatinhebrew' => 'ISO-8859-8', 172 + 'csiso88598i' => 'ISO-8859-8', 173 + 'iso-8859-8i' => 'ISO-8859-8', 174 + 'logical' => 'ISO-8859-8', 175 + 'csiso88598e' => 'ISO-8859-8-E', 176 + 'latin5' => 'ISO-8859-9', 177 + 'iso_8859-9' => 'ISO-8859-9', 178 + 'iso_8859-9:1989' => 'ISO-8859-9', 179 + 'iso-ir-148' => 'ISO-8859-9', 180 + 'l5' => 'ISO-8859-9', 181 + 'csisolatin5' => 'ISO-8859-9', 182 + 'unicode-1-1-utf-8' => 'UTF-8', 183 + 'utf8' => 'UTF-8', 184 + 'x-sjis' => 'Shift_JIS', 185 + 'shift-jis' => 'Shift_JIS', 186 + 'ms_kanji' => 'Shift_JIS', 187 + 'csshiftjis' => 'Shift_JIS', 188 + 'windows-31j' => 'Shift_JIS', 189 + 'cp932' => 'Shift_JIS', 190 + 'sjis' => 'Shift_JIS', 191 + 'cseucpkdfmtjapanese' => 'EUC-JP', 192 + 'x-euc-jp' => 'EUC-JP', 193 + 'csiso2022jp' => 'ISO-2022-JP', 194 + 'iso-2022-jp-2' => 'ISO-2022-JP', 195 + 'csiso2022jp2' => 'ISO-2022-JP', 196 + 'csbig5' => 'Big5', 197 + 'cn-big5' => 'Big5', 198 + 'x-x-big5' => 'Big5', 199 + 'zh_tw-big5' => 'Big5', 200 + 'cseuckr' => 'EUC-KR', 201 + 'ks_c_5601-1987' => 'EUC-KR', 202 + 'iso-ir-149' => 'EUC-KR', 203 + 'ks_c_5601-1989' => 'EUC-KR', 204 + 'ksc_5601' => 'EUC-KR', 205 + 'ksc5601' => 'EUC-KR', 206 + 'korean' => 'EUC-KR', 207 + 'csksc56011987' => 'EUC-KR', 208 + '5601' => 'EUC-KR', 209 + 'windows-949' => 'EUC-KR', 210 + 'gb_2312-80' => 'GB2312', 211 + 'iso-ir-58' => 'GB2312', 212 + 'chinese' => 'GB2312', 213 + 'csiso58gb231280' => 'GB2312', 214 + 'csgb2312' => 'GB2312', 215 + 'zh_cn.euc' => 'GB2312', 216 + 'gb_2312' => 'GB2312', 217 + 'x-cp1250' => 'windows-1250', 218 + 'x-cp1251' => 'windows-1251', 219 + 'x-cp1252' => 'windows-1252', 220 + 'x-cp1253' => 'windows-1253', 221 + 'x-cp1254' => 'windows-1254', 222 + 'x-cp1255' => 'windows-1255', 223 + 'x-cp1256' => 'windows-1256', 224 + 'x-cp1257' => 'windows-1257', 225 + 'x-cp1258' => 'windows-1258', 226 + 'windows-874' => 'windows-874', 227 + 'ibm874' => 'windows-874', 228 + 'dos-874' => 'windows-874', 229 + 'macintosh' => 'macintosh', 230 + 'x-mac-roman' => 'macintosh', 231 + 'mac' => 'macintosh', 232 + 'csmacintosh' => 'macintosh', 233 + 'cp866' => 'IBM866', 234 + 'cp-866' => 'IBM866', 235 + '866' => 'IBM866', 236 + 'csibm866' => 'IBM866', 237 + 'cp850' => 'IBM850', 238 + '850' => 'IBM850', 239 + 'csibm850' => 'IBM850', 240 + 'cp852' => 'IBM852', 241 + '852' => 'IBM852', 242 + 'csibm852' => 'IBM852', 243 + 'cp855' => 'IBM855', 244 + '855' => 'IBM855', 245 + 'csibm855' => 'IBM855', 246 + 'cp857' => 'IBM857', 247 + '857' => 'IBM857', 248 + 'csibm857' => 'IBM857', 249 + 'cp862' => 'IBM862', 250 + '862' => 'IBM862', 251 + 'csibm862' => 'IBM862', 252 + 'cp864' => 'IBM864', 253 + '864' => 'IBM864', 254 + 'csibm864' => 'IBM864', 255 + 'ibm-864' => 'IBM864', 256 + 't.61' => 'T.61-8bit', 257 + 'iso-ir-103' => 'T.61-8bit', 258 + 'csiso103t618bit' => 'T.61-8bit', 259 + 'x-unicode-2-0-utf-7' => 'UTF-7', 260 + 'unicode-2-0-utf-7' => 'UTF-7', 261 + 'unicode-1-1-utf-7' => 'UTF-7', 262 + 'csunicode11utf7' => 'UTF-7', 263 + 'csunicode' => 'UTF-16BE', 264 + 'csunicode11' => 'UTF-16BE', 265 + 'iso-10646-ucs-basic' => 'UTF-16BE', 266 + 'csunicodeascii' => 'UTF-16BE', 267 + 'iso-10646-unicode-latin1' => 'UTF-16BE', 268 + 'csunicodelatin1' => 'UTF-16BE', 269 + 'iso-10646' => 'UTF-16BE', 270 + 'iso-10646-j-1' => 'UTF-16BE', 271 + 'latin6' => 'ISO-8859-10', 272 + 'iso-ir-157' => 'ISO-8859-10', 273 + 'l6' => 'ISO-8859-10', 274 + 'csisolatin6' => 'ISO-8859-10', 275 + 'iso_8859-15' => 'ISO-8859-15', 276 + 'csisolatin9' => 'ISO-8859-15', 277 + 'l9' => 'ISO-8859-15', 278 + 'ecma-cyrillic' => 'ISO-IR-111', 279 + 'csiso111ecmacyrillic' => 'ISO-IR-111', 280 + 'csiso2022kr' => 'ISO-2022-KR', 281 + 'csviscii' => 'VISCII', 282 + 'zh_tw-euc' => 'x-euc-tw', 283 + 'iso88591' => 'ISO-8859-1', 284 + 'iso88592' => 'ISO-8859-2', 285 + 'iso88593' => 'ISO-8859-3', 286 + 'iso88594' => 'ISO-8859-4', 287 + 'iso88595' => 'ISO-8859-5', 288 + 'iso88596' => 'ISO-8859-6', 289 + 'iso88597' => 'ISO-8859-7', 290 + 'iso88598' => 'ISO-8859-8', 291 + 'iso88599' => 'ISO-8859-9', 292 + 'iso885910' => 'ISO-8859-10', 293 + 'iso885911' => 'ISO-8859-11', 294 + 'iso885912' => 'ISO-8859-12', 295 + 'iso885913' => 'ISO-8859-13', 296 + 'iso885914' => 'ISO-8859-14', 297 + 'iso885915' => 'ISO-8859-15', 298 + 'tis620' => 'TIS-620', 299 + 'cp1250' => 'windows-1250', 300 + 'cp1251' => 'windows-1251', 301 + 'cp1252' => 'windows-1252', 302 + 'cp1253' => 'windows-1253', 303 + 'cp1254' => 'windows-1254', 304 + 'cp1255' => 'windows-1255', 305 + 'cp1256' => 'windows-1256', 306 + 'cp1257' => 'windows-1257', 307 + 'cp1258' => 'windows-1258', 308 + 'x-gbk' => 'gbk', 309 + 'windows-936' => 'gbk', 310 + 'ansi-1251' => 'windows-1251', 311 + ]; 312 + 313 + /** 314 + * {@inheritdoc} 315 + */ 316 + public function decodeCharset($encodedString, $charset) 317 + { 318 + if (strtolower($charset) == 'utf-8' || strtolower($charset) == 'us-ascii') { 319 + return $encodedString; 320 + } else { 321 + return iconv($this->getCharsetAlias($charset), 'UTF-8//TRANSLIT//IGNORE', $encodedString); 322 + } 323 + } 324 + 325 + /** 326 + * {@inheritdoc} 327 + */ 328 + public function getCharsetAlias($charset) 329 + { 330 + $charset = strtolower($charset); 331 + 332 + if (array_key_exists($charset, $this->charsetAlias)) { 333 + return $this->charsetAlias[$charset]; 334 + } else { 335 + return null; 336 + } 337 + } 338 + }
+24
externals/mimemailparser/Contracts/CharsetManager.php
··· 1 + <?php namespace PhpMimeMailParser\Contracts; 2 + 3 + interface CharsetManager 4 + { 5 + 6 + /** 7 + * Decode the string from Charset 8 + * 9 + * @param string $encodedString The string in its original encoded state 10 + * @param string $charset The Charset header of the part. 11 + * 12 + * @return string The decoded string 13 + */ 14 + public function decodeCharset($encodedString, $charset); 15 + 16 + /** 17 + * Get charset alias 18 + * 19 + * @param string $charset . 20 + * 21 + * @return string The charset alias 22 + */ 23 + public function getCharsetAlias($charset); 24 + }
+23
externals/mimemailparser/Contracts/Middleware.php
··· 1 + <?php 2 + 3 + namespace PhpMimeMailParser\Contracts; 4 + 5 + use PhpMimeMailParser\MimePart; 6 + use PhpMimeMailParser\MiddlewareStack; 7 + 8 + /** 9 + * Process Mime parts by either: 10 + * processing the part or calling the $next MiddlewareStack 11 + */ 12 + interface Middleware 13 + { 14 + /** 15 + * Process a mime part, optionally delegating parsing to the $next MiddlewareStack 16 + * 17 + * @param MimePart $part 18 + * @param MiddlewareStack $next 19 + * 20 + * @return MimePart 21 + */ 22 + public function parse(MimePart $part, MiddlewareStack $next); 23 + }
+8
externals/mimemailparser/Exception.php
··· 1 + <?php 2 + 3 + namespace PhpMimeMailParser; 4 + 5 + class Exception extends \RuntimeException 6 + { 7 + 8 + }
+17 -121
externals/mimemailparser/LICENSE
··· 1 - The "Artistic License" 2 - 3 - Preamble 4 - 5 - The intent of this document is to state the conditions under which a 6 - Package may be copied, such that the Copyright Holder maintains some 7 - semblance of artistic control over the development of the package, 8 - while giving the users of the package the right to use and distribute 9 - the Package in a more-or-less customary fashion, plus the right to make 10 - reasonable modifications. 11 - 12 - Definitions: 13 - 14 - "Package" refers to the collection of files distributed by the 15 - Copyright Holder, and derivatives of that collection of files 16 - created through textual modification. 17 - 18 - "Standard Version" refers to such a Package if it has not been 19 - modified, or has been modified in accordance with the wishes 20 - of the Copyright Holder as specified below. 21 - 22 - "Copyright Holder" is whoever is named in the copyright or 23 - copyrights for the package. 24 - 25 - "You" is you, if you're thinking about copying or distributing 26 - this Package. 27 - 28 - "Reasonable copying fee" is whatever you can justify on the 29 - basis of media cost, duplication charges, time of people involved, 30 - and so on. (You will not be required to justify it to the 31 - Copyright Holder, but only to the computing community at large 32 - as a market that must bear the fee.) 33 - 34 - "Freely Available" means that no fee is charged for the item 35 - itself, though there may be fees involved in handling the item. 36 - It also means that recipients of the item may redistribute it 37 - under the same conditions they received it. 38 - 39 - 1. You may make and give away verbatim copies of the source form of the 40 - Standard Version of this Package without restriction, provided that you 41 - duplicate all of the original copyright notices and associated disclaimers. 42 - 43 - 2. You may apply bug fixes, portability fixes and other modifications 44 - derived from the Public Domain or from the Copyright Holder. A Package 45 - modified in such a way shall still be considered the Standard Version. 46 - 47 - 3. You may otherwise modify your copy of this Package in any way, provided 48 - that you insert a prominent notice in each changed file stating how and 49 - when you changed that file, and provided that you do at least ONE of the 50 - following: 51 - 52 - a) place your modifications in the Public Domain or otherwise make them 53 - Freely Available, such as by posting said modifications to Usenet or 54 - an equivalent medium, or placing the modifications on a major archive 55 - site such as uunet.uu.net, or by allowing the Copyright Holder to include 56 - your modifications in the Standard Version of the Package. 57 - 58 - b) use the modified Package only within your corporation or organization. 59 - 60 - c) rename any non-standard executables so the names do not conflict 61 - with standard executables, which must also be provided, and provide 62 - a separate manual page for each non-standard executable that clearly 63 - documents how it differs from the Standard Version. 64 - 65 - d) make other distribution arrangements with the Copyright Holder. 66 - 67 - 4. You may distribute the programs of this Package in object code or 68 - executable form, provided that you do at least ONE of the following: 69 - 70 - a) distribute a Standard Version of the executables and library files, 71 - together with instructions (in the manual page or equivalent) on where 72 - to get the Standard Version. 1 + The MIT License (MIT) 73 2 74 - b) accompany the distribution with the machine-readable source of 75 - the Package with your modifications. 3 + Copyright (c) 2016 Vincent Dauce 76 4 77 - c) give non-standard executables non-standard names, and clearly 78 - document the differences in manual pages (or equivalent), together 79 - with instructions on where to get the Standard Version. 5 + Permission is hereby granted, free of charge, to any person obtaining a copy 6 + of this software and associated documentation files (the "Software"), to deal 7 + in the Software without restriction, including without limitation the rights 8 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 + copies of the Software, and to permit persons to whom the Software is 10 + furnished to do so, subject to the following conditions: 80 11 81 - d) make other distribution arrangements with the Copyright Holder. 12 + The above copyright notice and this permission notice shall be included in 13 + all copies or substantial portions of the Software. 82 14 83 - 5. You may charge a reasonable copying fee for any distribution of this 84 - Package. You may charge any fee you choose for support of this 85 - Package. You may not charge a fee for this Package itself. However, 86 - you may distribute this Package in aggregate with other (possibly 87 - commercial) programs as part of a larger (possibly commercial) software 88 - distribution provided that you do not advertise this Package as a 89 - product of your own. You may embed this Package's interpreter within 90 - an executable of yours (by linking); this shall be construed as a mere 91 - form of aggregation, provided that the complete Standard Version of the 92 - interpreter is so embedded. 93 - 94 - 6. The scripts and library files supplied as input to or produced as 95 - output from the programs of this Package do not automatically fall 96 - under the copyright of this Package, but belong to whoever generated 97 - them, and may be sold commercially, and may be aggregated with this 98 - Package. If such scripts or library files are aggregated with this 99 - Package via the so-called "undump" or "unexec" methods of producing a 100 - binary executable image, then distribution of such an image shall 101 - neither be construed as a distribution of this Package nor shall it 102 - fall under the restrictions of Paragraphs 3 and 4, provided that you do 103 - not represent such an executable image as a Standard Version of this 104 - Package. 105 - 106 - 7. C subroutines (or comparably compiled subroutines in other 107 - languages) supplied by you and linked into this Package in order to 108 - emulate subroutines and variables of the language defined by this 109 - Package shall not be considered part of this Package, but are the 110 - equivalent of input as in Paragraph 6, provided these subroutines do 111 - not change the language in any way that would cause it to fail the 112 - regression tests for the language. 113 - 114 - 8. Aggregation of this Package with a commercial distribution is always 115 - permitted provided that the use of this Package is embedded; that is, 116 - when no overt attempt is made to make this Package's interfaces visible 117 - to the end user of the commercial distribution. Such use shall not be 118 - construed as a distribution of this Package. 119 - 120 - 9. The name of the Copyright Holder may not be used to endorse or promote 121 - products derived from this software without specific prior written permission. 122 - 123 - 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR 124 - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 125 - WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 15 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 + THE SOFTWARE.
+29
externals/mimemailparser/Middleware.php
··· 1 + <?php 2 + 3 + namespace PhpMimeMailParser; 4 + 5 + /** 6 + * Wraps a callable as a Middleware 7 + */ 8 + class Middleware implements Contracts\Middleware 9 + { 10 + protected $parser; 11 + 12 + /** 13 + * Create a middleware using a callable $fn 14 + * 15 + * @param callable $fn 16 + */ 17 + public function __construct(callable $fn) 18 + { 19 + $this->parser = $fn; 20 + } 21 + 22 + /** 23 + * Process a mime part, optionally delegating parsing to the $next MiddlewareStack 24 + */ 25 + public function parse(MimePart $part, MiddlewareStack $next) 26 + { 27 + return call_user_func($this->parser, $part, $next); 28 + } 29 + }
+89
externals/mimemailparser/MiddlewareStack.php
··· 1 + <?php 2 + 3 + namespace PhpMimeMailParser; 4 + 5 + use PhpMimeMailParser\Contracts\MiddleWare as MiddleWareContracts; 6 + 7 + /** 8 + * A stack of middleware chained together by (MiddlewareStack $next) 9 + */ 10 + class MiddlewareStack 11 + { 12 + /** 13 + * Next MiddlewareStack in chain 14 + * 15 + * @var MiddlewareStack 16 + */ 17 + protected $next; 18 + 19 + /** 20 + * Middleware in this MiddlewareStack 21 + * 22 + * @var Middleware 23 + */ 24 + protected $middleware; 25 + 26 + /** 27 + * Construct the first middleware in this MiddlewareStack 28 + * The next middleware is chained through $MiddlewareStack->add($Middleware) 29 + * 30 + * @param Middleware $middleware 31 + */ 32 + public function __construct(MiddleWareContracts $middleware = null) 33 + { 34 + $this->middleware = $middleware; 35 + } 36 + 37 + /** 38 + * Creates a chained middleware in MiddlewareStack 39 + * 40 + * @param Middleware $middleware 41 + * @return MiddlewareStack Immutable MiddlewareStack 42 + */ 43 + public function add(MiddleWareContracts $middleware) 44 + { 45 + $stack = new static($middleware); 46 + $stack->next = $this; 47 + return $stack; 48 + } 49 + 50 + /** 51 + * Parses the MimePart by passing it through the Middleware 52 + * @param MimePart $part 53 + * @return MimePart 54 + */ 55 + public function parse(MimePart $part) 56 + { 57 + if (!$this->middleware) { 58 + return $part; 59 + } 60 + $part = call_user_func(array($this->middleware, 'parse'), $part, $this->next); 61 + return $part; 62 + } 63 + 64 + /** 65 + * Creates a MiddlewareStack based on an array of middleware 66 + * 67 + * @param Middleware[] $middlewares 68 + * @return MiddlewareStack 69 + */ 70 + public static function factory(array $middlewares = array()) 71 + { 72 + $stack = new static; 73 + foreach ($middlewares as $middleware) { 74 + $stack = $stack->add($middleware); 75 + } 76 + return $stack; 77 + } 78 + 79 + /** 80 + * Allow calling MiddlewareStack instance directly to invoke parse() 81 + * 82 + * @param MimePart $part 83 + * @return MimePart 84 + */ 85 + public function __invoke(MimePart $part) 86 + { 87 + return $this->parse($part); 88 + } 89 + }
-494
externals/mimemailparser/MimeMailParser.class.php
··· 1 - <?php 2 - 3 - require_once('attachment.class.php'); 4 - 5 - /** 6 - * Fast Mime Mail parser Class using PHP's MailParse Extension 7 - * @author gabe@fijiwebdesign.com 8 - * @url http://www.fijiwebdesign.com/ 9 - * @license http://creativecommons.org/licenses/by-sa/3.0/us/ 10 - * @version $Id$ 11 - */ 12 - class MimeMailParser { 13 - 14 - /** 15 - * PHP MimeParser Resource ID 16 - */ 17 - public $resource; 18 - 19 - /** 20 - * A file pointer to email 21 - */ 22 - public $stream; 23 - 24 - /** 25 - * A text of an email 26 - */ 27 - public $data; 28 - 29 - /** 30 - * Stream Resources for Attachments 31 - */ 32 - public $attachment_streams; 33 - 34 - /** 35 - * Parts of an email 36 - */ 37 - private $parts = array(); 38 - 39 - /** 40 - * Inialize some stuff 41 - * @return 42 - */ 43 - public function __construct() { 44 - $this->attachment_streams = array(); 45 - } 46 - 47 - /** 48 - * Free the held resouces 49 - * @return void 50 - */ 51 - public function __destruct() { 52 - // clear the email file resource 53 - if (is_resource($this->stream)) { 54 - fclose($this->stream); 55 - } 56 - // clear the MailParse resource 57 - if (is_resource($this->resource)) { 58 - mailparse_msg_free($this->resource); 59 - } 60 - // remove attachment resources 61 - foreach($this->attachment_streams as $stream) { 62 - fclose($stream); 63 - } 64 - } 65 - 66 - /** 67 - * Set the file path we use to get the email text 68 - * @return Object MimeMailParser Instance 69 - * @param $mail_path Object 70 - */ 71 - public function setPath($path) { 72 - // should parse message incrementally from file 73 - $this->resource = mailparse_msg_parse_file($path); 74 - $this->stream = fopen($path, 'r'); 75 - $this->parse(); 76 - return $this; 77 - } 78 - 79 - /** 80 - * Set the Stream resource we use to get the email text 81 - * @return Object MimeMailParser Instance 82 - * @param $stream Resource 83 - */ 84 - public function setStream($stream) { 85 - 86 - // streams have to be cached to file first 87 - if (get_resource_type($stream) == 'stream') { 88 - $tmp_fp = tmpfile(); 89 - if ($tmp_fp) { 90 - while(!feof($stream)) { 91 - fwrite($tmp_fp, fread($stream, 2028)); 92 - } 93 - fseek($tmp_fp, 0); 94 - $this->stream =& $tmp_fp; 95 - } else { 96 - throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'); 97 - return false; 98 - } 99 - fclose($stream); 100 - } else { 101 - $this->stream = $stream; 102 - } 103 - 104 - $this->resource = mailparse_msg_create(); 105 - // parses the message incrementally low memory usage but slower 106 - while(!feof($this->stream)) { 107 - mailparse_msg_parse($this->resource, fread($this->stream, 2082)); 108 - } 109 - $this->parse(); 110 - return $this; 111 - } 112 - 113 - /** 114 - * Set the email text 115 - * @return Object MimeMailParser Instance 116 - * @param $data String 117 - */ 118 - public function setText($data) { 119 - // NOTE: This has been modified for Phabricator. If the input data does not 120 - // end in a newline, Mailparse fails to include the last line in the mail 121 - // body. This happens somewhere deep, deep inside the mailparse extension, 122 - // so adding a newline here seems like the most straightforward fix. 123 - if (!preg_match('/\n\z/', $data)) { 124 - $data = $data."\n"; 125 - } 126 - 127 - $this->resource = mailparse_msg_create(); 128 - // does not parse incrementally, fast memory hog might explode 129 - mailparse_msg_parse($this->resource, $data); 130 - $this->data = $data; 131 - $this->parse(); 132 - return $this; 133 - } 134 - 135 - /** 136 - * Parse the Message into parts 137 - * @return void 138 - * @private 139 - */ 140 - private function parse() { 141 - $structure = mailparse_msg_get_structure($this->resource); 142 - $this->parts = array(); 143 - foreach($structure as $part_id) { 144 - $part = mailparse_msg_get_part($this->resource, $part_id); 145 - $this->parts[$part_id] = mailparse_msg_get_part_data($part); 146 - } 147 - } 148 - 149 - /** 150 - * Retrieve the Email Headers 151 - * @return Array 152 - */ 153 - public function getHeaders() { 154 - if (isset($this->parts[1])) { 155 - return $this->getPartHeaders($this->parts[1]); 156 - } else { 157 - throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.'); 158 - } 159 - return false; 160 - } 161 - /** 162 - * Retrieve the raw Email Headers 163 - * @return string 164 - */ 165 - public function getHeadersRaw() { 166 - if (isset($this->parts[1])) { 167 - return $this->getPartHeaderRaw($this->parts[1]); 168 - } else { 169 - throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.'); 170 - } 171 - return false; 172 - } 173 - 174 - /** 175 - * Retrieve a specific Email Header 176 - * @return String 177 - * @param $name String Header name 178 - */ 179 - public function getHeader($name) { 180 - if (isset($this->parts[1])) { 181 - $headers = $this->getPartHeaders($this->parts[1]); 182 - if (isset($headers[$name])) { 183 - return $headers[$name]; 184 - } 185 - } else { 186 - throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.'); 187 - } 188 - return false; 189 - } 190 - 191 - /** 192 - * Returns the email message body in the specified format 193 - * @return Mixed String Body or False if not found 194 - * @param $type Object[optional] 195 - */ 196 - public function getMessageBody($type = 'text') { 197 - 198 - // NOTE: This function has been modified for Phabricator. The default 199 - // implementation returns the last matching part, which throws away text 200 - // for many emails. Instead, we concatenate all matching parts. See 201 - // issue 22 for discussion: 202 - // http://code.google.com/p/php-mime-mail-parser/issues/detail?id=22 203 - 204 - $body = false; 205 - $mime_types = array( 206 - 'text'=> 'text/plain', 207 - 'html'=> 'text/html' 208 - ); 209 - if (in_array($type, array_keys($mime_types))) { 210 - foreach($this->parts as $part) { 211 - $disposition = $this->getPartContentDisposition($part); 212 - if ($disposition == 'attachment') { 213 - // text/plain parts with "Content-Disposition: attachment" are 214 - // attachments, not part of the text body. 215 - continue; 216 - } 217 - if ($this->getPartContentType($part) == $mime_types[$type]) { 218 - $headers = $this->getPartHeaders($part); 219 - // Concatenate all the matching parts into the body text. For example, 220 - // if a user sends a message with some text, then an image, and then 221 - // some more text, the text body of the email gets split over several 222 - // attachments. 223 - $body .= $this->decode( 224 - $this->getPartBody($part), 225 - array_key_exists('content-transfer-encoding', $headers) 226 - ? $headers['content-transfer-encoding'] 227 - : ''); 228 - } 229 - } 230 - } else { 231 - throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); 232 - } 233 - return $body; 234 - } 235 - 236 - /** 237 - * get the headers for the message body part. 238 - * @return Array 239 - * @param $type Object[optional] 240 - */ 241 - public function getMessageBodyHeaders($type = 'text') { 242 - $headers = false; 243 - $mime_types = array( 244 - 'text'=> 'text/plain', 245 - 'html'=> 'text/html' 246 - ); 247 - if (in_array($type, array_keys($mime_types))) { 248 - foreach($this->parts as $part) { 249 - if ($this->getPartContentType($part) == $mime_types[$type]) { 250 - $headers = $this->getPartHeaders($part); 251 - } 252 - } 253 - } else { 254 - throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); 255 - } 256 - return $headers; 257 - } 258 - 259 - /** 260 - * Returns the attachments contents in order of appearance 261 - * @return Array 262 - * @param $type Object[optional] 263 - */ 264 - public function getAttachments() { 265 - // NOTE: This has been modified for Phabricator. Some mail clients do not 266 - // send attachments with "Content-Disposition" headers. 267 - $attachments = array(); 268 - $dispositions = array("attachment","inline"); 269 - $non_attachment_types = array("text/plain", "text/html"); 270 - $nonameIter = 0; 271 - foreach ($this->parts as $part) { 272 - $disposition = $this->getPartContentDisposition($part); 273 - $filename = 'noname'; 274 - if (isset($part['disposition-filename'])) { 275 - $filename = $part['disposition-filename']; 276 - } elseif (isset($part['content-name'])) { 277 - // if we have no disposition but we have a content-name, it's a valid attachment. 278 - // we simulate the presence of an attachment disposition with a disposition filename 279 - $filename = $part['content-name']; 280 - $disposition = 'attachment'; 281 - } elseif (!in_array($part['content-type'], $non_attachment_types, true) 282 - && substr($part['content-type'], 0, 10) !== 'multipart/' 283 - ) { 284 - // if we cannot get it with getMessageBody, we assume it is an attachment 285 - $disposition = 'attachment'; 286 - } 287 - 288 - if (in_array($disposition, $dispositions) && isset($filename) === true) { 289 - if ($filename == 'noname') { 290 - $nonameIter++; 291 - $filename = 'noname'.$nonameIter; 292 - } 293 - $attachments[] = new MimeMailParser_attachment( 294 - $filename, 295 - $this->getPartContentType($part), 296 - $this->getAttachmentStream($part), 297 - $disposition, 298 - $this->getPartHeaders($part) 299 - ); 300 - } 301 - } 302 - return $attachments; 303 - } 304 - 305 - /** 306 - * Return the Headers for a MIME part 307 - * @return Array 308 - * @param $part Array 309 - */ 310 - private function getPartHeaders($part) { 311 - if (isset($part['headers']) && $part['headers']) { 312 - return $part['headers']; 313 - } 314 - throw new Exception('MimeMailParser::getHeaders() could not parse any email headers.'); 315 - } 316 - 317 - /** 318 - * Return a Specific Header for a MIME part 319 - * @return Array 320 - * @param $part Array 321 - * @param $header String Header Name 322 - */ 323 - private function getPartHeader($part, $header) { 324 - if (isset($part['headers'][$header])) { 325 - return $part['headers'][$header]; 326 - } 327 - return false; 328 - } 329 - 330 - /** 331 - * Return the ContentType of the MIME part 332 - * @return String 333 - * @param $part Array 334 - */ 335 - private function getPartContentType($part) { 336 - if (isset($part['content-type'])) { 337 - return $part['content-type']; 338 - } 339 - return false; 340 - } 341 - 342 - /** 343 - * Return the Content Disposition 344 - * @return String 345 - * @param $part Array 346 - */ 347 - private function getPartContentDisposition($part) { 348 - if (isset($part['content-disposition'])) { 349 - return $part['content-disposition']; 350 - } 351 - return false; 352 - } 353 - 354 - /** 355 - * Retrieve the raw Header of a MIME part 356 - * @return String 357 - * @param $part Object 358 - */ 359 - private function getPartHeaderRaw(&$part) { 360 - $header = ''; 361 - if ($this->stream) { 362 - $header = $this->getPartHeaderFromFile($part); 363 - } else if ($this->data) { 364 - $header = $this->getPartHeaderFromText($part); 365 - } else { 366 - throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email parts.'); 367 - } 368 - return $header; 369 - } 370 - /** 371 - * Retrieve the Body of a MIME part 372 - * @return String 373 - * @param $part Object 374 - */ 375 - private function getPartBody(&$part) { 376 - $body = ''; 377 - if ($this->stream) { 378 - $body = $this->getPartBodyFromFile($part); 379 - } else if ($this->data) { 380 - $body = $this->getPartBodyFromText($part); 381 - } else { 382 - throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email parts.'); 383 - } 384 - return $body; 385 - } 386 - 387 - /** 388 - * Retrieve the Header from a MIME part from file 389 - * @return String Mime Header Part 390 - * @param $part Array 391 - */ 392 - private function getPartHeaderFromFile(&$part) { 393 - $start = $part['starting-pos']; 394 - $end = $part['starting-pos-body']; 395 - fseek($this->stream, $start, SEEK_SET); 396 - $header = fread($this->stream, $end-$start); 397 - return $header; 398 - } 399 - /** 400 - * Retrieve the Body from a MIME part from file 401 - * @return String Mime Body Part 402 - * @param $part Array 403 - */ 404 - private function getPartBodyFromFile(&$part) { 405 - $start = $part['starting-pos-body']; 406 - $end = $part['ending-pos-body']; 407 - fseek($this->stream, $start, SEEK_SET); 408 - $body = fread($this->stream, $end-$start); 409 - return $body; 410 - } 411 - 412 - /** 413 - * Retrieve the Header from a MIME part from text 414 - * @return String Mime Header Part 415 - * @param $part Array 416 - */ 417 - private function getPartHeaderFromText(&$part) { 418 - $start = $part['starting-pos']; 419 - $end = $part['starting-pos-body']; 420 - $header = substr($this->data, $start, $end-$start); 421 - return $header; 422 - } 423 - /** 424 - * Retrieve the Body from a MIME part from text 425 - * @return String Mime Body Part 426 - * @param $part Array 427 - */ 428 - private function getPartBodyFromText(&$part) { 429 - $start = $part['starting-pos-body']; 430 - $end = $part['ending-pos-body']; 431 - $body = substr($this->data, $start, $end-$start); 432 - return $body; 433 - } 434 - 435 - /** 436 - * Read the attachment Body and save temporary file resource 437 - * @return String Mime Body Part 438 - * @param $part Array 439 - */ 440 - private function getAttachmentStream(&$part) { 441 - $temp_fp = tmpfile(); 442 - 443 - array_key_exists('content-transfer-encoding', $part['headers']) ? $encoding = $part['headers']['content-transfer-encoding'] : $encoding = ''; 444 - 445 - if ($temp_fp) { 446 - if ($this->stream) { 447 - $start = $part['starting-pos-body']; 448 - $end = $part['ending-pos-body']; 449 - fseek($this->stream, $start, SEEK_SET); 450 - $len = $end-$start; 451 - $written = 0; 452 - $write = 2028; 453 - $body = ''; 454 - while($written < $len) { 455 - if (($written+$write < $len )) { 456 - $write = $len - $written; 457 - } 458 - $part = fread($this->stream, $write); 459 - fwrite($temp_fp, $this->decode($part, $encoding)); 460 - $written += $write; 461 - } 462 - } else if ($this->data) { 463 - $attachment = $this->decode($this->getPartBodyFromText($part), $encoding); 464 - fwrite($temp_fp, $attachment, strlen($attachment)); 465 - } 466 - fseek($temp_fp, 0, SEEK_SET); 467 - } else { 468 - throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'); 469 - return false; 470 - } 471 - return $temp_fp; 472 - } 473 - 474 - 475 - /** 476 - * Decode the string depending on encoding type. 477 - * @return String the decoded string. 478 - * @param $encodedString The string in its original encoded state. 479 - * @param $encodingType The encoding type from the Content-Transfer-Encoding header of the part. 480 - */ 481 - private function decode($encodedString, $encodingType) { 482 - if (strtolower($encodingType) == 'base64') { 483 - return base64_decode($encodedString); 484 - } else if (strtolower($encodingType) == 'quoted-printable') { 485 - return quoted_printable_decode($encodedString); 486 - } else { 487 - return $encodedString; 488 - } 489 - } 490 - 491 - } 492 - 493 - 494 - ?>
+119
externals/mimemailparser/MimePart.php
··· 1 + <?php 2 + 3 + namespace PhpMimeMailParser; 4 + 5 + /** 6 + * Mime Part 7 + * Represents the results of mailparse_msg_get_part_data() 8 + * 9 + * Note ArrayAccess::offsetSet() cannot modify deeply nestated arrays. 10 + * When modifying use getPart() and setPart() for deep nested data modification 11 + * 12 + * @example 13 + * 14 + * $MimePart['headers']['from'] = 'modified@example.com' // fails 15 + * 16 + * // correct 17 + * $part = $MimePart->getPart(); 18 + * $part['headers']['from'] = 'modified@example.com'; 19 + * $MimePart->setPart($part); 20 + */ 21 + class MimePart implements \ArrayAccess 22 + { 23 + /** 24 + * Internal mime part 25 + * 26 + * @var array 27 + */ 28 + protected $part = array(); 29 + 30 + /** 31 + * Immutable Part Id 32 + * 33 + * @var string 34 + */ 35 + private $id; 36 + 37 + /** 38 + * Create a mime part 39 + * 40 + * @param array $part 41 + * @param string $id 42 + */ 43 + public function __construct($id, array $part) 44 + { 45 + $this->part = $part; 46 + $this->id = $id; 47 + } 48 + 49 + /** 50 + * Retrieve the part Id 51 + * 52 + * @return string 53 + */ 54 + public function getId() 55 + { 56 + return $this->id; 57 + } 58 + 59 + /** 60 + * Retrieve the part data 61 + * 62 + * @return array 63 + */ 64 + public function getPart() 65 + { 66 + return $this->part; 67 + } 68 + 69 + /** 70 + * Set the mime part data 71 + * 72 + * @param array $part 73 + * @return void 74 + */ 75 + public function setPart(array $part) 76 + { 77 + $this->part = $part; 78 + } 79 + 80 + /** 81 + * ArrayAccess 82 + */ 83 + #[\ReturnTypeWillChange] 84 + public function offsetSet($offset, $value) 85 + { 86 + if (is_null($offset)) { 87 + $this->part[] = $value; 88 + return; 89 + } 90 + $this->part[$offset] = $value; 91 + } 92 + 93 + /** 94 + * ArrayAccess 95 + */ 96 + #[\ReturnTypeWillChange] 97 + public function offsetExists($offset) 98 + { 99 + return isset($this->part[$offset]); 100 + } 101 + 102 + /** 103 + * ArrayAccess 104 + */ 105 + #[\ReturnTypeWillChange] 106 + public function offsetUnset($offset) 107 + { 108 + unset($this->part[$offset]); 109 + } 110 + 111 + /** 112 + * ArrayAccess 113 + */ 114 + #[\ReturnTypeWillChange] 115 + public function offsetGet($offset) 116 + { 117 + return isset($this->part[$offset]) ? $this->part[$offset] : null; 118 + } 119 + }
+923
externals/mimemailparser/Parser.php
··· 1 + <?php 2 + 3 + namespace PhpMimeMailParser; 4 + 5 + use PhpMimeMailParser\Contracts\CharsetManager; 6 + 7 + /** 8 + * Parser of php-mime-mail-parser 9 + * 10 + * Fully Tested Mailparse Extension Wrapper for PHP 5.4+ 11 + * 12 + */ 13 + class Parser 14 + { 15 + /** 16 + * Attachment filename argument option for ->saveAttachments(). 17 + */ 18 + const ATTACHMENT_DUPLICATE_THROW = 'DuplicateThrow'; 19 + const ATTACHMENT_DUPLICATE_SUFFIX = 'DuplicateSuffix'; 20 + const ATTACHMENT_RANDOM_FILENAME = 'RandomFilename'; 21 + 22 + /** 23 + * PHP MimeParser Resource ID 24 + * 25 + * @var resource $resource 26 + */ 27 + protected $resource; 28 + 29 + /** 30 + * A file pointer to email 31 + * 32 + * @var resource $stream 33 + */ 34 + protected $stream; 35 + 36 + /** 37 + * A text of an email 38 + * 39 + * @var string $data 40 + */ 41 + protected $data; 42 + 43 + /** 44 + * Parts of an email 45 + * 46 + * @var array $parts 47 + */ 48 + protected $parts; 49 + 50 + /** 51 + * @var CharsetManager object 52 + */ 53 + protected $charset; 54 + 55 + /** 56 + * Valid stream modes for reading 57 + * 58 + * @var array 59 + */ 60 + protected static $readableModes = [ 61 + 'r', 'r+', 'w+', 'a+', 'x+', 'c+', 'rb', 'r+b', 'w+b', 'a+b', 62 + 'x+b', 'c+b', 'rt', 'r+t', 'w+t', 'a+t', 'x+t', 'c+t' 63 + ]; 64 + 65 + /** 66 + * Stack of middleware registered to process data 67 + * 68 + * @var MiddlewareStack 69 + */ 70 + protected $middlewareStack; 71 + 72 + /** 73 + * Parser constructor. 74 + * 75 + * @param CharsetManager|null $charset 76 + */ 77 + public function __construct(CharsetManager $charset = null) 78 + { 79 + if ($charset == null) { 80 + $charset = new Charset(); 81 + } 82 + 83 + $this->charset = $charset; 84 + $this->middlewareStack = new MiddlewareStack(); 85 + } 86 + 87 + /** 88 + * Free the held resources 89 + * 90 + * @return void 91 + */ 92 + public function __destruct() 93 + { 94 + // clear the email file resource 95 + if (is_resource($this->stream)) { 96 + fclose($this->stream); 97 + } 98 + // clear the MailParse resource 99 + if (is_resource($this->resource)) { 100 + mailparse_msg_free($this->resource); 101 + } 102 + } 103 + 104 + /** 105 + * Set the file path we use to get the email text 106 + * 107 + * @param string $path File path to the MIME mail 108 + * 109 + * @return Parser MimeMailParser Instance 110 + */ 111 + public function setPath($path) 112 + { 113 + if (is_writable($path)) { 114 + $file = fopen($path, 'a+'); 115 + fseek($file, -1, SEEK_END); 116 + if (fread($file, 1) != "\n") { 117 + fwrite($file, PHP_EOL); 118 + } 119 + fclose($file); 120 + } 121 + 122 + // should parse message incrementally from file 123 + $this->resource = mailparse_msg_parse_file($path); 124 + $this->stream = fopen($path, 'r'); 125 + $this->parse(); 126 + 127 + return $this; 128 + } 129 + 130 + /** 131 + * Set the Stream resource we use to get the email text 132 + * 133 + * @param resource $stream 134 + * 135 + * @return Parser MimeMailParser Instance 136 + * @throws Exception 137 + */ 138 + public function setStream($stream) 139 + { 140 + // streams have to be cached to file first 141 + $meta = @stream_get_meta_data($stream); 142 + if (!$meta || !$meta['mode'] || !in_array($meta['mode'], self::$readableModes, true)) { 143 + throw new Exception( 144 + 'setStream() expects parameter stream to be readable stream resource.' 145 + ); 146 + } 147 + 148 + /** @var resource $tmp_fp */ 149 + $tmp_fp = tmpfile(); 150 + if ($tmp_fp) { 151 + while (!feof($stream)) { 152 + fwrite($tmp_fp, fread($stream, 2028)); 153 + } 154 + 155 + if (fread($tmp_fp, 1) != "\n") { 156 + fwrite($tmp_fp, PHP_EOL); 157 + } 158 + 159 + fseek($tmp_fp, 0); 160 + $this->stream = &$tmp_fp; 161 + } else { 162 + throw new Exception( 163 + 'Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.' 164 + ); 165 + } 166 + fclose($stream); 167 + 168 + $this->resource = mailparse_msg_create(); 169 + // parses the message incrementally (low memory usage but slower) 170 + while (!feof($this->stream)) { 171 + mailparse_msg_parse($this->resource, fread($this->stream, 2082)); 172 + } 173 + $this->parse(); 174 + 175 + return $this; 176 + } 177 + 178 + /** 179 + * Set the email text 180 + * 181 + * @param string $data 182 + * 183 + * @return Parser MimeMailParser Instance 184 + */ 185 + public function setText($data) 186 + { 187 + if (empty($data)) { 188 + throw new Exception('You must not call MimeMailParser::setText with an empty string parameter'); 189 + } 190 + 191 + if (substr($data, -1) != "\n") { 192 + $data = $data.PHP_EOL; 193 + } 194 + 195 + $this->resource = mailparse_msg_create(); 196 + // does not parse incrementally, fast memory hog might explode 197 + mailparse_msg_parse($this->resource, $data); 198 + $this->data = $data; 199 + $this->parse(); 200 + 201 + return $this; 202 + } 203 + 204 + /** 205 + * Parse the Message into parts 206 + * 207 + * @return void 208 + */ 209 + protected function parse() 210 + { 211 + $structure = mailparse_msg_get_structure($this->resource); 212 + $this->parts = []; 213 + foreach ($structure as $part_id) { 214 + $part = mailparse_msg_get_part($this->resource, $part_id); 215 + $part_data = mailparse_msg_get_part_data($part); 216 + $mimePart = new MimePart($part_id, $part_data); 217 + // let each middleware parse the part before saving 218 + $this->parts[$part_id] = $this->middlewareStack->parse($mimePart)->getPart(); 219 + } 220 + } 221 + 222 + /** 223 + * Retrieve a specific Email Header, without charset conversion. 224 + * 225 + * @param string $name Header name (case-insensitive) 226 + * 227 + * @return string|bool 228 + * @throws Exception 229 + */ 230 + public function getRawHeader($name) 231 + { 232 + $name = strtolower($name); 233 + if (isset($this->parts[1])) { 234 + $headers = $this->getPart('headers', $this->parts[1]); 235 + 236 + return isset($headers[$name]) ? $headers[$name] : false; 237 + } else { 238 + throw new Exception( 239 + 'setPath() or setText() or setStream() must be called before retrieving email headers.' 240 + ); 241 + } 242 + } 243 + 244 + /** 245 + * Retrieve a specific Email Header 246 + * 247 + * @param string $name Header name (case-insensitive) 248 + * 249 + * @return string|false 250 + */ 251 + public function getHeader($name) 252 + { 253 + $rawHeader = $this->getRawHeader($name); 254 + if ($rawHeader === false) { 255 + return false; 256 + } 257 + 258 + return $this->decodeHeader($rawHeader); 259 + } 260 + 261 + /** 262 + * Retrieve all mail headers 263 + * 264 + * @return array 265 + * @throws Exception 266 + */ 267 + public function getHeaders() 268 + { 269 + if (isset($this->parts[1])) { 270 + $headers = $this->getPart('headers', $this->parts[1]); 271 + foreach ($headers as &$value) { 272 + if (is_array($value)) { 273 + foreach ($value as &$v) { 274 + $v = $this->decodeSingleHeader($v); 275 + } 276 + } else { 277 + $value = $this->decodeSingleHeader($value); 278 + } 279 + } 280 + 281 + return $headers; 282 + } else { 283 + throw new Exception( 284 + 'setPath() or setText() or setStream() must be called before retrieving email headers.' 285 + ); 286 + } 287 + } 288 + 289 + /** 290 + * Retrieve the raw mail headers as a string 291 + * 292 + * @return string 293 + * @throws Exception 294 + */ 295 + public function getHeadersRaw() 296 + { 297 + if (isset($this->parts[1])) { 298 + return $this->getPartHeader($this->parts[1]); 299 + } else { 300 + throw new Exception( 301 + 'setPath() or setText() or setStream() must be called before retrieving email headers.' 302 + ); 303 + } 304 + } 305 + 306 + /** 307 + * Retrieve the raw Header of a MIME part 308 + * 309 + * @return String 310 + * @param $part Object 311 + * @throws Exception 312 + */ 313 + protected function getPartHeader(&$part) 314 + { 315 + $header = ''; 316 + if ($this->stream) { 317 + $header = $this->getPartHeaderFromFile($part); 318 + } elseif ($this->data) { 319 + $header = $this->getPartHeaderFromText($part); 320 + } 321 + return $header; 322 + } 323 + 324 + /** 325 + * Retrieve the Header from a MIME part from file 326 + * 327 + * @return String Mime Header Part 328 + * @param $part Array 329 + */ 330 + protected function getPartHeaderFromFile(&$part) 331 + { 332 + $start = $part['starting-pos']; 333 + $end = $part['starting-pos-body']; 334 + fseek($this->stream, $start, SEEK_SET); 335 + $header = fread($this->stream, $end - $start); 336 + return $header; 337 + } 338 + 339 + /** 340 + * Retrieve the Header from a MIME part from text 341 + * 342 + * @return String Mime Header Part 343 + * @param $part Array 344 + */ 345 + protected function getPartHeaderFromText(&$part) 346 + { 347 + $start = $part['starting-pos']; 348 + $end = $part['starting-pos-body']; 349 + $header = substr($this->data, $start, $end - $start); 350 + return $header; 351 + } 352 + 353 + /** 354 + * Checks whether a given part ID is a child of another part 355 + * eg. an RFC822 attachment may have one or more text parts 356 + * 357 + * @param string $partId 358 + * @param string $parentPartId 359 + * @return bool 360 + */ 361 + protected function partIdIsChildOfPart($partId, $parentPartId) 362 + { 363 + $parentPartId = $parentPartId.'.'; 364 + return substr($partId, 0, strlen($parentPartId)) == $parentPartId; 365 + } 366 + 367 + /** 368 + * Whether the given part ID is a child of any attachment part in the message. 369 + * 370 + * @param string $checkPartId 371 + * @return bool 372 + */ 373 + protected function partIdIsChildOfAnAttachment($checkPartId) 374 + { 375 + foreach ($this->parts as $partId => $part) { 376 + if ($this->getPart('content-disposition', $part) == 'attachment') { 377 + if ($this->partIdIsChildOfPart($checkPartId, $partId)) { 378 + return true; 379 + } 380 + } 381 + } 382 + return false; 383 + } 384 + 385 + /** 386 + * Returns the email message body in the specified format 387 + * 388 + * @param string $type text, html or htmlEmbedded 389 + * 390 + * @return string Body 391 + * @throws Exception 392 + */ 393 + public function getMessageBody($type = 'text') 394 + { 395 + $mime_types = [ 396 + 'text' => 'text/plain', 397 + 'html' => 'text/html', 398 + 'htmlEmbedded' => 'text/html', 399 + ]; 400 + 401 + if (in_array($type, array_keys($mime_types))) { 402 + $part_type = $type === 'htmlEmbedded' ? 'html' : $type; 403 + $inline_parts = $this->getInlineParts($part_type); 404 + $body = empty($inline_parts) ? '' : $inline_parts[0]; 405 + } else { 406 + throw new Exception( 407 + 'Invalid type specified for getMessageBody(). Expected: text, html or htmlEmbeded.' 408 + ); 409 + } 410 + 411 + if ($type == 'htmlEmbedded') { 412 + $attachments = $this->getAttachments(); 413 + foreach ($attachments as $attachment) { 414 + if ($attachment->getContentID() != '') { 415 + $body = str_replace( 416 + '"cid:'.$attachment->getContentID().'"', 417 + '"'.$this->getEmbeddedData($attachment->getContentID()).'"', 418 + $body 419 + ); 420 + } 421 + } 422 + } 423 + 424 + return $body; 425 + } 426 + 427 + /** 428 + * Returns the embedded data structure 429 + * 430 + * @param string $contentId Content-Id 431 + * 432 + * @return string 433 + */ 434 + protected function getEmbeddedData($contentId) 435 + { 436 + foreach ($this->parts as $part) { 437 + if ($this->getPart('content-id', $part) == $contentId) { 438 + $embeddedData = 'data:'; 439 + $embeddedData .= $this->getPart('content-type', $part); 440 + $embeddedData .= ';'.$this->getPart('transfer-encoding', $part); 441 + $embeddedData .= ','.$this->getPartBody($part); 442 + return $embeddedData; 443 + } 444 + } 445 + return ''; 446 + } 447 + 448 + /** 449 + * Return an array with the following keys display, address, is_group 450 + * 451 + * @param string $name Header name (case-insensitive) 452 + * 453 + * @return array 454 + */ 455 + public function getAddresses($name) 456 + { 457 + $value = $this->getRawHeader($name); 458 + $value = (is_array($value)) ? $value[0] : $value; 459 + $addresses = mailparse_rfc822_parse_addresses($value); 460 + foreach ($addresses as $i => $item) { 461 + $addresses[$i]['display'] = $this->decodeHeader($item['display']); 462 + } 463 + return $addresses; 464 + } 465 + 466 + /** 467 + * Returns the attachments contents in order of appearance 468 + * 469 + * @return Attachment[] 470 + */ 471 + public function getInlineParts($type = 'text') 472 + { 473 + $inline_parts = []; 474 + $mime_types = [ 475 + 'text' => 'text/plain', 476 + 'html' => 'text/html', 477 + ]; 478 + 479 + if (!in_array($type, array_keys($mime_types))) { 480 + throw new Exception('Invalid type specified for getInlineParts(). "type" can either be text or html.'); 481 + } 482 + 483 + foreach ($this->parts as $partId => $part) { 484 + if ($this->getPart('content-type', $part) == $mime_types[$type] 485 + && $this->getPart('content-disposition', $part) != 'attachment' 486 + && !$this->partIdIsChildOfAnAttachment($partId) 487 + ) { 488 + $headers = $this->getPart('headers', $part); 489 + $encodingType = array_key_exists('content-transfer-encoding', $headers) ? 490 + $headers['content-transfer-encoding'] : ''; 491 + $undecoded_body = $this->decodeContentTransfer($this->getPartBody($part), $encodingType); 492 + $inline_parts[] = $this->charset->decodeCharset($undecoded_body, $this->getPartCharset($part)); 493 + } 494 + } 495 + 496 + return $inline_parts; 497 + } 498 + 499 + /** 500 + * Returns the attachments contents in order of appearance 501 + * 502 + * @return Attachment[] 503 + */ 504 + public function getAttachments($include_inline = true) 505 + { 506 + $attachments = []; 507 + $dispositions = $include_inline ? ['attachment', 'inline'] : ['attachment']; 508 + $non_attachment_types = ['text/plain', 'text/html']; 509 + $nonameIter = 0; 510 + 511 + foreach ($this->parts as $part) { 512 + $disposition = $this->getPart('content-disposition', $part); 513 + $filename = 'noname'; 514 + 515 + if (isset($part['disposition-filename'])) { 516 + $filename = $this->decodeHeader($part['disposition-filename']); 517 + } elseif (isset($part['content-name'])) { 518 + // if we have no disposition but we have a content-name, it's a valid attachment. 519 + // we simulate the presence of an attachment disposition with a disposition filename 520 + $filename = $this->decodeHeader($part['content-name']); 521 + $disposition = 'attachment'; 522 + } elseif (in_array($part['content-type'], $non_attachment_types, true) 523 + && $disposition !== 'attachment') { 524 + // it is a message body, no attachment 525 + continue; 526 + } elseif (substr($part['content-type'], 0, 10) !== 'multipart/' 527 + && $part['content-type'] !== 'text/plain; (error)' && $disposition != 'inline') { 528 + // if we cannot get it by getMessageBody(), we assume it is an attachment 529 + $disposition = 'attachment'; 530 + } 531 + if (in_array($disposition, ['attachment', 'inline']) === false && !empty($disposition)) { 532 + $disposition = 'attachment'; 533 + } 534 + 535 + if (in_array($disposition, $dispositions) === true) { 536 + if ($filename == 'noname') { 537 + $nonameIter++; 538 + $filename = 'noname'.$nonameIter; 539 + } else { 540 + // Escape all potentially unsafe characters from the filename 541 + $filename = preg_replace('((^\.)|\/|[\n|\r|\n\r]|(\.$))', '_', $filename); 542 + } 543 + 544 + $headersAttachments = $this->getPart('headers', $part); 545 + $contentidAttachments = $this->getPart('content-id', $part); 546 + 547 + $attachmentStream = $this->getAttachmentStream($part); 548 + $mimePartStr = $this->getPartComplete($part); 549 + 550 + $attachments[] = new Attachment( 551 + $filename, 552 + $this->getPart('content-type', $part), 553 + $attachmentStream, 554 + $disposition, 555 + $contentidAttachments, 556 + $headersAttachments, 557 + $mimePartStr 558 + ); 559 + } 560 + } 561 + 562 + return $attachments; 563 + } 564 + 565 + /** 566 + * Save attachments in a folder 567 + * 568 + * @param string $attach_dir directory 569 + * @param bool $include_inline 570 + * @param string $filenameStrategy How to generate attachment filenames 571 + * 572 + * @return array Saved attachments paths 573 + * @throws Exception 574 + */ 575 + public function saveAttachments( 576 + $attach_dir, 577 + $include_inline = true, 578 + $filenameStrategy = self::ATTACHMENT_DUPLICATE_SUFFIX 579 + ) { 580 + $attachments = $this->getAttachments($include_inline); 581 + 582 + $attachments_paths = []; 583 + foreach ($attachments as $attachment) { 584 + $attachments_paths[] = $attachment->save($attach_dir, $filenameStrategy); 585 + } 586 + 587 + return $attachments_paths; 588 + } 589 + 590 + /** 591 + * Read the attachment Body and save temporary file resource 592 + * 593 + * @param array $part 594 + * 595 + * @return resource Mime Body Part 596 + * @throws Exception 597 + */ 598 + protected function getAttachmentStream(&$part) 599 + { 600 + /** @var resource $temp_fp */ 601 + $temp_fp = tmpfile(); 602 + 603 + $headers = $this->getPart('headers', $part); 604 + $encodingType = array_key_exists('content-transfer-encoding', $headers) ? 605 + $headers['content-transfer-encoding'] : ''; 606 + 607 + if ($temp_fp) { 608 + if ($this->stream) { 609 + $start = $part['starting-pos-body']; 610 + $end = $part['ending-pos-body']; 611 + fseek($this->stream, $start, SEEK_SET); 612 + $len = $end - $start; 613 + $written = 0; 614 + while ($written < $len) { 615 + $write = $len; 616 + $data = fread($this->stream, $write); 617 + fwrite($temp_fp, $this->decodeContentTransfer($data, $encodingType)); 618 + $written += $write; 619 + } 620 + } elseif ($this->data) { 621 + $attachment = $this->decodeContentTransfer($this->getPartBodyFromText($part), $encodingType); 622 + fwrite($temp_fp, $attachment, strlen($attachment)); 623 + } 624 + fseek($temp_fp, 0, SEEK_SET); 625 + } else { 626 + throw new Exception( 627 + 'Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.' 628 + ); 629 + } 630 + 631 + return $temp_fp; 632 + } 633 + 634 + /** 635 + * Decode the string from Content-Transfer-Encoding 636 + * 637 + * @param string $encodedString The string in its original encoded state 638 + * @param string $encodingType The encoding type from the Content-Transfer-Encoding header of the part. 639 + * 640 + * @return string The decoded string 641 + */ 642 + protected function decodeContentTransfer($encodedString, $encodingType) 643 + { 644 + if (is_array($encodingType)) { 645 + $encodingType = $encodingType[0]; 646 + } 647 + 648 + $encodingType = strtolower($encodingType); 649 + if ($encodingType == 'base64') { 650 + return base64_decode($encodedString); 651 + } elseif ($encodingType == 'quoted-printable') { 652 + return quoted_printable_decode($encodedString); 653 + } else { 654 + return $encodedString; 655 + } 656 + } 657 + 658 + /** 659 + * $input can be a string or array 660 + * 661 + * @param string|array $input 662 + * 663 + * @return string 664 + */ 665 + protected function decodeHeader($input) 666 + { 667 + //Sometimes we have 2 label From so we take only the first 668 + if (is_array($input)) { 669 + return $this->decodeSingleHeader($input[0]); 670 + } 671 + 672 + return $this->decodeSingleHeader($input); 673 + } 674 + 675 + /** 676 + * Decodes a single header (= string) 677 + * 678 + * @param string $input 679 + * 680 + * @return string 681 + */ 682 + protected function decodeSingleHeader($input) 683 + { 684 + // For each encoded-word... 685 + while (preg_match('/(=\?([^?]+)\?(q|b)\?([^?]*)\?=)((\s+)=\?)?/i', $input, $matches)) { 686 + $encoded = $matches[1]; 687 + $charset = $matches[2]; 688 + $encoding = $matches[3]; 689 + $text = $matches[4]; 690 + $space = isset($matches[6]) ? $matches[6] : ''; 691 + 692 + switch (strtolower($encoding)) { 693 + case 'b': 694 + $text = $this->decodeContentTransfer($text, 'base64'); 695 + break; 696 + 697 + case 'q': 698 + $text = str_replace('_', ' ', $text); 699 + preg_match_all('/=([a-f0-9]{2})/i', $text, $matches); 700 + foreach ($matches[1] as $value) { 701 + $text = str_replace('='.$value, chr(hexdec($value)), $text); 702 + } 703 + break; 704 + } 705 + 706 + $text = $this->charset->decodeCharset($text, $this->charset->getCharsetAlias($charset)); 707 + $input = str_replace($encoded.$space, $text, $input); 708 + } 709 + 710 + return $input; 711 + } 712 + 713 + /** 714 + * Return the charset of the MIME part 715 + * 716 + * @param array $part 717 + * 718 + * @return string 719 + */ 720 + protected function getPartCharset($part) 721 + { 722 + if (isset($part['charset'])) { 723 + return $this->charset->getCharsetAlias($part['charset']); 724 + } else { 725 + return 'us-ascii'; 726 + } 727 + } 728 + 729 + /** 730 + * Retrieve a specified MIME part 731 + * 732 + * @param string $type 733 + * @param array $parts 734 + * 735 + * @return string|array 736 + */ 737 + protected function getPart($type, $parts) 738 + { 739 + return (isset($parts[$type])) ? $parts[$type] : false; 740 + } 741 + 742 + /** 743 + * Retrieve the Body of a MIME part 744 + * 745 + * @param array $part 746 + * 747 + * @return string 748 + */ 749 + protected function getPartBody(&$part) 750 + { 751 + $body = ''; 752 + if ($this->stream) { 753 + $body = $this->getPartBodyFromFile($part); 754 + } elseif ($this->data) { 755 + $body = $this->getPartBodyFromText($part); 756 + } 757 + 758 + return $body; 759 + } 760 + 761 + /** 762 + * Retrieve the Body from a MIME part from file 763 + * 764 + * @param array $part 765 + * 766 + * @return string Mime Body Part 767 + */ 768 + protected function getPartBodyFromFile(&$part) 769 + { 770 + $start = $part['starting-pos-body']; 771 + $end = $part['ending-pos-body']; 772 + $body = ''; 773 + if ($end - $start > 0) { 774 + fseek($this->stream, $start, SEEK_SET); 775 + $body = fread($this->stream, $end - $start); 776 + } 777 + 778 + return $body; 779 + } 780 + 781 + /** 782 + * Retrieve the Body from a MIME part from text 783 + * 784 + * @param array $part 785 + * 786 + * @return string Mime Body Part 787 + */ 788 + protected function getPartBodyFromText(&$part) 789 + { 790 + $start = $part['starting-pos-body']; 791 + $end = $part['ending-pos-body']; 792 + 793 + return substr($this->data, $start, $end - $start); 794 + } 795 + 796 + /** 797 + * Retrieve the content of a MIME part 798 + * 799 + * @param array $part 800 + * 801 + * @return string 802 + */ 803 + protected function getPartComplete(&$part) 804 + { 805 + $body = ''; 806 + if ($this->stream) { 807 + $body = $this->getPartFromFile($part); 808 + } elseif ($this->data) { 809 + $body = $this->getPartFromText($part); 810 + } 811 + 812 + return $body; 813 + } 814 + 815 + /** 816 + * Retrieve the content from a MIME part from file 817 + * 818 + * @param array $part 819 + * 820 + * @return string Mime Content 821 + */ 822 + protected function getPartFromFile(&$part) 823 + { 824 + $start = $part['starting-pos']; 825 + $end = $part['ending-pos']; 826 + $body = ''; 827 + if ($end - $start > 0) { 828 + fseek($this->stream, $start, SEEK_SET); 829 + $body = fread($this->stream, $end - $start); 830 + } 831 + 832 + return $body; 833 + } 834 + 835 + /** 836 + * Retrieve the content from a MIME part from text 837 + * 838 + * @param array $part 839 + * 840 + * @return string Mime Content 841 + */ 842 + protected function getPartFromText(&$part) 843 + { 844 + $start = $part['starting-pos']; 845 + $end = $part['ending-pos']; 846 + 847 + return substr($this->data, $start, $end - $start); 848 + } 849 + 850 + /** 851 + * Retrieve the resource 852 + * 853 + * @return resource resource 854 + */ 855 + public function getResource() 856 + { 857 + return $this->resource; 858 + } 859 + 860 + /** 861 + * Retrieve the file pointer to email 862 + * 863 + * @return resource stream 864 + */ 865 + public function getStream() 866 + { 867 + return $this->stream; 868 + } 869 + 870 + /** 871 + * Retrieve the text of an email 872 + * 873 + * @return string data 874 + */ 875 + public function getData() 876 + { 877 + return $this->data; 878 + } 879 + 880 + /** 881 + * Retrieve the parts of an email 882 + * 883 + * @return array parts 884 + */ 885 + public function getParts() 886 + { 887 + return $this->parts; 888 + } 889 + 890 + /** 891 + * Retrieve the charset manager object 892 + * 893 + * @return CharsetManager charset 894 + */ 895 + public function getCharset() 896 + { 897 + return $this->charset; 898 + } 899 + 900 + /** 901 + * Add a middleware to the parser MiddlewareStack 902 + * Each middleware is invoked when: 903 + * a MimePart is retrieved by mailparse_msg_get_part_data() during $this->parse() 904 + * The middleware will receive MimePart $part and the next MiddlewareStack $next 905 + * 906 + * Eg: 907 + * 908 + * $Parser->addMiddleware(function(MimePart $part, MiddlewareStack $next) { 909 + * // do something with the $part 910 + * return $next($part); 911 + * }); 912 + * 913 + * @param callable $middleware Plain Function or Middleware Instance to execute 914 + * @return void 915 + */ 916 + public function addMiddleware(callable $middleware) 917 + { 918 + if (!$middleware instanceof Middleware) { 919 + $middleware = new Middleware($middleware); 920 + } 921 + $this->middlewareStack = $this->middlewareStack->add($middleware); 922 + } 923 + }
-3
externals/mimemailparser/README
··· 1 - From: 2 - 3 - http://code.google.com/p/php-mime-mail-parser/
+267
externals/mimemailparser/README.md
··· 1 + # php-mime-mail-parser 2 + 3 + A fully tested email parser for PHP 8.0+ (mailparse extension wrapper). 4 + 5 + It's the most effective PHP email parser around in terms of performance, foreign character encoding, attachment handling, and ease of use. 6 + Internet Message Format RFC [822](https://tools.ietf.org/html/rfc822), [2822](https://tools.ietf.org/html/rfc2822), [5322](https://tools.ietf.org/html/rfc5322). 7 + 8 + [![Latest Version](https://img.shields.io/packagist/v/php-mime-mail-parser/php-mime-mail-parser.svg?style=flat-square)](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases) 9 + [![Total Downloads](https://img.shields.io/packagist/dt/php-mime-mail-parser/php-mime-mail-parser.svg?style=flat-square)](https://packagist.org/packages/php-mime-mail-parser/php-mime-mail-parser) 10 + [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) 11 + 12 + ## Why? 13 + 14 + This extension can be used to... 15 + * Parse and read email from Postfix 16 + * Read messages (Filename extension: `.eml`) 17 + * Create webmail 18 + * Store email information such a subject, HTML body, attachments, etc. into a database 19 + 20 + ## Is it reliable? 21 + 22 + Yes. All known issues have been reproduced, fixed and tested. 23 + 24 + We use GitHub Actions, Codecov, Codacy to help ensure code quality. You can see real-time statistics below: 25 + 26 + [![CI](https://github.com/php-mime-mail-parser/php-mime-mail-parser/actions/workflows/main.yml/badge.svg?style=flat-square)](https://github.com/php-mime-mail-parser/php-mime-mail-parser/actions/workflows/main.yml) 27 + [![Coverage](https://codecov.io/gh/php-mime-mail-parser/php-mime-mail-parser/branch/main/graph/badge.svg?token=wTSIbXJDL0)](https://codecov.io/gh/php-mime-mail-parser/php-mime-mail-parser) 28 + [![Code Quality](https://app.codacy.com/project/badge/Grade/8cbfe0fcd84c4b2b9282b9a0b4467607)](https://www.codacy.com/gh/php-mime-mail-parser/php-mime-mail-parser/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=php-mime-mail-parser/php-mime-mail-parser&amp;utm_campaign=Badge_Grade) 29 + 30 + ## How do I install it? 31 + 32 + The easiest way is via [Composer](https://getcomposer.org/). 33 + 34 + To install the latest version of PHP MIME Mail Parser, run the command below: 35 + 36 + composer require php-mime-mail-parser/php-mime-mail-parser 37 + 38 + ## Requirements 39 + 40 + The following versions of PHP are supported: 41 + 42 + * PHP 8.0 43 + * PHP 8.1 44 + * PHP 8.2 45 + * PHP 8.3 46 + 47 + Previous Versions: 48 + 49 + | PHP Compatibility | Version | 50 + |-------------------|-----------------------------| 51 + | HHVM | [php-mime-mail-parser 2.11.1](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/2.11.1) | 52 + | PHP 5.4 | [php-mime-mail-parser 2.11.1](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/2.11.1) | 53 + | PHP 5.5 | [php-mime-mail-parser 2.11.1](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/2.11.1) | 54 + | PHP 5.6 | [php-mime-mail-parser 3.0.4](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/3.0.4) | 55 + | PHP 7.0 | [php-mime-mail-parser 3.0.4](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/3.0.4) | 56 + | PHP 7.1 | [php-mime-mail-parser 5.0.5](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/5.0.5) | 57 + | PHP 7.2 | [php-mime-mail-parser 7.1.2](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/7.1.2) | 58 + | PHP 7.3 | [php-mime-mail-parser 7.1.2](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/7.1.2) | 59 + | PHP 7.4 | [php-mime-mail-parser 7.1.2](https://github.com/php-mime-mail-parser/php-mime-mail-parser/releases/tag/7.1.2) | 60 + 61 + Make sure you have the mailparse extension (http://php.net/manual/en/book.mailparse.php) properly installed. The command line `php -m | grep mailparse` needs to return "mailparse". 62 + 63 + 64 + ### Install mailparse extension 65 + 66 + #### Debian, Ubuntu & derivatives 67 + ``` 68 + sudo apt install php-cli php-mailparse 69 + ``` 70 + 71 + #### MacOS 72 + ``` 73 + brew install php 74 + pecl install mailparse 75 + ``` 76 + 77 + #### Other platforms 78 + ``` 79 + sudo apt install php-cli php-pear php-dev php-mbstring 80 + pecl install mailparse 81 + ``` 82 + 83 + #### From source 84 + 85 + AAAAMMDD should be `php-config --extension-dir` 86 + ``` 87 + git clone https://github.com/php/pecl-mail-mailparse.git 88 + cd pecl-mail-mailparse 89 + phpize 90 + ./configure 91 + sed -i 's/#if\s!HAVE_MBSTRING/#ifndef MBFL_MBFILTER_H/' ./mailparse.c 92 + make 93 + sudo mv modules/mailparse.so /usr/lib/php/AAAAMMDD/ 94 + echo "extension=mailparse.so" | sudo tee /etc/php/7.1/mods-available/mailparse.ini 95 + sudo phpenmod mailparse 96 + ``` 97 + 98 + #### Windows 99 + You need to download mailparse DLL from http://pecl.php.net/package/mailparse and add the line `extension=php_mailparse.dll` to `php.ini` accordingly. 100 + 101 + ## How do I use it? 102 + 103 + ### Loading an email 104 + 105 + You can load an email in 4 differents ways: 106 + 107 + ```php 108 + require_once __DIR__.'/vendor/autoload.php'; 109 + 110 + $path = 'path/to/email.eml'; 111 + $parser = new PhpMimeMailParser\Parser(); 112 + 113 + // 1. Either specify a file path (string) 114 + $parser->setPath($path); 115 + 116 + // 2. or specify the raw mime mail text (string) 117 + $parser->setText(file_get_contents($path)); 118 + 119 + // 3. or specify a php file resource (stream) 120 + $parser->setStream(fopen($path, "r")); 121 + 122 + // 4. or specify a stream to work with a mail server (stream) 123 + $parser->setStream(fopen("php://stdin", "r")); 124 + ``` 125 + 126 + ### Get the metadata of the message 127 + 128 + Get the sender and the receiver: 129 + 130 + ```php 131 + $rawHeaderTo = $parser->getHeader('to'); 132 + // return "test" <test@example.com>, "test2" <test2@example.com> 133 + 134 + $arrayHeaderTo = $parser->getAddresses('to'); 135 + // return [["display"=>"test", "address"=>"test@example.com", false]] 136 + 137 + $rawHeaderFrom = $parser->getHeader('from'); 138 + // return "test" <test@example.com> 139 + 140 + $arrayHeaderFrom = $parser->getAddresses('from'); 141 + // return [["display"=>"test", "address"=>"test@example.com", "is_group"=>false]] 142 + ``` 143 + 144 + Get the subject: 145 + 146 + ```php 147 + $subject = $parser->getHeader('subject'); 148 + ``` 149 + 150 + Get other headers: 151 + 152 + ```php 153 + $stringHeaders = $parser->getHeadersRaw(); 154 + // return all headers as a string, no charset conversion 155 + 156 + $arrayHeaders = $parser->getHeaders(); 157 + // return all headers as an array, with charset conversion 158 + ``` 159 + 160 + ### Get the body of the message 161 + 162 + ```php 163 + $text = $parser->getMessageBody('text'); 164 + // return the text version 165 + 166 + $html = $parser->getMessageBody('html'); 167 + // return the html version 168 + 169 + $htmlEmbedded = $parser->getMessageBody('htmlEmbedded'); 170 + // return the html version with the embedded contents like images 171 + 172 + ``` 173 + 174 + ### Get attachments 175 + 176 + Save all attachments in a directory 177 + 178 + ```php 179 + $parser->saveAttachments('/path/to/save/attachments/'); 180 + // return all attachments saved in the directory (include inline attachments) 181 + 182 + $parser->saveAttachments('/path/to/save/attachments/', false); 183 + // return all attachments saved in the directory (exclude inline attachments) 184 + 185 + // Save all attachments with the strategy ATTACHMENT_DUPLICATE_SUFFIX (default) 186 + $parser->saveAttachments('/path/to/save/attachments/', false, Parser::ATTACHMENT_DUPLICATE_SUFFIX); 187 + // return all attachments saved in the directory: logo.jpg, logo_1.jpg, ..., logo_100.jpg, YY34UFHBJ.jpg 188 + 189 + // Save all attachments with the strategy ATTACHMENT_RANDOM_FILENAME 190 + $parser->saveAttachments('/path/to/save/attachments/', false, Parser::ATTACHMENT_RANDOM_FILENAME); 191 + // return all attachments saved in the directory: YY34UFHBJ.jpg and F98DBZ9FZF.jpg 192 + 193 + // Save all attachments with the strategy ATTACHMENT_DUPLICATE_THROW 194 + $parser->saveAttachments('/path/to/save/attachments/', false, Parser::ATTACHMENT_DUPLICATE_THROW); 195 + // return an exception when there is attachments duplicate. 196 + 197 + ``` 198 + 199 + Get all attachments 200 + 201 + ```php 202 + $attachments = $parser->getAttachments(); 203 + // return an array of all attachments (include inline attachments) 204 + 205 + $attachments = $parser->getAttachments(false); 206 + // return an array of all attachments (exclude inline attachments) 207 + ``` 208 + 209 + 210 + Loop through all attachments 211 + ```php 212 + foreach ($attachments as $attachment) { 213 + echo 'Filename : '.$attachment->getFilename().'<br>'; 214 + // return logo.jpg 215 + 216 + echo 'Filesize : '.filesize($attach_dir.$attachment->getFilename()).'<br>'; 217 + // return 1000 218 + 219 + echo 'Filetype : '.$attachment->getContentType().'<br>'; 220 + // return image/jpeg 221 + 222 + echo 'MIME part string : '.$attachment->getMimePartStr().'<br>'; 223 + // return the whole MIME part of the attachment 224 + 225 + $stream = $attachment->getStream(); 226 + // get the stream of the attachment file 227 + 228 + $attachment->save('/path/to/save/myattachment/', Parser::ATTACHMENT_DUPLICATE_SUFFIX); 229 + // return the path and the filename saved (same strategy available than saveAttachments) 230 + } 231 + ``` 232 + 233 + ## Postfix configuration to manage email from a mail server 234 + 235 + To forward mails from [Postfix](http://www.postfix.org/) to the PHP script above, add this line at the end of your `/etc/postfix/master.cf` 236 + (to specify myhook to send all emails to the script `test.php`): 237 + 238 + ``` 239 + myhook unix - n n - - pipe 240 + flags=F user=www-data argv=php -c /etc/php5/apache2/php.ini -f /var/www/test.php ${sender} ${size} ${recipient} 241 + ``` 242 + 243 + Edit this line (register myhook) 244 + ``` 245 + smtp inet n - - - - smtpd 246 + -o content_filter=myhook:dummy 247 + ``` 248 + 249 + The PHP script must use the fourth method (see above) to work with this configuration. 250 + 251 + And finally the easiest way is to use my SaaS https://mailcare.io 252 + 253 + 254 + ## Can I contribute? 255 + 256 + Feel free to contribute! 257 + 258 + git clone https://github.com/php-mime-mail-parser/php-mime-mail-parser 259 + cd php-mime-mail-parser 260 + composer install 261 + ./vendor/bin/phpunit 262 + 263 + If you report an issue, please provide the raw email that triggered it. This helps us reproduce the issue and fix it more quickly. 264 + 265 + ## License 266 + 267 + The php-mime-mail-parser/php-mime-mail-parser is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
-136
externals/mimemailparser/attachment.class.php
··· 1 - <?php 2 - 3 - /** 4 - * Model of an Attachment 5 - */ 6 - class MimeMailParser_attachment { 7 - 8 - /** 9 - * @var $filename Filename 10 - */ 11 - public $filename; 12 - /** 13 - * @var $content_type Mime Type 14 - */ 15 - public $content_type; 16 - /** 17 - * @var $content File Content 18 - */ 19 - private $content; 20 - /** 21 - * @var $extension Filename extension 22 - */ 23 - private $extension; 24 - /** 25 - * @var $content_disposition Content-Disposition (attachment or inline) 26 - */ 27 - public $content_disposition; 28 - /** 29 - * @var $headers An Array of the attachment headers 30 - */ 31 - public $headers; 32 - 33 - private $stream; 34 - 35 - public function __construct($filename, $content_type, $stream, $content_disposition = 'attachment', $headers = array()) { 36 - $this->filename = $filename; 37 - $this->content_type = $content_type; 38 - $this->stream = $stream; 39 - $this->content = null; 40 - $this->content_disposition = $content_disposition; 41 - $this->headers = $headers; 42 - } 43 - 44 - /** 45 - * retrieve the attachment filename 46 - * @return String 47 - */ 48 - public function getFilename() { 49 - return $this->filename; 50 - } 51 - 52 - /** 53 - * Retrieve the Attachment Content-Type 54 - * @return String 55 - */ 56 - public function getContentType() { 57 - return $this->content_type; 58 - } 59 - 60 - /** 61 - * Retrieve the Attachment Content-Disposition 62 - * @return String 63 - */ 64 - public function getContentDisposition() { 65 - return $this->content_disposition; 66 - } 67 - 68 - /** 69 - * Retrieve the Attachment Headers 70 - * @return String 71 - */ 72 - public function getHeaders() { 73 - return $this->headers; 74 - } 75 - 76 - /** 77 - * Retrieve the file extension 78 - * @return String 79 - */ 80 - public function getFileExtension() { 81 - if (!$this->extension) { 82 - $ext = substr(strrchr($this->filename, '.'), 1); 83 - if ($ext == 'gz') { 84 - // special case, tar.gz 85 - // todo: other special cases? 86 - $ext = preg_match("/\.tar\.gz$/i", $ext) ? 'tar.gz' : 'gz'; 87 - } 88 - $this->extension = $ext; 89 - } 90 - return $this->extension; 91 - } 92 - 93 - /** 94 - * Read the contents a few bytes at a time until completed 95 - * Once read to completion, it always returns false 96 - * @return String 97 - * @param $bytes Int[optional] 98 - */ 99 - public function read($bytes = 2082) { 100 - return feof($this->stream) ? false : fread($this->stream, $bytes); 101 - } 102 - 103 - /** 104 - * Retrieve the file content in one go 105 - * Once you retrieve the content you cannot use MimeMailParser_attachment::read() 106 - * @return String 107 - */ 108 - public function getContent() { 109 - if ($this->content === null) { 110 - fseek($this->stream, 0); 111 - while(($buf = $this->read()) !== false) { 112 - $this->content .= $buf; 113 - } 114 - } 115 - return $this->content; 116 - } 117 - 118 - /** 119 - * Allow the properties 120 - * MimeMailParser_attachment::$name, 121 - * MimeMailParser_attachment::$extension 122 - * to be retrieved as public properties 123 - * @param $name Object 124 - */ 125 - public function __get($name) { 126 - if ($name == 'content') { 127 - return $this->getContent(); 128 - } else if ($name == 'extension') { 129 - return $this->getFileExtension(); 130 - } 131 - return null; 132 - } 133 - 134 - } 135 - 136 - ?>
+17 -15
scripts/mail/mail_handler.php
··· 14 14 15 15 $root = dirname(dirname(dirname(__FILE__))); 16 16 require_once $root.'/scripts/__init_script__.php'; 17 - require_once $root.'/externals/mimemailparser/MimeMailParser.class.php'; 17 + require_once $root.'/externals/mimemailparser/Contracts/CharsetManager.php'; 18 + require_once $root.'/externals/mimemailparser/Contracts/Middleware.php'; 19 + require_once $root.'/externals/mimemailparser/Parser.php'; 20 + require_once $root.'/externals/mimemailparser/Charset.php'; 21 + require_once $root.'/externals/mimemailparser/Attachment.php'; 22 + require_once $root.'/externals/mimemailparser/Exception.php'; 23 + require_once $root.'/externals/mimemailparser/Middleware.php'; 24 + require_once $root.'/externals/mimemailparser/MiddlewareStack.php'; 25 + require_once $root.'/externals/mimemailparser/MimePart.php'; 18 26 19 27 $args = new PhutilArgumentParser($argv); 20 28 $args->parseStandardArguments(); ··· 32 40 ), 33 41 )); 34 42 35 - $parser = new MimeMailParser(); 43 + if (!extension_loaded('mailparse')) { 44 + throw new Exception( 45 + pht( 46 + 'PhpMimeMailParser for handling incoming mail requires the PHP '. 47 + 'mailparse extension to be installed.')); 48 + } 49 + 50 + $parser = new \PhpMimeMailParser\Parser(); 36 51 $parser->setText(file_get_contents('php://stdin')); 37 52 38 53 $content = array(); 39 54 foreach (array('text', 'html') as $part) { 40 55 $part_body = $parser->getMessageBody($part); 41 - 42 - if (strlen($part_body) && !phutil_is_utf8($part_body)) { 43 - $part_headers = $parser->getMessageBodyHeaders($part); 44 - if (!is_array($part_headers)) { 45 - $part_headers = array(); 46 - } 47 - $content_type = idx($part_headers, 'content-type'); 48 - if (preg_match('/charset="(.*?)"/', $content_type, $matches) || 49 - preg_match('/charset=(\S+)/', $content_type, $matches)) { 50 - $part_body = phutil_utf8_convert($part_body, 'UTF-8', $matches[1]); 51 - } 52 - } 53 - 54 56 $content[$part] = $part_body; 55 57 } 56 58