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 {
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)
$this->charset = $charset;
......@@ -54,18 +54,18 @@ class Mail_Parse {
$params = array('crlf' => "\r\n",
'charset' => $this->charset,
'input' => $this->mime_message,
'include_bodies'=> $this->include_bodies,
'decode_headers'=> $this->decode_headers,
'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))
return false;
$this->splitBodyHeader();
// Handle wrapped emails when forwarded
if ($this->struct && $this->struct->parts) {
$outer = $this->struct;
......@@ -119,7 +119,7 @@ class Mail_Parse {
function splitBodyHeader() {
$match = array();
if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s",
if (preg_match("/^(.*?)\r?\n\r?\n./s",
$this->mime_message,
$match)) {
$this->header=$match[1];
......
......@@ -91,14 +91,6 @@ require_once 'PEAR.php';
*/
class Mail_mimeDecode extends PEAR
{
/**
* The raw email to decode
*
* @var string
* @access private
*/
var $_input;
/**
* The header part of the input
*
......@@ -157,13 +149,13 @@ class Mail_mimeDecode extends PEAR
* @param string The input to decode
* @access public
*/
function Mail_mimeDecode($input)
function Mail_mimeDecode(&$input)
{
list($header, $body) = $this->_splitBodyHeader($input);
$this->_input = $input;
$this->_header = $header;
$this->_body = $body;
$this->_input = &$input;
$this->_header = &$header;
$this->_body = &$body;
$this->_decode_bodies = false;
$this->_include_bodies = true;
}
......@@ -241,7 +233,7 @@ class Mail_mimeDecode extends PEAR
* @return object Results of decoding process
* @access private
*/
function _decode($headers, $body, $default_ctype = 'text/plain')
function _decode(&$headers, &$body, $default_ctype = 'text/plain')
{
$return = new stdClass;
$return->headers = array();
......@@ -324,8 +316,9 @@ class Mail_mimeDecode extends PEAR
$default_ctype = (strtolower($content_type['value']) === 'multipart/digest') ? 'message/rfc822' : 'text/plain';
$parts = $this->_boundarySplit($body, $content_type['other']['boundary']);
for ($i = 0; $i < count($parts); $i++) {
list($part_header, $part_body) = $this->_splitBodyHeader($parts[$i]);
while (count($parts)) {
$part = array_shift($parts);
list($part_header, $part_body) = $this->_splitBodyHeader($part);
$part = $this->_decode($part_header, $part_body, $default_ctype);
if($part === false)
$part = $this->raiseError($this->_error);
......@@ -409,10 +402,18 @@ class Mail_mimeDecode extends PEAR
* @return array Contains header and body section
* @access private
*/
function _splitBodyHeader($input)
function _splitBodyHeader(&$input)
{
if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $input, $match)) {
return array($match[1], $match[2]);
if ($input instanceof StringView)
$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';
return false;
......@@ -524,6 +525,12 @@ class Mail_mimeDecode extends PEAR
$boundary = $bs_possible;
}
if ($input instanceof StringView) {
$parts = $input->split('--' . $boundary);
array_shift($parts);
return $parts;
}
$tmp = explode('--' . $boundary, $input);
for ($i = 1; $i < count($tmp) - 1; $i++) {
......@@ -871,3 +878,51 @@ class Mail_mimeDecode extends PEAR
}
} // 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.
Finish editing this message first!
Please register or to comment