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