フォームの入力内容をAjaxで加工後、別タブに送信(Ajaxとsubmitの2回送信)


フォームで入力された内容を、別タブで確認させたいが、単にsubmitで送信するのではなく、一度プログラムを通して加工する必要がある、という面倒な案件があったので、メモとして残しておきます。

javascript

function sample(url){

  // フォームの入力内容を取得し、クエリ文字列に変換
  var form = $('#form_id');
  var query_str = form.serialize();

  var postData = {
    'query_str' : query_str,
  };

  $.ajax({
    async: false,       // ajax を同期処理にする
    url: './act.php',   // 送信先ファイル名
    type : 'POST',
    data : postData,
    timeout: 10000,

  }).done(function(getData){
    // 前回追加したフォームを削除
    var old = document.getElementById('append_data');
    if (old) {
      document.form_id.removeChild(old);
    }

    // ajaxで取得したデータをフォームに追加
    var appendData = document.createElement('input');
    appendData.type = 'hidden';
    appendData.id = 'append_data';
    appendData.name = 'append_data';
    appendData.value = getData;

    document.form_id.appendChild(appendData);
  });

  // 指定 URL に submit
  document.form_id.action = url;
  document.form_id.enctype = 'application/x-www-form-urlencoded';
  document.form_id.target = '_blank';
  document.form_id.submit();
}

 

処理内容は、以下の流れになってます。

1.フォームにデータを入力する
 

2.ボタンを押された際に「sample」関数を呼び出す

<input type="button" value="確認" onclick="sample('http://hoge.hoge/disp.html');">

 

3.フォームの入力内容を「serialize()」を使い、クエリ形式で取得

// クエリ形式
category=1&title=sample

 

4.act.php に ajax でPOST送信

act.php の例

// クエリ文字列の取得例
$input_data = '';

if (isset($_POST['query_str'])) {
    $query_str = $_POST['query_str'];

    // クエリ文字列として送られてきたフォームの値を、input_data に格納する
    parse_str($query_str, $input_data);

	// こんな感じで取得できる
    // $input_data['category'] = 1;
    // $input_data['title'] = 'sample';
}

// 適当に加工

// 出力例
// 配列などにも対応させるため、シリアル化している
echo serialize($output_data);

 

5.act.php の出力内容をフォームにhiddenで追加する
2回め以降は、前回追加したフォームデータが残っているので、まずは削除してから追加しています。
 

6.別タブに submit
action の URL を書き換えているので、必要であれば書き換え前のURLを保存し、書き戻してください。
同様に、enctype や target も。
 

7.submit されたデータを受け取って表示
PHP での受け取り例

// POSTデータの取得
$post_data = $_POST;

// 追加データの取得
$append_data = array();
if (isset($_POST['append_data'])) {
    $append_data = unserialize($_POST['append_data']);
}

// POSTデータに、追加データをセット
if (is_array($append_data)) {
    foreach ($append_data as $key => $val) {
        if (isset($val)) {
            if (isset($post_data[$key])) {
                $post_data[$key] += $val;
            } else {
                $post_data[$key] = $val;
            }
        }
    }
}

 

最初は ajax 完了後に submit したいということで ajaxの「always」で行けないか?と試したのですが、何故か「always」の中に「document.form_id.submit();」を書くと動きませんでした。
そこで、仕方なく ajax を「async: false」で同期処理にしています。

それなら「submit()」を辞めればいいんじゃないか?とも思いましたが、テキストエリアの入力に使っている CKEditor が、エディタの入力内容を textarea の value にセットするタイミングが submit の時だったようで、これを submit 以外の時にも対応させるのは時間が掛かりそうなため断念しました。

この辺は改良すれば、もっとスマートに行けそうです。


【PHP】配列の添字と文字列のオフセット指定


文字列のオフセット指定について、ちゃんと理解しないまま使用していたら、ちょっとハマッた箇所があったので整理しました。

配列の添字

$array = array('Yamada', 'Tarou',);

echo $array[0];		// 「Yamada」が出力される

文字列のオフセット指定

$string = 'Yamada';

echo $string[0];	// 「Y」が出力される

 

まあ、この辺の違いは今更書くまでもないことだろうけど・・・。

処理の高速化について調べていたところ、下記のような記述を見つけました。

 

