大量のPOST配列をJSONにしてPHPに送信することでPOST数を削減する


概要

大量の配列をPOSTするページがあり、
PHPのmax_input_varsで設定された上限(デフォルト1,000個)に引っかかってしまい、
POSTデータがPHPで受け取れないという現象が起きていた。
(配列のPOSTでも1件ずつカウントされるんだ…)

そのため、FormをJSON形式にシリアライズしてPOSTし、
CakePHPでアンシリアライズするようにした。

環境

PHP5.6
CakePHP2

POSTしたいデータ

FormHelperでinputタグを出力している

echo $this->Form->hidden('Param1.' . $idx . '.id');
echo $this->Form->hidden('Param1.' . $idx . '.name');

結果のHTMLではname属性に以下のようにセットされる

<input type="hidden" name="data[Param1][1][id]" value="value1"/>
<input type="hidden" name="data[Param1][1][name]" value="value2"/>
<input type="hidden" name="data[Param1][2][id]" value="value3"/>
<input type="hidden" name="data[Param1][2][name]" value="value4"/>

JSでシリアライズ

submitイベントで以下の処理を発火させる。

var form = $('#form');

//formの全要素をJSON化してサブミット
var $fields = form.serializeArray();
for (var i = 0; i < $fields.length; i++) {
    //name属性の配列表記をドット記法に変換
    $fields[i].name = $fields[i].name.replace('data[', 'data.').split('][').join('.').replace(']', '');
}
form.after('<form id="formJson" action="" method="post"><input type="hidden" name="json" value="' + h($fields ? JSON.stringify($fields) : "") + '"></form>');
form = $('#formJson');

form.submit();

CakePHPでアンシリアライズ

とにかくdataに突っ込んでいるので '_method' もdataに入るようになったけど動いてるからいいか。

IshigurosController.php
if ($this->request->is('post') && $this->request->data('json')) {
    //Json形式のプロパティデータを連想配列形式へ変換する
    //Json形式でなければ何もしない
    $decoded = json_decode($this->request->data('json'), true);
    if ($decoded && json_last_error() === JSON_ERROR_NONE) {
        $request = Hash::expand(Hash::combine($decoded, '{n}.name', '{n}.value'));

        //'data'のみ特別処理する
        $requestData = [];
        if (isset($request['data'])) {
            $requestData = $request['data'];
            unset($request['data']);
        }

        foreach($request as $k => $v) {
            $this->request->data($k, $v);
        }

        foreach($requestData as $k => $v) {
            $this->request->data($k, $v);
        }
    }
}