Code.004 2002年10月28日発行 ■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■ 【 Webプログラミング 】 〜 猫的プログラマーとその軌跡 〜 ■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■ ▼毎週月曜日に配信しています。 ▼等幅フォントでご覧いただくとキレイに見えます。 ▼登録・解除はこちらから可能です。 < http://www.ichikoro.com/webp/ > ※ぜひお友達にもご紹介ください(^^)/ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CGI(Perl)基本動作 その4:「URLエンコード・デコード」 ────────────────────────────────────── URLでは使ってはいけない文字があるんです。 例えば全角文字をそのままURL上に記述してはいけません。 http://www.google.co.jp/search?q=愛のタテーガミ〜♪ ← マズイ ~~~~~~~~~~~~~~~~~~ そんな時は対象の文字に対して「URLエンコード」を施してやります。 例えばGoogleで検索した場合、 http://www.google.co.jp/search?q=%88%A4%82%CC%83%5E%83e%83K%83%7E%81%60%81%F4 というようなURLを見たことありませんか? URLエンコードは通常ブラウザ(クライアント)が行います。 ところが、CGIで受け取った値もURLエンコードが施された状態のため、 そのままでは利用できません。 そこで、まずはエンコードされた物を元に戻す「デコード」と呼ばれる作業が 必要になるのです。 今回は、「URLエンコード」と、そのデコードについて解説したいと思います。 ─────── ソース1(HTML) ─────── <HTML> <HEAD> <TITLE>クエリー表示</TITLE> </HEAD> <BODY bgcolor="#FFFFFF"> <H2>クエリー表示</H2> <FORM action="printquery.cgi" method="POST"> 氏名:<INPUT type="text" name="namae"><BR> 年令:<INPUT type="text" name="age" size="10">歳<BR> 性別:<INPUT type="radio" name="sex" value="man">男性 <INPUT type="radio" name="sex" value="woman">女性<BR> 居住地域:<SELECT name="area"> <option value="1">北海道 <option value="2">東北 <option value="3">関東 <option value="4">東海 <option value="5">北陸 <option value="6">関西 <option value="7">中国 <option value="8">四国 <option value="9">九州・沖縄 <option value="99">その他 </SELECT><BR> 好きな食べ物: <INPUT type="checkbox" name="koubutsu" value="ichigo">いちご <INPUT type="checkbox" name="koubutsu" value="mikan">みかん <INPUT type="checkbox" name="koubutsu" value="ringo">りんご <INPUT type="checkbox" name="koubutsu" value="banana">ばなな<BR> <BR> 何か一言:<BR> <TEXTAREA rows="5" cols="50" name="word"></TEXTAREA><BR> <BR> <BR> <INPUT type="submit"> </FORM> <HR> <DIV align="right"><SMALL><I>Webプログラミング</I></SMALL></DIV> </BODY> </HTML> ─────── ソース2(CGI) ─────── #!/usr/bin/perl ;# ;#渡されたクエリーを表示する(printquery.cgi) ;# use strict; #==================================================# # メインルーチン # #==================================================# package main; { my %form; my $key; #--------------------------------------------------# # クエリーをデコードし取得 # #--------------------------------------------------# util::getQuery(\%form); #--------------------------------------------------# # ヘッダ表示 # #--------------------------------------------------# print "Content-type: text/html\n\n"; print <<"END_OF_HTML"; <HTML> <HEAD> <TITLE>printQuery</TITLE> </HEAD> <BODY bgcolor="#FFFFFF"> <H2 align="center">printQuery</H2> <DIV align="center"> <TABLE border="1"> END_OF_HTML #--------------------------------------------------# # クエリー表示 # #--------------------------------------------------# foreach $key ( sort keys %form ){ print qq{<TR><TD align="right">$key</TD><TD>$form{$key}</TD></TR>\n}; } #--------------------------------------------------# # フッタ表示 # #--------------------------------------------------# print <<"END_OF_HTML"; </TABLE> </DIV> <HR> <DIV align="right"><SMALL><I>Webプログラミング</I></SMALL></DIV> </BODY> </HTML> END_OF_HTML #--------------------------------------------------# # 正常終了 # #--------------------------------------------------# exit(0); } package util; #--------------------------------------------------------------# #■クエリーを取得する # 内容:GET/POST判定をしクエリーを取得する。 # URLデコード後、指定のハッシュへ格納する。 # # 引数:(1)格納先ハッシュ:リファレンス # 戻り値:なし #--------------------------------------------------------------# sub getQuery{ my $form = shift; #クエリーをセットするハッシュ(リファレンス) my $buff; my @pairs; my $pair; #-- クエリー文字列取得 --# if ($ENV{'REQUEST_METHOD'} eq "POST"){ read(STDIN, $buff, $ENV{'CONTENT_LENGTH'}); } else{ $buff = $ENV{'QUERY_STRING'}; } #-- name=valueの組み合わせに分ける --# @pairs = split(/&/, $buff); # $buffは # name1=value1&name2=value2& ... &nameN=valueN # となっているハズ #-- デコードしつつハッシュにセット --# foreach $pair ( @pairs ){ my( $name, $value ) = split(/=/, $pair); #$pairは name=value となっているハズ #-- URLデコード --# $value =~ tr/+/ /; #“+”を空白に $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # %XX を本来の # 文字コードに #-- ハッシュにセットする --# if( exists( $form->{$name} ) ) { $form->{$name} .= "," . $value; #同名の場合は','で連結する } else{ $form->{$name} = $value; } } } __END__ ─────── 実行方法 ─────── テキストエディタ(メモ帳やSimpleText)などで上記のソース(プログラム)を 保存してください。ソース1は適当な名前(xxxx.html)でOKです。ソース2は 「printquery.cgi」とすると、HTMLを変更せずにすみます。 CGIの詳しい実行方法については、Code.001をご参照ください。 http://backno.mag2.com/reader/BackBody?id=200210050820000000080329000 フォーム要素(プルダウンやラジオボタンなど)を色々といじったり、 追加・削除しつつ試してください。 ★重要! このCGIはセキュリティーホールを含みます。 学習以外の用途には使用しないでください。 ─────── 解 説 ─────── ■どんな時に必要なの?<URLエンコード デコードとはエンコードの逆の作業のことです。 というわけで、まずはURLエンコードについて学びます。 それでは、どんな時に必要になってくるのでしょうか? ここでは“エンコード不用の文字”を上げた方が理解しやすいでしょう。 ・エンコード不用の文字 (1)半角英数字 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 (2)一部の記号 * - . @ _ 例えば、以下の様な場合は問題ありません。 ・半角英数字のみ http://www.google.co.jp/search?q=WebPrograming ~~~~~~~~~~~~~ ・記号を含む http://www.google.co.jp/search?q=katsube@ichikoro.com ~~~~~~~~~~~~~~~~~~~~ ■URLエンコードのルール これ以外の文字について、以下の様なルールでエンコードを行います。 ・半角スペース 半角スペースは一律 '+' へ変換します。 name=value1 value2 ↓ name=value1+value2 ・それ以外 1byteづつ、文字コードを2桁の16進数に変換しその頭に '%' を付加する。 name=Hello! ↓ name=Hello%21 ■具体的にどうやって行うの? ・手動で行う 半角文字の場合は、ASCIIコード表と照らし合わせることで可能です。 ・e-Words:ASCII文字コード http://e-words.jp/p/r-ascii.html ※16進の列の、0xの右にある値をそのまま使います。 ・プログラム 半角の場合(で尚且つ少量の場合)は上記の方法で行えますが、大抵の場合 あまり現実的な方法とはいえません。 そんな時は ○プログラム例(Perl) print url_encode("こんにちは〜"); sub url_encode{ my $str = shift; $str =~ s/(\W)/sprintf("%%%02X", unpack("C", $1))/eg; #ここでエンコード return($str); } ○実行例(文字コードはSJIS) C:\>perl encode.pl %82%B1%82%F1%82%C9%82%BF%82%CD%81%60 といったプログラムを組むと良いかもしれません。 ※URLエンコードを行うモジュールがありますが、その解説は後日。 ■URLデコードはどうやるの? これまで解説したことの逆を行います。 つまり、 (1) '+' は半角スペースへ変換 (2) '%' の後に2桁の数値がある場合は、文字コードに変換 という作業を行えばいいわけです。 サンプル上で言えば、サブルーチンgetQuery内の下記の部分になります。 > $value =~ tr/+/ /; #“+”を空白に > $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; # %XX を本来の > # 文字コードに ■getQueryの使い方 (1) クエリーの値を使用する前に、getQueryを下記のように 呼び出します。 > #--------------------------------------------------# > # クエリーをデコードし取得 # > #--------------------------------------------------# > util::getQuery(\%form); 指定した連想配列(ハッシュ)に、クエリーが全て詰め込まれます。 この場合は %form に全て入ることになります。 では、ここからどうやって値を取り出すかと言うと、 例えばHTML上で <FORM action="〜.cgi"> <INPUT type="hidden" name="beer_middle" value="380"> <INPUT type="hidden" name="beer_big" value="500"> </FORM> というフォームの値をCGIへ渡した場合、 CGI上では util::getQuery(\%form); print "Content-type: text/plain\n\n"; print "中ジョッキは?" . $form{'beer_middle'} . "円\n"; print "大ジョッキは?" . $form{'beer_big'} . "円\n"; などと実行すると、動作が分かると思います。 ■getQueryの使い方 (2) では、同名のクエリーを渡した場合どうなるのでしょう? <FORM action="〜.cgi"> <INPUT type="checkbox" name="beer" value="big"> <INPUT type="checkbox" name="beer" value="middle"> </FORM> 下記のようなCGIを実行してみましょう。 util::getQuery(\%form); print "Content-type: text/plain\n\n"; print $form{"beer"}; ここまで解説すれば、後はgetQueryのコードを追って、 理解してください。そんなに難しくないハズです。 ─────── 次回予告 ─────── クエリーの受け渡しについて一通り解説しましたが、実はまだ問題があります。 それは「文字コード」です。 歴史的な経緯から、いくつかのコード体系が存在します。 CGIはどの文字コードで渡ってくるのか、あらかじめ知ることはできません。 そこで、次回は複数の文字コードに対応する術をご紹介したいと思います。 ─────── 分からない ─────── いまいちよく分からない場合は、以下へれっつらごー。 ・サポートBBS このメルマガ専用のサポート掲示板 http://www.ichikoro.com/webp/bbs/ ・CGIプログラミングML CGIなどWebに関する話題を繰り広げるメーリングリスト このメルマガとは何の関係もありませんので発言時は注意を。 http://www.ichikoro.com/cgi/ml/ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 編 集 後 記 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10月22日(火)の朝、大学へ願書を郵送しました。 後は小論文と面接です。 また一つ、やるべきことをやった、そう思うと気が楽になりました。 と同時に色々な思いが頭を駆け抜けました。 大学に通えば(残業代が丸々入ってこないので)収入は2/3程度になりますし、 自分の時間も減ります。その上で学費の工面。そして仕事との両立は、今私 が考えているより圧倒的にハードだと思います。 正直言うと、かなり不安です。 それでも、大学に通って、似たような人たちとワイワイ勉強している 様子を思い浮かべると、今度は期待に打ち震えそうになる自分もいる のです。 今は、やるべきことを、しっかりやろう。 後悔はしたくないですからね。 そうそう、「読むだけ小論文」という本を教えてもらって読んでいるのですが、 これが読み物としても面白いのです!小論文を書くためのノウハウ集ではなく、 「グローバル化」「豊かな社会のひづみ」など、ポイントを絞ってズバッズバッ と斬ってあるのが、非常に気持ちいいです。 サラリーマンだと、レジでちょっと勇気がいるかもしれませんが、 興味のある方はどうぞ(^-^)/ ・読むだけ小論文 (1) 大学受験ポケットシリーズ http://www.amazon.co.jp/exec/obidos/ASIN/4053011043 ※文庫本くらいの大きさです。 受験コーナーみたいなところに置いてあります。 それでは、また来週お会いしましょう (^-^)/~~ ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 【 Webプログラミング Code Sample 】 発 行 : ichikoro.com 発行責任者 : 勝部 麻季人 < katsube@ichikoro.com > Webサイト : < http://www.ichikoro.com/webp/ > お問い合わせ先 : < mm-webp@ichikoro.com > Powerd by まぐまぐ All Right Reserved, CopyRight(C) 2001 Webプログラミング Code Sample ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■