33. if (strlen($foo) < 5) を調べたいなら if (!isset($foo{5})) と書くと速い。

参考サイト PHPコード最適化高速化TIPSまとめ

 

この $foo{5} という記述を見慣れていなかった私は「おぉ、便利だなぁ」と、PHPマニュアルをちゃんと読んだりすることなく、整数を扱う変数にも使ってしまっていました。

if (isset($number['a']{0}))
{
 // 処理
}

ところが、期待したような結果を得られず、ちゃんと調べてみたところ、この {0} という記述は文字列のオフセット指定 [0] と同じ処理を行っており、変数が文字列型でない場合は当然ながら期待した動作を行いません。

 

注意:
その他の型の変数 (配列や、適切なインターフェイスを実装したオブジェクトを除く) に対して [] や {} でアクセスすると、何もメッセージを出さずに単に NULL を返します。

参考サイト PHP: 文字列 – Manual

 

また、波括弧 {}を使用したオフセット指定方法は、PHP 6で廃止予定とのことなので、角括弧 []に統一しておいた方が良いです。

ということで、整数値の変数が入っているかチェックを行いたい場合は

if (isset($number['a']))
{
 // 処理
}

通常通り、単にこれだけの記述になりますね。
何を今更な内容ですが、マニュアルをちゃんと読まなかったため、勘違いをしてしまいました。

数値か調べたい場合は is_numeric がありますが、今回の用途では「数値が入る」か「何も入らない」かの2パターンしかないため isset を使用しています。

 

17. $row[‘id’] は $row[id] より7倍速い。
参考サイト PHPコード最適化高速化TIPSまとめ

ついでといってはなんですが、配列の添字指定時に’(シングルクォーテーション)で括った場合の処理速度を確認してみました。

処理は単純に、配列の要素を変数に代入するだけという物を10万回実行。

$test = array(
	'a' => 'Yamada',
	'b' => 'Tarou',
);

$max = 100000;

for ($i=0; $i<$max; $i++)
{
	$x = $test['a'];
}

for ($i=0; $i<$max; $i++)
{
	$y = $test[a];
}

結果は下記のとおりとなりました。

$x = $test[‘a’]; 0.0095689296722412 秒
$y = $test[a]; 0.83886814117432 秒

また、添字が数字だった場合がどうなるかも試してみました。

$x = $test[‘0’]; 0.0065720081329346 秒
$y = $test[0]; 0.0066301822662354 秒

こちらは何回か試してみましたが、[‘0’]が早い時もあれば、[0]が早い時もあったので、処理速度に大きな差はないようです。
コーディングスピードを上げるという観点から考えると、添字が数字の場合は[0]で良さそうです。
といっても、数字の添字を直接指定して使う機会ってほとんどない気がします。

 

文字列のオフセット指定時の’(シングルクォーテーション)
また、文字列のオフセット指定についても’(シングルクォーテーション)のあり・なしで処理速度が変わるのか試してみました。

$test = 'Yamada Tarou';

実行回数を10回に増やして比較してみました。
早かった方が赤色です。

回数 $x = $test[‘0’]; $y = $test[0];
1 0.010056972503662 秒 0.012347936630249 秒
2 0.010039806365967 秒 0.009335994720459 秒
3 0.010890007019043 秒 0.0094809532165527 秒
4 0.0096769332885742 秒 0.012487173080444 秒
5 0.012174844741821 秒 0.0098400115966797 秒
6 0.0097651481628418 秒 0.0092430114746094 秒
7 0.0090720653533936 秒 0.0089559555053711 秒
8 0.012573003768921 秒 0.010463953018188 秒
9 0.0095231533050537 秒 0.0098400115966797 秒
10 0.012336015701294 秒 0.010035037994385 秒

大きな差は見られず誤差範囲のようです。
こちらもタイピング量を減らし、コーディングスピードを上げるという観点からシングルクォーテーション無しの [0] で良さそうでした。

結論としては、$a{0}のような波括弧を使用した記述は撲滅して欲しいです(笑)
ネットはどうしても古い記事がそのままメンテナンスされず残ってしまうので、非推奨な書き方がいつまでも出回るのが難しいところですね。

私も、古い記述の記事を掲載し続けないように気をつけねば。。。