Net_SMTP memory issue & quick fix

From: 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

« previous php.pear.dev (#14059) next »