feat: speed improvements

Signed-off-by: Sebastian Krupinski <root@LAPTOP-7DVOR6NC>
This commit is contained in:
Sebastian Krupinski
2026-02-20 23:34:30 -05:00
parent e51c65bf19
commit 7446edced3
37 changed files with 648 additions and 1086 deletions

View File

@@ -93,8 +93,10 @@ class MessagePart extends MessagePartMutableAbstract {
}
// Recursively process sub-parts
// When this part has no section ID (root multipart) children are
// numbered "1", "2", … to match IMAP section numbering.
foreach ($part->parts as $index => $subPart) {
$subPartId = $partId . '.' . ($index + 1);
$subPartId = ($partId === '') ? (string)($index + 1) : $partId . '.' . ($index + 1);
$this->parts[] = (new MessagePart())->fromImap($subPart, $subPartId);
}
}
@@ -135,42 +137,49 @@ class MessagePart extends MessagePartMutableAbstract {
}
/**
* Inject decoded body content from a parallel gricob Mime Part tree.
* Inject decoded body content from a map of IMAP section-ID → raw encoded text.
*
* Walks the gricob Mime Part tree alongside this MessagePart tree and
* sets 'content' on each leaf single-part node from its decoded body.
* Walks the MessagePart tree recursively. For each text/* leaf part whose
* partId is present in $sectionMap the raw text is decoded according to the
* part's Content-Transfer-Encoding and converted to UTF-8 before being
* stored in 'content'. Binary parts (images, PDFs, …) are skipped.
*
* @param \Gricob\IMAP\Mime\Part\Part $mimePart Corresponding gricob Mime Part node
* @param array<string,string> $sectionMap Keys: IMAP section IDs (e.g. "1", "1.2");
* Values: raw (transfer-encoded) body text
*/
public function injectBodyContent(\Gricob\IMAP\Mime\Part\Part $mimePart): void
public function injectSections(array $sectionMap): void
{
if ($mimePart instanceof \Gricob\IMAP\Mime\Part\MultiPart) {
foreach ($mimePart->parts as $index => $childMimePart) {
$childPart = $this->parts[$index] ?? null;
// MultiPart: recurse into children
if (!empty($this->parts)) {
foreach ($this->parts as $childPart) {
if ($childPart instanceof MessagePart) {
$childPart->injectBodyContent($childMimePart);
$childPart->injectSections($sectionMap);
}
}
return;
}
if ($mimePart instanceof \Gricob\IMAP\Mime\Part\SinglePart) {
// Only inject content for text/* parts; binary parts (images, PDFs, …)
// produce raw bytes that cannot be JSON-encoded as UTF-8 strings.
$type = strtolower($this->data['type'] ?? '');
if (!str_starts_with($type, 'text/')) {
return;
}
try {
$decoded = $mimePart->decodedBody();
} catch (\Throwable) {
return;
}
if ($decoded !== null && $decoded !== '') {
$charset = $mimePart->charset() ?? 'utf-8';
$this->data['content'] = MessageProperties::toUtf8($decoded, $charset);
}
// SinglePart: only inject decoded content for text/* MIME types
$type = strtolower($this->data['type'] ?? '');
if (!str_starts_with($type, 'text/')) {
return;
}
$partId = $this->data['partId'] ?? null;
if ($partId === null || !array_key_exists($partId, $sectionMap)) {
return;
}
$raw = $sectionMap[$partId];
$encoding = strtolower($this->data['encoding'] ?? '7bit');
$decoded = match ($encoding) {
'quoted-printable' => quoted_printable_decode($raw),
'base64' => base64_decode($raw, strict: false),
default => $raw, // 7bit, 8bit, binary
};
$charset = $this->data['charset'] ?? 'us-ascii';
$this->data['content'] = MessageProperties::toUtf8($decoded, $charset);
}
}