Skip to content

Commit

Permalink
Relay also iconv during decoding (#238)
Browse files Browse the repository at this point in the history
Close #237
  • Loading branch information
Slamdunk authored Oct 11, 2017
1 parent 8473132 commit a2f8185
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 16 deletions.
45 changes: 38 additions & 7 deletions src/Message/Transcoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -247,19 +247,50 @@ public static function decode(string $text, string $fromCharset): string
$fromCharset = self::$charsetAliases[$lowercaseFromCharset];
}

\set_error_handler(function ($nr, $message) use ($originalFromCharset, $fromCharset) {
$iconvDecodedText = self::iconvDecode($text, $originalFromCharset, $fromCharset);
if (false !== $iconvDecodedText) {
return $iconvDecodedText;
}

\error_clear_last();
$decodedText = @\mb_convert_encoding($text, 'UTF-8', $fromCharset);
if (null !== ($lastError = \error_get_last())) {
throw new UnsupportedCharsetException(\sprintf(
'Unsupported charset "%s"%s: %s',
$originalFromCharset,
($fromCharset !== $originalFromCharset) ? \sprintf(' (alias found: "%s")', $fromCharset) : '',
$message
), $nr);
});
$lastError['message']
), $lastError['type']);
}

return $decodedText;
}

/**
* Decode text to UTF-8 with iconv.
*
* @param string $text Text to decode
* @param string $originalFromCharset Original charset
* @param string $fromCharset Aliased charset
*
* @return bool|string
*/
private static function iconvDecode($text, $originalFromCharset, $fromCharset)
{
static $iconvLoaded;
if (null === $iconvLoaded) {
$iconvLoaded = \function_exists('iconv');
}

$decodedText = \mb_convert_encoding($text, 'UTF-8', $fromCharset);
if (false === $iconvLoaded) {
return false;
}

\restore_error_handler();
$iconvDecodedText = @\iconv($fromCharset, 'UTF-8', $text);
if (false === $iconvDecodedText) {
$iconvDecodedText = @\iconv($originalFromCharset, 'UTF-8', $text);
}

return $decodedText;
return $iconvDecodedText;
}
}
54 changes: 45 additions & 9 deletions tests/MessageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
*/
final class MessageTest extends AbstractTest
{
private static $encodings = [
Mime\Mime::ENCODING_7BIT,
Mime\Mime::ENCODING_8BIT,
Mime\Mime::ENCODING_QUOTEDPRINTABLE,
Mime\Mime::ENCODING_BASE64,
];

private static $charsets = [
'ASCII' => '! "#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~',
'GB18030' => " 、。〃々〆〇〈〉《》「」『』【】〒〓〔〕〖〗〝〞〡〢〣〤〥〦〧〨〩〾一\u{200b}\u{200b}丂踰\u{200b}\u{200b}\u{200b}",
Expand All @@ -40,6 +47,11 @@ final class MessageTest extends AbstractTest
'Windows-1252' => 'ƒŠŒŽšœžŸªºÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ',
];

private static $iconvOnlyCharsets = [
'macintosh' => '†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈«»…ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ',
'Windows-1250' => 'ŚŤŹśťźˇ˘ŁĄŞŻ˛łąşĽ˝ľż',
];

protected function setUp()
{
$this->mailbox = $this->createMailbox();
Expand Down Expand Up @@ -100,16 +112,8 @@ public function provideCharsets(): array

// This first data set mimics "us-ascii" imap server default settings
$provider[] = [null, self::$charsets['ASCII'], null];

$encodings = [
Mime\Mime::ENCODING_7BIT,
Mime\Mime::ENCODING_8BIT,
Mime\Mime::ENCODING_QUOTEDPRINTABLE,
Mime\Mime::ENCODING_BASE64,
];

foreach (self::$charsets as $charset => $charList) {
foreach ($encodings as $encoding) {
foreach (self::$encodings as $encoding) {
$provider[] = [$charset, $charList, $encoding];
}
}
Expand Down Expand Up @@ -177,6 +181,38 @@ public function testSpecialCharsetOnHeaders()
$this->assertSame('김 현진', $from->getName());
}

/**
* @dataProvider provideIconvCharsets
*/
public function testIconvFallback(string $charset, string $charList, string $encoding)
{
$subject = \sprintf('[%s:%s]', $charset, $encoding);
$this->createTestMessage(
$this->mailbox,
$subject,
\iconv('UTF-8', $charset, $charList),
$encoding,
$charset
);

$message = $this->mailbox->getMessage(1);

$this->assertSame($subject, $message->getSubject());
$this->assertSame($charList, \rtrim($message->getBodyText()));
}

public function provideIconvCharsets(): array
{
$provider = [];
foreach (self::$iconvOnlyCharsets as $charset => $charList) {
foreach (self::$encodings as $encoding) {
$provider[] = [$charset, $charList, $encoding];
}
}

return $provider;
}

public function testEmailAddress()
{
$this->mailbox->addMessage($this->getFixture('email_address'));
Expand Down

0 comments on commit a2f8185

Please sign in to comment.