Skip to content
This repository has been archived by the owner on Nov 17, 2021. It is now read-only.

Commit

Permalink
bug #553 Fix base64 encoding with streams (apinstein)
Browse files Browse the repository at this point in the history
This PR was merged into the 5.3-dev branch.

Discussion
----------

Fix base64 encoding with streams

Fixes [gh-207].

Commits
-------

ce0aa52 Fix bug when read() does not return a buffer of length 3n which caused the base64 stream to be truncated.
36219af Adjust Swift_Mime_ContentEncoder_Base64ContentEncoder read() to non-triplet aligned number to make test fail.
  • Loading branch information
fabpot committed Mar 14, 2015
2 parents a8dd3a1 + ce0aa52 commit c6f67bf
Showing 1 changed file with 39 additions and 2 deletions.
41 changes: 39 additions & 2 deletions lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php
Expand Up @@ -30,9 +30,42 @@ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStre
}

$remainder = 0;
$base64ReadBufferRemainderBytes = NULL;

while (false !== $bytes = $os->read(8190)) {
$encoded = base64_encode($bytes);
// To reduce memory usage, the output buffer is streamed to the input buffer like so:
// Output Stream => base64encode => wrap line length => Input Stream
// HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data)
// otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream.
// We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the
// chunk of bytes read in the next iteration.
// When the OutputStream is empty, we must flush any remainder bytes.
while (true) {
$readBytes = $os->read(8192);
$atEOF = ($readBytes === false);

if ($atEOF) {
$streamTheseBytes = $base64ReadBufferRemainderBytes;
} else {
$streamTheseBytes = $base64ReadBufferRemainderBytes . $readBytes;
}
$base64ReadBufferRemainderBytes = NULL;
$bytesLength = strlen($streamTheseBytes);

if ($bytesLength === 0) { // no data left to encode
break;
}

// if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data
// and carry over remainder 1-2 bytes to the next loop iteration
if (!$atEOF) {
$excessBytes = $bytesLength % 3;
if ($excessBytes !== 0) {
$base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes);
$streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes);
}
}

$encoded = base64_encode($streamTheseBytes);
$encodedTransformed = '';
$thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset;

Expand All @@ -51,6 +84,10 @@ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStre
}

$is->write($encodedTransformed);

if ($atEOF) {
break;
}
}
}

Expand Down

0 comments on commit c6f67bf

Please sign in to comment.