Обмен с 1С — единственная подсистема Битрикса, которую большинство разработчиков никогда не открывали. Её настраивают галочками, а когда она ломается, лечат тем же способом: снимают и ставят галочки обратно, чистят кэш, перезапускают обмен и ждут. Иногда помогает.
Между тем внутри нет ничего мистического. Это HTTP-протокол из пяти команд и XML-файл с кириллическими тегами. Разработчик, который один раз посмотрел на обмен через curl, чинит типовую проблему за двадцать минут вместо двух дней — просто потому, что видит, где именно оборвалась цепочка.
Эта статья — про провод, а не про админку. Что 1С отправляет, что Битрикс отвечает, где лежат файлы и в какой момент можно вмешаться.
Что такое CommerceML
CommerceML — это открытый XML-стандарт обмена коммерческой информацией, разработанный фирмой «1С» для передачи каталогов, цен, остатков и заказов между учётной системой и сайтом. Битрикс работает со второй версией стандарта: корневой элемент называется КоммерческаяИнформация, а все теги внутри написаны по-русски.
Кириллица в тегах смущает, но у неё есть практическое следствие: XML читается глазами без документации. Открыв import.xml, вы сразу понимаете, что <Артикул> — это артикул, а <ЗначенияРеквизитов> — дополнительные поля товара. Для отладки это дороже, чем кажется.
Версия схемы важна. В атрибуте ВерсияСхемы корневого элемента 1С указывает версию CommerceML — 2.03, 2.05, 2.08 и далее. Разные версии описывают одни и те же сущности слегка по-разному, и конфигурация 1С выбирает версию сама. Прежде чем спорить о том, «почему поле не приезжает», посмотрите на этот атрибут: возможно, поля в этой версии схемы просто нет.
Как устроен обмен: пять команд
Инициатор обмена — всегда 1С. Сайт ничего не запрашивает и не «забирает», он только отвечает. Вся точка входа — один скрипт:
/bitrix/admin/1c_exchange.phpОбмен каталогом идёт с параметром type=catalog, выгрузка заказов обратно в 1С — с type=sale. Второй параметр, mode, задаёт шаг.
1. GET ?type=catalog&mode=checkauth → авторизация
2. GET ?type=catalog&mode=init → параметры передачи
3. POST ?type=catalog&mode=file&filename=import.xml → тело файла
4. GET ?type=catalog&mode=import&filename=import.xml → разбор файла
5. повтор шага 4, пока ответ = progressОтвет всегда текстовый, и значение имеет первая строка: success, progress или failure. Всё остальное — детали для человека.
Шаг 1: checkauth
1С обращается с Basic Auth под пользователем сайта, у которого есть право на обмен. В ответ приходят три строки:
success
PHPSESSID
a1b2c3d4e5f6...Вторая и третья строки — имя и значение сессионной куки: то, что PHP вернёт из
session_name() и session_id(). Имя по умолчанию PHPSESSID, но оно настраивается,
поэтому 1С обязана брать его из ответа, а не подставлять константу. 1С обязана подставлять её во все следующие запросы, иначе каждый шаг будет создавать новую сессию, а вместе с ней — новый прогресс импорта. Обмен в такой ситуации бесконечно ходит по кругу, не двигаясь дальше первого шага.
Шаг 2: init
zip=no
file_limit=1048576zip говорит, принимает ли сайт архивы, file_limit — максимальный размер одной порции в байтах. Большой import.xml 1С режет на куски по file_limit и отправляет их последовательно с одинаковым filename, а Битрикс склеивает.
Шаг 3: file
Тело POST-запроса — сырые байты файла, без multipart и без формы. Файл ложится в /upload/1c_catalog/.
Шаг 4: import
Здесь начинается разбор. Битрикс читает XML, создаёт разделы, свойства и элементы — и не пытается сделать всё за один запрос. Отработав порцию, он отвечает:
progress
Импортировано 500 товаров из 120001С видит progress и повторяет тот же запрос. Битрикс продолжает с сохранённой позиции. И так, пока не вернётся success.
Понимание этого механизма решает половину проблем с обменом. Обмен не «висит» — он идёт шагами, и если шаг не укладывается в лимиты, цикл не двигается.
Как посмотреть обмен своими глазами
Самый полезный навык в этой теме — уметь пройти обмен руками. Никакого доступа к 1С для этого не нужно.
# 1. Авторизация. -u — логин и пароль пользователя с правом на обмен
curl -s -u "exchange1c:password" \
"https://site.ru/bitrix/admin/1c_exchange.php?type=catalog&mode=checkauth"
# success
# PHPSESSID
# 3f2a...
# 2. Параметры передачи — с полученной кукой
curl -s -b "PHPSESSID=3f2a..." \
"https://site.ru/bitrix/admin/1c_exchange.php?type=catalog&mode=init"
# zip=no
# file_limit=1048576
# 3. Запуск импорта уже лежащего на сайте файла
curl -s -b "PHPSESSID=3f2a..." \
"https://site.ru/bitrix/admin/1c_exchange.php?type=catalog&mode=import&filename=import.xml"
# progressТри команды дают больше информации, чем час чтения форумов. Если checkauth возвращает failure — проблема в правах, и её видно сразу, а не через сообщение «обмен завершился с ошибкой» в 1С.
Не запускайте mode=import на боевом сайте «чтобы посмотреть». Это настоящий импорт: он изменит товары, цены и активность элементов ровно так же, как если бы его инициировала 1С. Для экспериментов нужна копия сайта с копией базы — та же, на которой вы проверяете обновления.
Что внутри XML
import.xml — структура и товары
<?xml version="1.0" encoding="UTF-8"?>
<КоммерческаяИнформация ВерсияСхемы="2.05" ДатаФормирования="2026-10-02">
<Классификатор>
<Ид>d5a9c1e4-...</Ид>
<Группы>
<Группа>
<Ид>7b1f...</Ид>
<Наименование>Смесители</Наименование>
</Группа>
</Группы>
<Свойства>
<Свойство>
<Ид>a3c8...</Ид>
<Наименование>Материал корпуса</Наименование>
</Свойство>
</Свойства>
</Классификатор>
<Каталог>
<Товары>
<Товар>
<Ид>f4e2...</Ид>
<Артикул>SM-1024</Артикул>
<Наименование>Смеситель для кухни</Наименование>
<Группы><Ид>7b1f...</Ид></Группы>
<ЗначенияСвойств>
<ЗначенияСвойства>
<Ид>a3c8...</Ид>
<Значение>Латунь</Значение>
</ЗначенияСвойства>
</ЗначенияСвойств>
</Товар>
</Товары>
</Каталог>
</КоммерческаяИнформация>Ключевая сущность здесь — <Ид>. Это GUID из 1С, и он же уезжает в поле XML_ID элемента или раздела инфоблока. Вся связь между двумя системами держится на нём: 1С не знает про ID элемента Битрикса и опознаёт товар только по GUID.
Отсюда правило, которое стоит запомнить до первой аварии: XML_ID элементов и разделов трогать нельзя. Ни руками в админке, ни скриптом миграции. Стёртый XML_ID означает, что следующий обмен не найдёт товар и создаст его заново — с новым ID, пустой статистикой и битыми ссылками в заказах.
offers.xml — цены и остатки
<ПакетПредложений>
<Предложения>
<Предложение>
<Ид>f4e2...#9a71...</Ид>
<Цены>
<Цена>
<ИдТипаЦены>b2d4...</ИдТипаЦены>
<ЦенаЗаЕдиницу>4990</ЦенаЗаЕдиницу>
<Валюта>RUB</Валюта>
</Цена>
</Цены>
<Количество>17</Количество>
</Предложение>
</Предложения>
</ПакетПредложений>Обратите внимание на <Ид> предложения: GUID_товара#GUID_характеристики. Именно так торговое предложение привязывается к родительскому товару — Битрикс разбирает эту строку и записывает связь в служебное свойство CML2_LINK.
Разделение на два файла сделано ради скорости. import.xml тяжёлый, он несёт структуру и меняется редко. offers.xml лёгкий, его можно гонять хоть каждые пятнадцать минут — и именно так обычно и настраивают, чтобы остатки на витрине не расходились со складом.
Служебные свойства CML2
При первом обмене Битрикс сам создаёт в инфоблоке набор свойств с префиксом CML2_. Они выглядят как мусор в списке свойств, и их регулярно пытаются удалить «для порядка». Делать этого не надо — на них держится обмен.
| Код свойства | Что хранит |
|---|---|
CML2_LINK | Связь торгового предложения с товаром |
CML2_ARTICLE | Артикул из 1С |
CML2_BAR_CODE | Штрихкод |
CML2_MANUFACTURER | Производитель |
CML2_BASE_UNIT | Базовая единица измерения |
CML2_TAXES | Налоговые ставки |
CML2_ATTRIBUTES | Реквизиты, для которых нет отдельного свойства |
CML2_TRAITS | Признаки товара |
CML2_ATTRIBUTES — свалка, а не поле. Туда падает всё, что 1С прислала в <ЗначенияРеквизитов> и чему Битрикс не нашёл соответствия. Если нужное значение из 1С «не приезжает», сначала загляните именно сюда: скорее всего, оно приехало, просто легло в общую кучу. Как вытащить его в нормальное свойство — тема отдельного разбора про маппинг полей.
Где вмешаться в импорт
Импорт в конце концов создаёт и обновляет элементы инфоблока, поэтому работают обычные события инфоблоков — те же, что описаны в разборе событий Битрикса:
<?php
// /bitrix/php_interface/init.php
use Bitrix\Main\EventManager;
EventManager::getInstance()->addEventHandler(
'iblock',
'OnAfterIBlockElementUpdate',
function (&$arFields) {
// Обмен приходит на свой скрипт — это самый надёжный признак контекста,
// не зависящий от версии и от внутренних констант ядра
$isExchange = str_contains(
(string)($_SERVER['SCRIPT_NAME'] ?? ''),
'/bitrix/admin/1c_exchange.php'
);
if (!$isExchange) {
return;
}
// здесь — лёгкая работа: пометить элемент, положить ID в очередь
}
);Ключевое ограничение — цена обработчика. Он выполняется на каждом элементе. Обработчик, который делает один лишний запрос к базе, на каталоге в 50 000 товаров даст 50 000 запросов и превратит десятиминутный обмен в часовой. Поэтому в обработчике элемента складывают идентификаторы, а тяжёлую работу делают один раз после импорта:
<?php
EventManager::getInstance()->addEventHandler(
'catalog',
'OnSuccessCatalogImport1C',
function () {
// Импорт завершён: здесь пересчитываем, отправляем, сбрасываем кэш
// Один раз на весь обмен, а не на каждый товар
}
);Проверьте имя и сигнатуру события в своей версии. Набор событий модуля каталога между версиями Битрикса менялся, и обработчик, повешенный на несуществующее событие, не вызывает ошибки — он просто молча не срабатывает. Убедитесь, что обработчик реально выполняется, до того как повесите на него сброс кэша: обмен, который «прошёл успешно», но не сбросил кэш, оставит на витрине вчерашние цены, и узнаете вы об этом от покупателя.
Что ломается чаще всего
Обмен идёт по кругу и не завершается. 1С не сохраняет сессионную куку из checkauth либо каждый запрос создаёт новую сессию. Прогресс пишется в одну сессию, а следующий шаг читает другую — и начинает сначала.
failure без внятного текста. Смотрите вторую строку ответа и лог обмена, а не сообщение в 1С. Самое частое — нехватка прав на запись в /upload/1c_catalog/ или упавший по памяти шаг.
Товары продублировались. Кто-то изменил или очистил XML_ID. Битрикс не нашёл товар по GUID и создал новый. Восстанавливается только сопоставлением по артикулу и ручной склейкой — работа на день, поэтому XML_ID и не трогают.
Цены не обновились, хотя обмен успешен. Проверьте, что ИдТипаЦены из offers.xml сопоставлен с типом цены на сайте. Несопоставленный тип цены игнорируется тихо. Смежная классика — кэш каталога, который никто не сбросил после обмена; про политику кэширования каталога есть отдельный разбор.
Обмен съел память или упёрся в таймаут. Уменьшайте размер порции в настройках обмена. Увеличивать max_execution_time бессмысленно: шаговый механизм существует ровно для того, чтобы не упираться в лимиты, и правильный ответ — короче шаг, а не длиннее лимит. Как искать, во что именно упёрся PHP, разобрано в статье про диагностику PHP-FPM.
Итоги
Обмен с 1С перестаёт быть чёрным ящиком в тот момент, когда вы один раз прошли его руками через curl. Дальше диагностика превращается в механическую процедуру.
Сначала смотрите, что приехало. XML-файлы в /upload/1c_catalog/ — единственный достоверный источник. Если поля нет в XML, проблема в 1С, и обсуждать настройки сайта бесполезно.
Затем — на какой команде оборвалось. Пять шагов, у каждого свой характерный отказ. checkauth — права, file — доступ к папке и размер порции, import — лимиты PHP.
XML_ID — священная корова. Всё остальное в инфоблоке можно менять, это — нет.
Тяжёлую работу вешайте на завершение импорта, а не на элемент. Разница между этими двумя вариантами на большом каталоге измеряется часами.
И одно наблюдение, которое экономит больше всего времени: почти каждый раз, когда клиент говорит «обмен сломался», обмен работает. Ломается что-то одно на его краю — права у пользователя, сопоставление типа цены, кэш, который не сбросили. Протокол из пяти команд надёжен именно потому, что в нём нечему ломаться, и это хорошая новость: искать нужно не в нём.
Частые вопросы
Что такое CommerceML?
CommerceML — это открытый XML-стандарт обмена коммерческой информацией, разработанный фирмой «1С» для передачи каталогов, цен, остатков и заказов между учётными системами и сайтами. Битрикс работает с версией CommerceML 2 — той самой, где корневой элемент называется КоммерческаяИнформация, а имена тегов написаны кириллицей.
Куда 1С отправляет данные при обмене с Битриксом?
На скрипт /bitrix/admin/1c_exchange.php с параметрами type и mode. Обмен каталогом идёт с type=catalog, выгрузка заказов — с type=sale. Авторизация — Basic Auth под пользователем, у которого есть право на обмен; после успешного checkauth 1С получает из ответа имя и значение сессионной куки (по умолчанию PHPSESSID) и подставляет её во все последующие запросы.
Почему обмен с 1С обрывается на середине?
Потому что импорт пошаговый: Битрикс обрабатывает порцию данных, отвечает progress и ждёт повторного запроса. Если шаг не укладывается в max_execution_time PHP или в таймаут веб-сервера, соединение рвётся до того, как прогресс будет сохранён, и следующий запуск начинает тот же шаг заново. Лечится уменьшением размера порции в настройках обмена, а не увеличением таймаутов до бесконечности.
Чем import.xml отличается от offers.xml?
import.xml несёт структуру: классификатор групп, справочник свойств, единицы измерения и сами товары с их постоянными характеристиками. offers.xml несёт то, что меняется часто, — торговые предложения с ценами и остатками. Разделение сделано ради скорости: offers.xml можно гонять каждые 15 минут, не трогая тяжёлый каталог.
Как понять, что именно приехало из 1С?
Посмотреть XML-файлы, которые 1С загрузила на сайт: они лежат в /upload/1c_catalog/ до следующего обмена. Это единственный достоверный источник — админка показывает результат разбора, а не то, что было отправлено. Если товара нет в XML, спорить с Битриксом бессмысленно, проблема на стороне 1С.
Можно ли вмешаться в процесс импорта из 1С?
Да, через события. Импорт в конечном счёте создаёт и обновляет элементы инфоблока, поэтому работают обычные OnAfterIBlockElementAdd и OnAfterIBlockElementUpdate, а модуль каталога дополнительно бросает OnSuccessCatalogImport1C после завершения импорта. Обработчик, который делает тяжёлую работу на каждом элементе, замедлит обмен пропорционально числу товаров, поэтому массовые пересчёты вешают на завершение, а не на элемент.