ど素人から毛を生やす。<延>

[PHP]受信したメールがMIMEエンコードされている場合。

Web > PHP 2021年2月26日(最終更新:3年前)

2021年2月26日に作成されたページです。
情報が古かったり、僕が今以上のど素人だった頃の記事だったりする可能性があります。

前回、メール件名の文字列がMIMEエンコードされていた場合の対応を考えたわけですが、じゃあメール本文についてはどうするのが最適解よ??となるわけです。

MIMEヘッダの文字列には「=?utf-8?Q?」のように文字セットやエンコード方式が含まれているため正確に判定してデコードできますが、通常はそういった情報が含まれないので…、取り敢えず文字列から検出してみましょうか。

var_dump(mb_detect_encoding('=3D=E3=81=A9=E7=B4=A0=E4=BA=BA'));
	//string(5) "ASCII"
var_dump(mb_detect_encoding('PeOBqee0oOS6ug=='));
	//string(5) "ASCII"

アッ…

$a = '=E3=81=A9=E7=B4=A0=E4=BA=BA';
if(mb_detect_encoding($a)==='ASCII'){
	if(preg_match('/^=/', $a)){
		$a = imap_qprint($a);
	}else{
		$a = base64_decode($a);
	}
}
var_dump($a);
	//string(9) "ど素人"

MIMEエンコード方式はquoted-printableまたはBase64の2種類とのことなので、「=」から始まる場合はquoted-printable、そうでなければBase64という判断の仕方ができなくはないですが、ちょっと不安が残りますね。

ということで、メールに限った話で言えば、IMAPストリームを取得できるimap_fetchstructure()を使用するのが良さそうです。

$stream = imap_fetchstructure($imap, $message_num);
$message = imap_fetchbody($imap, $message_num, 1, FT_PEEK);
switch($stream->encoding){
	case ENCBASE64:
		$message = base64_decode($message);
		break;
	case ENCQUOTEDPRINTABLE:
		$message = imap_qprint($message);
		break;
	default:
		break;
}
var_dump($message);

これで良いらしい。
ただし、これだと文字セットが使用言語と噛み合っていない可能性があるため、実用のためにはmb_convert_encoding()もかける必要があるでしょう。

mb_detect_encoding()を使用しても良いですが、IMAPストリームにはcharsetも含まれているとのことなので、利用しましょう。

foreach($stream->parameters as $parameter){
	if(strtolower($parameter->attribute) == 'charset'){
		$message = mb_convert_encoding($message, 'UTF-8', $parameter->value);
		break;
	}
}
var_dump($message);

ちなみに、imap_fetchstructure()で取得したIMAPストリームは12の要素から成るオブジェクトのようです。

stdClass Object(
    [type] => 0
    [encoding] => 4
    [ifsubtype] => 1
    [subtype] => PLAIN
    [ifdescription] => 0
    [ifid] => 0
    [lines] => 247
    [bytes] => 10141
    [ifdisposition] => 0
    [ifdparameters] => 0
    [ifparameters] => 1
    [parameters] => Array(
            [0] => stdClass Object(
                    [attribute] => CHARSET
                    [value] => utf-8
            )
)

ENCBASE64=3、ENCQUOTEDPRINTABLE=4とのことなので、上の場合はquoted-printable、文字セットはutf-8ということですね。

この記事は役に立ちましたか?
  • _(:3」∠)_ 面白かった (0)
  • (・∀・) 参考になった (0)
  • (`・ω・´) 役に立った (0)