PHPのPOSTパラメータ数の上限トラップ

  • 26
    いいね
  • 3
    コメント

PHPでウェブなことしてると $_POST を空気のように使っていますが、この子は時として牙を剥きます。

POSTパラメータ数には上限値がある

人間が入力する程度のフォームならば普段は気にならないんですが、常軌を逸するような数のhiddenが搭載されたフォームだったり、APIやスクリプトやなんかでcurl等使って直接POSTリクエストを発生させるようなものがあったりすると、人知の及ばぬ大量のパラメータが飛び交うことになります。
このとき、運悪くPHP先生の限界を超えてしまうと上限数以降がカットされるという事態になり、それはそれは残念な結果になることもあります。ていうかなりました。
いちおう、カットが発生した場合はE_WARNINGが発生しますので、ちゃんとエラーレベル引き上げておきましょう。

こんなエラー。

error.log
PHP Warning:  Unknown: Input variables exceeded 1000. To increase the limit change max_input_vars in php.ini. in Unknown on line 0

PHPの設定

max_input_vars っていうまさにPOSTパラメータ数の上限値を設定しているパラメータがあります。デフォルトは1000になっていますので、もっと引き上げれば許容値を引き上げる事ができます。
というわけで該当プログラムの最初でini_set()すればおっけぃ!とやってみると、

Sample
~$ php -r "var_dump(ini_set('max_input_vars', 2000));"
bool(false)

できません。
調べてみると、PHP_INI_PERDIRとなっているため、スクリプトからは設定を変える事ができないようです。まぁ考えてみたらスクリプト入ってきてる時点で $_POST はできあがっているので、その後に設定変えても意味ないよね、っていう。

参考:http://www.php.net/manual/ja/ini.list.php

というわけでこのパラメータを変える場合は、PHPの設定ファイルかウェブサーバの設定から変えましょう。

php.ini
max_input_vars = 2000
apache.confもしくは.htaccess
php_value max_input_vars 2000

これでとりいそぎ大丈夫ですが、将来さらにパラメータ数が増えたときにまた上限値を引き上げなければならないということも考えられます。さらに言い始めるとこの設定値自体にも上限が存在する可能性が・・とか考えだすとキリがないので根本的な解決が欲しいところ。

$_POST を使わないという選択肢

$_POSTちゃんは気が効く反面、頑張りすぎてキャパオーバーしてしまうので、そのときには休んでもらいましょう。

幸運なことに、php://inputという定義済みなストリームがあり、リクエストボディを直接参照できます。POSTの場合でもbodyを直接見ると、hoge=xxx&hoge2=nnn のように普段見慣れたGETクエリと同様の形式でPOSTされたデータが繋がって格納されていますのでこれをパースしてあげましょう。

これまた幸運なことにparse_strっていうクエリ文字列をパースしてくれる関数が用意されているのでらくちんです。

samplePost.php
$rawdata = file_get_contents('php://input');
parse_str($rawdata, $postData); 

んでもってこれを走らせると怒られます

Warning: parse_str(): Input variables exceeded 1000. To increase the limit change max_input_vars in php.ini.

parse_str、お前もか。
っていうかたぶん$_POSTにぶっこむときに内部でこれ使ってるんでしょうかねぇ・・・。

というわけで全部自力でやるしかないようです。
こんなかんじ。

samplePostVer2.php
// 難しいことを考えずに作ったやつなので
// セパレータ文字が混ざってたりするとおかしくなるかも。
$postData = array();
$rawdata = file_get_contents('php://input');
foreach (explode('&', trim($rawdata)) as $data) {
    list ($key, $value) = explode('=', $data);
    $postData[$key] = $value;
}

なんだか昔のPerl CGI時代を思い出しますなぁ(懐古)。

おわりに

この上限値のことを知らなかったので一人でハマってたんですが、正直自分でトラップ発動を食らわないとこういう細かな設定群は覚えられないので、大事故になる前に発覚してよかったです(言い訳)。

ただ自分がこれで困ってググって出てきた記事が、設定値を引き上げる方法しか書いてないものばかりだったので、参考までに根本解決をする方法として紹介してみた次第です。参考になれれば幸いです。