23 August 2009

(PHP) Quoted-Printable エンコードとデコード

PHPのバージョン4以降には、quoted_printable_decode関数が存在し、バージョン5.3以降にはquoted_printable_encode関数も存在している。このため、デコードは最近のサーバでは標準関数で対応可能のようだ。

エンコードについては(このホームページが用いているサーバを含め)、標準関数が存在しないため、IMAPライブラリがビルド時に組み込まれている場合はimap_8bit関数を使ってみたり、mb_list_encodings関数で"Quoted-Printable"がサポートされていると分かればmb_convert_encoding関数を用いてエンコードを行える。

と、○○の場合… などと各種条件により用いる関数が違うという、全く開発者泣かせの状態だ。

ということで、どんな顧客のサーバに設置しても、とりあえず動いてくれそうなコード (ただし、この検証コードではISO-2022-JPはうまくデコードできない)

実際にサーバでテストを行った検証コード20090823-text-quote.phpをダウンロードする

プログラムの主要部分を次に示す。

エンコード

// エンコード関数
// $srCode には、'SJIS', 'UTF8', 'EUC', 'ISO-2022-JP' など文字コードを指定
function func_encode(&$str, $strCode, $strFunc)
{
// 利用した関数名
$strFuncName = '';

if($strFunc == 'disable_builtin')
{ // 強制的にPHPビルトイン関数を無効化する
$str = func_encode_self(mb_convert_encoding($str,$strCode,'auto'));
}
else if(function_exists('quoted_printable_encode'))
{
$str = quoted_printable_encode(mb_convert_encoding($str,$strCode,'auto'));
}
else if(function_exists('imap_8bit'))
{
$str = imap_8bit(mb_convert_encoding($str,$strCode,'auto'));
}
else
{
$arrEncodeSupport = mb_list_encodings();
if(array_search('Quoted-Printable', $arrEncodeSupport) != FALSE)
{
$str = mb_convert_encoding(mb_convert_encoding($str,$strCode,'auto'), 'Quoted-Printable', $strCode);
}
else
{
$str = func_encode_self(mb_convert_encoding($str,$strCode,'auto'));
}
}

return;
}

// エンコード関数(PHPの関数を使わないバージョン)
function func_encode_self($str)
{
$crlf="\r\n";

$str=trim($str);

$lines = preg_split("/(\r\n|\n|\r)/s", $str);
$out = '';
$temp = '';
foreach ($lines as $line)
{
for ($j = 0; $j < strlen($line); $j++)
{
$char = substr ( $line, $j, 1 );
$ascii = ord ( $char );

if ( $ascii < 32 || $ascii == 61 || $ascii > 126 )
{
$char = '=' . strtoupper ( dechex( $ascii ) );
}

if ( ( strlen ( $temp ) + strlen ( $char ) ) >= 76 )
{
$out .= $temp . '=' . $crlf; $temp = '';
}
$temp .= $char;
}
}
$out .= $temp;

return trim ( $out );
}

デコードは

デコード

// デコード関数
function func_decode(&$str, $strFunc)
{

if($strFunc == 'disable_builtin')
{ // 強制的にPHPビルトイン関数を無効化する
$str = mb_convert_encoding(func_decode_self($str), 'UTF8', 'auto');
}
else if(function_exists('quoted_printable_decode'))
{
$str = mb_convert_encoding(quoted_printable_decode($str), 'UTF8', 'auto');
}
else
{
$str = mb_convert_encoding(func_decode_self($str), 'UTF8', 'auto');
}

// 不要なスラッシュを除去
$str = stripslashes($str);

return;
}

// デコード関数(PHPの関数を使わないバージョン)
function func_decode_self($str)
{
$out = preg_replace('/=\r?\n/', '', $str);
$out = preg_replace('/=([A-F0-9]{2})/e', "chr(hexdec ('$1'))" , $out);
return trim($out);
}


実際に、Quoted-Printable に変換した例

もとの文字列 (朝日新聞より)

 「みんなが『政権交代』と叫ぶ中、たまには民主にとらせてもいいかなと思う。一度は政権交代させないと、この風を止めるのは容易じゃない」。自民党の小泉元首相は22日、愛知県小牧市での小選挙区の自民候補の集会で、こう演説した。

Quoted-Printable (SJIS)

=81@=81u=82=DD=82=F1=82=C8=82=AA=81w=90=AD=8C=A0=8C=F0=91=E3=81x=82=C6=8B=
=A9=82=D4=92=86=81A=82=BD=82=DC=82=C9=82=CD=96=AF=8E=E5=82=C9=82=C6=82=E7=
=82=B9=82=C4=82=E0=82=A2=82=A2=82=A9=82=C8=82=C6=8Ev=82=A4=81B=88=EA=93x=
=82=CD=90=AD=8C=A0=8C=F0=91=E3=82=B3=82=B9=82=C8=82=A2=82=C6=81A=82=B1=82=
=CC=95=97=82=F0=8E~=82=DF=82=E9=82=CC=82=CD=97e=88=D5=82=B6=82=E1=82=C8=82=
=A2=81v=81B=8E=A9=96=AF=93}=82=CC=8F=AC=90=F2=8C=B3=8E=F1=91=8A=82=CD=82=
Q=82Q=93=FA=81A=88=A4=92m=8C=A7=8F=AC=96q=8Es=82=C5=82=CC=8F=AC=91I=8B=93=
=8B=E6=82=CC=8E=A9=96=AF=8C=F3=95=E2=82=CC=8FW=89=EF=82=C5=81A=82=B1=82=A4=
=89=89=90=E0=82=B5=82=BD=81B

