[PHP-users 17013]Re: mb_send_mail()と mb_encode_mimeheader()
Shuji TANAKA
stanaka @ longpro.ne.jp
2003年 7月 28日 (月) 21:35:14 JST
stanakaです.
ご返事ありがとうございます.
少しよく分からなかったのですが,
> ヘッダフィールドは、US-ASCIIで記述されることと言うのと、
> From:ヘッダに関しては、
> From: [displayname] "<" addr-spec ">"
> といったような規定があるので "<" addr-spec ">"の部分をUS-ASCIIで無い
> 他文字コードとしてエンコードするのは拙いと思います。
この部分は,私の不満に賛同していただけたと思っていいのでしょうか?.それと
も逆でしょうか?.
> で、そのコードはいつ見せてもらえますかね :)
あれ?,なんか怒ってます?.
delegate の付属品にそんなものがあるとは知りませんでした.PHPで書くより明ら
かに軽そうですね.
とりあえず了解を頂いたものとして,以下にPHPコードを出させていただきます.
なんか,76バイトに収まるまで何度もmime_encode()を呼び出したり,mb_strwidth()
とか一字ごとに呼び出したりしてもうちょっとスマートな方法はないのか,と自分で
も思うのですが・・・・.
どうかよろしくご指導のほどをお願いいたします.
-- ▽ここから
function _encode_mimeheader( $string, $recurse = false ){
$lower_recurse = true;
if( $string == "" )
return "";
$idx = 0;
$length = mb_strlen( $string );
// ループ:内部で条件判断でbreakして脱出する
while( true ){
// とりあえず全体をエンコードしてみる
$estring = mime_encode( mb_substr( $string, 0, $length - $idx ),
$recurse );
$ustring = mb_substr( $string, 0, $length - $idx );
$cstring = mb_substr( $string, $length - $idx );
$u_last = mb_substr( $ustring, -1, 1 );
$c_top = mb_substr( $cstring, 0, 1 );
$c_next = mb_substr( $cstring, 1, 1 );
// エンコード結果が76バイトを超えるようであれば,
// 文字列の後尾から一文字ずつ減らして
// エンコーディングしなおしてみる:ループ継続
if( mb_strwidth( $estring ) > 76 ){
$idx++;
continue;
}
// 全体が問題なくエンコードできた(76バイト以内)ので,
// ループ脱出
else if( $cstring == "" )
break;
// 先頭からのエンコード結果が76バイト以内に収まったが・・・
else{
// 改行を挿入する位置を発見できないまま,
// 文字列の先頭まで戻ってきてしまったので,異常終了
if( $length == $idx ) die( "_encode_mimeheader():
".$idx."/".$length.": Cannot Generate!" );
// スペースではないASCII文字と,一スペースと
// それに続くスペースではないASCII文字があれば,
// スペースとその前の間を行の切れ目とする:ループ脱出
if( isSpace( $c_top ) && isAscii( $u_last ) && !isSpace( $u_last ) &&
isAscii( $c_next ) && !isSpace( $c_next ) ){
$lower_recurse = false;
break;
}
// 非ASCII文字の間を行の切れ目とする:ループ脱出
if( !isAscii( $c_top ) && !isAscii( $u_last ) ){
break;
}
// 先頭の一文字前まできてしまったら,仕方がないので
// そこを行の切れ目とする:ループ脱出
if( $length == $idx + 1 )
break;
// ループ継続
$idx++;
}
}
// 非ASCII文字の間を行の切れ目とした場合,次行の先頭にスペースを置く
if( $lower_recurse ) $line_top = " ";
else $line_top = "";
// 次行以降をエンコード
// 先頭におくスペースはエンコード後,連結
$cestring = $line_top._encode_mimeheader( $cstring, $lower_recurse );
// 連結
if( $cestring == "" )
return $estring;
else
return $estring."\r\n".$cestring;
}
function mime_encode( $string, $enc_start = false ){
$idx = 0;
$ret_string = "";
$s = "";
if( $enc_start )
$stat = "j";
else
$stat = "a";
// 文字列の先頭から順に一文字ずつ取り出してループ
while( ( $c = mb_substr( $string, $idx++, 1 ) ) != "" ){
$p = mb_substr( $string, $idx -2, 1 );
$n = mb_substr( $string, $idx, 1 );
// 何のために入れたか忘れた
// 最先頭でも最後尾でもなく,且つ非ASCII文字から
// スペースでないASCII文字に移る間のにあるスペース文字は
// 必ずASCII文字としてエンコードしないでおく
if( $p != "" && $n != "" && !isAscii( $p ) && $c == " " && isAscii( $n )
&& !isSpace( $n ) ){
$new_stat = "a";
}
// 通常スペース文字は,その前の文字と同じ
// 文字エンコーディング(ASCII,非ASCII)として
// MIMEエンコードする,しないを決める
else if( $c == " " ){
$s = $s." ";
continue;
}
if( isAscii( $c ) )
$new_stat = "a";
if( !isAscii( $c ) )
$new_stat = "j";
// この文字が前の文字と同じエンコーディングであれば,
// 前までの文字列と連結してループを継続
if( $stat == $new_stat )
$s = $s.$c;
// この文字が前の文字までと違うエンコーディングであれば,
// 前の文字までの列をエンコーディングするかしないか決める
else{
// 前の文字までがASCII文字の列の場合,
// エンコーディングしないでそのまま連結
if( $stat == "a" )
$ret_string = $ret_string.$s;
// 前の文字までが非ASCII文字の列の場合,
// Bエンコードして連結
else if( $stat == "j" )
$ret_string = $ret_string."=?ISO-2022-JP?B?".base64_encode(
mb_convert_encoding( $s, "ISO-2022-JP" ) )."?=";
// 新しい(この文字からの)文字エンコーディング
$stat = $new_stat;
// 新しく文字列の連結を始める
$s = $c;
}
}
// 最後に文字エンコーディングが変化してから,
// 文字列の最後尾までのエンコードをして/しないで連結する
if( $stat == "a" )
$ret_string = $ret_string.$s;
else
$ret_string = $ret_string."=?ISO-2022-JP?B?".base64_encode(
mb_convert_encoding( $s, "ISO-2022-JP" ) )."?=";
return $ret_string;
}
function isAscii( $char ){
if( mb_strlen( $char ) == 0 )
die( "isAscii(): Bad argument, the argument of function is an empty
string." );
if( mb_strlen( $char ) != 1 )
die( "isAscii(): Bad argument, the argument of function is not a string
of one charactor, but of multiple charactors." );
if( mb_strwidth( $char ) == 1 )
return true;
else
return false;
}
function isSpace( $char ){
if( mb_strlen( $char ) == 0 )
die( "isSpace(): Bad argument, the argument of function is an empty
string." );
if( mb_strlen( $char ) != 1 )
die( "isSpace(): Bad argument, the argument of function is not a string
of one charactor, but of multiple charactors." );
if( $char == " " )
return true;
else
return false;
}
-- △ここまで
因みに比較ですが,簡単ですが以下のようになります.エンコードはそれぞれの関
数で,デコードはそれぞれの関数で行ったものをmb_decode_mimeheader()で行ってい
ます.
元文字列
From: Japanese Name 日本語名 <youaddress @ your.domain>
エンコード文字列:mb_encode_mimeheader()
From: Japanese Name =?ISO-2022-JP?B?GyRCRnxLXDhsTD4bKEIgPHlvdWFkZHJlc3NA?=
=?ISO-2022-JP?B?eW91ci5kb21haW4+?=
エンコード文字列:mime_encode()
From: Japanese Name =?ISO-2022-JP?B?GyRCRnxLXDhsTD4bKEI=?=
<youaddress @ your.domain>
エンコード文字列:_encode_mimeheader()
From: Japanese Name =?ISO-2022-JP?B?GyRCRnxLXDhsGyhC?=
=?ISO-2022-JP?B?GyRCTD4bKEI=?= <youaddress @ your.domain>
デコード文字列:mb_encode_mimeheader()
From: Japanese Name 日本語名 <youaddress @ your.domain>
デコード文字列:mime_encode()
From: Japanese Name 日本語名 <youaddress @ your.domain>
デコード文字列:_encode_mimeheader()
From: Japanese Name 日本語名 <youaddress @ your.domain>
PHP-users メーリングリストの案内