Base64ContentEncoder.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. <?php
  2. /*
  3. * This file is part of SwiftMailer.
  4. * (c) 2004-2009 Chris Corbyn
  5. *
  6. * For the full copyright and license information, please view the LICENSE
  7. * file that was distributed with this source code.
  8. */
  9. /**
  10. * Handles Base 64 Transfer Encoding in Swift Mailer.
  11. *
  12. * @author Chris Corbyn
  13. */
  14. class Swift_Mime_ContentEncoder_Base64ContentEncoder extends Swift_Encoder_Base64Encoder implements Swift_Mime_ContentEncoder
  15. {
  16. /**
  17. * Encode stream $in to stream $out.
  18. *
  19. * @param int $firstLineOffset
  20. */
  21. public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
  22. {
  23. if (0 >= $maxLineLength || 76 < $maxLineLength) {
  24. $maxLineLength = 76;
  25. }
  26. $remainder = 0;
  27. $base64ReadBufferRemainderBytes = '';
  28. // To reduce memory usage, the output buffer is streamed to the input buffer like so:
  29. // Output Stream => base64encode => wrap line length => Input Stream
  30. // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data)
  31. // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream.
  32. // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the
  33. // chunk of bytes read in the next iteration.
  34. // When the OutputStream is empty, we must flush any remainder bytes.
  35. while (true) {
  36. $readBytes = $os->read(8192);
  37. $atEOF = (false === $readBytes);
  38. if ($atEOF) {
  39. $streamTheseBytes = $base64ReadBufferRemainderBytes;
  40. } else {
  41. $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes;
  42. }
  43. $base64ReadBufferRemainderBytes = '';
  44. $bytesLength = \strlen($streamTheseBytes);
  45. if (0 === $bytesLength) { // no data left to encode
  46. break;
  47. }
  48. // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data
  49. // and carry over remainder 1-2 bytes to the next loop iteration
  50. if (!$atEOF) {
  51. $excessBytes = $bytesLength % 3;
  52. if (0 !== $excessBytes) {
  53. $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes);
  54. $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes);
  55. }
  56. }
  57. $encoded = base64_encode($streamTheseBytes);
  58. $encodedTransformed = '';
  59. $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset;
  60. while ($thisMaxLineLength < \strlen($encoded)) {
  61. $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n";
  62. $firstLineOffset = 0;
  63. $encoded = substr($encoded, $thisMaxLineLength);
  64. $thisMaxLineLength = $maxLineLength;
  65. $remainder = 0;
  66. }
  67. if (0 < $remainingLength = \strlen($encoded)) {
  68. $remainder += $remainingLength;
  69. $encodedTransformed .= $encoded;
  70. $encoded = null;
  71. }
  72. $is->write($encodedTransformed);
  73. if ($atEOF) {
  74. break;
  75. }
  76. }
  77. }
  78. /**
  79. * Get the name of this encoding scheme.
  80. * Returns the string 'base64'.
  81. *
  82. * @return string
  83. */
  84. public function getName()
  85. {
  86. return 'base64';
  87. }
  88. }