PEAR ライブラリの Mail_mimeDecode-1.5.5 にガッカリなバグがあったので共有。
ユーザーからの画像付きメールを受信して、その画像を取り出して記録する処理を書いていたのですが、特定のユーザーからのメールだけいつも処理に失敗していました。Mail_mimeDecode::decode()
の引数に生メールを渡し、以下のようにオプションを指定すれば、base64 デコード済みの body が取得できるはずなのですが、そのユーザーからのメールだけは画像が base64 文字列のまま値を返されていました。
private function __encodeToMailObject($rawMail) {
$Decoder = new Mail_mimeDecode();
return $Decoder->decode([
'include_bodies' => true,
'decode_bodies' => true,
'decode_headers' => true,
]);
}
// 戻り値は base64 デコードされた形になるはずなのに、
// 特定のメールだけ base64 エンコードされたまま返ってしまう
原因は Mail_mimeDecode::_decodeBody()
でした。このメソッド内部では、メールヘッダーの Content-Transfer-Encoding
の文字列を見て、どんなデコードをするかを判断します。が、この条件判断文がケースセンシティブに作られており、全部小文字で base64 と書かれていなければ base64 decode はされないという仕様でした。
// pear/mail_mime-decode/Mail/mimeDecode.php
function _decodeBody($input, $encoding = '7bit')
{
switch ($encoding) {
case '7bit':
return $input;
break;
case 'quoted-printable':
return $this->_quotedPrintableDecode($input);
break;
case 'base64':
// 引数 $encoding が `base64` (小文字) じゃないと入れない
return base64_decode($input);
break;
default:
return $input;
問題のメールは Content-Transfer-Encoding: Base64
と書かれていたため、body 部が一切デコードされずスルーされていました。
ひとまず以下のように大文字小文字を無視するように修正して解決しました。
function _decodeBody($input, $encoding = '7bit')
{
//switch ($encoding) {
switch (strtolower($encoding)) {
ちなみにこのライブラリにプルリクを出したかったのですが、2010年12月以来更新が無いので無理そうです。そもそも PHP はメール送信ライブラリは山ほどあっても、受信ライブラリが少ない気がします。PHP でメール受信処理なんて誰もやらないということなのでしょうか…。
2015-09-09 追記
PHP: Diff of /pear/packages/Mail_mimeDecode/trunk/Mail/mimeDecode.php
本家PEAR では2010年12月の version 1.5.5 から更新が止まっていますが、svn.php.net を見るとつい最近も作者本人によってコミットがされていました。この記事の問題も修正されているようですし、PHP7 対応までされているようなので、むしろそっちのソースを使ったほうがよさそう。
なんで PEAR に反映しないんでしょうね…?