とあるエンジニアの闇歴史帳

コピペで使える便利Wiki ※現在構築中です。

ユーザ用ツール


webp:vol49

差分

このページの2つのバージョン間の差分を表示します。

この比較画面にリンクする

webp:vol49 [2020/06/23 14:10] (現在)
行 1: 行 1:
 +====== Code.004 CGI(Perl)基本動作 その4:「URLエンコード・デコード」 ======
 +<html><pre style="font-family:monospace; font-size:10pt">
 +   Code.004                                                 2002年10月28日発行
 +■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■
 +                           【 Webプログラミング 】
  
 +                       〜 猫的プログラマーとその軌跡 〜
 +■━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━■
 +
 +              ▼毎週月曜日に配信しています。
 +              ▼等幅フォントでご覧いただくとキレイに見えます。
 +              ▼登録・解除はこちらから可能です。
 +                &lt; http://www.ichikoro.com/webp/ &gt;
 +                  ※ぜひお友達にもご紹介ください(^^)/
 +
 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 + 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)
 +───────
 +&lt;HTML&gt;
 +&lt;HEAD&gt;
 +    &lt;TITLE&gt;クエリー表示&lt;/TITLE&gt;
 +&lt;/HEAD&gt;
 +&lt;BODY bgcolor="#FFFFFF"&gt;
 +
 +&lt;H2&gt;クエリー表示&lt;/H2&gt;
 +
 +&lt;FORM action="printquery.cgi" method="POST"&gt;
 +    氏名:&lt;INPUT type="text" name="namae"&gt;&lt;BR&gt;
 +    年令:&lt;INPUT type="text" name="age" size="10"&gt;歳&lt;BR&gt;
 +    性別:&lt;INPUT type="radio" name="sex" value="man"&gt;男性 
 +          &lt;INPUT type="radio" name="sex" value="woman"&gt;女性&lt;BR&gt;
 +    居住地域:&lt;SELECT name="area"&gt;
 +                    &lt;option value="1"&gt;北海道
 +                    &lt;option value="2"&gt;東北
 +                    &lt;option value="3"&gt;関東
 +                    &lt;option value="4"&gt;東海
 +                    &lt;option value="5"&gt;北陸
 +                    &lt;option value="6"&gt;関西
 +                    &lt;option value="7"&gt;中国
 +                    &lt;option value="8"&gt;四国
 +                    &lt;option value="9"&gt;九州・沖縄
 +                    &lt;option value="99"&gt;その他
 +            &lt;/SELECT&gt;&lt;BR&gt;
 +
 +    好きな食べ物:
 +        &lt;INPUT type="checkbox" name="koubutsu" value="ichigo"&gt;いちご 
 +        &lt;INPUT type="checkbox" name="koubutsu" value="mikan"&gt;みかん 
 +        &lt;INPUT type="checkbox" name="koubutsu" value="ringo"&gt;りんご 
 +        &lt;INPUT type="checkbox" name="koubutsu" value="banana"&gt;ばなな&lt;BR&gt;
 +    &lt;BR&gt;
 +    何か一言:&lt;BR&gt;
 +    &lt;TEXTAREA rows="5" cols="50" name="word"&gt;&lt;/TEXTAREA&gt;&lt;BR&gt;
 +    &lt;BR&gt;
 +    &lt;BR&gt;
 +    &lt;INPUT type="submit"&gt;
 +&lt;/FORM&gt;
 +
 +&lt;HR&gt;
 +&lt;DIV align="right"&gt;&lt;SMALL&gt;&lt;I&gt;Webプログラミング&lt;/I&gt;&lt;/SMALL&gt;&lt;/DIV&gt;
 +
 +&lt;/BODY&gt;
 +&lt;/HTML&gt;
 +
 +
 +───────
 + ソース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 &lt;&lt;"END_OF_HTML";
 +&lt;HTML&gt;
 +&lt;HEAD&gt;
 +    &lt;TITLE&gt;printQuery&lt;/TITLE&gt;
 +&lt;/HEAD&gt;
 +&lt;BODY bgcolor="#FFFFFF"&gt;
 +
 +&lt;H2 align="center"&gt;printQuery&lt;/H2&gt;
 +&lt;DIV align="center"&gt;
 +&lt;TABLE border="1"&gt;
 +END_OF_HTML
 +
 +    #--------------------------------------------------#
 +    #                   クエリー表示                   #
 +    #--------------------------------------------------#
 +    foreach $key ( sort keys %form ){
 +        print qq{&lt;TR&gt;&lt;TD align="right"&gt;$key&lt;/TD&gt;&lt;TD&gt;$form{$key}&lt;/TD&gt;&lt;/TR&gt;\n};
 +    }
 +
 +
 +    #--------------------------------------------------#
 +    #                   フッタ表示                     #
 +    #--------------------------------------------------#
 +    print &lt;&lt;"END_OF_HTML";
 +&lt;/TABLE&gt;
 +&lt;/DIV&gt;
 +
 +&lt;HR&gt;
 +&lt;DIV align="right"&gt;&lt;SMALL&gt;&lt;I&gt;Webプログラミング&lt;/I&gt;&lt;/SMALL&gt;&lt;/DIV&gt;
 +
 +&lt;/BODY&gt;
 +&lt;/HTML&gt;
 +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(/&amp;/, $buff);      # $buffは
 +                                     #     name1=value1&amp;name2=value2&amp; ... &amp;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-&gt;{$name} ) ) {
 +            $form-&gt;{$name} .= "," . $value;        #同名の場合は','で連結する
 +        }
 +        else{
 +            $form-&gt;{$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:\&gt;perl encode.pl
 +                %82%B1%82%F1%82%C9%82%BF%82%CD%81%60
 +
 +        といったプログラムを組むと良いかもしれません。
 +            ※URLエンコードを行うモジュールがありますが、その解説は後日。
 +
 +
 +■URLデコードはどうやるの?
 +
 +    これまで解説したことの逆を行います。
 +    つまり、
 +
 +        (1) '+' は半角スペースへ変換
 +        (2) '%' の後に2桁の数値がある場合は、文字コードに変換
 +
 +    という作業を行えばいいわけです。
 +    サンプル上で言えば、サブルーチンgetQuery内の下記の部分になります。
 +
 +&gt;        $value =~ tr/+/ /;    #“+”を空白に
 +&gt;        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;   # %XX を本来の
 +&gt;                                                                       # 文字コードに
 +
 +
 +■getQueryの使い方 (1)
 +
 +    クエリーの値を使用する前に、getQueryを下記のように
 +    呼び出します。
 +
 +&gt;    #--------------------------------------------------#
 +&gt;    #             クエリーをデコードし取得             #
 +&gt;    #--------------------------------------------------#
 +&gt;    util::getQuery(\%form);
 +
 +    指定した連想配列(ハッシュ)に、クエリーが全て詰め込まれます。
 +    この場合は %form に全て入ることになります。
 +
 +    では、ここからどうやって値を取り出すかと言うと、
 +    例えばHTML上で
 +
 +        &lt;FORM action="〜.cgi"&gt;
 +            &lt;INPUT type="hidden" name="beer_middle" value="380"&gt;
 +            &lt;INPUT type="hidden" name="beer_big"    value="500"&gt;
 +        &lt;/FORM&gt;
 +
 +    というフォームの値をCGIへ渡した場合、
 +    CGI上では
 +
 +        util::getQuery(\%form);
 +
 +        print "Content-type: text/plain\n\n";
 +        print "中ジョッキは?" . $form{'beer_middle'} . "円\n";
 +        print "大ジョッキは?" . $form{'beer_big'   . "円\n";
 +
 +    などと実行すると、動作が分かると思います。
 +
 +
 +■getQueryの使い方 (2)
 +    では、同名のクエリーを渡した場合どうなるのでしょう?
 +
 +        &lt;FORM action="〜.cgi"&gt;
 +            &lt;INPUT type="checkbox" name="beer" value="big"&gt;
 +            &lt;INPUT type="checkbox" name="beer" value="middle"&gt;
 +        &lt;/FORM&gt;
 +
 +    下記のような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
 +                発行責任者 : 勝部 麻季人
 +                              &lt; mailto:katsube@ichikoro.com &gt;
 +                 Webサイト : &lt; http://www.ichikoro.com/webp/ &gt;
 +            お問い合わせ先 : &lt; mailto:mm-webp@ichikoro.com &gt;
 +
 +                            Powerd by まぐまぐ
 +    All Right Reserved, CopyRight(C) 2001 Webプログラミング Code Sample
 +■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
 +</pre></html>

関連ページ

webp/vol49.txt · 最終更新: 2020/06/23 14:10 (外部編集)