メールにおける添付ファイルのファイル名の文字化け

Re: メールにおける添付ファイルのファイル名の文字化け

- Tatsuya Shirai の投稿
返信数: 2

 もし,mbstring.languageが指定されていない場合は,mb_language()も設定しないといけないようです.

 mb_encode_mimeheader(arg1, arg2, arg3, arg4)の4つの引数のうち,必須はarg1で,これがエンコードしたい文字列です.オプションであるarg2は変換したい文字コード,arg3はBASE64などのテキスト化するエンコード形式,arg4は折り返し時の改行コード(だったと思います).
 mb_encode_mimeheader()はarg1の文字列をphp.iniで指定されたmbstring.internal_encoding (UTF-8が望ましい)の文字コードあるいはmb_internalencoding()で指定された文字コードから,php.iniのmbstring.languageで指定された言語圏(japaneseなど)において適切な文字コード(japaneseならばISO-2022-JP)あるいはmb_language()で指定された言語圏(この場合は'ja'など)において適切な文字コードに変換します.arg1の文字コードを自動班別しません(そもそもファイル名程度の短い文字列の場合は誤認識することが多い).その後,ヘッダーとしての条件(79byte程度で改行でしたか?)を満たした上でBASE64などのASCIIキャラクタに変換します.

 Moodleではファイル名などの情報はUTF-8で取り扱います.したがって,mbstring.internal_encodingはUTF-8が好ましいですが,レンタルサーバなどではこの設定が行われていない場合もあるのかも知れませんね.それに対応するために先のパッチではmb_internal_encoding('UTF-8')を追加しました.
 同様にサーバによってはmbstring.languageがjapaneseに設定されていない場合もあるでしょう.(でも,その場合はmbstring系の関数が激しくワーニングを発生しますが...) それに対応するにはmb_language()を指定するか,あるいはarg2を指定する必要があります.ここで少し考えなくてはなりません.一つはメール送信先のユーザのメールの文字コード設定を調べてその文字コードにファイル名を変換する方法.もう一つはUTF-8のままとする方法.前者はコードが複雑になり,後者はメールクライアントがBASE64デコードして得られたファイル名の情報がUTF-8でも正しくファイル名として復元できるかどうか.前者はもしmb_language()を使用するならばその言語指定の文字列を取得する必要があります.(日本語圏ならばISO-2022-JPではなく,jaを)

 もし,文字コードをUTF-8に変換してBASE64でエンコードするならばmb_mimeheader($name, 'UTF-8')とするのだが,UTF-8からUTF-8に変換するのは無駄のような気もする.base64_encode($name)で良いのかも知れない.でも,それはそれで少し不安なので,

        $cur = count($this->attachment);
        $this->attachment[$cur][0] = $path;
        $this->attachment[$cur][1] = $filename;
// (Shirai010): ここからコメントアウト
//
      $this->attachment[$cur][2] = $name;
// (Shirai010): ここから追加
        $oldcharset = mb_internal_encoding();
        mb_internal_encoding('UTF-8');
        $this->attachment[$cur][2] = mb_encode_mimeheader($name, 'UTF-8');
        mb_internal_encoding($oldcharset);
// (Shirai010): ここまで追加
        $this->attachment[$cur][3] = $encoding;
        $this->attachment[$cur][4] = $type;
        $this->attachment[$cur][5] = false; // isStringAttachment
        $this->attachment[$cur][6] = "attachment";
        $this->attachment[$cur][7] = 0;

        return true;
    }

これが無難でしょうか.まだ結論は出ません.ご意見お待ちしています.


湯川さんご指摘のinternal_encodingの設定を元に戻す処理も追加しました.
さらに私のケアレスミスを湯川さんが指摘してくれた命令の順番も訂正しました.

Tatsuya Shirai への返信

Re: メールにおける添付ファイルのファイル名の文字化け

- K Yukawa の投稿

心配事について
修正時に調べたのですが、AddAttachmentを実際に呼んでいるのはmoodlelib.phpのみです。

(1.9.5+のソースをGrepにて検索)
lib\phpmailer\class.phpmailer.php(1050,14)  [SJIS]:     function AddAttachment($path, $name = "", $encoding = "base64",
lib\phpmailer\README(78,8)  [SJIS]: $mail->AddAttachment("/var/tmp/file.tar.gz");         // add attachments
lib\phpmailer\README(79,8)  [SJIS]: $mail->AddAttachment("/tmp/image.jpg", "new.jpg");    // optional name
lib\moodlelib.php(4263,20)  [UTF-8]:             $mail->AddAttachment($CFG->dataroot .'/'. $attachment, $attachname, 'base64', $mimetype);
tags(146,1)  [SJIS]: AddAttachment lib/phpmailer/class.phpmailer.php /^    function AddAttachment($path, $name = "", $encoding = "base64", $/;" f

呼ぶライブラリが変わったのでしたら、呼び出し元の処理も当然変える必要があると思います。

ソースについて
        mb_internal_encoding('UTF-8');
        mb_internal_encoding($oldcharset);
        $this->attachment[$cur][2] = mb_encode_mimeheader($name, 'UTF-8');

編集ミスだと思いますが、これだと値をセットする前に最初の状態に文字コードを戻してしまっているので意味がないのではと思います。

        mb_internal_encoding('UTF-8');
        $this->attachment[$cur][2] = mb_encode_mimeheader($name
, 'UTF-8');
        mb_internal_encoding($oldcharset);
の順番ではないでしょうか。

K Yukawa への返信

Re: メールにおける添付ファイルのファイル名の文字化け

- Tatsuya Shirai の投稿

 ご指摘ありがとうございます! いやぁお恥ずかしい^^;

 混乱するといけないので,元の私の書き込みの方を修正しました.