Skip to content

Commit

Permalink
Refactor data reader in Protocol\Smtp to use Generator
Browse files Browse the repository at this point in the history
This isolates the logic of handling incomplete reads to own unit.
  • Loading branch information
glensc committed Feb 27, 2021
1 parent 2e17655 commit e80773f
Showing 1 changed file with 26 additions and 27 deletions.
53 changes: 26 additions & 27 deletions src/Protocol/Smtp.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,41 +317,42 @@ public function data($data)
$this->_send('DATA');
$this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2

if (($fp = fopen("php://temp", "r+")) === false) {
throw new Exception\RuntimeException('cannot fopen');
}
if (fwrite($fp, $data) === false) {
throw new Exception\RuntimeException('cannot fwrite');
}
unset($data);
rewind($fp);
$chunkReader = static function($data, $chunkSize = 4096) {
if (($fp = fopen("php://temp", "r+")) === false) {
throw new Exception\RuntimeException('cannot fopen');
}
if (fwrite($fp, $data) === false) {
throw new Exception\RuntimeException('cannot fwrite');
}
rewind($fp);

$line = null;
while (($buffer = fgets($fp, $chunkSize)) !== false) {
$line .= $buffer;

$chunkSize = 4096;
$line = '';
while (($buffer = fgets($fp, $chunkSize)) !== false) {
$line .= $buffer;
// partial read, continue loop to read again to complete the line
if (strlen($buffer) === $chunkSize - 1 && $buffer[$chunkSize - 2] !== "\n") {
continue;
}

// partial read, continue loop to read again to complete the line
if (strlen($buffer) === $chunkSize - 1 && $buffer[$chunkSize - 2] !== "\n") {
continue;
yield $line;
$line = null;
}

if ($line !== null) {
yield $line;
}

fclose($fp);
};

foreach ($chunkReader($data) as $line) {
$line = rtrim($line, "\r\n");
if (isset($line[0]) && $line[0] === '.') {
// Escape lines prefixed with a '.'
$line = '.' . $line;
}

// max line length is 998 char + \r\n = 1000
if (strlen($line) > 998) {
// Long lines are "folded" by inserting "<CR><LF><SPACE>"
// https://tools.ietf.org/html/rfc5322#section-2.2.3
$line = substr(chunk_split($line, 998, Headers::FOLDING), 0, -strlen(Headers::FOLDING));
}
$this->_send($line);
$line = '';
}
if ($line) {
// max line length is 998 char + \r\n = 1000
if (strlen($line) > 998) {
// Long lines are "folded" by inserting "<CR><LF><SPACE>"
Expand All @@ -362,8 +363,6 @@ public function data($data)
$this->_send($line);
}

fclose($fp);

$this->_send('.');
$this->_expect(250, 600); // Timeout set for 10 minutes as per RFC 2821 4.5.3.2
$this->data = true;
Expand Down

0 comments on commit e80773f

Please sign in to comment.