Получение данных 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
с помощью alert, и она отображается в правильном формате: $field1=whatever&$field2=anything
.
Обычно мне не нужно парсить результаты для доступа к переменным $_POST[], согласно тому, что я прочитал здесь, но очевидно это не работает. В чем проблема? Должен ли я использовать что-то другое вместо data
для передачи моих аргументов?
РЕДАКТИРОВАНИЕ: $_POST["newFormRecherche"]
существует на стороне PHP и содержит ожидаемую строку $field1=whatever&$field2=anything
.
РЕДАКТИРОВАНИЕ #2: Вот обновление, согласно интересному замечанию от @czerspalace и подробному посту от @bosco. Попробую здесь кратко изложить то, что они сказали, и предложить несколько решений.
Проблема здесь была в двойной сериализации - одна сделана "вручную", другая выполнена jQuery при выполнении AJAX-запроса. Тот факт, что переменные $_POST[]
не могут быть правильно получены на стороне сервера, связан с data
, которая должна соответствовать формализму WordPress, а именно: action
(который является PHP-функцией) и отправляемые данные (обычно из формы).
Решение от @Bosco - Использовать jQuery метод
serializeArray()
. В этом случае отправленные данные состоят из 2 объектов. Чтобы правильно получить поля на стороне сервера, я должен работать с ассоциативным массивом так:$_POST['newFormRecherche'][0]['name']
и$_POST['newFormRecherche'][0]['value']
. То же самое для других полей (заменяя [0] на другие числа). Для решения этого @Bosco предлагает ниже функциюformFieldsToObject
, которая вызывается для данных при выполнении AJAX-запроса.Решение от @czerspalace - Использовать jQuery метод
serialize()
и выполнить ручную десериализацию на стороне сервера, используяparse_str( $_POST[ 'newFormRecherche' ], $newFormRecherche );
, чтобы иметь возможность получить нужные поля: $newFormRecherche['field1'] и так далее.
В обоих случаях данные на стороне сервера должны быть правильно санитизированы, как всегда должны быть очищены данные, отправленные пользователем через формы. Это включает: проверку типов полей, проверку (и даже обрезку) длины полей... другими словами: никогда не доверяйте пользователю.
РЕДАКТИРОВАНИЕ #3: В случае использования FormData
убедитесь, что вы добавили эту строку в ваш AJAX-запрос: processData: false,
. Однако, я не реализовал полное решение с этой техникой.
Проблема
"Сериализация" — это процесс преобразования объекта данных в строковое представление. jQuery автоматически сериализует свойство data
перед отправкой AJAX-запроса. Затем сервер десериализует строку запроса GET
из URL и тело запроса для POST
-запросов перед заполнением переменных запроса в PHP.
Ваш код работал ожидаемо, когда data
состоял только из сериализованных данных формы (т.е. data: newFormRecherche,
), так как данные уже были в строковом формате и не могли быть сериализованы повторно. Десериализация на сервере корректно преобразовывала данные формы в переменные запроса.
Однако, когда аргумент data
является объектом, jQuery должен его сериализовать для передачи на сервер. Будучи свойством этого объекта, ваши предварительно сериализованные данные формы обрабатываются как обычная строка — а именно, экранируются таким образом, чтобы предотвратить их "ошибочное" распознавание как сериализованного объекта. Поэтому при десериализации data
сервером, newFormRecherche
преобразуется в исходное строковое значение, и для получения ассоциативного массива данных формы требуется второй проход десериализации, о котором упоминал @czerspalace в комментариях.
Решения
- jQuery
Чтобы избежать двойной сериализации данных формы, получите их как массив пар ключ/значение, используя метод jQuery .serializeArray()
вместо .serialize()
.
Хотя jQuery может корректно сериализовать такой массив пар ключ/значение, она не справляется, когда этот массив является вложенным свойством объекта 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
Альтернативно, если вам нужно поддерживать только современные браузеры или вы не против использовать полифил для старых, можно использовать объект 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 ) );
}
}
Я склонен считать, что другие подходы более "профессиональны", так как все данные отправляются на сервер в едином и ожидаемом формате — серверу не требуется дополнительная "декодировка", что улучшает модульность кода.
Но модульность кода и субъективная "профессиональность" не всегда являются главными факторами — иногда самое простое решение оказывается наиболее подходящим.
Не забывайте проверять и очищать данные запроса на сервере перед использованием, чтобы снизить риски уязвимостей безопасности.

большое спасибо за это ясное и понятное объяснение, теперь я понимаю, в чем была проблема! Хотя вы написали, что "jQuery правильно сериализует эти пары ключ/значение в переменные запроса", я все равно не могу получить к ним доступ и больше не могу их парсить, так как они больше не являются строками. Какое самое чистое решение для получения их значений?

@Fafanellu похоже, я переоценил возможности jQuery - она не очень хорошо работает с массивами ключ/значение во вложенных структурах данных и фактически не может правильно их сериализовать в таких ситуациях. Я добавил небольшую вспомогательную функцию, которая должна исправить ситуацию - данные должны быть доступны в PHP через правильно структурированный массив $_POST
, например $_POST["newFormRecherche"]["field1"]
. Вы можете использовать echo json_encode( $_POST );
в вашем AJAX обработчике или var_dump( $_POST );
чтобы увидеть точную структуру данных формы.

спасибо за эту очень интересную тему! Я обновил свой первоначальный пост, чтобы учесть конструктивные комментарии, оставленные здесь

Это просто временная заглушка вместо вашего кода =). Функция die()
немедленно завершает выполнение PHP-скрипта, при этом может вывести аргумент с помощью echo()
, если он указан - таким образом она сразу завершает AJAX-запрос, возвращая полученные сервером данные формы в виде JSON-объекта (хотя, вероятно, с неправильным заголовком Content-Type
, но jQuery не должен возражать). В сочетании с callback-функцией success
, которую вы указали в JavaScript и которая выводит ответ сервера через console.log()
, вы получите удобное для просмотра представление данных формы в консоли JavaScript вашего браузера.

Ок, спасибо! На самом деле я не писал весь PHP-код, но в конце был пустой die(). Если я правильно понимаю, цель - как можно быстрее завершить AJAX-запрос, чтобы отправить данные обратно.

Именно так! Эта страница Codex кратко затрагивает этот вопрос. Основная идея в том, что после обработки AJAX-запроса и вывода ответа через echo()
, нет особого смысла продолжать выполнение WordPress. Если позволить WordPress работать дальше в обычном режиме, есть риск что код, выполняемый после вашего AJAX-обработчика, может что-то ещё вывести через echo()
в ответ, что скорее всего сломает ваш JavaScript, когда callback success
попытается его обработать.

wp_die()
считается более предпочтительной альтернативой die()
. Редко когда стоит использовать что-то из этого вне AJAX-обработчиков, за исключением временной отладки - почти всегда есть лучший способ обработать проблему или сообщить об ошибке, чем просто прерывать выполнение скрипта!
