Skip to content
Snippets Groups Projects
Commit b17ddd6c authored by Peter Rotich's avatar Peter Rotich
Browse files

Merge pull request #861 from greezybacon/issue/mailparse-large-messages


Make mail parsing more memory efficient

Reviewed-By: default avatarPeter Rotich <peter@osticket.com>
parents 09279cdd 87277dd6
No related branches found
No related tags found
No related merge requests found
...@@ -32,9 +32,9 @@ class Mail_Parse { ...@@ -32,9 +32,9 @@ class Mail_Parse {
var $tnef = false; // TNEF encoded mail var $tnef = false; // TNEF encoded mail
function Mail_parse($mimeMessage, $charset=null){ function Mail_parse(&$mimeMessage, $charset=null){
$this->mime_message = $mimeMessage; $this->mime_message = &$mimeMessage;
if($charset) if($charset)
$this->charset = $charset; $this->charset = $charset;
...@@ -54,18 +54,18 @@ class Mail_Parse { ...@@ -54,18 +54,18 @@ class Mail_Parse {
$params = array('crlf' => "\r\n", $params = array('crlf' => "\r\n",
'charset' => $this->charset, 'charset' => $this->charset,
'input' => $this->mime_message,
'include_bodies'=> $this->include_bodies, 'include_bodies'=> $this->include_bodies,
'decode_headers'=> $this->decode_headers, 'decode_headers'=> $this->decode_headers,
'decode_bodies' => $this->decode_bodies); 'decode_bodies' => $this->decode_bodies);
$this->struct=Mail_mimeDecode::decode($params); $this->splitBodyHeader();
$decoder = new Mail_mimeDecode($this->mime_message);
$this->struct = $decoder->decode($params);
if (PEAR::isError($this->struct)) if (PEAR::isError($this->struct))
return false; return false;
$this->splitBodyHeader();
// Handle wrapped emails when forwarded // Handle wrapped emails when forwarded
if ($this->struct && $this->struct->parts) { if ($this->struct && $this->struct->parts) {
$outer = $this->struct; $outer = $this->struct;
...@@ -119,7 +119,7 @@ class Mail_Parse { ...@@ -119,7 +119,7 @@ class Mail_Parse {
function splitBodyHeader() { function splitBodyHeader() {
$match = array(); $match = array();
if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", if (preg_match("/^(.*?)\r?\n\r?\n./s",
$this->mime_message, $this->mime_message,
$match)) { $match)) {
$this->header=$match[1]; $this->header=$match[1];
......
...@@ -91,14 +91,6 @@ require_once 'PEAR.php'; ...@@ -91,14 +91,6 @@ require_once 'PEAR.php';
*/ */
class Mail_mimeDecode extends PEAR class Mail_mimeDecode extends PEAR
{ {
/**
* The raw email to decode
*
* @var string
* @access private
*/
var $_input;
/** /**
* The header part of the input * The header part of the input
* *
...@@ -157,13 +149,13 @@ class Mail_mimeDecode extends PEAR ...@@ -157,13 +149,13 @@ class Mail_mimeDecode extends PEAR
* @param string The input to decode * @param string The input to decode
* @access public * @access public
*/ */
function Mail_mimeDecode($input) function Mail_mimeDecode(&$input)
{ {
list($header, $body) = $this->_splitBodyHeader($input); list($header, $body) = $this->_splitBodyHeader($input);
$this->_input = $input; $this->_input = &$input;
$this->_header = $header; $this->_header = &$header;
$this->_body = $body; $this->_body = &$body;
$this->_decode_bodies = false; $this->_decode_bodies = false;
$this->_include_bodies = true; $this->_include_bodies = true;
} }
...@@ -241,7 +233,7 @@ class Mail_mimeDecode extends PEAR ...@@ -241,7 +233,7 @@ class Mail_mimeDecode extends PEAR
* @return object Results of decoding process * @return object Results of decoding process
* @access private * @access private
*/ */
function _decode($headers, $body, $default_ctype = 'text/plain') function _decode(&$headers, &$body, $default_ctype = 'text/plain')
{ {
$return = new stdClass; $return = new stdClass;
$return->headers = array(); $return->headers = array();
...@@ -324,8 +316,9 @@ class Mail_mimeDecode extends PEAR ...@@ -324,8 +316,9 @@ class Mail_mimeDecode extends PEAR
$default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain'; $default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';
$parts = $this->_boundarySplit($body, $content_type['other']['boundary']); $parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
for ($i = 0; $i < count($parts); $i++) { while (count($parts)) {
list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]); $part = array_shift($parts);
list($part_header, $part_body) = $this->_splitBodyHeader($part);
$part = $this->_decode($part_header, $part_body, $default_ctype); $part = $this->_decode($part_header, $part_body, $default_ctype);
if($part === false) if($part === false)
$part = $this->raiseError($this->_error); $part = $this->raiseError($this->_error);
...@@ -409,10 +402,18 @@ class Mail_mimeDecode extends PEAR ...@@ -409,10 +402,18 @@ class Mail_mimeDecode extends PEAR
* @return array Contains header and body section * @return array Contains header and body section
* @access private * @access private
*/ */
function _splitBodyHeader($input) function _splitBodyHeader(&$input)
{ {
if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) { if ($input instanceof StringView)
return array($match[1], $match[2]); $check = $input->substr(0, 64<<10);
else
$check = &$input;
if (preg_match("/^.*?(\r?\n\r?\n)(.)/s", $check, $match, PREG_OFFSET_CAPTURE)) {
$headers = ($input instanceof StringView)
? (string) $input->substr(0, $match[1][1]) : substr($input, 0, $match[1][1]);
$body = ($input instanceof StringView)
? $input->substr($match[2][1]) : new StringView($input, $match[2][1]);
return array($headers, $body);
} }
$this->_error = 'Could not split header and body'; $this->_error = 'Could not split header and body';
return false; return false;
...@@ -524,6 +525,12 @@ class Mail_mimeDecode extends PEAR ...@@ -524,6 +525,12 @@ class Mail_mimeDecode extends PEAR
$boundary = $bs_possible; $boundary = $bs_possible;
} }
if ($input instanceof StringView) {
$parts = $input->split('--' . $boundary);
array_shift($parts);
return $parts;
}
$tmp = explode('--' . $boundary, $input); $tmp = explode('--' . $boundary, $input);
for ($i = 1; $i < count($tmp) - 1; $i++) { for ($i = 1; $i < count($tmp) - 1; $i++) {
...@@ -871,3 +878,51 @@ class Mail_mimeDecode extends PEAR ...@@ -871,3 +878,51 @@ class Mail_mimeDecode extends PEAR
} }
} // End of class } // End of class
class StringView {
var $string;
var $start;
var $end;
function __construct(&$string, $start=0, $end=false) {
$this->string = &$string;
$this->start = $start;
$this->end = $end;
}
function __toString() {
return $this->end
? substr($this->string, $this->start, $this->end - $this->start)
: substr($this->string, $this->start);
}
function substr($start, $end=false) {
return new StringView($this->string, $this->start + $start,
$end ? min($this->start + $end, $this->end ?: PHP_INT_MAX) : $this->end);
}
function split($token) {
$ltoken = strlen($token);
$windows = array();
$offset = $this->start;
for ($i = 0;; $i++) {
$windows[$i] = array('start' => $offset);
$offset = strpos($this->string, $token, $offset);
if (!$offset || ($this->end && $offset >= $this->end))
break;
// Enforce local window
$windows[$i]['stop'] = min($this->end ?: $offset, $offset);
$offset += $ltoken;
if ($this->end && $offset > $this->end)
break;
}
$parts = array();
foreach ($windows as $w) {
$parts[] = new static($this->string, $w['start'], @$w['stop'] ?: false);
}
return $parts;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment