PEAR Mail_mimeDecodeでヘッダー文字化け

By | 2018/03/02

PHPで送信されてきたメールを解析して処理を行うため、ネット情報を参考に以下のようにやってみた。

PEAR::Mail_mimeDecodeをインストールして以下のように処理したのだが、$mail_body->bodyの処理は良かったとして、ヘッダーの文字列が内部エンコードに変換されず元のままのエンコードで入ってきている。UTF-8だったりJISだったり。。困った。

ネット情報を参考に書いた元ソースがこれ

require_once 'Mail/mimeDecode.php';

$rawdata = file_get_contents("php://stdin"); // 標準入力から

// メールParse
$params = array();
$params['include_bodies'] = true;
$params['decode_bodies']  = true;
$params['decode_headers'] = true';
$params['crlf'] = "\r\n";
$Mail = new Mail_mimeDecode($rawdata);
$mail_data = $Mail->decode($params);

$form = array();
$form['from'] = preg_replace('/^.*<([^<>]+?)>.*$/', '$1', $mail_data->headers['from']);
$form['to'] = preg_replace('/^.*<([^<>]+?)>.*$/', '$1', $mail_data->headers['to']);
$form['subject'] = $mail_data->headers['subject'];

// 本文の取得
$encode = "ISO-2022-JP";
if ($mail_data->ctype_primary == 'multipart') {
	foreach ($mail_data->parts as $parts) {
		if ($parts->ctype_primary == 'text' and $parts->ctype_secondary == 'plain') {
			$MailBody = $parts->body;
			if ($parts->ctype_parameters['charset']) {
				$encode = $parts->ctype_parameters['charset'];
			}
			break;
		}
	}
} else {
	if ($mail_data->ctype_parameters['charset']) {
		$encode = $mail_data->ctype_parameters['charset'];
	}
	$MailBody = $mail_data->body;
}
$form['body'] = mb_convert_encoding($MailBody, "UTF-8", $encode);

print_r($form);

$mail_dataを見てもヘッダーの素のエンコードが何だったかパラメータに入ってこないから、後処理しようがないじゃん!

とmimeDecodeのソースを覗いてみたらこう書かれてるじゃない。

     * @param array An array of various parameters that determine
*              various things:
*              include_bodies - Whether to include the body in the returned
*                               object.
*              decode_bodies  - Whether to decode the bodies
*                               of the parts. (Transfer encoding)
*              decode_headers - Whether to decode headers,
*                             - use "UTF8//IGNORE" to convert charset.
*
*              input          - If called statically, this will be treated
*                               as the input
* @return object Decoded results
* @access public
*/
function decode($params = null)

つまり、decode_bodiesはtrue/falseで良いけど、decode_headresはtrue/falseじゃなくて期待する変換後エンコードを文字で指定するのが正解。

ただ、これも間違ってる。iconvで処理してるから、UTF8じゃなくてUTF-8ね。

それにIGNOREだと不正文字をカットされちゃって不正文字が混ざってた事が分からなくなるので、不正文字マークにしてくれるTRANSLITの方が良いと思われ。

$params['decode_headers'] = 'UTF-8//TRANSLIT';

これで解決!ネット情報もソースのコメントさえもあやふや。

疑って掛かる事をしばらく忘れていましたが、何もかも確認は必要ですね。


Category: PHP