7

私は最近、PHP/IMAP ベースの電子メール処理機能をいくつか実装しており、(状況によっては) メッセージ本文のデコードを除いて、ほとんどすべてがうまく機能しています。

今では、RFC 2822 (「インターネット メッセージ フォーマット」ドキュメント ガイドライン) を半分記憶し、半ダースのオープン ソース CMS の電子メール処理コードを読み、膨大な数のフォーラム投稿、ブログ投稿、 PHPでメールを扱うなど。

また、PHP、 Imapのクラスをフォークして完全に書き直しました。このクラスは電子メールを適切に処理します。自動応答 (不在、古いアドレスなど) を検出し、base64 と 8bit をデコードするための便利なメソッドがいくつかあります。メッセージなど

ただし、確実に動作しない (または、場合によってはまったく動作しない) ことの 1 つは、メッセージがContent-Transfer-Encoding: 7bit.

さまざまな電子メール クライアント/サービス7BITが、さまざまなことを意味するように解釈されているようです。実際にBase64 でエンコードされ7BITていると思われる電子メールをいくつか受け取りました。実際に引用された印刷可能なエンコードされたものをいくつか入手しました。また、何らかの方法でエンコードされていないものもあります。また、HTML であるが、HTML であると示されていないものもあり、それらは...としてリストされています。7BIT

以下は、7Bit エンコーディングで受信したメッセージ本文のいくつかの例 (抜粋) です。

1:

A random message=20

Sent from my iPhone

2:

PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwi
IHhtbG5zOm89InVybjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9m

3:

tangerine apricot pepper.=0A=C2=A0=0ALet me know if you have any availabili=
ty over the next month or so. =0A=C2=A0=0AThank you,=0ANames Withheld=0A908=
-319-5916=0A=C2=A0=0A=C2=A0=0A=C2=A0=0A=0A=0A______________________________=
__=0AFrom: Names Witheld =0ATo: Names Withheld=

これらはすべて「7Bit」エンコーディングで送信されます (まあ、少なくとも PHP/ によるとimap_*) が、プレーンテキストとして渡す前に、明らかにさらにデコードする必要があります。おそらく7ビットのエンコーディングを持つすべてのメッセージをプレーンテキストに確実に変換する方法はありますか?

4

3 に答える 3

10

もう少し時間をかけて、最初の質問に対するコメントで Max が示唆したように、ヒューリスティック検出を書き出すことにしました。

Imap.phpでより堅牢なdecode7Bit()メソッドを構築しました。これは、一般的なエンコードされた文字 ( など) の束を通過し、それらを UTF-8 に相当するものに置き換え、base64 でエンコードされているように見える場合はメッセージをデコードします。=A0

/**
 * Decodes 7-Bit text.
 *
 * PHP seems to think that most emails are 7BIT-encoded, therefore this
 * decoding method assumes that text passed through may actually be base64-
 * encoded, quoted-printable encoded, or just plain text. Instead of passing
 * the email directly through a particular decoding function, this method
 * runs through a bunch of common encoding schemes to try to decode everything
 * and simply end up with something *resembling* plain text.
 *
 * Results are not guaranteed, but it's pretty good at what it does.
 *
 * @param $text (string)
 *   7-Bit text to convert.
 *
 * @return (string)
 *   Decoded text.
 */
public function decode7Bit($text) {
  // If there are no spaces on the first line, assume that the body is
  // actually base64-encoded, and decode it.
  $lines = explode("\r\n", $text);
  $first_line_words = explode(' ', $lines[0]);
  if ($first_line_words[0] == $lines[0]) {
    $text = base64_decode($text);
  }

  // Manually convert common encoded characters into their UTF-8 equivalents.
  $characters = array(
    '=20' => ' ', // space.
    '=E2=80=99' => "'", // single quote.
    '=0A' => "\r\n", // line break.
    '=A0' => ' ', // non-breaking space.
    '=C2=A0' => ' ', // non-breaking space.
    "=\r\n" => '', // joined line.
    '=E2=80=A6' => '…', // ellipsis.
    '=E2=80=A2' => '•', // bullet.
  );

  // Loop through the encoded characters and replace any that are found.
  foreach ($characters as $key => $value) {
    $text = str_replace($key, $value, $text);
  }

  return $text;
}

これは、GitHub にあるPHP の Imap クラスのバージョン 1.0-beta2 から取得したものです。

これをより効率的にするためのアイデアがあれば教えてください。私は当初、 を介してすべてを実行しようとしましquoted_printable_decode()たが、PHP があいまいで役に立たない例外をスローすることがあったため、そのアプローチを断念しました。

于 2012-10-03T00:48:39.227 に答える
5

私はこれが古い質問であることを知っています....しかし、私は今この問題に直面しており、PHPには解決策があるようです。

この関数imap_fetchstructure()は、エンコーディングのタイプを提供します。

0   7BIT
1   8BIT
2   BINARY
3   BASE64
4   QUOTED-PRINTABLE
5   OTHER

そこから、メッセージをデコードするためにこのような関数を作成できるはずです

function _encodeMessage($msg, $type){

            if($type == 0){
                return mb_convert_encoding($msg, "UTF-8", "auto");
            } elseif($type == 1){
                return imap_8bit($msg); //imap_utf8
            } elseif($type == 2){
                return imap_base64(imap_binary($msg));
            } elseif($type == 3){
                return imap_base64($msg);
            } elseif($type == 4){
                return imap_qprint($msg);
                //return quoted_printable_decode($msg);
            } else {
                return $msg;
            }
        }

この関数を次のように呼び出すことができます

$struct = imap_fetchstructure($conn, $messageNumber, 0);
$message = imap_fetchbody($conn, $messageNumber, 1);
$message = _encodeMessage($message, $struct->encoding);
echo $message;

これが誰かに役立つことを願っています:)

于 2015-03-16T15:58:15.517 に答える