PHPでPOSTの生データを扱う

下書き保存したと思ってたらそんなものは無かった・・・
何を書いてたのやら思い出しつつ書き直してみる。
なんとなく覚えてるんですよ。うっすらと。
多分あれだ、PHPチェックボックスとかラジオボタンとか扱う時の話。

下書き保存してたはずなのに記事が無かったのは何故?
<form method="post">
	<input type="checkbox" name="chk" value="1" />下書きしたと思い込んでるだけ
	<input type="checkbox" name="chk" value="2" />雪のせい
	<input type="checkbox" name="chk" value="3" />電池が切れた
	<input type="checkbox" name="chk" value="4" />ネジが外れた
	<input type="submit" value="下書きは忘れずに!" />
</form>

こんな風にnameを同じ値に揃えるとグループ化できるけど、
複数にチェック入れた状態でPHPに値を渡すと最後にチェックした値だけが返ってくるんですよ。


なのでそれを回避するためにnameをちょっぴり細工するのが流行ってます。

下書き保存してたはずなのに記事が無かったのは何故?
<form method="post">
	<input type="checkbox" name="chk[]" value="1" />下書きしたと思い込んでるだけ
	<input type="checkbox" name="chk[]" value="2" />雪のせい
	<input type="checkbox" name="chk[]" value="3" />電池が切れた
	<input type="checkbox" name="chk[]" value="4" />ネジが外れた
	<input type="submit" value="下書きは忘れずに!" />
</form>

nameをchkからchkにしてあげるとPHP側で配列と解釈されて複数チェックしたものがちゃんと配列に格納されます。
が、しかしこんなへんてこりんな書き方すると今度はJavaScriptがとばっちりを受けるからやんなっちゃう。


name="chk"だとdocument.form[0].chk[0].valueで1が取得できるが、name="chk"の時はエラーになる。
というのもchkまで含めてnameとみなされるから、document.form[0]["chk[]"][0].valueな風に書かなきゃ値が取れない。
なんだそりゃって感じですよねー
それもこれも$_POSTのあんちくしょうのせいだってんでPOSTの生データを取ってやろうということです。


なんとまぁ長い前振りだこと。前書いた時よりも断然長くなってる気がする。
てことで結論はさらりと流す方向であっさり書くと、PHPでPOSTの生データを取得するにはphp://inputってのを使えば簡単です。
ソースはこんな感じ。

<?php
	$posts = file_get_contents('php://input');
?>

これでPOSTしたデータがGETした時のQUERY_STRINGみたいに取得できます。
キー=値のセットが&で連結されてるので(例:chk=1&chk=3&chk=4)てきとーに分割してやって、キーが同じなら配列にしちゃえば完成!
全体のソースはこんな感じ。

<?php
	$posts = explode('&', urldecode(file_get_contents('php://input')));
	foreach($posts as $buf){
		list($key, $val) = explode('=', $buf);
		if(isset($post[$key])){
			if(is_array($post[$key])){
				array_push($post[$key], $val);
			}else{
				$post[$key] = array($post[$key], $val);
			}
		}else{
			$post[$key] = $val;
		}
	}
?>

しかしこの方式には一つ大きな弱点が・・・
formのenctypeがmultipart/form-dataの時は値が取ってこれない!!!!
すなわちファイルのアップロード用フォームなんかでは全く使いもんにならんっちゅう話です。
PHP使うのもうやめようかな、、、(下書き保存はもう二度と使わない)


参考:
PHP: PHP 入出力ストリーム - Manual