As others say, mb_encode_mimeheader() seems to have a bug with JIS(ISO-2022-JP) encording. Token indicating start and end of multibyte char is inserted only before start of encoding and after the all.
We need the tokens at start and end of *all* encoded-text.
# PHP 4.3.2
So, we needs some workaround.
The post by "gordon at kanazawa-gu dot ac dot jp" seems to work well, but it doesn't. JIS nees some special tokens and base64_encode does'nt output them, so the code cannot used.
The post "RE: N03L in Japan", which simply splitting words in eash 10 chars is good enough in most case, there are some problem left. When there are some splited parts starting with ascii chars, 1 additional space will be inserted.
# RFC2047 only say within 76 words, shorter is not bad.
Additionally, thought it is really rare case, when we use "=?charset?" as literal string, we have to escape them.
# Some mailer can actually send this without escape and header will be broken. :(
Now, a little non-smart but maybe more accurate code is below function. I tested only with ISO-2022-JP, only in costomized phpBB2.0.5, only some cases.
As far as my test this code worked well, but I'm not sure.
# $str: source text
# $indent: ex. for "Subject: " header, give 9 and first line will be shorter than 76-1-9=66
# $encoding: source text encoding
# $mail_encoding: $str will be converted into this before base64 encode
function encode_mimeheader($str, $indent = 0, $encoding = 'utf-8', $mail_encoding = 'iso-2022-jp')
{
$start_delimiter = strtoupper("=?$mail_encoding?B?");
$start_pattern = strtoupper("=\\?$mail_encoding\\?B\\?");
$end_delimiter = '?=';
$str = mb_convert_encoding($str, $mail_encoding, $encoding);
$length = mb_strlen($str, $mail_encoding);
$max_part_length = 20; // enough short in most case (you can change this default value)
for ($i=0, $index=0; $index<$length; $i++) {
$part_length = $max_part_length;
$s = mb_substr($str, $index, $part_length, $mail_encoding);
// workaround for literally used start delimiter (without below, subject may break)
// note: mb_encode_mimeheader() don't encode ascii including start delimiter
if (preg_match('/^' . $start_pattern . '/i', $s))
{
$lines[$i] = $start_delimiter . base64_encode($start_delimiter) . "?=";
$index += strlen($start_delimiter);
continue;
}
$lines[$i] = mb_encode_mimeheader($s, $mail_encoding);
while (strlen($lines[$i]) > 76-1 - ($i?0:$indent)) { // max par line - first space - indent (first line only)
$part_length = floor($part_length * (76-1 - ($i?0:$indent)) / strlen($lines[$i])); // at least 1 decrement
$s = mb_substr($str, $index, $part_length, $mail_encoding);
$lines[$i] = mb_encode_mimeheader($s, $mail_encoding);
}
// workaround for starting new line with ascii (without below, 1 space may cut in)
// note: mb_encode_mimeheader() starts encode after encounterring multibyte char
if ($i > 0 && !preg_match('/^' . $start_pattern . '/i', $lines[$i]))
{
$p = strpos($lines[$i], $start_delimiter); //never 0 (false when not found)
$p = $p ? $p : strlen($lines[$i]);
$lines[$i] = $start_delimiter . base64_encode(substr($lines[$i], 0, $p)) . "?=";
$part_length = $p;
}
$index += $part_length;
}
$str = join("\r\n ", $lines); // RFC 2047,822 say newline must be ^\r\n, not only\n
return $str;
}