Реализация импорта товаров из 1С (CommerceML/XML)
Обмен данными между 1С и сайтом — одна из самых востребованных и технически неоднозначных задач в веб-разработке. Стандарт CommerceML существует с 2000-х, но каждая конфигурация 1С реализует его по-своему: отличаются структура XML, наполнение полей, логика выгрузки категорий и характеристик. Универсального решения нет — нужна интеграция под конкретную конфигурацию.
Стандарт CommerceML
1С выгружает данные в ZIP-архивах с XML-файлами нескольких типов:
import.zip
├── import.xml — каталог товаров, категории, свойства
├── offers.xml — склады, цены, остатки
└── import0.xml — продолжение каталога (при разбивке на файлы)
Структура import.xml:
<?xml version="1.0" encoding="UTF-8"?>
<КоммерческаяИнформация ВерсияСхемы="2.10">
<Каталог>
<Группы>
<Группа>
<Ид>f47ac10b-58cc-4372-a567-0e02b2c3d479</Ид>
<Наименование>Электроника</Наименование>
<Группы>
<Группа>
<Ид>6ba7b810-9dad-11d1-80b4-00c04fd430c8</Ид>
<Наименование>Смартфоны</Наименование>
</Группа>
</Группы>
</Группа>
</Группы>
<Товары>
<Товар>
<Ид>550e8400-e29b-41d4-a716-446655440000</Ид>
<Артикул>IPH-15-PRO-256</Артикул>
<Наименование>iPhone 15 Pro 256GB Natural Titanium</Наименование>
<ЗначенияСвойств>
<ЗначениеСвойства>
<Ид>color-property-id</Ид>
<Значение>Natural Titanium</Значение>
</ЗначениеСвойства>
</ЗначенияСвойств>
<Картинка>images/iphone15pro.jpg</Картинка>
</Товар>
</Товары>
</Каталог>
</КоммерческаяИнформация>
Протокол обмена
1С инициирует обмен через HTTP-запросы к сайту. Сайт реализует обработчик на определённых URL:
GET /1c-exchange/?type=catalog&mode=checkauth
GET /1c-exchange/?type=catalog&mode=init
POST /1c-exchange/?type=catalog&mode=file&filename=import.zip
GET /1c-exchange/?type=catalog&mode=import&filename=import.xml
Последовательность:
-
checkauth— 1С проверяет авторизацию -
init— получает лимиты (максимальный размер файла, zip или нет) -
file— загружает XML-файлы -
import— запрашивает импорт конкретного файла
Реализация обработчика (PHP/Laravel)
class OnecExchangeController extends Controller
{
public function handle(Request $request)
{
$mode = $request->query('mode');
return match($mode) {
'checkauth' => $this->checkAuth($request),
'init' => $this->init(),
'file' => $this->uploadFile($request),
'import' => $this->importFile($request),
default => response('failure', 400),
};
}
private function checkAuth(Request $request): Response
{
// 1С отправляет логин/пароль в Basic Auth
if (!$this->validateCredentials($request)) {
return response("failure\nНеверный логин или пароль");
}
$cookie = Str::random(32);
Cache::put("1c_session_{$cookie}", true, 600);
return response("success\nCOOKIE\n1c_session={$cookie}");
}
private function init(): Response
{
return response(implode("\n", [
'zip=yes',
'file_limit=' . (32 * 1024 * 1024), // 32MB
]));
}
private function uploadFile(Request $request): Response
{
$filename = $request->query('filename');
$request->file('file')->storeAs('1c-exchange', $filename);
return response('success');
}
private function importFile(Request $request): Response
{
$filename = $request->query('filename');
ImportFrom1cJob::dispatch($filename);
return response('success');
}
}
Парсинг XML
XML из 1С — это кириллические теги в пространстве имён. Парсинг через SimpleXML/DOMDocument прямолинеен:
class CommerceMLParser
{
public function parseImport(string $xmlPath): void
{
$xml = simplexml_load_file($xmlPath, 'SimpleXMLElement', LIBXML_NOCDATA);
$catalog = $xml->Каталог;
// Рекурсивно обрабатываем дерево категорий
$this->processGroups($catalog->Группы->Группа);
// Товары
foreach ($catalog->Товары->Товар as $item) {
$this->processProduct($item);
}
}
private function processProduct(SimpleXMLElement $item): void
{
$guid = (string) $item->Ид;
$sku = (string) $item->Артикул;
$name = (string) $item->Наименование;
// Свойства товара
$attributes = [];
foreach ($item->ЗначенияСвойств->ЗначениеСвойства as $prop) {
$attributes[(string)$prop->Ид] = (string)$prop->Значение;
}
Product::updateOrCreate(
['onec_guid' => $guid],
['sku' => $sku, 'name' => $name, 'attributes' => $attributes]
);
}
}
Обработка offers.xml (цены и остатки)
public function parseOffers(string $xmlPath): void
{
$xml = simplexml_load_file($xmlPath);
$packageOffers = $xml->ПакетПредложений;
foreach ($packageOffers->Предложения->Предложение as $offer) {
$guid = (string) $offer->Ид;
$price = (float) $offer->Цены->Цена->ЦенаЗаЕдиницу;
$stock = (int) $offer->Количество;
Product::where('onec_guid', $guid)->update([
'price' => $price,
'stock' => $stock,
]);
}
}
Асинхронный импорт
Большие каталоги (10 000+ товаров) нельзя обрабатывать синхронно — 1С ожидает ответа в течение нескольких секунд. Решение:
- Файл сохраняется сразу (
uploadFile) -
importFileвозвращаетsuccessнемедленно - Обработка запускается в фоне через Laravel Queue / Celery
- Прогресс доступен через отдельный endpoint или административный интерфейс
Изображения
1С выгружает пути к картинкам относительно архива. Обработка:
- Распаковка архива во временную директорию
- Обработка изображений (ресайз, конвертация в WebP)
- Загрузка в CDN/S3
- Обновление записей в БД
Типичные проблемы
- Encoding — 1С выгружает в UTF-8, но иногда попадаются файлы в Windows-1251
-
Большие файлы — XML на 100+ МБ, нужен потоковый парсинг через
XMLReaderвместоSimpleXML - Конфликты GUID — при работе нескольких баз 1С GUID может пересекаться
- Неполные выгрузки — 1С может отправлять только изменения, не весь каталог
Сроки
Импорт товаров из одной конфигурации 1С (каталог + цены + остатки): 8–12 рабочих дней. Включает тестирование на реальных данных клиента и отладку edge-cases конкретной конфигурации 1С.







