-
-
Save redolent/9146584 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Model of an Attachment | |
*/ | |
class MimeMailParser_attachment { | |
/** | |
* @var $filename Filename | |
*/ | |
public $filename; | |
/** | |
* @var $content_type Mime Type | |
*/ | |
public $content_type; | |
/** | |
* @var $content File Content | |
*/ | |
private $content; | |
/** | |
* @var $extension Filename extension | |
*/ | |
private $extension; | |
/** | |
* @var $content_disposition Content-Disposition (attachment or inline) | |
*/ | |
public $content_disposition; | |
/** | |
* @var $headers An Array of the attachment headers | |
*/ | |
public $headers; | |
private $stream; | |
public function __construct($filename, $content_type, $stream, $content_disposition = 'attachment', $headers = array()) { | |
$this->filename = $filename; | |
$this->content_type = $content_type; | |
$this->stream = $stream; | |
$this->content = null; | |
$this->content_disposition = $content_disposition; | |
$this->headers = $headers; | |
} | |
/** | |
* retrieve the attachment filename | |
* @return String | |
*/ | |
public function getFilename() { | |
return $this->filename; | |
} | |
/** | |
* Retrieve the Attachment Content-Type | |
* @return String | |
*/ | |
public function getContentType() { | |
return $this->content_type; | |
} | |
/** | |
* Retrieve the Attachment Content-Disposition | |
* @return String | |
*/ | |
public function getContentDisposition() { | |
return $this->content_disposition; | |
} | |
/** | |
* Retrieve the Attachment Headers | |
* @return String | |
*/ | |
public function getHeaders() { | |
return $this->headers; | |
} | |
/** | |
* Retrieve the file extension | |
* @return String | |
*/ | |
public function getFileExtension() { | |
if (!$this->extension) { | |
$ext = substr(strrchr($this->filename, '.'), 1); | |
if ($ext == 'gz') { | |
// special case, tar.gz | |
// todo: other special cases? | |
$ext = preg_match("/\.tar\.gz$/i", $ext) ? 'tar.gz' : 'gz'; | |
} | |
$this->extension = $ext; | |
} | |
return $this->extension; | |
} | |
/** | |
* Read the contents a few bytes at a time until completed | |
* Once read to completion, it always returns false | |
* @return String | |
* @param $bytes Int[optional] | |
*/ | |
public function read($bytes = 2082) { | |
return feof($this->stream) ? false : fread($this->stream, $bytes); | |
} | |
/** | |
* Retrieve the file content in one go | |
* Once you retreive the content you cannot use MimeMailParser_attachment::read() | |
* @return String | |
*/ | |
public function getContent() { | |
if ($this->content === null) { | |
fseek($this->stream, 0); | |
while(($buf = $this->read()) !== false) { | |
$this->content .= $buf; | |
} | |
} | |
return $this->content; | |
} | |
/** | |
* For ease of use and compatibiliy, returns the file in the same format as an | |
* uploaded file. | |
* | |
* Once you retreive the content you cannot use MimeMailParser_attachment::read() | |
*/ | |
public function getFileAsUploaded() { | |
$content = $this->getContent(); | |
$temp_file = tmpfile(); | |
fwrite( $temp_file, $content ); | |
$meta = stream_get_meta_data( $temp_file ); | |
$path = $meta['uri']; | |
return array( | |
'name' => $this->getFilename(), | |
'type' => $this->getContentType(), | |
'size' => filesize( $path ), | |
'handle' => $temp_file, // PHP will delete the file if this is not kept | |
'tmp_name' => $path, | |
); | |
} | |
/** | |
* Allow the properties | |
* MimeMailParser_attachment::$name, | |
* MimeMailParser_attachment::$extension | |
* to be retrieved as public properties | |
* @param $name Object | |
*/ | |
public function __get($name) { | |
if ($name == 'content') { | |
return $this->getContent(); | |
} else if ($name == 'extension') { | |
return $this->getFileExtension(); | |
} | |
return null; | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This file has been modified by appdetex. See commit log. | |
* | |
* - decode() function has been modified by Mark on 10/22/2015 | |
* | |
*/ | |
require_once(__DIR__ . "/../../util/util.class.php" ); | |
require_once('attachment.class.php'); | |
/** | |
* Fast Mime Mail parser Class using PHP's MailParse Extension | |
* @author [email protected] | |
* @url http://www.fijiwebdesign.com/ | |
* @license http://creativecommons.org/licenses/by-sa/3.0/us/ | |
* @version $Id$ | |
*/ | |
class MimeMailParser { | |
/** | |
* PHP MimeParser Resource ID | |
*/ | |
public $resource; | |
/** | |
* A file pointer to email | |
*/ | |
public $stream; | |
/** | |
* A text of an email | |
*/ | |
public $data; | |
/** | |
* Stream Resources for Attachments | |
*/ | |
public $attachment_streams; | |
/** | |
* Inialize some stuff | |
* @return | |
*/ | |
public function __construct() { | |
$this->attachment_streams = array(); | |
} | |
/** | |
* Free the held resouces | |
* @return void | |
*/ | |
public function __destruct() { | |
// clear the email file resource | |
if (is_resource($this->stream)) { | |
fclose($this->stream); | |
} | |
// clear the MailParse resource | |
if (is_resource($this->resource)) { | |
mailparse_msg_free($this->resource); | |
} | |
// remove attachment resources | |
foreach($this->attachment_streams as $stream) { | |
fclose($stream); | |
} | |
} | |
/** | |
* Set the file path we use to get the email text | |
* @return Object MimeMailParser Instance | |
* @param $mail_path Object | |
*/ | |
public function setPath($path) { | |
// should parse message incrementally from file | |
$this->resource = mailparse_msg_parse_file($path); | |
$this->stream = fopen($path, 'r'); | |
$this->parse(); | |
return $this; | |
} | |
/** | |
* Set the Stream resource we use to get the email text | |
* @return Object MimeMailParser Instance | |
* @param $stream Resource | |
*/ | |
public function setStream($stream) { | |
// streams have to be cached to file first | |
if (get_resource_type($stream) == 'stream') { | |
$tmp_fp = tmpfile(); | |
if ($tmp_fp) { | |
while(!feof($stream)) { | |
fwrite($tmp_fp, fread($stream, 2028)); | |
} | |
fseek($tmp_fp, 0); | |
$this->stream =& $tmp_fp; | |
} else { | |
throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'); | |
return false; | |
} | |
fclose($stream); | |
} else { | |
$this->stream = $stream; | |
} | |
$this->resource = mailparse_msg_create(); | |
// parses the message incrementally low memory usage but slower | |
while(!feof($this->stream)) { | |
mailparse_msg_parse($this->resource, fread($this->stream, 2082)); | |
} | |
$this->parse(); | |
return $this; | |
} | |
/** | |
* Set the email text | |
* @return Object MimeMailParser Instance | |
* @param $data String | |
*/ | |
public function setText($data) { | |
$this->resource = mailparse_msg_create(); | |
// does not parse incrementally, fast memory hog might explode | |
mailparse_msg_parse($this->resource, $data); | |
$this->data = $data; | |
$this->parse(); | |
return $this; | |
} | |
/** | |
* Parse the Message into parts | |
* @return void | |
* @private | |
*/ | |
private function parse() { | |
$structure = mailparse_msg_get_structure($this->resource); | |
$this->parts = array(); | |
foreach($structure as $part_id) { | |
$part = mailparse_msg_get_part($this->resource, $part_id); | |
$this->parts[$part_id] = mailparse_msg_get_part_data($part); | |
} | |
} | |
/** | |
* Retrieve the Email Headers | |
* @return Array | |
*/ | |
public function getHeaders() { | |
if (isset($this->parts[1])) { | |
return $this->getPartHeaders($this->parts[1]); | |
} else { | |
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.'); | |
} | |
return false; | |
} | |
/** | |
* Retrieve the raw Email Headers | |
* @return string | |
*/ | |
public function getHeadersRaw() { | |
if (isset($this->parts[1])) { | |
return $this->getPartHeaderRaw($this->parts[1]); | |
} else { | |
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.'); | |
} | |
return false; | |
} | |
/** | |
* Retrieve a specific Email Header | |
* @return String | |
* @param $name String Header name | |
*/ | |
public function getHeader($name) { | |
if (isset($this->parts[1])) { | |
$headers = $this->getPartHeaders($this->parts[1]); | |
if (isset($headers[$name])) { | |
return $headers[$name]; | |
} | |
} else { | |
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email headers.'); | |
} | |
return false; | |
} | |
/** | |
* Returns the email message body in the specified format | |
* @return Mixed String Body or False if not found | |
* @param $type Object[optional] | |
*/ | |
public function getMessageBody($type = 'text') { | |
$body = false; | |
$mime_types = array( | |
'text'=> 'text/plain', | |
'html'=> 'text/html' | |
); | |
if (in_array($type, array_keys($mime_types))) { | |
foreach($this->parts as $part) { | |
if ($this->getPartContentType($part) == $mime_types[$type]) { | |
$headers = $this->getPartHeaders($part); | |
$body = $this->decode($this->getPartBody($part), array_key_exists('content-transfer-encoding', $headers) ? $headers['content-transfer-encoding'] : ''); | |
} | |
} | |
} else { | |
throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); | |
} | |
return $body; | |
} | |
/** | |
* get the headers for the message body part. | |
* @return Array | |
* @param $type Object[optional] | |
*/ | |
public function getMessageBodyHeaders($type = 'text') { | |
$headers = false; | |
$mime_types = array( | |
'text'=> 'text/plain', | |
'html'=> 'text/html' | |
); | |
if (in_array($type, array_keys($mime_types))) { | |
foreach($this->parts as $part) { | |
if ($this->getPartContentType($part) == $mime_types[$type]) { | |
$headers = $this->getPartHeaders($part); | |
} | |
} | |
} else { | |
throw new Exception('Invalid type specified for MimeMailParser::getMessageBody. "type" can either be text or html.'); | |
} | |
return $headers; | |
} | |
/** | |
* Returns the attachments contents in order of appearance | |
* @return Array | |
* @param $type Object[optional] | |
*/ | |
public function getAttachments() { | |
$attachments = array(); | |
$dispositions = array("attachment","inline"); | |
foreach($this->parts as $part) { | |
$disposition = $this->getPartContentDisposition($part); | |
if (in_array($disposition, $dispositions)) { | |
$attachments[] = new MimeMailParser_attachment( | |
$part['disposition-filename'], | |
$this->getPartContentType($part), | |
$this->getAttachmentStream($part), | |
$disposition, | |
$this->getPartHeaders($part) | |
); | |
} | |
} | |
return $attachments; | |
} | |
/** | |
* Return the Headers for a MIME part | |
* @return Array | |
* @param $part Array | |
*/ | |
private function getPartHeaders($part) { | |
if (isset($part['headers'])) { | |
return $part['headers']; | |
} | |
return false; | |
} | |
/** | |
* Return a Specific Header for a MIME part | |
* @return Array | |
* @param $part Array | |
* @param $header String Header Name | |
*/ | |
private function getPartHeader($part, $header) { | |
if (isset($part['headers'][$header])) { | |
return $part['headers'][$header]; | |
} | |
return false; | |
} | |
/** | |
* Return the ContentType of the MIME part | |
* @return String | |
* @param $part Array | |
*/ | |
private function getPartContentType($part) { | |
if (isset($part['content-type'])) { | |
return $part['content-type']; | |
} | |
return false; | |
} | |
/** | |
* Return the Content Disposition | |
* @return String | |
* @param $part Array | |
*/ | |
private function getPartContentDisposition($part) { | |
if (isset($part['content-disposition'])) { | |
return $part['content-disposition']; | |
} | |
return false; | |
} | |
/** | |
* Retrieve the raw Header of a MIME part | |
* @return String | |
* @param $part Object | |
*/ | |
private function getPartHeaderRaw(&$part) { | |
$header = ''; | |
if ($this->stream) { | |
$header = $this->getPartHeaderFromFile($part); | |
} else if ($this->data) { | |
$header = $this->getPartHeaderFromText($part); | |
} else { | |
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email parts.'); | |
} | |
return $header; | |
} | |
/** | |
* Retrieve the Body of a MIME part | |
* @return String | |
* @param $part Object | |
*/ | |
private function getPartBody(&$part) { | |
$body = ''; | |
if ($this->stream) { | |
$body = $this->getPartBodyFromFile($part); | |
} else if ($this->data) { | |
$body = $this->getPartBodyFromText($part); | |
} else { | |
throw new Exception('MimeMailParser::setPath() or MimeMailParser::setText() must be called before retrieving email parts.'); | |
} | |
return $body; | |
} | |
/** | |
* Retrieve the Header from a MIME part from file | |
* @return String Mime Header Part | |
* @param $part Array | |
*/ | |
private function getPartHeaderFromFile(&$part) { | |
$start = $part['starting-pos']; | |
$end = $part['starting-pos-body']; | |
fseek($this->stream, $start, SEEK_SET); | |
$header = fread($this->stream, $end-$start); | |
return $header; | |
} | |
/** | |
* Retrieve the Body from a MIME part from file | |
* @return String Mime Body Part | |
* @param $part Array | |
*/ | |
private function getPartBodyFromFile(&$part) { | |
$start = $part['starting-pos-body']; | |
$end = $part['ending-pos-body']; | |
fseek($this->stream, $start, SEEK_SET); | |
$body = fread($this->stream, $end-$start); | |
return $body; | |
} | |
/** | |
* Retrieve the Header from a MIME part from text | |
* @return String Mime Header Part | |
* @param $part Array | |
*/ | |
private function getPartHeaderFromText(&$part) { | |
$start = $part['starting-pos']; | |
$end = $part['starting-pos-body']; | |
$header = substr($this->data, $start, $end-$start); | |
return $header; | |
} | |
/** | |
* Retrieve the Body from a MIME part from text | |
* @return String Mime Body Part | |
* @param $part Array | |
*/ | |
private function getPartBodyFromText(&$part) { | |
$start = $part['starting-pos-body']; | |
$end = $part['ending-pos-body']; | |
$body = substr($this->data, $start, $end-$start); | |
return $body; | |
} | |
/** | |
* Read the attachment Body and save temporary file resource | |
* @return String Mime Body Part | |
* @param $part Array | |
*/ | |
private function getAttachmentStream(&$part) { | |
$temp_fp = tmpfile(); | |
array_key_exists('content-transfer-encoding', $part['headers']) ? $encoding = $part['headers']['content-transfer-encoding'] : $encoding = ''; | |
if ($temp_fp) { | |
if ($this->stream) { | |
$start = $part['starting-pos-body']; | |
$end = $part['ending-pos-body']; | |
fseek($this->stream, $start, SEEK_SET); | |
$len = $end-$start; | |
$written = 0; | |
$write = 2028; | |
$body = ''; | |
while($written < $len) { | |
if (($written+$write < $len )) { | |
$write = $len - $written; | |
} | |
$part = fread($this->stream, $write); | |
fwrite($temp_fp, $this->decode($part, $encoding)); | |
$written += $write; | |
} | |
} else if ($this->data) { | |
$attachment = $this->decode($this->getPartBodyFromText($part), $encoding); | |
fwrite($temp_fp, $attachment, strlen($attachment)); | |
} | |
fseek($temp_fp, 0, SEEK_SET); | |
} else { | |
throw new Exception('Could not create temporary files for attachments. Your tmp directory may be unwritable by PHP.'); | |
return false; | |
} | |
return $temp_fp; | |
} | |
/** | |
* Decode the string depending on encoding type. | |
* @return String the decoded string. | |
* @param $encodedString The string in its original encoded state. | |
* @param $encodingType The encoding type from the Content-Transfer-Encoding header of the part. | |
*/ | |
private function decode($encodedString, $encodingType) { | |
if (strtolower($encodingType) == 'base64') { | |
return AppDetex_Util::verifyEncoding( | |
base64_decode( $encodedString ) | |
); | |
} else if (strtolower($encodingType) == 'quoted-printable') { | |
return AppDetex_Util::verifyEncoding( | |
quoted_printable_decode( $encodedString ) | |
); | |
} else if (strtolower($encodingType) == '7bit') { | |
return AppDetex_Util::verifyEncoding( | |
quoted_printable_decode( $encodedString ) | |
); | |
} else { | |
if ( $encodingType ){ error_log("MimeMailParser->decode(): unknown email encoding: $encodingType"); } | |
return AppDetex_Util::verifyEncoding( | |
$encodedString | |
); | |
} | |
} | |
} | |
?> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require_once('MimeMailParser.class.php'); | |
$path = 'path/to/mail.txt'; | |
$Parser = new MimeMailParser(); | |
$Parser->setPath($path); | |
$to = $Parser->getHeader('to'); | |
$from = $Parser->getHeader('from'); | |
$subject = $Parser->getHeader('subject'); | |
$text = $Parser->getMessageBody('text'); | |
$html = $Parser->getMessageBody('html'); | |
$attachments = $Parser->getAttachments(); | |
// attachment processing | |
$save_dir = '/path/to/save/attachments/'; | |
foreach($attachments as $attachment) { | |
// get the attachment name | |
$filename = $attachment->filename; | |
// write the file to the directory you want to save it in | |
if ($fp = fopen($save_dir.$filename, 'w')) { | |
while($bytes = $attachment->read()) { | |
fwrite($fp, $bytes); | |
} | |
fclose($fp); | |
} | |
} | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment