Net_SMTP memory issue & quick fix
| From: | Brice Joly | Date: | Mon, 03 Mar 2003 16:46:16 +0000 |
| Subject: | Net_SMTP memory issue & quick fix | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-14059@lists.php.net to get a copy of this message | ||
I'm using Mail_mime to send an attachment via Mail::factory('smtp'), and I
have some memory issues with Net_SMTP.
The problem being that the file I'm sending is a server-generated .pdf (more
than 500Kb) and when Net_SMTP checks CRLF in the mail body, it also checks
INSIDE the attachments. Since that means 3 preg_replace() in a row on a
500Kb file, server memory is spoiled and I come up with the 8MB memory size
error... presumably during the very first preg_replace().
Since I thought there was no need to check CRLF into the attachements (at
least in my case, I'm no mime guru so that might not be true for any file
type), I decided to change the data() function responsible for those
preg_replace().
Apparently the boundary isn't accessed in the class, and there's no way to
know if a mime part is an attachment either, so I had to grab those from the
$data variable, which is a bit tricky and wouldn't work in some rare cases
(if in the body there's 'boundary="' or 'Content-Disposition:
attachment').
Besides it assumes that the mime part with the attachment (built somewhere
else) has correct CRLF since it's not checked at all.
Of course the clean way would be to pass the boundary and attachment part
number into a $params array to avoid the lame parsing, but that would mean
changing the function structure and function call in Mail class so...
Anyway he's the 'new' function for those interested
=================================
class Net_SMTP {
...
function data($data)
{
/*
* RFC 1870, section 3, subsection 3 states "a value of zero
indicates
* that no fixed maximum message size is in force". Furthermore, it
* says that if "the parameter is omitted no information is conveyed
* about the server's fixed maximum message size".
*/
if (isset($this->_esmtp['SIZE']) && ($this->_esmtp['SIZE']
> 0)) {
if (strlen($data) >= $this->_esmtp['SIZE']) {
$this->disconnect();
return new PEAR_Error('Message size excedes the server
limit');
}
}
/*
* Change Unix (\n) and Mac (\r) linefeeds into Internet-standard
CRLF
* (\r\n) linefeeds.
* Because a single leading period (.) signifies an end to the data,
* legitimate leading periods need to be "doubled" (e.g. '..').
*/
$pattern = array("/([^\r]{1})\n/", "/\n\n/", "/\n\./");
$replacement = array("\\1\r\n", "\n\r\n", "\n..");
/*
* Jump over attachments to avoid useless server processing and
* memory size errors if files are quite heavy
*/
$boundary_position = strpos($data, 'boundary="');
$boundary = '--=_' . substr($data, ($boundary_position +
12), 32);
$mime_parts = explode($boundary, $data);
$data = '';
foreach ($mime_parts as $key => $part) {
if (!strstr($part, 'Content-Disposition: attachment')) {
$part = preg_replace($pattern, $replacement, $part);
}
$data .= $part;
if ($key < (count($mime_parts) - 1)) {
$data .= $boundary;
}
}
if (PEAR::isError($error = $this->_put('DATA'))) {
return $error;
}
if (PEAR::isError($error = $this->_parseResponse(354))) {
return $error;
}
if (PEAR::isError($this->_send($data . "\r\n.\r\n"))) {
return new PEAR_Error('write to socket failed');
}
if (PEAR::isError($error = $this->_parseResponse(250))) {
return $error;
}
return true;
}
...
}
====
Maybe the class author or anyone who worked on it or knows a lot about SMTP
might want to have a look and tell us more about this topic
Regards,
Brice