Для обеспечения синхронизации каталога товаров между системой 1С и сайтом на системе управления Битрикс, используется стандартный для Битрикса протокол обмена XML файлами в формате CommerceML, основанный на передаче от 1С к Битриксу HTTP GET и POST запросов с определёнными параметрами, и получении стандартных ответов, содержащих статус операции, обозначающий результат её выполнения.
В первой статье этой серии дано обоснование возможности применения отдельного скрипта, берущего сформированные 1С или другой системой или программой, XML файлы, и передающего их Битриксу, используя стандартный протокол.
В этой статье я дам подробные комментарии к каждой строчке скрипта. Это позволит упростить его модификацию под ваши нужды.
Скрипт написан на BASH и является одним из нескольких скриптов, обеспечивающих различные обмены через один и тот же стандарт, который предлагает 1С-Битрикс для передачи товаров каталога из 1С и загрузки заказов с сайта, построенного на основе системы управления Битрикс.
Далее идёт текст скрипта с комментариями. Краткий вид скрипта, содержащий исключительно код, приведён в предыдущей статье, и доступен на github проекта bitrexchange.
Для того, чтобы не передались пустые или битые файлы, для предотвращения порчи данных, при любой ошибке завершаем работу скрипта.
Это такой интересный приём перехода в текущую директорию, и одновременно сохранение полного текущего пути в переменную
Обычно, 1С выкладывает файлы в какую-то расшареную папку на сервере в сети, которую мы заранее примонтируем. Но это может быть и локальная директория для вас, которая расшарена вами в сети
Имя файла zip, в который будут запакованы xml файлы. Вместо этого, можно использовать просто временное имя. Но такое жёстко заданное имя файла используется для сохранения копий ранее переданных файлов. Очень удобно: можно в любой момент посмотреть, в какой день появился какой-то товар и по какой цене и т.п.
Имена файлов, которые мы будем передавать. Эти файлы формирует 1С, обычно у них такие имена, но могут быть и другие! Нужно проверить это! Файлы перечисляются через пробел.
Почта администратора, на которую направляются сообщения об ошибках.
Определяем текущее время:
Этот скрипт — частный случай всех многочисленных видов загрузок. Кроме выгрузки каталога, которую мы сейчас делаем, существуют другие обмены, для которых существуют свои отдельные скрипты. Но и в рамках этой выгрузки — выгрузки каталога, определены два типа: так называемая инкрементальная выгрузка, то есть, выгрузка изменений, и полная выгрузка. По формату отличаются они друг от друга только одним параметром: значением атрибута
— он равен либо true, либо false. Говоря о содержимом XML файлов, можно сказать, что инкрементальная выгрузка может содержать и полный набор товаров, разница в другом: если битрикс получает полную выгрузку, то он полностью стирает весь имеющийся каталог товаров и заполняет его заново. Также теряются и все картинки товаров, поэтому полная выгрузка обязательно включает в себя все изображения, тогда как инкрементальная может не включать. Ну и конечно, если важно сохранить какие-то созданные вами привязки в базе сайта, то лучше не удалять существующий каталог. В общем, так или иначе, есть огромная, определяющая разница, какой именно тип выгрузки использовать. Поэтому обязательно проверим, ни в коем случае не доверяя 1C, что эта выгрузка действительно инкрементальная, причём проверим в обоих файлах. Заодно проверим, что эти файлы вообще существуют, и что их именно два. Иногда, например, 1С почему-то выгружает только номерклатуру, а может так случиться, что шара отвалилась и файлы вообще не выгрузились. Поэтому, в случае проблемы, сообщаем себе о ней и выходим.
Начинаем собственно работу: запаковываем файлы и делаем архив предыдущего файла текущей датой. Обратите внимание, что эта команда запаковывает все xml файлы в каталоге.
Задаём заголовки HTTP запроса. На самом деле это, во-первых, совершенно необязательно, а во-вторых, можно задать какие-то свои, например, user-agent, по которому потом можно отловить эти запросы в логах апача на принимающей стороне.
Логин и пароль пользователя, под которым будет логиниться загрузка. Обычно это 1c_import или import. Эти логин и пароль задаются в панели управления битрикса! Для теста вы можете использовать и свой администраторский аккаунт, admin.
Чтобы не загромождать скрипт, вынесем в отдельную переменную базовый url всех запросов. обычно это вашдомен/bitrix/admin/1c_exchange.php
Поскольку документация весьма(!) поверхностная, и конкретные способы применения протокола разнятся от конфигурации 1С, используемый способ обмена проверен и подтверждён экспериментально и работает без изменений на нескольких рабочих проектах, что подтверждает возможность его массового использования.
Согласно протоколу обмена, запросы нескольких типов передаются последовательно. Тип запроса определяется параметром, который добавляется к базовому url, который мы уже задали выше как baseurl. Две переменные в url задают тип запроса. Первая, type, у нас принимает значения либо sale, либо catalog. Вы можете попробовать изменить это, по крайней мере для первого запроса, и использовать всегда catalog. Вторая, более важная для нас, так как она и определяет этап обмена, в переменной mode.
Первый запрос, mode=checkauth
Второй запрос, mode=init
Третий запрос, mode=file + POST zip-файла.
Последующие запросы, mode=import
Мы логинимся с помощью аутентификации по HTTP протоколу! Обычно, такой способ включен в битриксе, но если нет, проверьте настройки сервера. Насколько я знаю, какой-то настройки для включения или выключения этого способа в битриксе нет, но аутентификация может быть выключена программно многими способами. Также может мешаться так называемая «проактивная защита», если вы никак не можете залогиниться, попробуйте отключить её на время тестирования.
Согласно протоколу, в случае успешного входа, битрикс отдаёт ответ в виде трёх строк в теле HTTP ответа:
Первая — строка success
Вторая — переменная сессии, обычно PHPSESSID
Третье — значение сессии, строка.
Если sussecc получен, сохраняем переменнную сессии и её значение для дальнейшего использования, если нет, выходим из скрипта. На этом моменте в случае ошибки мы можем получить HTML страницу, которую вы можете сохранить и кое-как просмотреть, и, скорее всего, вы найдёте в ней сообщение о том, что вам нужно залогиниться. На этом этапе — наиболее вероятно — проверяйте логин и пароль пользователя, попробуйте, прежде всего, зайти под этими логином и паролем в панель управления битрикса.
Второй запрос — Init. При получении этого запроса полностью очищается(!) директория /upload/1c_catalog/ Будьте внимательны, если вам нужны какие-то данные предыдущей загрузки. Например, это будет важно, если вы передаёте картинки товаров. 1С версии 8.3, как было обнаружено, почему-то этот запрос не передаёт, а переходит сразу к запросу file. На этом этапе возможно появление ошибки, которая будет описана далее в приложении, см. возможные ошибки(1).
В третьем запросе нужно передать POST-запросом zip-файл. mode должно быть = file, а вот имя файла — параметр filename — я как понимаю, может быть любым, потому что оно нигде больше не фигурирует в запросе, и задаёт только имя, под которым передаваемые данные сохраняются в виде файла (ведь файл передаётся через POST-запрос и поэтому на самом деле в контексте HTTP это не файл а просто какой-то кусок данных который может быть чем угодно).
На этом шаге в директории upload/1c_catalog находится файл import.zip, нераспакованный. Интересно, что больше никаких дополнительных запросов на него посылать не нужно. Как только будет первый запрос на импорт, он сам распакуется.
Далее, согласно протоколу обмена 1C-Битрикс, нужно посылать запросы с mode=file, до тех пор, пока не будет получена строка success. На самом деле, нужно проверять не success, а то, что на каждый запрос есть ответ progress, и если он есть, то можно продолжать импорт, а если пришло что-то другое, то импорт закончился по каким-то причинам, одной из которых может быть и success. Один из многочисленных недокументированных моментов состоит в том, что такой цикл запросов нужно повторять для каждого распакованного файла, а имя zip-файла больше нигде указывать не нужно, поскольку он распаковывается сразу после получения. Также см. приложение, возможные ошибки(2).
После этого цикла нужно проверять, что последнее сообщение = success, и в ином случае, опять уведомлять себя. Это можно делать в рамках этого скрипта, либо каким-то другим способом, например, проверять лог.
Согласно документации, последним запросом должен идти type=success, 1С этот запрос отсылает, но этот скрипт обходится без него.
На втором запросе выдаётся ошибка «failure». Компонент должен выдавать при ошибке слово «failure» и далее описание ошибки. Но, видимо, не может определить язык при запросе, и поэтому отдаётся просто failure без детализации ошибки. Хотя должен существовать какой-то язык по умолчанию. Возможно, причина в чём-то другом, но факт тот, что отдаётся failure и всё. Источник ошибки определить невозможно. Решается, как всегда, залезанием в код.
можно отключить проверку этого параметра прямо в коде, можно установить его в N:
Настройки — Инструменты — Командная PHP-строка.
Неочевидная ошибка: на каждом этапе отдаются две строки: первая — progress, и вторая — описание, что делается. Так вот, обязательно обязательно должны быть блоки progress. Обработано XXXX из YYYYY элементов.
— Вот это «обработано столько-то из столько-то элементов» — это и есть импорт. если этого нет, то импорт не делается. такие случаи были в определённых конфигурациях.
Стандартный обмен 1С-Битрикс на BASH: Первая статья серии публикаций.
В первой статье этой серии дано обоснование возможности применения отдельного скрипта, берущего сформированные 1С или другой системой или программой, XML файлы, и передающего их Битриксу, используя стандартный протокол.
В этой статье я дам подробные комментарии к каждой строчке скрипта. Это позволит упростить его модификацию под ваши нужды.
Скрипт написан на BASH и является одним из нескольких скриптов, обеспечивающих различные обмены через один и тот же стандарт, который предлагает 1С-Битрикс для передачи товаров каталога из 1С и загрузки заказов с сайта, построенного на основе системы управления Битрикс.
Далее идёт текст скрипта с комментариями. Краткий вид скрипта, содержащий исключительно код, приведён в предыдущей статье, и доступен на github проекта bitrexchange.
Настройки скрипта и локальных файлов
Для того, чтобы не передались пустые или битые файлы, для предотвращения порчи данных, при любой ошибке завершаем работу скрипта.
set -e
Это такой интересный приём перехода в текущую директорию, и одновременно сохранение полного текущего пути в переменную
cd $(dirname $0)
cdir=$(pwd)"/"
Обычно, 1С выкладывает файлы в какую-то расшареную папку на сервере в сети, которую мы заранее примонтируем. Но это может быть и локальная директория для вас, которая расшарена вами в сети
remote_dir="/mnt/localwinserver_fs/import/webdata/"
Имя файла zip, в который будут запакованы xml файлы. Вместо этого, можно использовать просто временное имя. Но такое жёстко заданное имя файла используется для сохранения копий ранее переданных файлов. Очень удобно: можно в любой момент посмотреть, в какой день появился какой-то товар и по какой цене и т.п.
zip_fname="catalogue.zip"
Имена файлов, которые мы будем передавать. Эти файлы формирует 1С, обычно у них такие имена, но могут быть и другие! Нужно проверить это! Файлы перечисляются через пробел.
xml_files="import0_1.xml offers0_1.xml"
Почта администратора, на которую направляются сообщения об ошибках.
email1="admin@yourinternetshop.com";
email2="alert@yourinternetshop.com";
Определяем текущее время:
ctime=$(date +%Y-%m-%d-%H%M)
Проверка и подготовка файлов
Этот скрипт — частный случай всех многочисленных видов загрузок. Кроме выгрузки каталога, которую мы сейчас делаем, существуют другие обмены, для которых существуют свои отдельные скрипты. Но и в рамках этой выгрузки — выгрузки каталога, определены два типа: так называемая инкрементальная выгрузка, то есть, выгрузка изменений, и полная выгрузка. По формату отличаются они друг от друга только одним параметром: значением атрибута
СодержитТолькоИзменения
— он равен либо true, либо false. Говоря о содержимом XML файлов, можно сказать, что инкрементальная выгрузка может содержать и полный набор товаров, разница в другом: если битрикс получает полную выгрузку, то он полностью стирает весь имеющийся каталог товаров и заполняет его заново. Также теряются и все картинки товаров, поэтому полная выгрузка обязательно включает в себя все изображения, тогда как инкрементальная может не включать. Ну и конечно, если важно сохранить какие-то созданные вами привязки в базе сайта, то лучше не удалять существующий каталог. В общем, так или иначе, есть огромная, определяющая разница, какой именно тип выгрузки использовать. Поэтому обязательно проверим, ни в коем случае не доверяя 1C, что эта выгрузка действительно инкрементальная, причём проверим в обоих файлах. Заодно проверим, что эти файлы вообще существуют, и что их именно два. Иногда, например, 1С почему-то выгружает только номерклатуру, а может так случиться, что шара отвалилась и файлы вообще не выгрузились. Поэтому, в случае проблемы, сообщаем себе о ней и выходим.
chan=$(grep -e "СодержитТолькоИзменения=\"true" ${remote_dir}*.xml | wc -l)
if test "$chan" != "2"; then
echo "Error: XMLs are not in 'changes only' mode or file(s) are missing"
mail -s "Загрузка цен" -a "From: bitrexchange <${email1}>" $email1,$email2 <<< "Не прошла загрузка цен на сайт."
exit 1
else
echo "OK: Format of XMLs are 'changes only'"
fi
Начинаем собственно работу: запаковываем файлы и делаем архив предыдущего файла текущей датой. Обратите внимание, что эта команда запаковывает все xml файлы в каталоге.
if [ -f $zip_fname ]; then mv $zip_fname "${zip_fname}.${ctime}"; fi
/usr/bin/zip -9j "$zip_fname" ${remote_dir}*.xml
Настройки HTTP запросов
Задаём заголовки HTTP запроса. На самом деле это, во-первых, совершенно необязательно, а во-вторых, можно задать какие-то свои, например, user-agent, по которому потом можно отловить эти запросы в логах апача на принимающей стороне.
headers="--header=\"User-Agent: 1C+Enterprise/8.2\" --header=\"Accept-Encoding: deflate\""
Логин и пароль пользователя, под которым будет логиниться загрузка. Обычно это 1c_import или import. Эти логин и пароль задаются в панели управления битрикса! Для теста вы можете использовать и свой администраторский аккаунт, admin.
login="import"
password="yourpasswordonbitrix"
Чтобы не загромождать скрипт, вынесем в отдельную переменную базовый url всех запросов. обычно это вашдомен/bitrix/admin/1c_exchange.php
baseurl="http://yourinternetshop.com/bitrix/admin/1c_exchange.php"
Собственно обмен
Поскольку документация весьма(!) поверхностная, и конкретные способы применения протокола разнятся от конфигурации 1С, используемый способ обмена проверен и подтверждён экспериментально и работает без изменений на нескольких рабочих проектах, что подтверждает возможность его массового использования.
Согласно протоколу обмена, запросы нескольких типов передаются последовательно. Тип запроса определяется параметром, который добавляется к базовому url, который мы уже задали выше как baseurl. Две переменные в url задают тип запроса. Первая, type, у нас принимает значения либо sale, либо catalog. Вы можете попробовать изменить это, по крайней мере для первого запроса, и использовать всегда catalog. Вторая, более важная для нас, так как она и определяет этап обмена, в переменной mode.
Первый запрос, mode=checkauth
Второй запрос, mode=init
Третий запрос, mode=file + POST zip-файла.
Последующие запросы, mode=import
Первый запрос
Мы логинимся с помощью аутентификации по HTTP протоколу! Обычно, такой способ включен в битриксе, но если нет, проверьте настройки сервера. Насколько я знаю, какой-то настройки для включения или выключения этого способа в битриксе нет, но аутентификация может быть выключена программно многими способами. Также может мешаться так называемая «проактивная защита», если вы никак не можете залогиниться, попробуйте отключить её на время тестирования.
ret_line=$( wget $headers --user=${login} --password=${password} --auth-no-challenge -O - -q "${baseurl}?type=sale&mode=checkauth" )
read -a ret_ar <<< $ret_line
Согласно протоколу, в случае успешного входа, битрикс отдаёт ответ в виде трёх строк в теле HTTP ответа:
Первая — строка success
Вторая — переменная сессии, обычно PHPSESSID
Третье — значение сессии, строка.
Если sussecc получен, сохраняем переменнную сессии и её значение для дальнейшего использования, если нет, выходим из скрипта. На этом моменте в случае ошибки мы можем получить HTML страницу, которую вы можете сохранить и кое-как просмотреть, и, скорее всего, вы найдёте в ней сообщение о том, что вам нужно залогиниться. На этом этапе — наиболее вероятно — проверяйте логин и пароль пользователя, попробуйте, прежде всего, зайти под этими логином и паролем в панель управления битрикса.
if [ ${ret_ar[0]} != "success" ]; then echo "Login error\r\n"; exit -1; fi
sessvar=${ret_ar[1]}
sessid=${ret_ar[2]}
echo sessid=$sessid
Второй запрос
Второй запрос — Init. При получении этого запроса полностью очищается(!) директория /upload/1c_catalog/ Будьте внимательны, если вам нужны какие-то данные предыдущей загрузки. Например, это будет важно, если вы передаёте картинки товаров. 1С версии 8.3, как было обнаружено, почему-то этот запрос не передаёт, а переходит сразу к запросу file. На этом этапе возможно появление ошибки, которая будет описана далее в приложении, см. возможные ошибки(1).
ret=$(wget $headers --header="Cookie: ${sessvar}=${sessid}" -O - -q "${baseurl}?type=catalog&mode=init"); echo $ret
Третий запрос
В третьем запросе нужно передать POST-запросом zip-файл. mode должно быть = file, а вот имя файла — параметр filename — я как понимаю, может быть любым, потому что оно нигде больше не фигурирует в запросе, и задаёт только имя, под которым передаваемые данные сохраняются в виде файла (ведь файл передаётся через POST-запрос и поэтому на самом деле в контексте HTTP это не файл а просто какой-то кусок данных который может быть чем угодно).
На этом шаге в директории upload/1c_catalog находится файл import.zip, нераспакованный. Интересно, что больше никаких дополнительных запросов на него посылать не нужно. Как только будет первый запрос на импорт, он сам распакуется.
ret=$(wget $headers --post-file ${zip_fname} --header="Cookie: ${sessvar}=${sessid}" -O - -q "${baseurl}?type=catalog&mode=file&filename=import.zip"); echo $ret
Запросы импорта
Далее, согласно протоколу обмена 1C-Битрикс, нужно посылать запросы с mode=file, до тех пор, пока не будет получена строка success. На самом деле, нужно проверять не success, а то, что на каждый запрос есть ответ progress, и если он есть, то можно продолжать импорт, а если пришло что-то другое, то импорт закончился по каким-то причинам, одной из которых может быть и success. Один из многочисленных недокументированных моментов состоит в том, что такой цикл запросов нужно повторять для каждого распакованного файла, а имя zip-файла больше нигде указывать не нужно, поскольку он распаковывается сразу после получения. Также см. приложение, возможные ошибки(2).
for fname in $xml_files; do
st="progress";
while [ "$st" = "progress" ]; do
ret=$(wget $headers --header="Cookie: ${sessvar}=${sessid}" -O - -q "${baseurl}?type=catalog&mode=import&filename=${fname}");
st=$( <<< "$ret" head -n1 | cut -c1-8); echo "$ret" | iconv -f cp1251 -t utf-8
done
done
После этого цикла нужно проверять, что последнее сообщение = success, и в ином случае, опять уведомлять себя. Это можно делать в рамках этого скрипта, либо каким-то другим способом, например, проверять лог.
Последний запрос
Согласно документации, последним запросом должен идти type=success, 1С этот запрос отсылает, но этот скрипт обходится без него.
Приложение:
Возможные ошибки(1)
На втором запросе выдаётся ошибка «failure». Компонент должен выдавать при ошибке слово «failure» и далее описание ошибки. Но, видимо, не может определить язык при запросе, и поэтому отдаётся просто failure без детализации ошибки. Хотя должен существовать какой-то язык по умолчанию. Возможно, причина в чём-то другом, но факт тот, что отдаётся failure и всё. Источник ошибки определить невозможно. Решается, как всегда, залезанием в код.
COption::GetOptionString("sale", "secure_1c_exchange", "N") == "Y"
можно отключить проверку этого параметра прямо в коде, можно установить его в N:
Настройки — Инструменты — Командная PHP-строка.
COption::SetOptionString("catalog", "DEFAULT_SKIP_SOURCE_CHECK", "Y" );
COption::SetOptionString("sale", "secure_1c_exchange", "N" );
Возможные ошибки(2)
Неочевидная ошибка: на каждом этапе отдаются две строки: первая — progress, и вторая — описание, что делается. Так вот, обязательно обязательно должны быть блоки progress. Обработано XXXX из YYYYY элементов.
— Вот это «обработано столько-то из столько-то элементов» — это и есть импорт. если этого нет, то импорт не делается. такие случаи были в определённых конфигурациях.
Стандартный обмен 1С-Битрикс на BASH: Первая статья серии публикаций.