From c78c4ceb7ee91b84bed4c19e3635c23826d27b1f Mon Sep 17 00:00:00 2001 From: braito4 <1913498+braito4@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:06:22 +0100 Subject: [PATCH] Fix quadratic memory usage in Structure::parsePart --- src/Structure.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Structure.php b/src/Structure.php index 11f4cd66..1df613b9 100644 --- a/src/Structure.php +++ b/src/Structure.php @@ -103,11 +103,23 @@ public function findContentType(): void { * @throws InvalidMessageDateException */ private function parsePart(string $context, int $part_number = 0): array { + // Optimize split of headers/body to avoid quadratic memory usage on large messages. + // The previous line-by-line substr loop could allocate huge intermediate strings (e.g. when body contains large attachments). + $headers = ''; $body = $context; - while (($pos = strpos($body, "\r\n")) > 0) { - $body = substr($body, $pos + 2); + + $pos = strpos($context, "\r\n\r\n"); + if ($pos !== false) { + // Keep the first CRLF (line terminator of last header) in headers, like legacy behavior. + $headers = substr($context, 0, $pos + 2); + $body = substr($context, $pos + 2); + } else { + while (($pos = strpos($body, "\r\n")) > 0) { + $body = substr($body, $pos + 2); + } + $headers = substr($context, 0, strlen($body) * -1); } - $headers = substr($context, 0, strlen($body) * -1); + $body = substr($body, 0, -2); $config = $this->header->getConfig();