Вместо кириллических символов в JSON запросе на PHP я получаю искаженную строку в кодировке ASCII?
Проект на 1С-Битрикс (open server). Использую PHP для обработки JSON-запросов, отправленных с фронтенда. Столкнулся с проблемой: вместо кириллических символов, отправленных в JSON, я получаю искажённые строки в массиве answers и в поле comment в формате ASCII.
Фронтенд отправляет запрос с корректными данными (в UTF-8), но на стороне PHP они выглядят как искажённые символы.
Код JS
// объект для отправки на сервер
const formData =
{
"notification_id": data.id,
"rating": ratingStar,
"answers": ["привет"],
"comment": sanitizeText(notificationFormText),
"user_response": true,
"closed_status": true,
"notification_read": true
}
const response = await fetch(`${BASE_URL_SET_DATA}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify(
{
action: 'add_notification_feedback', // для обработки запроса в php файле
data: formData
}
)
});
Пример данных, отправляемых с фронтенда (из консоли браузера):
{
"action": "add_notification_feedback",
"data": {
"notification_id": 2,
"rating": "2",
"answers": ["привет"],
"comment": "привет",
"user_response": true,
"closed_status": true,
"notification_read": true
}
}
Лог данных на сервере (сырые данные из php://input):
{
"action":"add_notification_feedback",
"data": {
"notification_id":2,
"rating":"2",
"answers":["?@825B"],
"comment":"?@825B",
"user_response":true,
"closed_status":true,
"notification_read":true
}
}
Код PHP:
<?php
header("Content-Type: application/json; charset=UTF-8");
// Получение входящих данных
$input = file_get_contents('php://input');
file_put_contents('debug_raw.log', $input); // Сырые данные запроса
// Преобразование в UTF-8
$input = mb_convert_encoding($input, 'UTF-8', 'auto');
file_put_contents('debug_utf8.log', $input); // Данные после приведения к UTF-8
// Декодирование JSON
$response = json_decode($input, true);
file_put_contents('debug_response.log', print_r($response, true)); // Результат декодирования JSON
// Вывод результата для теста
echo "<pre>";
var_dump(mb_detect_encoding($input)); // Ожидаю "UTF-8"
var_dump($response);
echo "</pre>";
?>
Лог вывода на сервере:
Сырые данные (из php://input
):
{"action":"add_notification_feedback","data":{"notification_id":2,"rating":"2","answers":["?@825B"],"comment":"?@825B","user_response":true,"closed_status":true,"notification_read":true}}
После преобразования в UTF-8
:
{"action":"add_notification_feedback","data":{"notification_id":2,"rating":"2","answers":["?@825B"],"comment":"?@825B","user_response":true,"closed_status":true,"notification_read":true}}
После декодирования JSON
:
Array
(
[action] => add_notification_feedback
[data] => Array
(
[notification_id] => 2
[rating] => 2
[answers] => Array
(
[0] => ?@825B
)
[comment] => ?@825B
[user_response] => 1
[closed_status] => 1
[notification_read] => 1
)
)
- На фронтенде данные отправляются в кодировке
UTF-8
. В консоли браузера данные выглядят корректно. - Заголовок
Content-Type
на стороне клиента включаетcharset=utf-8
- Сайт работает в кодировке UTF-8 (define('BX_UTF', true))
php.ini
default_charset = "UTF-8"
$string = mb_convert_encoding($string, 'HTML-ENTITIES', "UTF-8");
не помог- Каждое слово тоже не получилось перекодировать
// Преобразуем содержимое массива в UTF-8
if (isset($response['data']['answers'])) {
foreach ($response['data']['answers'] as &$answer) {
$answer = mb_convert_encoding($answer, 'UTF-8', 'auto');
}
}
При выводе
var_dump(mb_detect_encoding($input)); // Должно вернуть "UTF-8"
Получаю ASCII
Через PowerShell использовал команду - Format-Hex debug_raw.log
. Результат ->
00000000: 7b 22 61 63 74 69 6f 6e 22 3a 22 61 64 64 5f 6e {"action":"add_n
00000010: 6f 74 69 66 69 63 61 74 69 6f 6e 5f 66 65 65 64 otification_feed
00000020: 62 61 63 6b 22 2c 22 64 61 74 61 22 3a 7b 22 6e back","data":{"n
00000030: 6f 74 69 66 69 63 61 74 69 6f 6e 5f 69 64 22 3a otification_id":
00000040: 31 2c 22 72 61 74 69 6e 67 22 3a 22 33 22 2c 22 1,"rating":"3","
00000050: 61 6e 73 77 65 72 73 22 3a 5b 22 2e 40 43 33 3e answers":[".@C3>
00000060: 35 22 2c 22 2e 30 3b 38 47 38 35 20 42 3e 32 30 5",".0;8G85 B>20
00000070: 40 30 22 5d 2c 22 63 6f 6d 6d 65 6e 74 22 3a 22 @0"],"comment":"
00000080: 30 32 30 22 2c 22 75 73 65 72 5f 72 65 73 70 6f 020","user_respo
00000090: 6e 73 65 22 3a 74 72 75 65 2c 22 63 6c 6f 73 65 nse":true,"close
000000a0: 64 5f 73 74 61 74 75 73 22 3a 74 72 75 65 2c 22 d_status":true,"
000000b0: 6e 6f 74 69 66 69 63 61 74 69 6f 6e 5f 72 65 61 notification_rea
000000c0: 64 22 3a 74 72 75 65 7d 7d d":true}}
Как правильно обработать запрос, чтобы сохранить оригинальные символы?
Ответы (1 шт):
Похоже ваш RAW всё-таки кем то преобразован. У вас в php.ini нет каких-нибудь настроек mbstring....
?
Строка .0;8G85 B>20@0
это испорченное Наличие товара
.
Портится примерно так:
- конвертируем из utf-8 в ucs2
- получаем байты вида
04 1d 04 30 04 3b 04 38 04 47 04 38 04 35 00 20 04 42 04 3e 04 32 04 30 04 40 04 30
- байты вида
0X
удаляются - байты вида
1X
заменяются на точку (2e
) - получаем
2e 30 3b 38 47 38 35 20 42 3e 32 30 40 30
- это и есть
.0;8G85 B>20@0
.
Остаётся только вопрос в какой момент кто-то это всё проделывает. Либо это PHP, либо какой-то сервер перед ним.