web-dev-qa-db-ja.com

取得する POST からのデータ AJAX コール

次のJSスクリプトがあります。

jQuery('#form-recherche').submit(ajaxSubmit);

        function ajaxSubmit(){

            var newFormRecherche = jQuery(this).serialize();

            jQuery.ajax({
                type:"post",
                data: { 
                    action: "mon_action",
                    newFormRecherche: newFormRecherche,
                },

                url: ajaxurl,
                success: function(response){
                    console.log(response);
                }
            });

        return false;
        }

PHP側:

    add_action( 'wp_ajax_mon_action', 'mon_action' );
    add_action( 'wp_ajax_nopriv_mon_action', 'mon_action' );

    function mon_action() {

        if (isset($_POST["newFormRecherche"])) {
            $field1= $_POST["field1"];
            $field2= $_POST["field2"];
        }
    }

ご想像のとおり、$_POST["newFormRecherche"]$_POST["field1"]も取得できませんが、$_POST["field2"]にアクセスできます。

jQueryのserialize()は正しく動作します。アラートを付けてnewFormRecherche varをテストしましたが、正しい形式で表示されます:$field1=whatever&$field2=anything

通常、 ここ を読んだことによると、$ _POST []変数にアクセスするために結果を解析する必要はないはずですが、明らかに機能していません。この問題はどこから来たのでしょうか。引数を渡すためにdata以外のものを使用する必要がありますか?

_ edit _ $_POST["newFormRecherche"]はPHP側にあり、予想される文字列$field1=whatever&$field2=anythingが含まれています。

編集#2 :@czerspalaceからの興味深い発言および@boscoからの非常に詳細な投稿によると、これが更新です。私はここで、彼らが言ったことを簡単に説明し、いくつかの解決策を提示しようとします。

ここでの問題は、AJAX呼び出しを行っている間にjQueryによって作成されたもの、「手作業で」作成された二重直列化でした。 $_POST[]変数がサーバー側で正しく取得できないという事実はdataから来ています。それはWordpressの形式、つまりaction(PHP関数)と送信されたデータ(通常、フォームから).

  • @Boscoによる解決策 - jQueryメソッドserializeArray()を使用します。この場合、送信されるデータは2つのオブジェクトで構成されています。サーバー側でフィールドを正しく取得するには、$_POST['newFormRecherche'][0]['name']$_POST['newFormRecherche'][0]['value']のような連想配列を処理する必要があります。他のフィールドについても同様です([0]を他の数字に置き換えます)。それを解決するために、@ <B>は、AJAX呼び出しを実行するときに、データに対して呼び出されるformFieldsToObject関数を提案します。

  • @czerspalaceによる解決策 - 必要なフィールドを取得できるようにするには、serialize() jQueryメソッドを使用し、parse_str( $_POST[ 'newFormRecherche' ], $newFormRecherche );を使用してサーバー側で手動で逆シリアル化を行います。$ newFormRecherche ['field1']など。

どちらの場合も、ユーザーがフォームを介して送信されるデータは常に正しくなければならないため、サーバー側のデータは正しくサニタイズする必要があります。つまり、フィールドタイプのチェック、フィールド長のチェック(および切り捨て)さえも行います。つまり、ユーザーを信頼しないでください。

編集#3 FormDataを使用する場合は、AJAX呼び出し内にこの行を必ず追加してください:processData: false,。ただし、この手法では完全なソリューションを実装しませんでした。

5
Fafanellu

問題

「直列化」とは、データオブジェクトを文字列表現に変換することです。 jQueryはAJAXリクエストを送信する前にdataプロパティを自動的にシリアル化します。その後、サーバーはURLからのGETクエリ文字列、およびPOSTリクエストのリクエストボディを、PHPのリクエスト変数に値を設定する前に逆シリアル化します。

dataがシリアル化されたフォームデータ(つまりdata: newFormRecherche,)のみで構成されている場合、データは既に文字列形式であり、それ以上シリアル化できないため、コードは予想どおりに機能しました。サーバーの逆シリアル化パスは、フォームデータを要求変数に正しく解析しました。

