Changeset View
Changeset View
Standalone View
Standalone View
externals/mimemailparser/MimeMailParser.class.php
| Show First 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | class MimeMailParser { | ||||
| } | } | ||||
| /** | /** | ||||
| * Set the email text | * Set the email text | ||||
| * @return Object MimeMailParser Instance | * @return Object MimeMailParser Instance | ||||
| * @param $data String | * @param $data String | ||||
| */ | */ | ||||
| public function setText($data) { | public function setText($data) { | ||||
| // NOTE: This has been modified for Phabricator. If the input data does not | // NOTE: This has been modified for Phabricator. If the input data does not | ||||
| // end in a newline, Mailparse fails to include the last line in the mail | // end in a newline, Mailparse fails to include the last line in the mail | ||||
| // body. This happens somewhere deep, deep inside the mailparse extension, | // body. This happens somewhere deep, deep inside the mailparse extension, | ||||
| // so adding a newline here seems like the most straightforward fix. | // so adding a newline here seems like the most straightforward fix. | ||||
| if (!preg_match('/\n\z/', $data)) { | if (!preg_match('/\n\z/', $data)) { | ||||
| $data = $data."\n"; | $data = $data."\n"; | ||||
| } | } | ||||
| $this->resource = mailparse_msg_create(); | $this->resource = mailparse_msg_create(); | ||||
| // does not parse incrementally, fast memory hog might explode | // does not parse incrementally, fast memory hog might explode | ||||
| mailparse_msg_parse($this->resource, $data); | mailparse_msg_parse($this->resource, $data); | ||||
| $this->data = $data; | $this->data = $data; | ||||
| $this->parse(); | $this->parse(); | ||||
| return $this; | return $this; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | public function getMessageBody($type = 'text') { | ||||
| $body = false; | $body = false; | ||||
| $mime_types = array( | $mime_types = array( | ||||
| 'text'=> 'text/plain', | 'text'=> 'text/plain', | ||||
| 'html'=> 'text/html' | 'html'=> 'text/html' | ||||
| ); | ); | ||||
| if (in_array($type, array_keys($mime_types))) { | if (in_array($type, array_keys($mime_types))) { | ||||
| foreach($this->parts as $part) { | foreach($this->parts as $part) { | ||||
| $disposition = $this->getPartContentDisposition($part); | $disposition = $this->getPartContentDisposition($part); | ||||
| if ($disposition == 'attachment') { | if ($disposition == 'attachment') { | ||||
| // text/plain parts with "Content-Disposition: attachment" are | // text/plain parts with "Content-Disposition: attachment" are | ||||
| // attachments, not part of the text body. | // attachments, not part of the text body. | ||||
| continue; | continue; | ||||
| } | } | ||||
| if ($this->getPartContentType($part) == $mime_types[$type]) { | if ($this->getPartContentType($part) == $mime_types[$type]) { | ||||
| $headers = $this->getPartHeaders($part); | $headers = $this->getPartHeaders($part); | ||||
| // Concatenate all the matching parts into the body text. For example, | // Concatenate all the matching parts into the body text. For example, | ||||
| // if a user sends a message with some text, then an image, and then | // if a user sends a message with some text, then an image, and then | ||||
| // some more text, the text body of the email gets split over several | // some more text, the text body of the email gets split over several | ||||
| // attachments. | // attachments. | ||||
| $body .= $this->decode( | $body .= $this->decode( | ||||
| $this->getPartBody($part), | $this->getPartBody($part), | ||||
| array_key_exists('content-transfer-encoding', $headers) | array_key_exists('content-transfer-encoding', $headers) | ||||
| ? $headers['content-transfer-encoding'] | ? $headers['content-transfer-encoding'] | ||||
| : ''); | : ''); | ||||
| } | } | ||||
| } | } | ||||
| } else { | } else { | ||||
| throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); | throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); | ||||
| } | } | ||||
| return $body; | return $body; | ||||
| } | } | ||||
| Show All 15 Lines | if (in_array($type, array_keys($mime_types))) { | ||||
| } | } | ||||
| } | } | ||||
| } else { | } else { | ||||
| throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); | throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); | ||||
| } | } | ||||
| return $headers; | return $headers; | ||||
| } | } | ||||
| /** | /** | ||||
| * Returns the attachments contents in order of appearance | * Returns the attachments contents in order of appearance | ||||
| * @return Array | * @return Array | ||||
| * @param $type Object[optional] | * @param $type Object[optional] | ||||
| */ | */ | ||||
| public function getAttachments() { | public function getAttachments() { | ||||
| // NOTE: This has been modified for Phabricator. Some mail clients do not | |||||
epriestley: Missing some text in this comment ("Some mail clients do not..."), but I'll fix that locally. | |||||
| // send attachments with "Content-Disposition" headers. | |||||
| $attachments = array(); | $attachments = array(); | ||||
| $dispositions = array("attachment","inline"); | $dispositions = array("attachment","inline"); | ||||
| $non_attachment_types = array("text/plain", "text/html"); | |||||
| $nonameIter = 0; | |||||
| foreach($this->parts as $part) { | foreach ($this->parts as $part) { | ||||
| $disposition = $this->getPartContentDisposition($part); | $disposition = $this->getPartContentDisposition($part); | ||||
| if (in_array($disposition, $dispositions)) { | $filename = 'noname'; | ||||
| if (isset($part['disposition-filename'])) { | |||||
| $filename = $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 = $part['content-name']; | |||||
| $disposition = 'attachment'; | |||||
| } elseif (!in_array($part['content-type'], $non_attachment_types, true) | |||||
| && substr($part['content-type'], 0, 10) !== 'multipart/' | |||||
| ) { | |||||
| // if we cannot get it with getMessageBody, we assume it is an attachment | |||||
| $disposition = 'attachment'; | |||||
| } | |||||
| if (in_array($disposition, $dispositions) && isset($filename) === true) { | |||||
| if ($filename == 'noname') { | |||||
| $nonameIter++; | |||||
| $filename = 'noname'.$nonameIter; | |||||
| } | |||||
| $attachments[] = new MimeMailParser_attachment( | $attachments[] = new MimeMailParser_attachment( | ||||
| $part['disposition-filename'], | $filename, | ||||
| $this->getPartContentType($part), | $this->getPartContentType($part), | ||||
| $this->getAttachmentStream($part), | $this->getAttachmentStream($part), | ||||
| $disposition, | $disposition, | ||||
| $this->getPartHeaders($part) | $this->getPartHeaders($part) | ||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| return $attachments; | return $attachments; | ||||
| ▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | class MimeMailParser { | ||||
| /** | /** | ||||
| * Read the attachment Body and save temporary file resource | * Read the attachment Body and save temporary file resource | ||||
| * @return String Mime Body Part | * @return String Mime Body Part | ||||
| * @param $part Array | * @param $part Array | ||||
| */ | */ | ||||
| private function getAttachmentStream(&$part) { | private function getAttachmentStream(&$part) { | ||||
| $temp_fp = tmpfile(); | $temp_fp = tmpfile(); | ||||
| array_key_exists('content-transfer-encoding', $part['headers']) ? $encoding = $part['headers']['content-transfer-encoding'] : $encoding = ''; | array_key_exists('content-transfer-encoding', $part['headers']) ? $encoding = $part['headers']['content-transfer-encoding'] : $encoding = ''; | ||||
| if ($temp_fp) { | if ($temp_fp) { | ||||
| if ($this->stream) { | if ($this->stream) { | ||||
| $start = $part['starting-pos-body']; | $start = $part['starting-pos-body']; | ||||
| $end = $part['ending-pos-body']; | $end = $part['ending-pos-body']; | ||||
| fseek($this->stream, $start, SEEK_SET); | fseek($this->stream, $start, SEEK_SET); | ||||
| $len = $end-$start; | $len = $end-$start; | ||||
| $written = 0; | $written = 0; | ||||
| Show All 15 Lines | private function getAttachmentStream(&$part) { | ||||
| } else { | } else { | ||||
| throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'); | throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'); | ||||
| return false; | return false; | ||||
| } | } | ||||
| return $temp_fp; | return $temp_fp; | ||||
| } | } | ||||
| /** | /** | ||||
| * Decode the string depending on encoding type. | * Decode the string depending on encoding type. | ||||
| * @return String the decoded string. | * @return String the decoded string. | ||||
| * @param $encodedString The string in its original encoded state. | * @param $encodedString The string in its original encoded state. | ||||
| * @param $encodingType The encoding type from the Content-Transfer-Encoding header of the part. | * @param $encodingType The encoding type from the Content-Transfer-Encoding header of the part. | ||||
| */ | */ | ||||
| private function decode($encodedString, $encodingType) { | private function decode($encodedString, $encodingType) { | ||||
| if (strtolower($encodingType) == 'base64') { | if (strtolower($encodingType) == 'base64') { | ||||
| return base64_decode($encodedString); | return base64_decode($encodedString); | ||||
| } else if (strtolower($encodingType) == 'quoted-printable') { | } else if (strtolower($encodingType) == 'quoted-printable') { | ||||
| return quoted_printable_decode($encodedString); | return quoted_printable_decode($encodedString); | ||||
| } else { | } else { | ||||
| return $encodedString; | return $encodedString; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ?> | ?> | ||||
Missing some text in this comment ("Some mail clients do not..."), but I'll fix that locally. Thanks!