7

カスタム php 電子メール マーケティング アプリと興味深い問題があります。メッセージの件名にアクセント付きの単語が含まれている場合、それと次の単語の間のスペースが「飲み込まれて」しまいます。例: フレーズ

Ángel Ríos escucha y sorprende

として表示されます (少なくとも gmail と Lotus Notes によって)

ÁngelRíos escucha y sorprende

メッセージ ソースの特定の行は次のように表示されます。

Subject: =?ISO-8859-1?Q?=C1ngel?= =?ISO-8859-1?Q?R=EDos?= escucha y sorprende

(セミフルヘッダー):

Delivered-To: me@gmail.com
Received: {elided}
Return-Path: <return@path>
Received: {elided}
Received: (qmail 23734 invoked by uid 48); 18 Aug 2009 13:51:14 -0000
Date: 18 Aug 2009 13:51:14 -0000
To: "Adriano" <me@gmail.com>
Subject: =?ISO-8859-1?Q?=C1ngel?= =?ISO-8859-1?Q?R=EDos?= escucha y sorprende
MIME-Version: 1.0
From: {elided}
X-Mailer: PHP
X-Lista: 1290
X-ID: 48163
Content-Type: text/html; charset="ISO-8859-1"
Content-Transfer-Encoding: quoted-printable
Message-ID: <kokrte.rpq06m@example.com>

編集:

このアプリは古いバージョンの Html Mime Mail を使用してメッセージを作成します。新しいバージョンにアップグレードしてみます。とにかく、これはサブジェクトをエンコードする関数です:

/**
 * Function to encode a header if necessary
 * according to RFC2047
 */
function _encodeHeader($input, $charset = 'ISO-8859-1')
{
    preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
    foreach ($matches[1] as $value) {
        $replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
        $input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input);
    }

    return $input;
}

そして、これはサブジェクトがエンコードされているコードです:

if (!empty($this->headers['Subject'])) {
    $subject = $this->_encodeHeader($this->headers['Subject'],
                                    $this->build_params['head_charset']);
    unset($this->headers['Subject']);
}

要約

問題は、実際、プログラムが前述のケースでスペースをエンコードしていなかったことです。インストールされているPHPのバージョンが特定の実装の詳細をサポートしていなかったため、受け入れられた回答は私の問題を解決しました。

最終的な答え

受け入れられた回答は問題を解決しましたが、何千もの電子メールと相まって、サーバーで利用可能なすべてのメモリを食い尽くしていることがわかりました. このメールフレームワークの元の開発者のウェブサイトを確認したところ、次のように機能が更新されていることがわかりました。

function _encodeHeader($input, $charset = 'ISO-8859-1') {
        preg_match_all('/(\w*[\x80-\xFF]+\w*)/', $input, $matches);
        foreach ($matches[1] as $value) {
            $replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
            $input = str_replace($value, $replacement , $input);
        }
        if (!empty($matches[1])) {
            $input = str_replace(' ', '=20', $input);
            $input = '=?' . $charset .  '?Q?' .$input . '?=';
        }
        return $input;
    }

問題をきちんと解決し、メモリ制限内にとどまりました。

4

4 に答える 4

5

間のスペースもエンコードする必要があります ( RFC 2047を参照)。

(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)     (ab)

隣接する「エンコードされた単語」の間の空白は表示されません。

[…]

(=?ISO-8859-1?Q?a_b?=)                      (a b)

スペースをエンコードされたテキストの一部に表示するには、スペースを「エンコードされた単語」の一部としてエンコードする必要があります。

(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=)    (a b)

スペースがエンコードされたテキストの 2 つの文字列の間に表示されるようにするために、スペースは「エンコードされた単語」の 1 つの一部としてエンコードされる場合があります。

したがって、これでうまくいくはずです:

Subject: =?ISO-8859-1?Q?=C1ngel=20R=EDos?= escucha y sorprende

編集    この機能を試してください:

function _encodeHeader($str, $charset='ISO-8859-1')
{
    $words = preg_split('/(\s+)/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
    $func = create_function('$match', 'return $match[0] === " " ? "_" : sprintf("=%02X", ord($match[0]));');
    $encoded = false;
    foreach ($words as $key => &$word) {
        if (!ctype_space($word)) {
            $tmp = preg_replace_callback('/[^\x21-\x3C\x3E-\x5E\x60-\x7E]/', $func, $word);
            if ($tmp !== $word) {
                if (!$encoded) {
                    $word = '=?'.$charset.'?Q?'.$tmp;
                } else {
                    $word = $tmp;
                    if ($key > 0) {
                        $words[$key-1] = preg_replace_callback('/[^\x21-\x3C\x3E-\x5E\x60-\x7E]/', $func, $words[$key-1]);
                    }
                }
                $encoded = true;
            } else {
                if ($encoded) {
                    $words[$key-2] .= '?=';
                }
                $encoded = false;
            }
        }
    }
    if ($encoded) {
        $words[$key] .= '?=';
    }
    return implode('', $words);
}
于 2009-08-18T14:52:24.237 に答える
2

追加

$input = str_replace('?', '=3F', $input);

このフラグメントでは:

if (!empty($matches[1])) {
$input = str_replace('?', '=3F', $input);
$input = str_replace(' ', '=20', $input);
$input = '=?' . $charset .  '?Q?' .$input . '?=';
}
于 2011-09-06T12:21:45.247 に答える
1

mbstringとUTFの変換を調べます。英語以外の言語の特殊文字の多くは、UTF8文字セットで処理されます。

件名文字列をUTF8に変換し、電子メールがそのように送信されるようにすると、件名が正しく表示されます。

少なくとも、メールの送信で同様の問題が発生したときは、

于 2009-08-18T14:36:47.740 に答える
0

Subject: =?ISO-8859-1?Q?=C1ngel R=EDos escucha y sorprende?=問題は ?= エンコーディングの終わりの近くで発生するため、 を送信した方がよいようです。

于 2009-08-18T14:26:47.290 に答える