解码传入电子邮件主题的正确方法(utf 8)

Posted

技术标签:

【中文标题】解码传入电子邮件主题的正确方法(utf 8)【英文标题】:Proper way to decode incoming email subject (utf 8) 【发布时间】:2012-01-27 10:43:36 【问题描述】:

我正在尝试将收到的邮件通过管道传输到 php 脚本,以便将它们存储在数据库和其他东西中。我正在使用 MIME E-mail message parser (registration required) 类,尽管我认为这并不重要。

我对电子邮件主题有疑问。当标题是英文时它可以正常工作,但如果主题使用非拉丁字符,我会得到类似

=?UTF-8?B?2KLYstmF2KfbjNi0?=

对于像这样的标题 するうううき

我这样解码主题:

  $subject  = str_replace('=?UTF-8?B?' , '' , $subject);
  $subject  = str_replace('?=' , '' , $subject);      
  $subject = base64_decode($subject); 

它适用于 10 到 15 个字符的短主题,但如果标题较长,我会得到原始标题的一半,末尾带有 �� 之类的内容。

如果标题更长,比如 30 个字符,我什么也得不到。我这样做对吗?

【问题讨论】:

这不是您在那里挑选的最高质量的软件。查看***.com/questions/4721410/…,他们可能都进行解码并且不需要这样的接收黑客。 【参考方案1】:

尽管这已经快一年了 - 我发现了这个并且面临着类似的问题。

我不确定你为什么会得到奇怪的字符,但也许你正试图在你的字符集不受支持的地方显示它们。

这是我编写的一些代码,它应该可以处理除字符集转换之外的所有事情,这是一个很多库处理得更好的大问题。 (例如 PHP 的 MB library)

class mail 
    /**
      * If you change one of these, please check the other for fixes as well
     *
     * @const Pattern to match RFC 2047 charset encodings in mail headers
     */
    const rfc2047header = '/=\?([^ ?]+)\?([BQbq])\?([^ ?]+)\?=/';

    const rfc2047header_spaces = '/(=\?[^ ?]+\?[BQbq]\?[^ ?]+\?=)\s+(=\?[^ ?]+\?[BQbq]\?[^ ?]+\?=)/';

    /**
     * http://www.rfc-archive.org/getrfc.php?rfc=2047
     *
     * =?<charset>?<encoding>?<data>?=
     *
     * @param string $header
     */
    public static function is_encoded_header($header) 
        // e.g. =?utf-8?q?Re=3a=20Support=3a=204D09EE9A=20=2d=20Re=3a=20Support=3a=204D078032=20=2d=20Wordpress=20Plugin?=
        // e.g. =?utf-8?q?Wordpress=20Plugin?=
        return preg_match(self::rfc2047header, $header) !== 0;
    

    public static function header_charsets($header) 
        $matches = null;
        if (!preg_match_all(self::rfc2047header, $header, $matches, PREG_PATTERN_ORDER)) 
            return array();
        
        return array_map('strtoupper', $matches[1]);
    

    public static function decode_header($header) 
        $matches = null;

        /* Repair instances where two encodings are together and separated by a space (strip the spaces) */
        $header = preg_replace(self::rfc2047header_spaces, "$1$2", $header);

        /* Now see if any encodings exist and match them */
        if (!preg_match_all(self::rfc2047header, $header, $matches, PREG_SET_ORDER)) 
            return $header;
        
        foreach ($matches as $header_match) 
            list($match, $charset, $encoding, $data) = $header_match;
            $encoding = strtoupper($encoding);
            switch ($encoding) 
                case 'B':
                    $data = base64_decode($data);
                    break;
                case 'Q':
                    $data = quoted_printable_decode(str_replace("_", " ", $data));
                    break;
                default:
                    throw new Exception("preg_match_all is busted: didn't find B or Q in encoding $header");
            
            // This part needs to handle every charset
            switch (strtoupper($charset)) 
                case "UTF-8":
                    break;
                default:
                    /* Here's where you should handle other character sets! */
                    throw new Exception("Unknown charset in header - time to write some code.");
            
            $header = str_replace($match, $data, $header);
        
        return $header;
    

通过脚本运行并使用 UTF-8 显示在浏览器中时,结果是:

无名氏

你会这样运行它:

$decoded = mail::decode_header("=?UTF-8?B?2KLYstmF2KfbjNi0?=");

【讨论】:

您可以使用$data = iconv($charset, 'UTF-8//TRANSLIT', $data);$data = mb_convert_encoding($data, 'UTF-8', $charset); 来解码异常字符。我更喜欢第二种方式。【参考方案2】:

您可以使用mb_decode_mimeheader() 函数来解码您的字符串。

【讨论】:

这是更好的答案。像魅力一样工作。【参考方案3】:

使用php原生函数

<?php
mb_decode_mimeheader($text);
?>

此函数可以处理 utf8 以及 iso-8859-1 字符串。 我已经测试过了。

【讨论】:

这也将解码非 utf8 主题。试试 if (preg_match('/\?utf-8\?/', $subject)) $subject = mb_decode_mimeheader($subject); 据我所知@Juergen 这不是真的。还有 Prashant 为什么要复制 TIMESPLiNTER 的答案?【参考方案4】:

使用php函数:

<?php
imap_utf8($text);
?>

【讨论】:

我也在尝试这个...希望它有效!【参考方案5】:

只是添加另一种方法来执行此操作(或者如果您没有安装 mbstring 扩展但有 iconv):

iconv_mime_decode($str, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8')

【讨论】:

【参考方案6】:

imap-mime-header-decode 功能在这里有帮助吗?

今天发现自己处于类似情况。

http://www.php.net/manual/en/function.imap-mime-header-decode.php

【讨论】:

以上是关于解码传入电子邮件主题的正确方法(utf 8)的主要内容,如果未能解决你的问题,请参考以下文章

如何解码收到的电子邮件主题行的UTF8字符集[重复]

解码 UTF8 电子邮件标头

在 Rust 中解码带引号的可打印电子邮件字符串(如 =?UTF-8?Q??=D1=81_=D0)

这是一个破碎的主题线?

只获取 MIME 电子邮件的“文本/纯文本”部分

保存带有特定主题的传入电子邮件的附件