【问题标题】:Convert inline specified UTF-8 mail subject转换内联指定的 UTF-8 邮件主题
【发布时间】:2012-03-10 04:35:36
【问题描述】:

想要将以下原始邮件主题转换为普通的 UTF-8 文本:

=?utf-8?Q?Schuker_hat_sich_vom_=C3=9Cbungsabend_(01.01.2012)_abgem?= =?utf-8?Q?eldet?=

真正的文字是:

Schuker hat sich vom Übungsabend (01.01.2012) abgemeldet

我的第一个转换方法:

$mime = '=?utf-8?Q?Schuker_hat_sich_vom_=C3=9Cbungsabend_(01.01.2012)_abgem?=  =?utf-8?Q?eldet?=';
mb_internal_encoding("UTF-8");
echo mb_decode_mimeheader($mime);

这给了我以下结果:

Schuker_hat_sich_vom_Übungsabend_(01.01.2012)_abgemeldet

(这里的问题:我做错了什么?为什么会出现这些下划线?)

我的第二种转换方法:

$mime = '=?utf-8?Q?Schuker_hat_sich_vom_=C3=9Cbungsabend_(01.01.2012)_abgem?=  =?utf-8?Q?eldet?=';
echo imap_utf8($mime);

这给了我以下(正确的)结果:

Schuker hat sich vom Übungsabend (01.01.2012) abgemeldet

为什么会这样?我应该依靠哪种方法?

我问的原因是我之前问过另一个mail subject decoding related questionmb_decode_mimeheader 是解决方案,而这里imap_utf8 是要走的路。我如何确保解码这两个示例的所有内容都是正确的:

=?utf-8?Q?Schuker_hat_sich_vom_=C3=9Cbungsabend_(01.01.2012)_abgem?= =?utf-8?Q?eldet?

=?UTF-8?B?UmU6ICMyLUZpbmFsIEFjY2VwdGFuY2UgdGVzdCB3aXRoIG5ldyB0ZXh0IHdpdGggU2xvdg==?= =?UTF-8?B?YWsgaW50ZXJwdW5jdGlvbnMgIivEvsWhxI3FpcW+w73DocOtw6khxYgi?=

应该给我预期的结果:

Schuker hat sich vom Übungsabend (01.01.2012) abgemeldet

Re:#2-最终验收测试,新文本带有斯洛伐克语解释“+ľščťžýáíé!ň”

【问题讨论】:

  • 您确定真实文本中包含空格吗?看起来它是用下划线编码的,或者编码它的应用程序有问题。不需要对空格进行编码,即使它被编码,也应该是=20而不是下划线。
  • 是的,真正的文本包含空格。请参阅修改后的问题。谢谢!
  • 这就是 RFC 2048 修改quoted-printable 以用于 7 位标头的方式。 =?encoding?x?...?= 包装器也在该规范中定义。 - 如果imap_utf8 给你正确的结果,我会毫不犹豫地使用它(但是,我会犹豫首先使用PHP,所以我可能不是一个合法的来源:-) mb_decode_mimeheaders如果您将"Subject: " 放在测试字符串前面,是否可以正常工作?
  • 不,添加 Subject 没有帮助。仅使用 imap_utf8 无济于事,因为它无法转换第二个主题行 Re: #2...
  • 我假设imap_utf8()在开头添加了一个BOM(字节顺序标记),所以字符串不相等(不可见字符)

标签: php email encoding utf-8


【解决方案1】:

基于hbit 响应,我改进了imapUtf8() 函数以使用字符集信息将主题文本转换为UTF-8。结果是这样的:

function imapUtf8($str){
    $convStr = '';
    $subLines = preg_split('/[\r\n]+/', $str);
    for ($i=0; $i < count($subLines); $i++) {
        $convLine = '';
        $linePartArr = imap_mime_header_decode($subLines[$i]);
        for ($j=0; $j < count($linePartArr); $j++) {
            if ($linePartArr[$j]->charset === 'default') {
                if ($linePartArr[$j]->text != " ") {
                    $convLine .= ($linePartArr[$j]->text);
                }
            } else {
                $convLine .= iconv($linePartArr[$j]->charset, 'UTF-8', $linePartArr[$j]->text);
            }
        }
        $convStr .= $convLine;
    }

    return $convStr;
}

【讨论】:

    【解决方案2】:

    此函数适用于两个示例:

    function imapUtf8($str){
        $convStr = '';
        $subLines = preg_split('/[\r\n]+/',$str); // split multi-line subjects
        for($i=0; $i < count($subLines); $i++){ // go through lines
            $convLine = '';
            $linePartArr = imap_mime_header_decode(trim($subLines[$i])); // split and decode by charset
            for($j=0; $j < count($linePartArr); $j++){
                $convLine .= ($linePartArr[$j]->text); // append sub-parts of line together
            }
            $convStr .= $convLine; // append to whole subject
        }
        return $convStr; // return converted subject
    } 
    

    测试:

    $sub1 = '=?utf-8?Q?Schuker_hat_sich_vom_=C3=9Cbungsabend_(01.01.2012)_abgem?=  =?utf-8?Q?eldet?=';
    $sub2 = '=?UTF-8?B?UmU6ICMyLUZpbmFsIEFjY2VwdGFuY2UgdGVzdCB3aXRoIG5ldyB0ZXh0IHdpdGggU2xvdg==?= =?UTF-8?B?YWsgaW50ZXJwdW5jdGlvbnMgIivEvsWhxI3FpcW+w73DocOtw6khxYgi?=';
    echo imapUtf8($sub1);
    echo imapUtf8($sub2);
    

    结果:

    Schuker hat sich vom Übungsabend (01.01.2012) abgemeldet

    Re:#2-最终验收测试,新文本带有斯洛伐克语解释“+ľščťžýáíé!ň”

    【讨论】:

    • 您还应该在附加每个子部分之前检查 $linePartArr[$j]->字符集(必要时将字符串转换为 UTF-8)。
    • preg_split() 应该使用 /u 修饰符
    【解决方案3】:

    它也在mb_decode_mimeheader 手册的 cmets 中,我实际上认为这是一个错误。数据库中没有,所以我将它作为一个新的归档。

    但是,AFAIK imap_mime_header_decode 将毫无问题地处理您的两种编码,因此您的代码将继续运行。

    【讨论】:

    • 感谢您为我指出正确的方向 - imap_mime_header_decode 原来解决了这个问题(见我的回答)。
    【解决方案4】:

    关于 Subject 标头字段中的神秘下划线:

    RFC2047 4.2(2) 明确声明:

    8 位十六进制值 20(例如,ISO-8859-1 SPACE)可以是 表示为“_”(下划线,ASCII 95。)。 (这个角色可能 不通过一些互联网邮件网关,但它的使用 将大大提高邮件中“Q”编码数据的可读性 不支持此编码的读者。)请注意,“_” 始终表示十六进制 20,即使 SPACE 字符 在使用的字符集中占据不同的代码位置。

    主题行的编码规则记录在非常 RFC2047 中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-25
      • 2015-10-01
      • 2013-06-08
      • 2011-11-26
      • 1970-01-01
      • 2015-12-06
      • 1970-01-01
      • 2013-02-25
      相关资源
      最近更新 更多