ただし、data引数がオブジェクトの場合、jQueryはそれをサーバーに渡すためにシリアル化する必要があります。そのオブジェクトのプロパティとして、事前シリアル化されたフォームデータは他の文字列と同様に処理されます。具体的には、シリアル化されたオブジェクトと間違えられないようにエスケープされます。そのため、サーバがdataを逆シリアル化すると、newFormRechercheはjQueryが最初に受け取った値(つまり文字列)に逆シリアル化されるので、連想配列を生成するために@czerspalaceがコメントで暗示した2段階の逆シリアル化が必要ですフォームデータ.


ソリューション

- jQuery

フォームデータが二重にシリアル化されないようにするには、フォーム要素で.serializeArray()ではなく jQueryの.serialize() method を呼び出して、シリアル化された文字列ではなくキー/値ペアの配列として取得します。

JQueryはこのキー/値配列形式のdataを正しくシリアル化できますが、そのような配列がdataオブジェクトのプロパティとしてネストされていると(代わりに各キー/値ペアの代わりに文字列'[object Object]'を送信する)そのようなキー/値配列を別のものの中にネストしようとしたときも同様です。そのため、多次元データの一部としてフォームデータを送信する最良の方法は、キー/値配列をオブジェクトに変換することです。

これはすべて次のように実行できます。

function ajaxSubmit() {
  var newFormRecherche = jQuery( this ).serializeArray();

  jQuery.ajax({
    type:"POST",
    data: { 
      action: "mon_action",
      newFormRecherche: formFieldsToObject( newFormRecherche )
    },
    url: ajaxurl,
    success: function( response ){
      console.log( response );
    }
  });

  return false;
}

function formFieldsToObject( fields ) {
  var product = {};

  for( var i = 0; i < fields.length; i++ ) {
    var field = fields[ i ];

    if( ! product.hasOwnProperty( field.name ) ) {
      product[ field.name ] = field.value;
    }
    else {
      if( ! product[ field.name ] instanceof Array )
        product[ field.name ] = [ product[ field.name ] ];

      product[ field.name ].Push( field.value );
    }
  }

  return product;
}

- HTML5のFormData

あるいは、最新のブラウザだけをサポートする必要がある場合、または古いものをサポートするためにpolyfillをロードすることを気にしない場合は、 FormDataオブジェクト を使用してフォームデータを適切なデータオブジェクトとして渡します。

function ajaxSubmit() {
  var newFormRecherche = new FormData( this );

  jQuery.ajax({
    type:"POST",
    data: { 
      action: "mon_action",
      newFormRecherche: newFormRecherche
    },
    url: ajaxurl,
    success: function( response ){
      console.log( response );
    }
  });

  return false;
}

- サーバサイドのダブルデシリアライゼーション

@czerspalaceがコメントで示唆しているように、サーバー上のフォームデータを手動で逆シリアル化することによって二重シリアル化を考慮することも、まったく有効な解決策です。

add_action( 'wp_ajax_mon_action', 'mon_action' );
add_action( 'wp_ajax_nopriv_mon_action', 'mon_action' );

function mon_action() {
  if( isset( $_POST[ 'newFormRecherche' ] ) ) {
    parse_str( $_POST[ 'newFormRecherche' ], $newFormRecherche );
    die( json_encode( $newFormRecherche ) );
  }
}

私は他のアプローチがより専門的であると思う傾向があります - サーバーに送られるすべてのデータは一貫したそして期待されたフォーマットでパッケージ化されます - 追加の「デコーディング」はサーバー側に必要でなく、コードモジュール性を改善します。

しかし、コードのモジュール性と主観的な「プロ意識」は、常に最も重要な要素ではありません。最も単純な解決策が最も適切な場合があります。


セキュリティの脆弱性を軽減するために、使用する前にサーバー上で リクエストデータの検証とサニタイズ を忘れないでください。

7
bosco