WEBプログラミングをする際に必ず出てくる処理として、メール送信プログラムがあります。この場合に、サブジェクトが長い場合は、RFC2047によれば、「76文字以内で」複数行に分割すべきとあります。どこからどこまでを76文字とするのかが議論になることも多いようですが、とりあえず形式としては、
Subject: =?UTF-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR?=
=?UTF-8?B?YeOBk+ODhuOCueODiOOBp+OBmeOAguKRoOKFseOIseKEoXjpq5nvqJDlvYU=?=
=?UTF-8?B?76iR5b637JWI64WV7ZWY7IS47JqU?=
|
のような形になります。2行目以降にも同様に「=?UTF-8?B?」で始まり、真ん中にBase64エンコードされた文字列、お尻に「?=」がつながります。ただし、二行目以降の先頭は空白スペースが入らなければなりません。
もちろん、PHPなら、mb_encode_mimeheader関数がありますので、素直に「$subject_b = mb_encode_mimeheader($subject,"UTF-8");」などとすればいいことかもしれません。しかし、ここでは勉強のために、自力で書いてみましょう。
複数行に分割する際に、例えば「あ」という文字を構成する文字列が複数の行にまたがると面倒なことになります。実際テストしてみたところ、文字化けするメールソフトもありました。というか文字化けしない方が変?
そこで、サブジェクトとなる文字を一文字ずつ(一バイトずつではありません)、切り出す必要があります。アルファベットなら1バイトですが、非アルファベットならUTF-8の場合、3バイトです。この切り出しには、mbstrlen関数やmbsubstr関数を用いますが、プログラムの前に大前提があります。
mbstring.internal_encodingがUTF-8である必要があります。もし、レンタルサーバなどでmbstring.internal_encodingがEUC-JPに設定されているのなら、ini_set関数で「ini_set("mbstring.internal_encoding","UTF-8");」とすることで、そのプログラム内だけでも設定を変える必要があります。そうでないと、「あいうえお」を5文字ではなく、10文字と計算したりします。
下記のようなサンプルプログラムを作成してみました。エンコード前のサブジェクトを引数に渡すと、複数行が必要な場合は、複数行のMIMEエンコードされたサブジェクトを生成します。
<?php
// このプログラムはUTF-8で作成されていることを前提としています。
// 本文中に「\」と表示されている場合、円マーク(\)と同値です。読み替えてください。
// このプログラムは無保証です。このプログラムに派生するいかなる問題についても責任を負いかねます。
//内部エンコードをUTF-8と宣言し、UTF-8の文字列を処理できるようにします。
ini_set("mbstring.internal_encoding","UTF-8");
function get_utf_header($subject){
$length = 0;
$base64_moji = ""; //最終的にサブジェクトとしてメールヘッダーに書き込まれるもの
$moji_tmp = "";
$parts = 1; //処理している文字列が、サブジェクトの何行目になるかを示しています。
for($i=0;$i<mbstrlen($subject);$i++){
//一文字ずつ取り出します。このようにUTF-8文字を取り扱うことができるためには
//mbstring.internal_encodingがUTF-8である必要があります。
//一般レンタルサーバでも、(少なくとも私が利用しているサーバでは)
//ini_set("mbstring.internal_encoding","UTF-8");と冒頭で宣言することで
//可能になる場合があります。interl_encodingがEUC-JPのままだと、
//ただしい結果になりません。
$moji = mbsubstr($subject,$i,1);
$length += strlen($moji); //切り出した文字のバイト数を計算
$moji_tmp .= $moji; //切り出した文字を集めておきます。
if($length > 36){ //これがTRUEになるのは最大で$length=39の時。
//UTF-8で39バイト(漢字のような非ascill文字だけで構成されている
//と考えると、計13文字に相当)の時、39×8ビットで計312ビット。
//これをbase64で6ビットずつに区切るので312÷6で52文字。
//「Subject: =?utf-8?B?」で19文字。お知りの「?=」で2文字。
//52+19+2=73文字。76文字以内でなければならないとする
//RFCに適合となるのではないかと思います。ただし、自信はありません。
//「$length>36」のところは適当に数字を少なくしてぜんぜんOK。
if($parts == 1){ //一行目
$base64_moji .= "=?utf-8?B?" . base64_encode($moji_tmp) . "?=";
} else {
$base64_moji .= "\n =?utf-8?B?" . base64_encode($moji_tmp) . "?=";
}
$parts++; //サブジェクトの次の行の形成を行うために、インクリメント
$moji_tmp = ""; //切り出した文字の集合を初期化
$length = 0; //次の行へ変わる前に、初期化
}
}
//37~39バイトに満たないで残っている「余り」の処理
if($moji_tmp != ""){
$base64_moji .= "\n =?utf-8?B?" . base64_encode($moji_tmp) . "?=\n";
} else {
$base64_moji .= "\n";
}
return $base64_moji;
}
$subject = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよ";
print "<pre>" . get_utf_header($subject) . "</pre>";
?>
|
決して洗練されたプログラムであるとは思いませんが、自力でMIMEエンコーディングすべきときに叩き台ににしていたでければ幸いです。
ちなみに、上のプログラムを実行すると、
=?utf-8?B?44GC44GE44GG44GI44GK44GL44GN44GP44GR44GT44GV44GX44GZ?=
=?utf-8?B?44Gb44Gd44Gf44Gh44Gk44Gm44Go44Gq44Gr44Gs44Gt44Gu44Gv?=
=?utf-8?B?44Gy44G144G444G744G+44G/44KA44KB44KC44KE44KG44KI?=
|
のように出力されます。もちろん、この自作get_utf_header関数を別ファイルにして、PHPファイルからrequireして使いまわすことも可能です。
|