【PHP, JavaScript】POSTデータが多すぎてエラーになったときにとった対応
画面からユーザーの入力値をPOSTするプログラムで500エラーが発生し、エラーログを確認すると以下のメッセージを吐いていました。
このエラーはユーザーの入力値が多すぎて、submitしたときサーバー側で弾かれているエラーで、しきい値は php.ini の以下で設定できます。
しかし本来セキュリティの観点から、この値は抑えられている(デフォルトは1000)ケースがあります。その場合は、フロント側で吸収する必要があるためその方法をまとめます。※あくまで一つの例なので他に良い方法があるかもしれません。
今回発生したケースでは、ユーザーや店舗などの設定値を縦に並べて一括で更新するという処理で、100は余裕で超えてしまうため対応を行いました。
これはユーザーの年齢を一括で更新する例で、submitするとユーザーIDをキーに持った連想配列で年齢がPOSTされます。
この場合、ユーザー数に依存してPOSTデータの数が増えていき、ユーザー数が100を超えたとき前述のエラーとなります。
まず入力値のinputタグをformの外へ出します。これをしないと結局 submit で全部サーバーに送られてしまいます。
次にJSでformのsubmitイベントをハンドリングするため、id属性を付与します。
さらにPOSTするjson用の項目(hidden)をformに用意します。
入力値になるinputタグにはカスタム属性(data-user-id)を追加します。これによりJS側で入力値に対するユーザーIDが特定できます。
get_values関数はリスト形式で定義されたinputタグを {user_id : value, user_id : value, ...} の形式で取得する関数で、こうしておけば新たな項目が増えても即対応できます。
これでひとまとめにした入力値のjsonをhiddenで用意した領域にセットしてsubmitしてやります。
サーバー側ではPOSTデータのinput_dataに修正前と同じ形で入って来るので、同じValidationを通してやれば良いわけです。
*413 FastCGI sent in stderr: "PHP message: PHP Warning: Unknown: Input variables exceeded nnn.
このエラーはユーザーの入力値が多すぎて、submitしたときサーバー側で弾かれているエラーで、しきい値は php.ini の以下で設定できます。
php.ini
; How many GET/POST/COOKIE input variables may be accepted max_input_vars = 100
しかし本来セキュリティの観点から、この値は抑えられている(デフォルトは1000)ケースがあります。その場合は、フロント側で吸収する必要があるためその方法をまとめます。※あくまで一つの例なので他に良い方法があるかもしれません。
今回発生したケースでは、ユーザーや店舗などの設定値を縦に並べて一括で更新するという処理で、100は余裕で超えてしまうため対応を行いました。
POSTデータを入力するView(修正前)
(※だいぶ簡単にしたもの)<form method="post" action="/users/index">
<input type="submit" name="regist">更新</input>
<?php foreach($users as $user):?>
<label><?php echo $user['id'];?></label>
<label><?php echo $user['name'];?></label>
<input type="text" name="age[<?php echo $user['id'];?>]"
value="<?php echo $user['age'];?>" />
<br>
<?php endforeach;>
</form>
これはユーザーの年齢を一括で更新する例で、submitするとユーザーIDをキーに持った連想配列で年齢がPOSTされます。
この場合、ユーザー数に依存してPOSTデータの数が増えていき、ユーザー数が100を超えたとき前述のエラーとなります。
POSTデータを入力するView(修正後)
方法としては入力値を一つのJSONに圧縮してJavaScriptでsubmitするという対応をとりました。そのためのViewが以下です。<form id="input_form" method="post" action="/users/index">
<input type="hidden" name="input_data" />
<input type="submit" name="regist">更新</input>
</form>
<?php foreach($users as $user):?>
<label><?php echo $user['id'];?></label>
<label><?php echo $user['name'];?></label>
<input
type="text"
data-user-id="<?php echo $user['id'];?>"
name="age[]"
value="<?php echo $user['age'];?>" />
<br>
<?php endforeach;>
まず入力値のinputタグをformの外へ出します。これをしないと結局 submit で全部サーバーに送られてしまいます。
次にJSでformのsubmitイベントをハンドリングするため、id属性を付与します。
さらにPOSTするjson用の項目(hidden)をformに用意します。
入力値になるinputタグにはカスタム属性(data-user-id)を追加します。これによりJS側で入力値に対するユーザーIDが特定できます。
JavaScript
JSで複数の入力値をJSONに圧縮してsubmitするコードが以下...$(document).ready(function() {
$('#input_form').submit(function() {
var post_json = {
age:get_values('age'),
};
var f = document.forms['input_form'];
f.input_data.value = JSON.stringify(post_json);
f.submit();
});
function get_values(name) {
var ret = {};
var input_values = $('input[name="' + name + '[]"]');
for (i = 0; i < input_values.length; i++) {
user_id = $('#' + input_values[i].id).data('user-id');
value = input_values[i].value;
ret[user_id] = value;
}
return ret;
}
});
get_values関数はリスト形式で定義されたinputタグを {user_id : value, user_id : value, ...} の形式で取得する関数で、こうしておけば新たな項目が増えても即対応できます。
これでひとまとめにした入力値のjsonをhiddenで用意した領域にセットしてsubmitしてやります。
サーバー側ではPOSTデータのinput_dataに修正前と同じ形で入って来るので、同じValidationを通してやれば良いわけです。
コメント
コメントを投稿