0
0
mirror of https://github.com/PHPMailer/PHPMailer.git synced 2024-09-20 10:02:14 +02:00

Deal with excessively long lines, see #314

This commit is contained in:
Synchro 2014-11-14 10:15:45 +01:00
parent de5c035380
commit aa8e499b8a
2 changed files with 101 additions and 3 deletions

View File

@ -570,6 +570,12 @@ class PHPMailer
*/
const CRLF = "\r\n";
/**
* The maximum line length allowed by RFC 2822 section 2.1.1
* @type integer
*/
const MAX_LINE_LENGTH = 998;
/**
* Constructor.
* @param boolean $exceptions Should we throw external exceptions?
@ -1001,8 +1007,9 @@ class PHPMailer
throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
}
$this->MIMEHeader = $this->createHeader();
//Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
$this->MIMEBody = $this->createBody();
$this->MIMEHeader = $this->createHeader();
// To capture the complete message when using mail(), create
// an extra header list which createHeader() doesn't fold in
@ -1823,16 +1830,30 @@ class PHPMailer
$bodyEncoding = $this->Encoding;
$bodyCharSet = $this->CharSet;
//Can we do a 7-bit downgrade?
if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
$bodyEncoding = '7bit';
$bodyCharSet = 'us-ascii';
}
//If lines are too long, change to quoted-printable transfer encoding
if (self::hasLineLongerThanMax($this->Body)) {
$this->Encoding = 'quoted-printable';
$bodyEncoding = 'quoted-printable';
$bodyCharSet = 'us-ascii'; //qp always fits into ascii
}
$altBodyEncoding = $this->Encoding;
$altBodyCharSet = $this->CharSet;
//Can we do a 7-bit downgrade?
if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
$altBodyEncoding = '7bit';
$altBodyCharSet = 'us-ascii';
}
//If lines are too long, change to quoted-printable transfer encoding
if (self::hasLineLongerThanMax($this->AltBody)) {
$altBodyEncoding = 'quoted-printable';
$altBodyCharSet = 'us-ascii';
}
switch ($this->message_type) {
case 'inline':
$body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
@ -3371,6 +3392,18 @@ class PHPMailer
return $dkimhdrs . $signed . "\r\n";
}
/**
* Detect if a string contains a line longer than the maximum line length allowed.
* @param $str
* @return boolean
* @static
*/
public static function hasLineLongerThanMax($str)
{
//+2 to include CRLF line break for a 1000 total
return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
}
/**
* Allows for public read access to 'to' property.
* @access public

View File

@ -146,12 +146,12 @@ class PHPMailerTest extends PHPUnit_Framework_TestCase
// Determine line endings for message
if ($this->Mail->ContentType == 'text/html' || strlen($this->Mail->AltBody) > 0) {
$eol = '<br/>';
$eol = "<br/>". PHPMailer::CRLF;
$bullet = '<li>';
$bullet_start = '<ul>';
$bullet_end = '</ul>';
} else {
$eol = "\n";
$eol = PHPMailer::CRLF;
$bullet = ' - ';
$bullet_start = '';
$bullet_end = '';
@ -1040,6 +1040,57 @@ EOT;
$this->assertFalse($this->Mail->send(), $this->Mail->ErrorInfo);
}
/**
* Test constructing a message that contains lines that are too long for RFC compliance.
*/
public function testLongBody()
{
$oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . PHPMailer::CRLF, 10);
$badlen = str_repeat(str_repeat('1', PHPMailer::MAX_LINE_LENGTH + 1) . PHPMailer::CRLF, 2);
$this->Mail->Body = "This message contains lines that are too long.".
PHPMailer::CRLF . PHPMailer::CRLF . $oklen . $badlen . $oklen;
$this->assertTrue(
PHPMailer::hasLineLongerThanMax($this->Mail->Body),
'Test content does not contain long lines!'
);
$this->buildBody();
$this->Mail->Encoding = '8bit';
$this->Mail->preSend();
$message = $this->Mail->getSentMIMEMessage();
$this->assertFalse(PHPMailer::hasLineLongerThanMax($message), 'Long line not corrected.');
$this->assertContains(
'Content-Transfer-Encoding: quoted-printable',
$message,
'Long line did not cause transfer encoding switch.'
);
}
/**
* Test constructing a message that does NOT contain lines that are too long for RFC compliance.
*/
public function testShortBody()
{
$oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH) . PHPMailer::CRLF, 10);
$this->Mail->Body = "This message does not contain lines that are too long.".
PHPMailer::CRLF . PHPMailer::CRLF . $oklen;
$this->assertFalse(
PHPMailer::hasLineLongerThanMax($this->Mail->Body),
'Test content contains long lines!'
);
$this->buildBody();
$this->Mail->Encoding = '8bit';
$this->Mail->preSend();
$message = $this->Mail->getSentMIMEMessage();
$this->assertFalse(PHPMailer::hasLineLongerThanMax($message), 'Long line not corrected.');
$this->assertNotContains(
'Content-Transfer-Encoding: quoted-printable',
$message,
'Short line caused transfer encoding switch.'
);
}
/**
* Test keepalive (sending multiple messages in a single connection)
*/
@ -1288,6 +1339,20 @@ EOT;
$this->assertEquals($target, PHPMailer::normalizeBreaks($mixedsrc), 'Mixed break reformatting failed');
}
/**
* Test line length detection
*/
public function testLineLength()
{
$oklen = str_repeat(str_repeat('0', PHPMailer::MAX_LINE_LENGTH)."\r\n", 10);
$badlen = str_repeat(str_repeat('1', PHPMailer::MAX_LINE_LENGTH + 1) . "\r\n", 2);
$this->assertTrue(PHPMailer::hasLineLongerThanMax($badlen), 'Long line not detected (only)');
$this->assertTrue(PHPMailer::hasLineLongerThanMax($oklen . $badlen), 'Long line not detected (first)');
$this->assertTrue(PHPMailer::hasLineLongerThanMax($badlen . $oklen), 'Long line not detected (last)');
$this->assertTrue(PHPMailer::hasLineLongerThanMax($oklen . $badlen . $oklen), 'Long line not detected (middle)');
$this->assertFalse(PHPMailer::hasLineLongerThanMax($oklen), 'Long line false positive');
}
/**
* Test setting and retrieving message ID
*/