URLエンコードは、HTTP のフォーム送信などに用いられるエンコード形式で、CGI にフォームデータを渡す場合などに使用されます。例えば下記のようにエンコードされます。
NAME=ABC日本語 → NAME=ABC%93%FA%96%7B%8C%EA
空白文字を + に置換し、日本語や記号などの特殊文字を %nn 形式(nn は 16進数の文字コード)にエンコードします。エンコードされる記号は下記のものです。
( ) { } [ ] < > ! # $ % & " ' ` ^ ~ = \ | ; : + / ? ,
下記の記号はエンコードされません。
- @ * . _
URLエンコード形式のエンコード・デコードを行うサブルーチンを以下に示します。(プログラムはシフトJISであることを想定しています。)
print UrlEncode("ABC日本語") . "\n"; print UrlDecode("ABC%93%FA%96%7B%8C%EA") . "\n"; # URLエンコード sub UrlEncode { local($str) = @_; $str =~ s/([^ 0-9a-zA-Z\-@\*\._])/sprintf("%%%02X", ord($1))/eg; $str =~ s/ /+/g; return $str; } # URLデコード sub UrlDecode { local($str) = @_; $str =~ s/\+/ /g; $str =~ s/%([0-9A-Fa-f]{2})/pack("C", hex($1))/eg; return $str; }
BASE64 は、バイナリファイルをメールに添付する際などによく用いられます。バイナリデータや日本語データを ASCIIテキストとして扱えるようになるのが特徴です。例えば、下記のようなエンコードが行われます。
This is a pen. → VGhpcyBpcyBhIHBlbi4=
入力データの 3バイト 24ビットを 6ビット×4ブロックに分けます。6ビットは 0~63 の値を表しますが、0→A、1→B、2→C のように A~Z、a~z、0~9、+、/ の 64文字に割り当てていきます。入力データが 3バイトの倍数でない場合は、0 埋めでエンコードし、足りないバイト数分、末尾を = で置き換えます。
xxx → 01111000 01111000 01111000 → 011110 000111 100001 111000 → eHh4 xxx → eHh4 xx → eHg= x → eA==
MIME::Base64 モジュールを利用できる環境であれば、encode_base64() や decode_base64() を使用することができます。
use MIME::Base64; $encstr = encode_base64("Hello"); print "[$encstr]\n"; $decstr = decode_base64($encstr); print "[$decstr]\n";
encode_base64() でエンコードされたデータは、76文字毎に "\n" で区切られ、最後にも "\n" が付加されます。"\n" で区切りたくない場合は第2引数(区切り文字)に "" を指定してください。
$encstr = encode_base64("Hello", "");
MIME:Base64 モジュールが使用できない環境のために、BASE64 エンコード・デコードを行うサブルーチンを下記に示します。
# BASE64エンコードする # $encoded_string = Base64Encode($str) sub Base64Encode { local($buf) = @_; local($mode, $tmp, $ret); local($b64) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "abcdefghijklmnopqrstuvwxyz" . "0123456789+/"; $mode = length($buf) % 3; if ($mode == 1) { $buf .= "\0\0"; } if ($mode == 2) { $buf .= "\0"; } $buf =~ s/(...)/{ $tmp = unpack("B*", $1); $tmp =~ s|(......)|substr($b64, ord(pack("B*", "00$1")), 1)|eg; $ret .= $tmp; }/eg; if ($mode == 1) { $ret =~ s/..$/==/; } if ($mode == 2) { $ret =~ s/.$/=/; } return $ret; } # BASE64デコードする # $str = Base64Decode($encoded_string) sub Base64Decode { local($buf) = @_; local($mode, $tmp, $ret); local($b64) = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" . "abcdefghijklmnopqrstuvwxyz" . "0123456789+/"; $mode = ($buf =~ tr/=/A/); $buf =~ s/(.)(.)(.)(.)/{ $tmp = sprintf("%06b%06b%06b%06b", index($b64, $1), index($b64, $2), index($b64, $3), index($b64, $4)); $tmp =~ s|(........)|$ret .= pack("B8", $1)|eg; }/eg; return substr($ret, 0, length($ret) - $mode); }
Compress::Zlib モジュールを用いて、データを gzip 形式に圧縮することができます。
use Compress::Zlib; $infile = "xx2"; # 圧縮前の入力ファイル $outfile = "xx2.gz"; # 圧縮後の出力ファイル # 入力ファイルからデータを読み込む open(IN, $infile) || die "Can't open $infile.\n"; binmode(IN); read(IN, $indata, (lstat(IN))[7]) || die "Can't read $infile\n"; close(IN); # 出力ファイルに書き込む open(OUT, "> $outfile") || die "Can't open $outfile.\n"; binmode(OUT); print OUT Compress::Zlib::memGzip($indata); close(OUT);
ブラウザがサポートしていれば、CGI がブラウザに送りかえすデータを gzip 形式に圧縮して転送することもできます。HTTP ヘッダ部に Content-Encoding で gzip を指定します。
use Compress::Zlib; # 入力ファイルからデータを読み込む open(IN, "file.txt"); binmode(IN); read(IN, $indata, (lstat(IN))[7]); close(IN); # CGIの結果として書き出す binmode(STDOUT); print "Content-Type: text/html\r\n"; print "Content-Encoding: gzip\r\n"; print "\r\n"; print Compress::Zlib::memGzip($indata);