入力されたデータに従って処理が変わってくる、これがサーバサイド処理(CGI,PHPなど)の醍醐味ですからまずはデータ取得から考えていきましょ
CGIの場合 ...取得したデータをまず文字に直す(URLデコード処理)
PHPの場合 ...取得したデータは既に文字に直されている。
ということで、便利な配列$_REQUESTから取得するだけで済みます。もう七面鳥は焼き上がっていてあとは食べるだけといった感じでしょうか
$data = $_REQUEST['key1']; // key1のデータを変数$dataへ代入
if ($_REQUEST['key2'] == '壷') // key2のデータが"壷"かどうか
といった感じで使っていくことになります。
しかーし!
設定にもよりますがPHPでは存在しない(未定義の)データを参照しようとすると警告が出るようになっています。
そこでこの警告を回避するためにも事前に未定義かどうかのチェックをする必要があります。
間違っても設定で警告を出さないようになどと思ってはいけません。それは邪教です。
そこで下記の関数を用意することで、もし未定義ならば自動的に空文字を返すようにすればいいわけです。
isset()という関数(正しくは言語構造)は非常に便利で、未定義の変数でも警告を出さずにチェックしてくれます。
これと似たものにempty()というこれまた便利なものもあります。
と、ここまでは、取得しようとしているデータが未定義(送信されてきていない)なのかも知れない。
食べようと思った七面鳥が実はCG映像なのかも知れない。
ということのチェックでした。
しかし待ってください。どこの誰が送ってきたかわからないデータですよ、まだチェックすべき項目はあります。
では文字コードをチェックしましょう。
一般に、画面表示に使用した文字コードと同一の文字コードでブラウザからは送られてくるものですが絶対というわけではありません。
そこで、どんな文字コードで送られてきてもサーバ側スクリプトで使う文字コード(ここではシフトJIS)に変換しちゃえばいいわけです。
mb_convert_variables()関数は、配列の中身でも一気に変換してくれます。注目すべきはごく短いデータだと文字コードの誤判別が起こりやすいので、内部で全データをつなげてトータルで文字コードを判別してくれる点です。
元の文字コードが判別できなかったり、日本語に変換できないようなデータ(外国の文字やバイナリなど)ならば公式マニュアルではfalseを返すと書いてありますが、わたしの環境だと文字列"pass"を返します。
『SJIS-win』は、現状ではより多くの環境依存文字に対応したシフトJISの指定子です。
『UTF-8』は、言うまでもありません、最近流行りですね。
『CP51932』は、現状ではより多くの環境依存文字に対応した日本語EUCの指定子です。
『JIS』は、わずかな可能性でも拾うぞという意気込みの表れです。
シフトJIS画面表示なので、可能性として一番高いSJIS-winを先頭に書いています。
次に流行りもののUTF-8を書いておきます。
シフトJISと日本語EUCの間では誤判別の問題がありますが、シフトJISのハンカクのみ入力が、日本語EUCの小難しい漢字のみよりも入力される確率が高いのでシフトJISが先というのを考慮しています。
これで、どこの誰が焼いたかわからない七面鳥の丸焼きは自分好みの味にすることができました。
上記は見落としがありました。
どうやらmb系を使って文字コード判別させる際には、"ASCII,JIS,UTF-8"から判別させるように書かないと誤判別の可能性が高くなるようです。
なので書き直すとしたら
でも好みの味付けでも、毒を盛られている可能性があります。
期待していたデータ以外が送られてきたら、これはある種の攻撃(なんとかインジェクション系)かも知れません
これに関しては、次項のバリデーションにて考えるとしましょう。
**福音書その1**
フォームがGET送信指定のデータは$_GETから取得し、POST送信指定のデータは$_POSTから取得すべきという宗派があります。
つまりGETとPOSTどちらでも取得できる便利な$_REQUESTを全否定ということです。
確かに気持ちはわかりますが、ウェブ送信ではこちらの期待に関係なくGETでもPOSTでもCOOKIEでもどうにでも送れてしまいます。
だとしたら、GETで送信されてきたかPOSTで送信されてきたかを分けて書くよりも、結局やるであろうバリデーション(次項でやります)をしっかりやった方がスマートなやり方だとわたしの宗教では洗脳することとします。
入力された値をサーバ側で取得したら、その値が妥当なのかどうかすべてチェックする必要があります。
入信を希望する人物が異教徒かも知れないのでその素性を調べ上げることは非常に大事なことです。
これをうまくやれば、なんちゃらインジェクション系の攻撃を未然に防げることでしょう。
まずは必須入力のチェック。先ほど書いたreq()関数を使います。
req()関数を使って取得して、空文字列かどうかチェックするだけで済みます。
比較演算子"==="は、型の一致(この場合文字列を示すsrting型であること)も同一でないとハネてしまうので処理が速いです。
一方、比較演算子"=="は、型が違っても値が同じなら真を返します。(文字列として比較したら違ったから次は数値として比較しようとする分の変換作業に時間がかかるのは当然ですね)
では今度は数値の場合を考えていきます。期待する入力値はいろんなパターンが考えられます。
- num値は空でもいいのかどうか(必須入力かどうか)
- 期待した半角数字が入力されたかどうか
- 数字は0から始まるもの(001 002など)はいいのか
- 数字の範囲はどうなのか(最大桁数)
以上に基づいて考えていくと
このように、バリデーションではpreg_match()関数使いまくりになります。
しかもD修飾子付きが目立ちますがこれは$が末尾改行にマッチしないようにするためです。
先に書いたreq()関数を使って値を取得する場合、数値を期待するなら
このようにトリミングをしてからチェックしてあげた方がより親切かも知れません。
(入力時にうっかり空白入れてしまう人対策)
あとmaxlength属性値を設定していたところで簡単に乗り越えられてくるという前提で考えれば、あくまでもmaxlengthは飾りとして書いたぐらいのつもりで結局はバリデーションをきっちりやるということを常に意識しておけばよござんす。
余興として日本語(シフトJIS)のいろいろなマッチでも書いておきます。
シフトJISおよびアスキー文字にマッチ
▼ シフトJISの文字コード解剖
範囲 | 正規表現 | 備考 |
[ぁ-ん] | \x82[\x9F-\xF1] | 「かな」文字 |
[、] | \x81\x41 | 読点 |
[。] | \x81\x42 | 句点 |
[ー\] | \x81\x5B | 2バイト目が正規表現メタ文字の"["とかち合うので直接文字として書く場合は要エスケープ |
[ァ-ヶ] | \x83[\x40-\x96] | 「カナ」文字 |
[0-9] | \x82[\x4F-\x58] | 全角数字 |
[A-Z] | \x82[\x60-\x79] | 全角英大文字 |
[a-z] | \x82[\x81-\x9A] | 全角英小文字 |
[。-゚] | [\xA1-\xDF] | 半角カナ |
これを踏まえて、いろいろ書いて行きまっせ
よく掲示板とかで日本語文字が入力されてこなかったら弾くみたいな処理がありますが、一番下のなんかまさにそれですね。