トップ
新規
一覧
Farm
検索
ヘルプ
RSS
ログイン
sub decodeの編集
!!!sub decode 目次 {{outline}} !!はじめに ここではSOSIIがCGIとして動作するための要となるsub decodeについて解説します。 sub decodeでは主に *URLのデコード *文字コードのコンバート *HTMLタグの無効化 *スプリッターとして使用する文字列のエスケープ を行っています。 !!ソースコードの解説 # Sub Decode # sub decode { if ($ENV{'REQUEST_METHOD'} eq "POST") { まず環境変数からファイルメソッドPOSTまたはGETを評価します。 $post = 1; POSTメソッドであった場合、$postという変数に1を代入しフラグを立てます。 Ver.1.10の場合、$post変数が真でなければ多くのサブルーチンが実行できません。 これは不正行為への対策と思われます。 read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); STDINで入力されたフォームデータをファイルハンドルによりCONTENT_LENGTHの長さ(ようするに全て)読み込み、$bufferに代入します。 @pairs = split(/&/, $buffer); $bufferに代入されたフォームデータをsplit関数で、&をスプリッターとして分解し@pairsという配列に格納します。 例としてフォームデータが「id=0000&ps=PASS&nm=NAME」であった場合 *@pairs = (id=0000,ps=PASS,nm=NAME); となります。 } else { @pairs = split(/&/, $ENV{'QUERY_STRING'}); } GETであった場合、上と同じくQUERY_STRINGを@pairsという配列に格納します。 QUERY_STRINGはフォームデータ自体が格納されていますので、ファイルハンドルによる操作は不要になります。 foreach $pair (@pairs) { foreach構文によるループ構文で@pairs配列を展開します。 $pairには@pairsの要素が順に代入されてゆきます。 ループは@pairsの要素の数だけ繰り返して行われます。 ($name, $value) = split(/=/, $pair); $pairに代入された変数をsplit関数で、今度は=をスプリッターとして分解します。 分解されたものは、それぞれ$name、$valueという変数に代入されます。 例として$pairが「id=0000」であった場合 *$name = id; *$value = 0000; となります。 $value =~ tr/+/ /; tr///演算子を使いパターンマッチによる置き換えを行っています。 +という文字を (半角スペース)に変換しています。 URLエンコードのさい、送られてくるデータの半角スペースが+に置き換えられてCGIに渡されるためこのような変換が必要になります。 $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; s///演算子を使いパターンマッチによる置き換えを行っています。 日本語の文字列はURLエンコードによって%xxという形でフォームに送られます。 これをpack関数でもとの文字列に置き換えています。 $1には左側の一番目の括弧([a-fA-F0-9][a-fA-F0-9])にマッチした内容が入ります。 オプションeは右側の評価を行います。 上の式の場合、置き換えを行う前にpack("C", hex($1))を実行し、その評価結果を置き換えの対象としています。 オプションgは繰り返し置き換えを行います。 上の式の場合、%xxという形式の文字列をすべて置き換えるまで実行しています。 &jcode'convert(*value,'sjis'); $valueの変数を日本語コード(Shift-JIS)に変換しています。 *&jcode'convert(*スカラ,"文字コード"); というのはjcode.plというライブラリに入っている命令文です。 スカラを文字コードのタイプへと変換します。 $value =~ s/</</g; $value =~ s/>/>/g; $value =~ s/"/"/g; $value =~ s/\,/,/g; $value =~ s/△/▲/g; $value =~ s/\r\n/<br>/g; $value =~ s/\r/<br>/g; $value =~ s/\n/<br>/g; $valueに代入された一意の文字を置き換えています。 HTMLタグや改行コード、システム上スプリッターとして使用している文字等が該当しています。 $Fm{$name} = $value; フォームで送信された値を最終的な形($Fm{'hoge'})として代入しています。 *$Fm{'id'}; という形は%Fmという連想配列(ハッシュ)の参照です。 *id=0000(<input type=hidden name=id value=0000>) であるならば *$Fm{'id'} = 0000; となります。これは%Fmというハッシュのキー値idに対してペア値0000を代入している式になります。 この部分がSOSIIの汎用性の高さを物語っていると、勝手に思っています。 } } !!実際の動き <input type=hidden name=nm value=なまえ> <input type=hidden name=ps value=ぱす> 上記のようなフォームであった場合、これをスクリプトへ送信すると、クエリーは「nm=なまえ&ps=ぱす」となります。 この時、URLエンコードが行われ、実際の文字列は「nm=%82%C8%82%DC%82%A6&ps=%82%CF%82%B7」と変換されます。 この文字列がファイルハンドルにより$bufferに代入されます。 $buffer = 'nm=%82%C8%82%DC%82%A6&ps=%82%CF%82%B7'; $bufferは分割され@pairsに格納されます。 @pairs = (nm=%82%C8%82%DC%82%A6,ps=%82%CF%82%B7); ループにより@pairsの要素を順に評価していきます。 $pairへ代入された要素をさらに分割し、$nameと$valueに代入されます。 $name = 'nm'; $value = '%82%C8%82%DC%82%A6'; $valueの置き換えを行います。 $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; に当てはめた場合、gオプションによって $value =~ s/%82/pack("C", hex(82))/e; $value =~ s/%C8/pack("C", hex(C8))/e; $value =~ s/%82/pack("C", hex(82))/e; $value =~ s/%DC/pack("C", hex(DC))/e; $value =~ s/%82/pack("C", hex(82))/e; $value =~ s/%A6/pack("C", hex(A6))/e; このようになるはずです。 しかし、実際には $value =~ s/%82%C8/pack("C2", hex(82), hex(C8))/e; # pack("C2", hex(82), hex(C8)) = な $value =~ s/%82%DC/pack("C2", hex(82), hex(DC))/e; # pack("C2", hex(82), hex(DC)) = ま $value =~ s/%82%A6/pack("C2", hex(82), hex(A6))/e; # pack("C2", hex(82), hex(A6)) = え と同じ動作をしているようです。 eオプションで右側式の評価結果に置き換えられますので、最終的には $value = 'なまえ'; となります。 ここまでで(URLエンコードに対する)URLデコードが終了します。 これがデコードの必要性です。 さらに$valueはコンピューターで扱うための文字、Shift-JISにコンバートされます。 $valueに一意の置き換えを行った後、%Fmというハッシュに格納されます。 ループ構文を繰り返し最終的にすべての$pairをハッシュに格納します。 %Fm = ('nm','なまえ','ps','ぱす'); このハッシュを各々のルーチン内でフォームで送信された情報として参照します。 %Fm{'nm'} = 'なまえ'; %Fm{'ps'} = 'ぱす'; !!キーワード解説 $ENV{'hoge'} は環境変数を表します。 環境変数とはクライアント(プレイヤー)側の情報で、%ENVという連想配列に格納されます。 !REQUEST_METHOD スクリプト(CGI)へのデータの受け渡し方法(GETまたはPOST)を格納しています。 !CONTENT_LENGTH POSTによるフォームデータの長さ(バイト数)を格納しています。 !QUERY_STRINGS GETによるフォームデータそのものを格納しています。 !read関数(read FILEHANDLE, SCALAR, LENGTH, [OFFSET]) ファイルハンドルからデータを読み込む関数です。 FILEHANDLEからLENGTH分の長さのデータを読み取りSCALARに代入します。 OFFSETを指定することで任意の部分からLENGTH分の長さの読み出しが可能になります。 !STDIN 標準入力の意味で、パソコンの場合はキーボード入力が標準入力デバイスとして指定されています。 FILEHANDLEが指定されなかった場合もSTDINになります。 !split関数(split /PATTERN/, [EXPR, LIMIT]) PATTERNをスプリッターとしてEXPRを分解します。 LIMITを指定することで分解する最大数を指定することができます。 !foreach構文(foreach SCALAR ( LIST ) { BLOCK }) LISTを順にSCALARへと代入し、BLOCKを実行します。 LISTのからの代入が終了した時点でループは終了します。 !pack関数(pack TEMPLATE, LIST) LISTをTEMPLATEで指定したフォーマット文字によりパック(変換)します。 長いし複雑なので省略します。 ただし日本語のデコード操作には必須です。 !hex関数(hex EXPR) EXPRを16進数と解釈し、10進数へと変換します。 !tr///演算子(tr/SEARCH/REPLACE/cds) 検索文字SEARCHに含まれる各文字を置き換え文字REPLACEに一文字ずつ置き換えます。 この場合の一文字ずつ置き換えるとは、例えば $str = 'ABACBC'; $str =~ tr/ABC/DEF/; のとき、tr演算子はAをDに、BをEに、CをFに置き換えます。結果は print $str; # DEDFEF となります。 tr///演算子の詳しい動作、オプションについては省略します。 ※SEARCH、REPLACE とも、正規表現ではないので注意。 !s///演算子(s/PATTERN/REPLACE/egimosx) 検索文字PATTERNを使って検索を行い、PATTERNにマッチする文字が見つかればREPLACEで置き換えます。 s///演算子の詳しい動作、オプションについては省略します。 ※SEARCH は正規表現、REPLACE は正規表現ではないので注意。 !!関連項目 *コラム ----
タイムスタンプを更新しない
添付ファイル
リネーム・コピー
リネーム
メッセージを残してリネーム
コピー
[
ヘルプ
]
Counter 713209
はじめに
SOS2 Wikiの使い方
コンテンツ
SOS2を設置する
SOS2を改造する
困ったときには
コラム
改造&FAQ
リファレンスマニュアル
機能別改造一覧
雑談
BBS
Masters Bar
公式BBS
サポート
サポートBBS
Link
リンク
SIONJamの改造ソース
設置サイトはこちらへ
検索
キーワード
AND
OR
ページ内容も含める
最近更新されたページ
雑談
Script of Saga II Wiki
パーティシステム
D2C風、レアアイテム生成システム
洋ゲー風、拾得アイテム強化プログラム
SOSIIを分割しよう
戦闘関連強化・特技&魔法
SOSII Check Script
乱数ロールプログラム
不具合情報
参照数の多いページ
Script of Saga II Wiki
(75206)
リンク
(16503)
SOS2を設置する
(12584)
雑談
(11984)
SOS2改造利用規約
(9825)