Quoted-Printable (UTF8)

=E3=80=80=E3=80=8C=E3=81=BF=E3=82=93=E3=81=AA=E3=81=8C=E3=80=8E=E6=94=BF=
=E6=A8=A9=E4=BA=A4=E4=BB=A3=E3=80=8F=E3=81=A8=E5=8F=AB=E3=81=B6=E4=B8=AD=
=E3=80=81=E3=81=9F=E3=81=BE=E3=81=AB=E3=81=AF=E6=B0=91=E4=B8=BB=E3=81=AB=
=E3=81=A8=E3=82=89=E3=81=9B=E3=81=A6=E3=82=82=E3=81=84=E3=81=84=E3=81=8B=
=E3=81=AA=E3=81=A8=E6=80=9D=E3=81=86=E3=80=82=E4=B8=80=E5=BA=A6=E3=81=AF=
=E6=94=BF=E6=A8=A9=E4=BA=A4=E4=BB=A3=E3=81=95=E3=81=9B=E3=81=AA=E3=81=84=
=E3=81=A8=E3=80=81=E3=81=93=E3=81=AE=E9=A2=A8=E3=82=92=E6=AD=A2=E3=82=81=
=E3=82=8B=E3=81=AE=E3=81=AF=E5=AE=B9=E6=98=93=E3=81=98=E3=82=83=E3=81=AA=
=E3=81=84=E3=80=8D=E3=80=82=E8=87=AA=E6=B0=91=E5=85=9A=E3=81=AE=E5=B0=8F=
=E6=B3=89=E5=85=83=E9=A6=96=E7=9B=B8=E3=81=AF=EF=BC=92=EF=BC=92=E6=97=A5=
=E3=80=81=E6=84=9B=E7=9F=A5=E7=9C=8C=E5=B0=8F=E7=89=A7=E5=B8=82=E3=81=A7=
=E3=81=AE=E5=B0=8F=E9=81=B8=E6=8C=99=E5=8C=BA=E3=81=AE=E8=87=AA=E6=B0=91=
=E5=80=99=E8=A3=9C=E3=81=AE=E9=9B=86=E4=BC=9A=E3=81=A7=E3=80=81=E3=81=93=
=E3=81=86=E6=BC=94=E8=AA=AC=E3=81=97=E3=81=9F=E3=80=82

Quoted-Printable (EUC)

=A1=A1=A1=D6=A4=DF=A4=F3=A4=CA=A4=AC=A1=D8=C0=AF=B8=A2=B8=F2=C2=E5=A1=D9=
=A4=C8=B6=AB=A4=D6=C3=E6=A1=A2=A4=BF=A4=DE=A4=CB=A4=CF=CC=B1=BC=E7=A4=CB=
=A4=C8=A4=E9=A4=BB=A4=C6=A4=E2=A4=A4=A4=A4=A4=AB=A4=CA=A4=C8=BB=D7=A4=A6=
=A1=A3=B0=EC=C5=D9=A4=CF=C0=AF=B8=A2=B8=F2=C2=E5=A4=B5=A4=BB=A4=CA=A4=A4=
=A4=C8=A1=A2=A4=B3=A4=CE=C9=F7=A4=F2=BB=DF=A4=E1=A4=EB=A4=CE=A4=CF=CD=C6=
=B0=D7=A4=B8=A4=E3=A4=CA=A4=A4=A1=D7=A1=A3=BC=AB=CC=B1=C5=DE=A4=CE=BE=AE=
=C0=F4=B8=B5=BC=F3=C1=EA=A4=CF=A3=B2=A3=B2=C6=FC=A1=A2=B0=A6=C3=CE=B8=A9=
=BE=AE=CB=D2=BB=D4=A4=C7=A4=CE=BE=AE=C1=AA=B5=F3=B6=E8=A4=CE=BC=AB=CC=B1=
=B8=F5=CA=E4=A4=CE=BD=B8=B2=F1=A4=C7=A1=A2=A4=B3=A4=A6=B1=E9=C0=E2=A4=B7=
=A4=BF=A1=A3

Quoted-Printable (ISO-2022-JP)

=1B$B!!!V$_$s$J$,!X@/8"8rBe!Y$H6+$VCf!"$?$^$K$OL1<g$K$H$i$;$F$b$$$$$+$J$H;W=
$&!#0lEY$O@/8"8rBe$5$;$J$$$H!"$3$NIw$r;_$a$k$N$OMF0W$8$c$J$$!W!#<+L1E^$N>.@=
t85<sAj$O#2#2F|!"0&CN8)>.KR;T$G$N>.A*5s6h$N<+L18uJd$N=3D82q$G!"$3$&1i@b$7$?=
!#=1B(B