[PHP-users 16627]PEARのmimeDecodeで日本語ファイル名を化けずに受け取るには
藤本悟司
satoshi @ try-square.co.jp
2003年 7月 10日 (木) 20:28:57 JST
はじめて投稿します。藤本と申します。
PHP-4.2.2と、PEARのMail_Mime-1.2.1を利用しています。
おそらく正式にはサポートされていない、日本語のファイル名を
正しく受け取る方法について、ご相談なのですが。
例えば「技術メモ.txt」というファイルを添付すると、
MIMEヘッダの中で
Content-Disposition: attachment;
filename="=?ISO-2022-JP?B?GyRCNTs9USVhJWIbKEIudHh0?="
↑"技術メモ.txt"をmimeheaderエンコードしたもの
のような形で書かれると理解しています。
次のようなソースでそのままこのファイル名を取得、表示しようと
すると、化けてしまいます。
// $mailtextにメール本文を取得
(省略)
// デコード方法の指定
$params['include_bodies'] = TRUE;
$params['decode_bodies'] = TRUE;
$params['decode_headers'] = TRUE;
// デコード処理
$decoder = new Mail_mimeDecode( $mailtext );
// メールの構造を取得
$mail = $decoder->decode( $params );
// 複数パート?(添付ファイルがある?)
if ( count($mail->parts) > 1 ) {
// 添付ファイルがある場合、multipartからbodyおよびfileを取得
// (一つ目は本文、二つ目は添付ファイルと仮定。三つ目以降は無視)
$body = $mail->parts[0]->body;
$file = $mail->parts[1]->body;
$filename = $mail->parts[1]->d_parameters['filename'];
if ( $filename == "" ) {
// オプションフィールド名がnameだった場合
$filename = $mail->parts[1]->d_parameters['name'];
}
} else {
// 添付ファイルが無い場合、そのままbodyを取得
$body = $mail->body;
}
$header = $mail->headers;
// デバッグ表示
printf("本文:%s\n", $body );
printf("差出人:%s\n", $header['from'] );
printf("件名:%s\n", $header['subject'] );
printf("添付ファイル:'%s'\n", $filename);
デバッグ表示される結果は、本文、差出人、件名は正常でしたが
添付ファイル名だけが化けていました。
(mb_detect_encoding()で調べたところ、いずれもJIS)
Mail_Mimeに含まれる、mimeDecode.phpのソースを追ってみたのですが、
原因は、
function _parseHeaderValue()
が呼ばれる順序にあるようです。すなわち・・・
1) メールヘッダをparseして各フィールドに切り分ける
2) 各フィールドをデコードする(decode_headersがTRUEの場合)
3) 各フィールドをparseしてオプションに切り分ける
(function _parseHeaderValue())
という順となっているため、上記関数の中では、既にJIS(?)に
デコードされてしまった文字列をpreg_splitしているようです。
filename="技術メモ.txt"
をurlencodeしてみると、次のようになります。
filename%3D%22%1B%24B5%3B%3DQ%25a%25b%1B%28B.txt%22
↑ ↑
"=" "="?
「技術メモ」の途中でpreg_splitでちぎられているのではないか?と
思ったら、ビンゴでした。
そこで対策なのですが、以下のようなコードを加えました。
423行目:
function _parseHeaderValue($input)
{
// added
$input = mb_convert_encoding( $input, "EUC-JP", "JIS" );
442行目:
$param_value = substr($parameters[$i], $pos + 1);
if ($param_value[0] == '"') {
$param_value = substr($param_value, 1, -1);
}
// added
$param_value = mb_convert_encoding( $param_value, "JIS", "EUC-JP" );
$return['other'][$param_name] = $param_value;
$return['other'][strtolower($param_name)] = $param_value;
関数の入り口でEUC-JPに変換してやって、値を切り出したあとJISに
戻してやる、というものです。
おそらく、EUC-JPならば、イコールやダブルクオートなどと
まぎらわしいコードは、含まれないと思ったからです。
このような方法で、どこかに問題ありませんでしょうか?
識者の方の、ご意見をお願いいたします。
長文で恐縮ですが、よろしくお願いします。
----
藤本 悟司
PHP-users メーリングリストの案内