diff --git a/src/PhpImap/Mailbox.php b/src/PhpImap/Mailbox.php index edb065a0..bd8f22ae 100644 --- a/src/PhpImap/Mailbox.php +++ b/src/PhpImap/Mailbox.php @@ -2027,7 +2027,7 @@ protected function possiblyGetEmailAndNameFromRecipient(object $recipient): ?arr } if ('' !== \trim($recipientMailbox) && '' !== \trim($recipientHost)) { - $recipientEmail = \strtolower($recipientMailbox.'@'.$recipientHost); + $recipientEmail = \mb_strtolower($recipientMailbox.'@'.$recipientHost, 'UTF-8'); $recipientName = (\is_string($recipientPersonal) && '' !== \trim($recipientPersonal)) ? $this->decodeMimeStr($recipientPersonal) : null; return [ @@ -2105,7 +2105,7 @@ protected function possiblyGetHostNameAndAddress(array $t): array } /** @var string */ - $out[] = \strtolower($t[0]->mailbox.'@'.(string) $out[0]); + $out[] = \mb_strtolower($t[0]->mailbox.'@'.(string) $out[0], 'UTF-8'); /** @var array{0:string|null, 1:string|null, 2:string} */ return $out; @@ -2142,7 +2142,7 @@ protected function searchMailboxFromWithOrWithoutDisablingServerEncoding(string * @return string */ static function ($sender) use ($criteria): string { - return $criteria.' FROM '.\mb_strtolower($sender); + return $criteria.' FROM '.\mb_strtolower($sender, 'UTF-8'); }, $senders ))); diff --git a/tests/unit/Fixtures/Mailbox.php b/tests/unit/Fixtures/Mailbox.php index 68c276b9..18ac0d09 100644 --- a/tests/unit/Fixtures/Mailbox.php +++ b/tests/unit/Fixtures/Mailbox.php @@ -13,6 +13,24 @@ public function decodeRFC2231ForTests(string $string): string return $this->decodeRFC2231($string); } + /** + * @return (null|string)[]|null + */ + public function possiblyGetEmailAndNameFromRecipientForTests(object $recipient): ?array + { + return $this->possiblyGetEmailAndNameFromRecipient($recipient); + } + + /** + * @param array $t + * + * @return array{0:string|null, 1:string|null, 2:string} + */ + public function possiblyGetHostNameAndAddressForTests(array $t): array + { + return $this->possiblyGetHostNameAndAddress($t); + } + public function getImapPassword(): string { return $this->imapPassword; diff --git a/tests/unit/MailboxAddressParsingTest.php b/tests/unit/MailboxAddressParsingTest.php new file mode 100644 index 00000000..5165842c --- /dev/null +++ b/tests/unit/MailboxAddressParsingTest.php @@ -0,0 +1,103 @@ +mailbox = 'FÜR.MICH'; + $recipient->host = 'EXAMPLE.DE'; + + $mailbox = new Fixtures\Mailbox('', '', ''); + + $this->assertSame( + ['für.mich@example.de', null], + $mailbox->possiblyGetEmailAndNameFromRecipientForTests($recipient) + ); + } + + public function testPossiblyGetHostNameAndAddressUsesMultibyteSafeLowercasing(): void + { + $sender = new stdClass(); + $sender->mailbox = 'GRÜNE.POST'; + $sender->host = 'EXAMPLE.DE'; + + $mailbox = new Fixtures\Mailbox('', '', ''); + + $this->assertSame( + ['EXAMPLE.DE', null, 'grüne.post@example.de'], + $mailbox->possiblyGetHostNameAndAddressForTests([$sender]) + ); + } + + public function testSearchMailboxFromLowercasesSendersUsingUtf8RegardlessOfInternalEncoding(): void + { + $mailbox = new class('', '', '') extends Fixtures\Mailbox { + /** @var array{disableServerEncoding: bool, criteria: string[]} */ + public array $capturedSearchMailboxArguments = []; + + public function searchMailboxFromWithOrWithoutDisablingServerEncodingForTests(string $criteria, bool $disableServerEncoding, string $sender, string ...$senders): array + { + return $this->searchMailboxFromWithOrWithoutDisablingServerEncoding($criteria, $disableServerEncoding, $sender, ...$senders); + } + + /** + * @param bool $disableServerEncoding + * @param string $single_criteria + * @param string ...$criteria + * + * @return int[] + */ + protected function searchMailboxMergeResultsWithOrWithoutDisablingServerEncoding($disableServerEncoding, $single_criteria, ...$criteria) + { + \array_unshift($criteria, $single_criteria); + + $this->capturedSearchMailboxArguments = [ + 'disableServerEncoding' => $disableServerEncoding, + 'criteria' => $criteria, + ]; + + return []; + } + }; + + $previousInternalEncoding = \mb_internal_encoding(); + + try { + \mb_internal_encoding('ISO-8859-1'); + + $this->assertSame( + [], + $mailbox->searchMailboxFromWithOrWithoutDisablingServerEncodingForTests( + 'ALL', + true, + 'FÜR@EXAMPLE.DE', + 'für@example.de', + 'NOREPLY@EXAMPLE.DE' + ) + ); + } finally { + \mb_internal_encoding($previousInternalEncoding); + } + + $this->assertSame( + [ + 'disableServerEncoding' => true, + 'criteria' => [ + 'ALL FROM für@example.de', + 'ALL FROM noreply@example.de', + ], + ], + $mailbox->capturedSearchMailboxArguments + ); + } +}