mb_decode_mimeheaderと機種依存文字

Subjectなどで機種依存文字が入っている場合、普通にmb_decode_mimeheaderをやってもダメだよという話。


これ以降の前提条件として、

  • internal_encodingはUTF-8
  • ここは機種依存文字が書き込めないみたいなので、(1)丸付きの1と読みかえてください

mb_decode_mimeheaderだとダメ

<?php
$subject = '=?ISO-2022-JP?B?GyhJMTIzNDUbJEItIRsoQkFCQw==?='; // アイウエオ(1)ABC
var_dump(mb_decode_mimeheader($subject));
// string(19) "アイウエオ?ABC"

原因はISO-2022-JPに変換しているから。
これを(PHP5の場合は)ISO-2022-JP-MSで変換してあげなければいけない。

自作する

ちゃんとやるにはこんな関数を作ることになると思う。

<?php
function decode_mimeheader($str)
{
  $decode_str = '';
  foreach (preg_split('/\s/', $str) as $split_str) {
    if (strlen($split_str) === 0) {    continue;   }

    if (preg_match('/=\?([^\?]+)\?([^\?]+)\?([^\?]+)\?=$/', $split_str, $matches)) {
      if (strtolower($matches[1]) === 'iso-2022-jp') {
        $match_decode = null;
        switch (strtoupper($matches[2])) {
        case 'B':
          $match_decode = base64_decode($matches[3]);
          break;
        case 'Q':
          $match_decode = quoted_printable_decode($matches[3]);
          break;
        }
        if (!is_null($match_decode)) {
          $decode_str .= mb_convert_encoding(
            $match_decode, mb_internal_encoding(), 'iso-2022-jp-ms'
          );
          continue;
        }
      }
    }
    $decode_str .= mb_decode_mimeheader($split_str);
  }
  return $decode_str;
}

この関数を使うとちゃんとdecode出来る。

<?php
$subject = '=?ISO-2022-JP?B?GyhJMTIzNDUbJEItIRsoQkFCQw==?='; // アイウエオ(1)ABC
var_dump(decode_mimeheader($subject));
// string(21) "アイウエオ(1)ABC"

力技

力技だとこんなやり方でもいいのかも。

<?php
$subject = '=?ISO-2022-JP?B?GyhJMTIzNDUbJEItIRsoQkFCQw==?='; // アイウエオ(1)ABC
$subject = str_ireplace('?iso-2022-jp?', '?iso-2022-jp-ms?', $subject);
var_dump(mb_decode_mimeheader($subject));
// string(21) "アイウエオ(1)ABC"

おまけ

力技の時に知った。
mb_encode_mimeheaderの場合は$charsetにちゃんと(?)指定してあげるといいみたい。

<?php
$subject = 'アイウエオ(1)ABC';
var_dump(mb_encode_mimeheader($subject, 'iso-2022-jp-ms'));
// string(46) "=?ISO-2022-JP?B?GyRCJSIlJCUmJSglKi0hGyhCQUJD?="
var_dump(mb_encode_mimeheader($subject, 'sjis-win'));
// string(36) "=?Shift_JIS?B?g0GDQ4NFg0eDSYdAQUJD?="

もしかして、mb_encode_mimeheaderのバグっていつの間にか直ってる?