$_POST、$_GETのよくある間違い

先に言っておくと、ある程度PHPに慣れている方には読んでも価値のない内容であることをお断りしておく。
それと、mixiでも一度書いたネタなので、そちらで見た人にもあまり意味はない。が、少しだけ内容は増えている。

※色々と指摘を受けたので、それを元に書き直し作業中。
名前は挙げませんが、指摘を下さった方の指導に感謝します。

まずは御託から

$_POSTや$_GETでのチェック判定の勘違いを時々見かける。
値がきちんと入っている場合はそれほどでもない。
その値に対してチェックをかけるせいか、意識がきちんと行き届いており、ほとんどの場合間違ってはいない。


問題は、「値が入力されているか?」という存在チェックだ。
きちんとできていないと、思わぬ落とし穴になる部分にも関わらず、よく間違ったスクリプトがある。


無論、使われていても問題ないような、取るに足らないものも多い。
それらは、挙動を理解したうえで適切な場合に用いるのならばそれほど問題にはならない。
だが、理解しないで使っていると、いつかどこかでほころびが出てしまう。そして、その問題に対処できなくなるのだ。


理解さえしていれば、「つい」使ってしまい、何か問題が起きても、すぐにその箇所だと気がつける。
(それでは手遅れだ、と言うこともあるのだが。最初から正しい物だけを使う癖を付ければよいのだ)
そういう意味で、取るに足らない挙動の細部の違いを理解しておくことは、意味のあることだろう。

やっと本題

さて、まず一番最初に頭に叩き込んでおいて欲しいのが、
「$_POSTも$_GETも、ユーザーからの入力は(通常なら)文字列型になる」
ということ(あくまでも、不正な入力でない場合だ。不正な入力の場合に他の型を持ち得るかは私は知らない。)
と、
PHPは弱い型変換をする言語である」
ということだ。


ぽかーん、とされるかもしれない。
そんなこと、当たり前だ。常識なのだ。
だが、意外と間違えている人が多いのだ。
説明自体は、ただの関数の挙動の話になるだろう。
どれも当たり前の話だが、$_POST、$_GETの挙動への先入観のためにその「当たり前」を勘違いしてしまう。


では、よくある間違いと、それがどういう部分でまずいのかを連ねていこう。
ちなみに、労力を減らすためtrim()は省略。$_POST、$_GETの両方は大変なので、$_POSTのみで。
(先頭にifが付いているのは、可読性のため。)


※考え落ちを指摘されてしまったが、POST値の判定をする前にPOSTされたかどうかの判定をしておかないと、NOTICEが出るものが多々。
申し訳ない限りです。とりあえず、POSTの値があるかどうかの判定、ということで読んでください。

if ($_POST["hoge"]) ...

暗黙の変換なので忘れがちだが、これはbooleanへのキャストが行われている。
以下の全てにわたってそうなのだが、これはPOSTされた値を直にキャストする。


従って、フォームの内容が空("")でも0("0")でも、falseになる。他の値が入っていれば、trueだ。
テキストフォームはいい。が、セレクトボックスでこれをやったら笑うしかない。
だが、これが使われている例は多い。

if (isset($_POST["hoge"])) ...

isset()は、その変数が定義されているかどうかだ。
つまり、name="hoge"でPOSTするフォームがある時点で、GETのストリングにhoge=がある時点で、値に関わらずこの判定はtrueだ。
従って、POST値の存在判定には使用できない。判定できるのは、POST動作がされたかどうかだ。
POST値の判定にこれを用いたら、まずい。

if (empty($_POST["hoge"])...

これが意外とフェイク。
empty()は空文字列がtrueになるが、困ったことに"0"もtrueとして扱うのだ。他の値が入力されれば、falseだ。
最初の単純なbooleanへのキャストの逆の動作をすることになる。

if (is_null($_POST["hoge"]) ...

これは・・・もう言うまでもないだろう。
何をPOSTしてもfalseだ。これもPOST動作が行われたかどうかを判定するのにしか使えない。

if (count($_POST) > 0)...
if (sizeof($_POST) > 0)...

こんなものも見かけた。個別チェックではないから、少し趣旨が違うのだが。
これも、出来ることはPOSTの動作判定だけだ。
buttonに名前が付いていれば当然それも拾うし、form名の指定がないので用途が狭い。
それに、どこから来たのかわからないPOSTもtrueで通してしまうのだ。
カッコよく書いたつもりが赤っ恥だ。
無論、POSTがされたかどうか自体を知りたいならこれらも良い。
が、値の判定時に使うものではない。

では、正しい判定法は何がある?

理屈まで含めてもっとも良いのは

if ($_POST["hoge"] === "")...

だ。なお、"0"と""はゆるい型変換でも等価とみなされないので

if ($_POST["hoge"] == "")....

でもよい。empty()の場合とは違うので注意。


また、少し知ったかぶって書こうとするなら

if (strlen($_POST["hoge"])...

が余計な記号がなくていいかもしれない。
このあたりは、文字列関数でなんとでも書きようはありそうだが。

最後に

また、どうでもいい事を長々書いてしまった。
まだ足りないものもあるだろうし、記述が完全でないものもあるだろう。
だが、これを通じて各種動作への配慮が行われるようになれば、それで本記事の役割は十分果たしたことになる。


本当に些細な事だが、こういった事にも自然と気を配れる用になるのは、大事なことではないだろうか。