Интеграция между платформой 1С:Предприятие и веб-серверами, работающими на PHP — одна из самых частых задач для разработчиков. И зачастую при передаче данных в формате JSON возникает классическая проблема: 1С успешно формирует и отправляет JSON, однако на стороне PHP разработчик видит «кривой» или пустой массив. Разберем по шагам, почему возникает эта ошибка, проанализируем исходный код и найдем правильные пути решения.
Посмотрим на типичный пример, с которым сталкиваются разработчики. Со стороны 1С формируется структура, сериализуется в JSON и отправляется POST-запросом на сервер:
тДанные = Новый Структура;
тДанные.Вставить("onec_id_order", "ЦВ000001381");
тДанные.Вставить("id_order", "111");
тДанные.Вставить("phone", "79999999999");
тДанные.Вставить("post_track", Массив);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, тДанные);
СтрокаПараметров = ЗаписьJSON.Закрыть();
ЗаголовокHTTP = Новый Соответствие();
ЗаголовокHTTP.Вставить("Content-type", "application/x-www-form-urlencoded");
HTTPЗапрос = Новый HTTPЗапрос("/api/connector/", ЗаголовокHTTP);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаПараметров);
HTTPСоединение = Новый HTTPСоединение("example.com", , , , , , Новый ЗащищенноеСоединениеOpenSSL);
Ответ = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
На стороне PHP скрипт пытается получить переданные данные классическим способом через суперглобальный массив $_POST и записывает их в файл:
file_put_contents(__DIR__ . '/post.txt', print_r($_POST, true) . PHP_EOL, FILE_APPEND);
В результате в лог-файле мы видим очень странную картину:
Array
(
[{
"onec_id_order":_"ЦВ000001381",
"id_order":_"111",
"phone":_"_79999999999",
"post_track":_] => Array
(
[
"80111457622359",
"80111457621468"
] =>
)
)
Вместо нормального ассоциативного массива весь наш JSON-текст разбился на куски и превратился в ключи массива. Выясним причину такого поведения и рассмотрим детально каждую ошибку.
Если мы посмотрим на код 1С, то увидим использование заголовка application/x-www-form-urlencoded. Этот заголовок сообщает веб-серверу и интерпретатору PHP, что данные в теле запроса передаются в формате стандартной веб-формы, то есть в виде пар ключ=значение&ключ2=значение2.
PHP, увидев такой заголовок, послушно пытается разобрать тело запроса по правилам URL-кодирования. Но 1С отправляет чистую строку JSON, которая начинается с символа открывающей фигурной скобки и не содержит знаков равенства (в нужном контексте). Из-за этого PHP берет огромный кусок строки JSON до ближайшего пробела, амперсанда или другого спецсимвола, и делает его ключом массива $_POST. Именно поэтому мы видим "разорванный" JSON в ключах массива.
Когда вы передаете данные с правильным заголовком для JSON (например, application/json), суперглобальный массив $_POST в PHP будет абсолютно пустым. Это нормальное поведение языка PHP: он автоматически заполняет $_POST только для типов application/x-www-form-urlencoded и multipart/form-data.
Если внимательно присмотреться к дампу массива в начале статьи, перед первой открывающей скобкой JSON стоит невидимый спецсимвол: [{. Это маркер последовательности байтов или BOM (Byte Order Mark).
Платформа 1С:Предприятие часто добавляет символ BOM по умолчанию при формировании строк или текстовых файлов в кодировке UTF-8. Наличие этого символа является фатальным для стандартной PHP функции json_decode(). Она воспримет строку как синтаксически неверный JSON и вернет ошибку.
Рассмотрим подробнее, как необходимо переписать код на обеих сторонах, чтобы наладить корректный обмен данными.
Шаг 1. Исправляем код в 1С:
Content-Type на правильный.
// 1. Указываем правильный тип контента
ЗаголовокHTTP = Новый Соответствие();
ЗаголовокHTTP.Вставить("Content-type", "application/json");
HTTPЗапрос = Новый HTTPЗапрос("/api/connector/", ЗаголовокHTTP);
// 2. Устанавливаем тело без символа BOM
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаПараметров, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Шаг 2. Исправляем код на стороне PHP:
Поскольку $_POST будет пуст, нам необходимо получить "сырое" тело запроса, обратившись к потоку ввода php://input.
// 1. Читаем сырые данные из тела запроса
$json_string = file_get_contents('php://input');
// 2. Декодируем JSON-строку в ассоциативный массив (второй параметр true)
$data = json_decode($json_string, true);
// 3. Теперь массив $data содержит корректную структуру
file_put_contents(__DIR__ . '/post.txt', print_r($data, true) . PHP_EOL, FILE_APPEND);
После применения этих правок вы получите на стороне PHP идеально структурированный ассоциативный массив, с которым легко работать.
Иногда возникают ситуации, когда API на стороне PHP строго требует заголовок application/x-www-form-urlencoded и разработчик PHP не может или не хочет переписывать механизм приема данных. Разберем по шагам, как действовать разработчику 1С в таком случае.
Вам необходимо отправить JSON не как «голое» тело запроса, а как значение определенного параметра, например data. При этом саму строку нужно обязательно URL-кодировать.
Код на стороне 1С:
ЗаголовокHTTP = Новый Соответствие();
ЗаголовокHTTP.Вставить("Content-type", "application/x-www-form-urlencoded");
HTTPЗапрос = Новый HTTPЗапрос("/api/connector/", ЗаголовокHTTP);
// Формируем строку в формате ключ=кодированное_значение
ТелоЗапроса = "data=" + КодироватьСтроку(СтрокаПараметров, СпособКодированияСтроки.КодировкаURL);
// BOM здесь не так страшен, но лучше все равно его отключать
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Код на стороне PHP:
В этом случае данные корректно попадут в массив $_POST, и интерпретатор PHP сам выполнит URL-декодирование.
// Проверяем, существует ли наш ключ
if (isset($_POST['data'])) {
// Декодируем строку JSON
$data = json_decode($_POST['data'], true);
// Записываем результат
file_put_contents(__DIR__ . '/post.txt', print_r($data, true) . PHP_EOL, FILE_APPEND);
}
Мы проанализировали частую проблему, возникающую при интеграции систем. Чтобы избежать «кривого» JSON на приемной стороне, запомните три главных правила:
application/json.ИспользованиеByteOrderMark.НеИспользовать, чтобы скрыть маркер BOM.application/json читайте данные исключительно через поток php://input.Соблюдение этих простых правил сэкономит вам массу времени и убережет от долгих поисков ошибок интеграции!