Правильный способ декодировать тему входящей почты (utf 8) - PullRequest
12 голосов
/ 25 декабря 2011

Я пытаюсь передать свои входящие письма в скрипт PHP, чтобы сохранить их в базе данных и другие вещи. Я использую класс MIME Парсер сообщений электронной почты (требуется регистрация) , хотя я не думаю, что это важно.

У меня проблема с темой электронной почты. Он отлично работает, когда заголовок на английском, но если в теме используются нелатинские символы, я получаю что-то вроде

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

для названия вроде 101 دو سه

Я расшифрую тему следующим образом:

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

Отлично работает с короткими предметами, например, с 10-15 символами, но с более длинным заголовком я получаю половину исходного заголовка с чем-то вроде в конце.

Если заголовок еще длиннее, например, 30 символов, я ничего не получу. Я правильно это делаю?

Ответы [ 6 ]

15 голосов
/ 29 апреля 2014

Вы можете использовать функцию mb_decode_mimeheader() для декодирования вашей строки.

14 голосов
/ 04 декабря 2012

Несмотря на то, что это почти год - я обнаружил это и столкнулся с похожей проблемой.

Я не уверен, почему вы получаете странные символы, но, возможно, вы пытаетесь отобразить ихгде-то ваша кодировка не поддерживается.

Вот код, который я написал, который должен обрабатывать все, кроме преобразования кодировки, что является большой проблемой, которую многие библиотеки обрабатывают намного лучше.(Например, библиотека PHP )

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, результат будет:

1012 *

Вы бы запустили его так:

$decoded = mail::decode_header("=?UTF-8?B?2KLYstmF2KfbjNi0?=");
7 голосов
/ 25 февраля 2016

Использовать собственную функцию php

<?php
mb_decode_mimeheader($text);
?>

Эта функция может обрабатывать как utf8, так и строку iso-8859-1. Я проверил это.

4 голосов
/ 16 декабря 2015

Используйте функцию php:

<?php
imap_utf8($text);
?>
0 голосов
/ 06 мая 2019

Просто добавьте еще один способ сделать это (или если у вас не установлено расширение mbstring, но есть iconv):

iconv_mime_decode($str, ICONV_MIME_DECODE_CONTINUE_ON_ERROR, 'UTF-8')
0 голосов
/ 21 февраля 2014

Может ли здесь помочь функция imap-mime-header-decode?

Сегодня попал в похожую ситуацию.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...