从AJAX调用检索POST数据

时间:2016-04-28 作者:Fafanellu

我有以下几点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"].

jQueryserialize() 正常工作:我已测试newFormRecherche 带有警报的var,并显示在右侧窗体下:$field1=whatever&$field2=anything.

根据我所读的内容,通常情况下,我不需要解析结果来访问$\\u POST[]变量here, 但很明显,它不起作用。这个问题是从哪里来的?我应该用别的东西吗data 来传递我的论点?

EDIT : $_POST["newFormRecherche"] 存在于PHP端,并包含所需的字符串$field1=whatever&$field2=anything.

EDIT #2 : 根据@Czersplace的有趣评论和@bosco的非常详细的帖子,这里有一个更新。我试着把他们说的话简单地说出来,并给出一些解决方案。

这里的问题是双重序列化,一个是“手动”完成的,另一个是在进行AJAX调用时由jQuery完成的。事实上$_POST[] 无法在服务器端正确检索VAR来自data, 这必须符合Wordpress的形式主义,也就是说:action (这是一个PHP函数)和发送的数据(通常来自表单)。

@Bosco提供的解决方案-使用jQuery方法serializeArray(). 在这种情况下,发送的数据由2个对象组成。为了正确检索服务器端的字段,我必须处理如下关联数组:$_POST[\'newFormRecherche\'][0][\'name\']$_POST[\'newFormRecherche\'][0][\'value\']. 其他字段也是如此(用其他数字替换[0])。为了解决这个问题,@Bosco建议formFieldsToObject 在执行AJAX调用时对数据调用的函数。

@Czersplace提供的解决方案-使用serialize() jQuery方法,并在服务器端进行手动反序列化,使用parse_str( $_POST[ \'newFormRecherche\' ], $newFormRecherche ); 为了能够检索我想要的字段:$newFormRecherche[\'field1\',。。。等等

在这两种情况下,服务器端的数据都必须经过适当的清理,因为用户通过表单发送的数据总是必须经过清理。这意味着:检查字段类型,检查(甚至截断)字段长度。。。,换句话说:永远不要信任用户。

EDIT #3 : 如果您使用FormData, 确保在AJAX调用中添加这一行:processData: false,. 然而,我没有用这种技术实现完整的解决方案。

1 个回复
最合适的回答,由SO网友:bosco 整理而成

问题“序列化”是将数据对象转换为字符串表示的行为。jQuery自动序列化data 属性,然后再发送AJAX请求。然后服务器反序列化GET 来自URL的querystring和的请求正文POST 在填充PHP的请求变量之前请求。

您的代码在以下情况下按预期运行data 仅由序列化的表单数据(即。data: newFormRecherche,) 因为数据已经是字符串格式,因此无法进一步序列化。然后服务器的反序列化过程将表单数据正确解析为请求变量。

但是,当data 参数是一个对象,jQuery必须将其序列化才能将其传递给服务器。作为该对象的一个属性,预序列化的表单数据的处理方式就像处理任何其他字符串一样,具体来说,它的转义方式可以防止它被“误认为”是序列化对象。所以当服务器反序列化时data, newFormRecherche 反序列化为jQuery最初作为字符串接收的值,因此需要进行第二次反序列化,这是@Czerspaluate在注释中提到的,以便生成表单数据的关联数组。

要防止表单数据的双重序列化,请通过调用jQuery\'s .serializeArray() method 在form元素上,而不是.serialize().

而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;
}
HTML5FormData

或者,如果您只需要支持现代浏览器,或者不介意加载polyfill来支持旧浏览器,只需使用the FormData object 要将表单数据作为适当的数据对象传递,请执行以下操作:

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;
}
服务器端双重反序列化正如@Czersplace在评论中所建议的那样,通过简单地手动反序列化服务器上的表单数据来解释双重序列化也是一个完全有效的解决方案:

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 ) );
  }
}
我倾向于认为其他方法更“专业”,因为发送到服务器的所有数据都是以一致和预期的格式打包的——服务器不需要额外的“解码”,从而提高代码模块化。

但是代码模块化和主观的“专业性”并不总是最重要的因素,有时最简单的解决方案是最合适的。

记住validate and sanitize request data 在使用服务器之前,请先在服务器上安装,以减轻安全漏洞。