Path: blob/master/PHPMailer/examples/smtp_low_memory.phps
738 views
<?php /** * SMTP low memory example. */ namespace PHPMailer\PHPMailer; require '../vendor/autoload.php'; /** * This class demonstrates sending an already-built RFC822 message via SMTP * by extending PHPMailer's SMTP class. * It uses less memory that PHPMailer's usual approach because it keeps * the message as a single string rather than splitting its lines into * an array, which can consume very large amounts of memory if you have * large attachments. The downside is that it's somewhat slower. * This is mainly of academic interest, but shows how you can change how * core classes work without having to alter the library itself. */ class SMTPLowMemory extends SMTP { public function data($msg_data) { //This will use the standard timelimit if (!$this->sendCommand('DATA', 'DATA', 354)) { return false; } /* The server is ready to accept data! * According to rfc821 we should not send more than 1000 characters on a single line (including the LE) * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into * smaller lines to fit within the limit. * We will also look for lines that start with a '.' and prepend an additional '.'. * NOTE: this does not count towards line-length limit. */ // Normalize line breaks $msg_data = str_replace(["\r\n", "\r"], "\n", $msg_data); /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field * of the first line (':' separated) does not contain a space then it _should_ be a header and we will * process all lines before a blank line as headers. */ $firstline = substr($msg_data, 0, strcspn($msg_data, "\n", 0)); $field = substr($firstline, 0, strpos($firstline, ':')); $in_headers = false; if (!empty($field) && strpos($field, ' ') === false) { $in_headers = true; } $offset = 0; $len = strlen($msg_data); while ($offset < $len) { //Get position of next line break $linelen = strcspn($msg_data, "\n", $offset); //Get the next line $line = substr($msg_data, $offset, $linelen); //Remember where we have got to $offset += ($linelen + 1); $lines_out = []; if ($in_headers && $line === '') { $in_headers = false; } //We need to break this line up into several smaller lines //This is a small micro-optimisation: isset($str[$len]) is equivalent to (strlen($str) > $len) while (isset($line[self::MAX_LINE_LENGTH])) { //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on //so as to avoid breaking in the middle of a word $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); //Deliberately matches both false and 0 if (!$pos) { //No nice break found, add a hard break $pos = self::MAX_LINE_LENGTH - 1; $lines_out[] = substr($line, 0, $pos); $line = substr($line, $pos); } else { //Break at the found point $lines_out[] = substr($line, 0, $pos); //Move along by the amount we dealt with $line = substr($line, $pos + 1); } //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 if ($in_headers) { $line = "\t" . $line; } } $lines_out[] = $line; //Send the lines to the server foreach ($lines_out as $line_out) { //RFC2821 section 4.5.2 if (!empty($line_out) && $line_out[0] === '.') { $line_out = '.' . $line_out; } $this->client_send($line_out . self::LE); } } //Message data has been sent, complete the command //Increase timelimit for end of DATA command $savetimelimit = $this->Timelimit; $this->Timelimit *= 2; $result = $this->sendCommand('DATA END', '.', 250); //Restore timelimit $this->Timelimit = $savetimelimit; return $result; } } /** * We need to use a PHPMailer subclass to make it use our SMTP implementation. * @package PHPMailer\PHPMailer */ class PHPMailerLowMemory extends PHPMailer { /** * Patch in the new SMTP class. * @return SMTP */ public function getSMTPInstance() { if (!is_object($this->smtp)) { $this->smtp = new SMTPLowMemory; } return $this->smtp; } }