Экспорт и импорт
Импорт и экспорт в модуле каталога работают через профили и PHP-шаблоны. Профиль хранит имя рабочего шаблона и параметры запуска в поле SETUP_VARS. Шаблон выполняет прикладную задачу: выгружает товары в файл, читает файл импорта, обновляет карточки товаров, цены или остатки.
Для обмена данными подготовьте рабочий шаблон, передайте ему настройки через профиль, запустите экспорт или импорт и проверьте результат.
Как устроен обмен
Шаблоны размещают в папках проекта:
-
экспорт — в
/bitrix/php_interface/include/catalog_export/, -
импорт — в
/bitrix/php_interface/include/catalog_import/.
Имя рабочего скрипта шаблона заканчивается на _run.php. При запуске по профилю система подключает файл с этим суффиксом.
Файл _setup.php рядом с рабочим скриптом используют для мастера настроек в административной части.
Профиль связывает настройки и рабочий файл. В FILE_NAME хранится имя шаблона без _run.php, а в SETUP_VARS — строка параметров. Если профиль не помечен как DEFAULT_PROFILE, при запуске система передает эти параметры в шаблон как обычные PHP-переменные, например $IBLOCK_ID, $SETUP_FILE_NAME или $URL_DATA_FILE.
Перед выполнением примеров кода подключите модули iblock и catalog, проверьте права пользователя на чтение и изменение каталога. Товарный инфоблок подготовьте по статье Работа с товарами и торговыми предложениями.
Выбрать сценарий
Сценарий зависит от того, что нужно сделать с данными каталога.
|
Сценарий |
Что подготовить |
|
Разовая выгрузка товаров в файл |
Шаблон экспорта и профиль с путем к файлу результата |
|
Регулярная выгрузка по расписанию |
Профиль экспорта с |
|
Разовая загрузка файла |
Шаблон импорта и профиль с путем к файлу данных |
|
Мастер с настройками в административной части |
Файл |
|
Обновление существующих профилей |
Методы |
Если нужно загрузить цены, остатки или торговые предложения, используйте шаблон импорта как точку входа. Внутри шаблона вызывайте API из статей Работа с товарами и торговыми предложениями, Доступность, цены и подписка и Складской учет.
Экспорт
Экспорт выгружает данные каталога в файл. Для запуска подготовьте рабочий шаблон, сохраните настройки в профиле и вызовите профиль вручную, агентом или через cron.
Подготовить шаблон экспорта
Пользовательский шаблон экспорта размещают в /bitrix/php_interface/include/catalog_export/. В шаблоне должен быть весь код, который нужен для выгрузки данных. Предустановленные шаблоны могут только подключать рабочие скрипты.
Шаблон экспорта — обычный PHP-скрипт без вывода данных на экран. В скрипте доступны стандартные переменные системы и переменные, которые установил мастер экспорта или профиль.
В примере ниже $IBLOCK_ID — идентификатор инфоблока каталога. Профиль передает его в шаблон через SETUP_VARS, а шаблон приводит значение к числу и сохраняет в $productIblockId.
Ключевые переменные шаблона экспорта:
-
$SETUP_FILE_NAME— путь к файлу данных, в который шаблон записывает результат. Путь может быть относительным или абсолютным. После экспорта система покажет полный путь к файлу. -
$strExportErrorMessage— текст ошибки экспорта. Если шаблон установит эту переменную, система считает экспорт неудачным и покажет ее содержимое.
//<title>Экспорт мебели в CSV</title>
$productIblockId = (int)$IBLOCK_ID;
$exportFile = (string)$SETUP_FILE_NAME;
$allowedDirectory = '/upload/export/';
if ($productIblockId <= 0)
{
$strExportErrorMessage = 'Не выбран инфоблок каталога';
}
elseif ($exportFile === '')
{
$strExportErrorMessage = 'Не указан файл экспорта';
}
elseif (strncmp($exportFile, $allowedDirectory, strlen($allowedDirectory)) !== 0)
{
$strExportErrorMessage = 'Файл экспорта должен находиться в /upload/export/';
}
else
{
$filePath = $_SERVER['DOCUMENT_ROOT'] . $exportFile;
$file = fopen($filePath, 'wb');
if (!$file)
{
$strExportErrorMessage = 'Не удалось открыть файл экспорта';
}
else
{
fputcsv($file, ['ID', 'XML_ID', 'NAME'], ';');
$elementsIterator = \CIBlockElement::GetList(
['ID' => 'ASC'],
[
'IBLOCK_ID' => $productIblockId,
'ACTIVE' => 'Y',
],
false,
false,
['ID', 'XML_ID', 'NAME']
);
while ($element = $elementsIterator->Fetch())
{
fputcsv(
$file,
[
(int)$element['ID'],
(string)$element['XML_ID'],
(string)$element['NAME'],
],
';'
);
}
fclose($file);
}
}
Этот пример выгружает только карточки элементов инфоблока. В вызове CIBlockElement::GetList() первый массив задает сортировку по ID, второй — фильтр по инфоблоку и активности, последний — поля, которые попадут в CSV. Если нужно добавить цены, остатки или свойства, расширьте выборку и получите дополнительные данные через API каталога.
Подготовить мастер экспорта
Мастер экспорта задает дополнительные параметры шаблона: инфоблок, группы товаров, путь к файлу данных и другие настройки. Если шаблону не нужны дополнительные параметры, файл _setup.php можно не создавать.
Мастер может состоять из нескольких шагов. Номер текущего шага хранит переменная $STEP. При переходе к следующему шагу увеличьте $STEP. На последнем шаге установите $FINITE = true. После этого система передаст управление шаблону экспорта или сохранит профиль.
После окончания мастера подготовьте переменные:
-
$SETUP_FIELDS_LIST— список имен переменных, которые установил мастер. Имена разделяют запятыми. -
$SETUP_PROFILE_NAME— название профиля. Переменная нужна, если действие мастера создает профиль экспорта и$ACTIONравенEXPORT_SETUP.
Для пути к файлу данных используйте $SETUP_FILE_NAME, чтобы после экспорта система показала полный путь к созданному файлу.
Поля из $SETUP_FIELDS_LIST попадут в SETUP_VARS профиля. При запуске профиля система разберет эту строку и создаст одноименные переменные в рабочем шаблоне.
В примере показана серверная логика мастера: проверка параметров и передача списка полей в профиль. HTML-форму мастера добавьте по правилам административной страницы проекта.
$errorMessage = '';
if ($STEP > 1)
{
$IBLOCK_ID = (int)$IBLOCK_ID;
if ($IBLOCK_ID <= 0)
{
$errorMessage .= 'Инфоблок не выбран.<br>';
}
if ((string)$SETUP_FILE_NAME === '')
{
$errorMessage .= 'Не указан файл данных.<br>';
}
if ($ACTION === 'EXPORT_SETUP' && (string)$SETUP_PROFILE_NAME === '')
{
$errorMessage .= 'Не указано имя профиля.<br>';
}
if ($errorMessage !== '')
{
$STEP = 1;
}
}
if ((int)$STEP === 1)
{
$SETUP_FIELDS_LIST = 'IBLOCK_ID,SETUP_FILE_NAME';
}
elseif ((int)$STEP === 2)
{
$FINITE = true;
}
Создать профиль экспорта
Чтобы создать профиль экспорта, вызовите метод CCatalogExport::Add. В примере $productIblockId — идентификатор инфоблока каталога, товары которого нужно выгрузить. Его значение сохраняется в SETUP_VARS как параметр IBLOCK_ID, чтобы при запуске шаблон получил переменную $IBLOCK_ID.
В метод передайте массив с параметрами:
-
FILE_NAME— имя шаблона без суффикса_run.php, -
NAME— название профиля, -
SETUP_VARS— строка с параметрами шаблона в формате URL-запроса, -
IN_MENU— показывать в административном меню:YилиN, -
IN_AGENT— запускать агентом:YилиN, -
IN_CRON— запускать через cron:YилиN, -
DEFAULT_PROFILE— назначить профилем по умолчанию:YилиN, -
NEED_EDIT— требовать редактирования перед запуском:YилиN.
FILE_NAME должен совпадать с именем файла шаблона без суффикса _run.php. Например, для файла furniture_csv_run.php передайте furniture_csv.
$setupVars = http_build_query([
'IBLOCK_ID' => $productIblockId,
'SETUP_FILE_NAME' => '/upload/export/furniture.csv',
]);
$exportProfileId = \CCatalogExport::Add([
'FILE_NAME' => 'furniture_csv',
'NAME' => 'Экспорт мебели в CSV',
'IN_MENU' => 'Y',
'IN_AGENT' => 'N',
'IN_CRON' => 'N',
'DEFAULT_PROFILE' => 'N',
'NEED_EDIT' => 'N',
'SETUP_VARS' => $setupVars,
]);
if (!$exportProfileId)
{
throw new \RuntimeException('Не удалось создать профиль экспорта');
}
Метод возвращает идентификатор профиля или false. В примере результат сохраняется в $exportProfileId. Этот идентификатор нужен для запуска, обновления и удаления профиля.
Запустить экспорт по профилю
Запуск выполняет CCatalogExport::PreGenerateExport(). В метод передайте $exportProfileId — идентификатор профиля, который вернул CCatalogExport::Add() или CCatalogExport::GetByID().
Метод находит профиль, подключает файл шаблона и обновляет дату последнего запуска. Для профиля, у которого DEFAULT_PROFILE не равен Y, метод разбирает параметры из SETUP_VARS и передает их в шаблон.
$agentCall = \CCatalogExport::PreGenerateExport($exportProfileId);
if ($agentCall === false)
{
throw new \RuntimeException('Не удалось запустить экспорт по профилю');
}
Метод возвращает строку для запуска агента или false. Запуск отменяется, если профиль не найден, требует редактирования или файл шаблона отсутствует.
После запуска проверьте файл, путь к которому передан в SETUP_FILE_NAME. Если шаблон установил $strExportErrorMessage, экспорт завершится с ошибкой.
Получить список профилей экспорта
Метод CCatalogExport::GetList возвращает список профилей экспорта.
$profilesIterator = \CCatalogExport::GetList(
['NAME' => 'ASC'],
['IN_MENU' => 'Y']
);
while ($profile = $profilesIterator->Fetch())
{
echo $profile['ID'] . ': ' . $profile['NAME'] . "\n";
}
$profileCount = \CCatalogExport::GetList([], [], true);
В первом параметре GetList() передайте сортировку, во втором — фильтр. В примере метод выбирает профили, которые показываются в административном меню, и сортирует их по названию. Если вызвать метод GetList() с третьим параметром true, он вернет только количество записей.
Получить профиль экспорта по идентификатору
Один профиль экспорта можно получить через GetByID(). В метод передайте идентификатор профиля.
$profile = \CCatalogExport::GetByID($exportProfileId);
Метод GetByID() возвращает массив полей профиля или false, если профиль не найден.
Обновить и удалить профиль экспорта
Чтобы изменить профиль экспорта, используйте CCatalogExport::Update(). Чтобы удалить — CCatalogExport::Delete().
$updatedExportProfileId = \CCatalogExport::Update($exportProfileId, [
'NAME' => 'Экспорт мебели в CSV для витрины',
'SETUP_VARS' => http_build_query([
'IBLOCK_ID' => $productIblockId,
'SETUP_FILE_NAME' => '/upload/export/furniture-public.csv',
]),
]);
if (!$updatedExportProfileId)
{
throw new \RuntimeException('Не удалось обновить профиль экспорта');
}
\CCatalogExport::Delete($exportProfileId);
Метод Update() возвращает идентификатор обновленного профиля или false. Delete() удаляет профиль и возвращает результат операции.
Импорт
Импорт загружает данные из файла в каталог. Для запуска подготовьте рабочий шаблон, передайте путь к файлу через профиль и обработайте строки файла в шаблоне.
Подготовить шаблон импорта
Пользовательский шаблон импорта размещают в /bitrix/php_interface/include/catalog_import/. В качестве шаблонов система предлагает файлы, которые заканчиваются на _run.php. Если рядом есть файл с таким же именем и суффиксом _setup.php, система считает его мастером импорта.
Шаблон импорта — обычный PHP-скрипт без вывода данных на экран. В нем доступны стандартные переменные системы и переменные, которые установил мастер импорта или профиль.
В примере ниже $IBLOCK_ID — идентификатор инфоблока каталога, а $URL_DATA_FILE — путь к CSV-файлу импорта. Профиль передает эти значения через SETUP_VARS, затем шаблон сохраняет их в $productIblockId и $dataFile.
Ключевые переменные шаблона импорта:
-
$URL_DATA_FILE— путь к файлу данных для импорта. -
$strImportErrorMessage— текст ошибки импорта. Если шаблон установит эту переменную, система считает импорт неудачным и покажет ее содержимое.
//<title>Импорт мебели из CSV</title>
$productIblockId = (int)$IBLOCK_ID;
$dataFile = (string)$URL_DATA_FILE;
$allowedDirectory = '/upload/import/';
if ($productIblockId <= 0)
{
$strImportErrorMessage = 'Не выбран инфоблок каталога';
}
elseif ($dataFile === '')
{
$strImportErrorMessage = 'Не указан файл импорта';
}
elseif (strncmp($dataFile, $allowedDirectory, strlen($allowedDirectory)) !== 0)
{
$strImportErrorMessage = 'Файл импорта должен находиться в /upload/import/';
}
elseif (!is_readable($_SERVER['DOCUMENT_ROOT'] . $dataFile))
{
$strImportErrorMessage = 'Файл импорта недоступен для чтения';
}
else
{
$file = fopen($_SERVER['DOCUMENT_ROOT'] . $dataFile, 'rb');
$element = new \CIBlockElement;
if (!$file)
{
$strImportErrorMessage = 'Не удалось открыть файл импорта';
}
else
{
fgetcsv($file, 0, ';'); // пропускаем строку заголовков
while (($row = fgetcsv($file, 0, ';')) !== false)
{
[$xmlId, $name] = array_pad($row, 2, '');
$xmlId = trim((string)$xmlId);
$name = trim((string)$name);
if ($xmlId === '' || $name === '')
{
$strImportErrorMessage = 'В файле импорта есть строка без XML_ID или названия';
break;
}
$elementRow = \CIBlockElement::GetList(
[],
[
'IBLOCK_ID' => $productIblockId,
'=XML_ID' => $xmlId,
],
false,
false,
['ID']
)->Fetch();
if ($elementRow)
{
$result = $element->Update((int)$elementRow['ID'], [
'NAME' => $name,
]);
}
else
{
$result = $element->Add([
'IBLOCK_ID' => $productIblockId,
'XML_ID' => $xmlId,
'NAME' => $name,
'ACTIVE' => 'Y',
]);
}
if (!$result)
{
$strImportErrorMessage = $element->LAST_ERROR ?: 'Не удалось сохранить элемент каталога';
break;
}
}
fclose($file);
}
}
Пример импортирует только карточки элементов инфоблока. В каждой строке CSV первое значение попадает в $xmlId, второе — в $name. Поле XML_ID используется как внешний идентификатор товара: по нему пример ищет существующий элемент и обновляет его, а если элемент не найден — создает новый.
Чтобы элемент стал товаром торгового каталога, добавьте товарные параметры через \Bitrix\Catalog\Model\Product::add() или update(). Чтобы загрузить цену, вызовите методы класса \Bitrix\Catalog\Model\Price. Для остатков по складам используйте API складского учета.
Подготовить мастер импорта
Мастер импорта задает дополнительные параметры шаблона: тип инфоблока, действие с отсутствующими товарами, путь к файлу данных и другие настройки. Если шаблону не нужны дополнительные параметры, файл _setup.php можно не создавать.
Многошаговый мастер импорта использует те же служебные переменные, что и мастер экспорта.
-
$STEP— текущий шаг мастера. -
$FINITE— признак последнего шага. Установитеtrue, чтобы система передала управление шаблону импорта или сохранению профиля. -
$SETUP_FIELDS_LIST— список имен переменных, которые установил мастер. Имена разделяют запятыми. -
$SETUP_PROFILE_NAME— название профиля. Переменная нужна, если действие мастера создает профиль импорта и$ACTIONравенIMPORT_SETUP.
Минимальная логика мастера импорта может проверять файл данных и передавать в профиль список переменных:
$errorMessage = '';
if ($STEP > 1)
{
$IBLOCK_ID = (int)$IBLOCK_ID;
if ($IBLOCK_ID <= 0)
{
$errorMessage .= 'Инфоблок не выбран.<br>';
}
if ((string)$URL_DATA_FILE === '')
{
$errorMessage .= 'Не указан файл импорта.<br>';
}
if ($ACTION === 'IMPORT_SETUP' && (string)$SETUP_PROFILE_NAME === '')
{
$errorMessage .= 'Не указано имя профиля.<br>';
}
if ($errorMessage !== '')
{
$STEP = 1;
}
}
if ((int)$STEP === 1)
{
$SETUP_FIELDS_LIST = 'IBLOCK_ID,URL_DATA_FILE';
}
elseif ((int)$STEP === 2)
{
$FINITE = true;
}
Создать профиль импорта
Профиль импорта можно создать методом CCatalogImport::Add. Параметры и логика совпадают с экспортом.
В примере $productIblockId — идентификатор инфоблока каталога. В SETUP_VARS передайте его через IBLOCK_ID, а путь к файлу данных — через URL_DATA_FILE.
$importProfileId = \CCatalogImport::Add([
'FILE_NAME' => 'furniture_csv',
'NAME' => 'Импорт мебели из CSV',
'IN_MENU' => 'Y',
'IN_AGENT' => 'N',
'IN_CRON' => 'N',
'DEFAULT_PROFILE' => 'N',
'NEED_EDIT' => 'N',
'SETUP_VARS' => http_build_query([
'IBLOCK_ID' => $productIblockId,
'URL_DATA_FILE' => '/upload/import/furniture.csv',
]),
]);
if (!$importProfileId)
{
throw new \RuntimeException('Не удалось создать профиль импорта');
}
Метод возвращает идентификатор профиля или false. В примере результат сохраняется в $importProfileId. Этот идентификатор нужен для запуска, обновления и удаления профиля импорта.
Запустить импорт по профилю
Запуск выполняет CCatalogImport::PreGenerateImport(). В метод передайте $importProfileId — идентификатор профиля, который вернул CCatalogImport::Add() или CCatalogImport::GetByID().
Метод подключает шаблон и обновляет дату запуска. Для профиля, у которого DEFAULT_PROFILE не равен Y, метод разбирает параметры из SETUP_VARS и передает их в шаблон.
$agentCall = \CCatalogImport::PreGenerateImport($importProfileId);
if ($agentCall === false)
{
throw new \RuntimeException('Не удалось запустить импорт по профилю');
}
Метод возвращает строку агента или false при ошибке запуска.
После запуска проверьте измененные элементы инфоблока, цены и остатки, если шаблон их обновляет. Если шаблон установил $strImportErrorMessage, импорт завершится с ошибкой.
Получить, обновить и удалить профили импорта
Работа с профилями импорта повторяет логику экспорта. Используйте методы GetList(), GetByID(), Update() и Delete() класса CCatalogImport.
$profilesIterator = \CCatalogImport::GetList(
['ID' => 'DESC'],
['FILE_NAME' => 'furniture_csv']
);
while ($profile = $profilesIterator->Fetch())
{
echo $profile['ID'] . ': ' . $profile['NAME'] . "\n";
}
$profile = \CCatalogImport::GetByID($importProfileId);
$updatedImportProfileId = \CCatalogImport::Update($importProfileId, [
'NAME' => 'Импорт мебели из CSV по расписанию',
]);
if (!$updatedImportProfileId)
{
throw new \RuntimeException('Не удалось обновить профиль импорта');
}
\CCatalogImport::Delete($importProfileId);
В примере GetList() выбирает профили импорта с именем шаблона furniture_csv и сортирует результат по убыванию ID.
Методы возвращают:
-
GetList()— список профилей, -
GetByID()— один профиль в виде массива, -
Update()— идентификатор профиля илиfalse, -
Delete()— результат удаления.
PreGenerateExport() и PreGenerateImport() выполняют PHP-файл шаблона через include. Не передавайте в FILE_NAME данные из запроса пользователя и не создавайте профиль для непроверенного файла.
Проверить результат
После экспорта проверьте:
-
профиль найден через
CCatalogExport::GetByID(), -
файл создан в каталоге, который указан в
SETUP_FILE_NAME, -
файл содержит ожидаемые строки и кодировку,
-
в результате запуска нет сообщения из
$strExportErrorMessage.
После импорта проверьте:
-
профиль найден через
CCatalogImport::GetByID(), -
элементы инфоблока созданы или обновлены,
-
товарные параметры, цены и остатки изменились, если шаблон их обрабатывает,
-
в результате запуска нет сообщения из
$strImportErrorMessage.
$profile = \CCatalogExport::GetByID($exportProfileId);
if (!$profile)
{
throw new \RuntimeException('Профиль экспорта не найден');
}
$exportFile = '/upload/export/furniture.csv';
if (!is_readable($_SERVER['DOCUMENT_ROOT'] . $exportFile))
{
throw new \RuntimeException('Файл экспорта не найден');
}
В примере $exportProfileId — идентификатор профиля экспорта, а $exportFile — путь к файлу, который должен создать шаблон.
Учитывать ограничения
Экспорт и импорт подключают рабочий файл шаблона как PHP-код. Из-за этого шаблон должен быть частью проекта, а не файлом, который загрузил пользователь.
Правила работы с путями к файлам данных:
-
хранить файлы импорта и экспорта в заранее выбранных каталогах, например,
/upload/import/и/upload/export/, -
не передавать в
FILE_NAME,SETUP_FILE_NAMEиURL_DATA_FILEзначения из запроса без проверки, -
проверять чтение файла импорта и возможность записи файла экспорта до обработки данных,
-
записывать описание ошибки в
$strExportErrorMessageили$strImportErrorMessage, если входные данные некорректны.
Для регулярного обмена учитывайте объем каталога. Большой импорт лучше разбить на шаги в мастере или вынести запуск в cron, чтобы не зависеть от времени выполнения административного запроса.