Интеграция с 1С: способы передачи данных через PHP
Обмен данными между системой 1С:Предприятие и веб-приложениями на PHP часто требуется при построении корпоративных решений (ERP, интернет-магазины). Существует несколько протоколов и подходов для реализации такого обмена. В статье рассматриваются основные варианты, их назначение, примеры кода и типичные трудности.
Основной подход: обмен через CommerceML с помощью cURL
Наиболее распространённый способ интеграции 1С с сайтами на PHP - использование протокола CommerceML (Common Markup Language). 1С отправляет XML-файлы по HTTP на скрипт PHP, который обрабатывает их и возвращает результат. PHP-скрипт выступает в роли веб-сервиса.
Как настроить обмен данными между 1С и PHP-сайтом через HTTP-запросы?
Для приёма данных от 1С используется стандартный скрипт (например, exchange.php). Он принимает POST-запрос с XML-данными.
// exchange.php - пример обработки CommerceML из 1С
$mode = $_GET['mode'] ?? ''; // 'catalog' или 'sale'
$type = $_GET['type'] ?? ''; // 'import' или 'checkauth' и т.д.
// 1. Аутентификация (проверка auth)
if ($type === 'checkauth') {
// возврат сессии
header('Content-Type: text/plain; charset=utf-8');
echo "success\n";
echo session_id()."\n";
exit;
}
// 2. Инициализация
if ($type === 'init') {
// возврат параметров обмена
header('Content-Type: text/plain; charset=utf-8');
echo "zip=no\n";
echo "file_limit=10485760\n";
exit;
}
// 3. Загрузка файла
if ($type === 'file') {
$file = file_get_contents('php://input');
// сохраняем или обрабатываем XML
$xml = simplexml_load_string($file);
// ... обработка
header('Content-Type: text/plain; charset=utf-8');
echo "success\n";
exit;
}
1c exchange php type (обмен данными с 1с через php)
Со стороны 1С настраивается HTTP-сервис, указывающий на этот скрипт.
Типичные проблемы:
- Неправильная кодировка (файлы должны быть в UTF-8).
- Ошибка аутентификации (1С посылает Basic Auth, нужно настроить проверку).
- Превышение лимита размера файла (настройки php.ini: post_max_size, upload_max_filesize).
- Некорректный XML (отсутствие соответствующей библиотеки для парсинга).
Как упростить интеграцию с помощью готовой библиотеки для PHP?
Существует открытая PHP-библиотека 1c_exchange, реализующая протокол CommerceML. Она берёт на себя аутентификацию, обработку файлов и генерацию ответов.
// Пример работы с библиотекой 1c_exchange
require_once 'vendor/autoload.php';
use OpenData\OneCExchange\Exchange;
$exchange = new Exchange([
'auth' => ['login' => 'admin', 'password' => 'pass'],
'temp_dir' => '/tmp/1c_exchange/',
]);
$exchange->run();
Библиотека автоматически обрабатывает запросы типов checkauth, init, file, import. Требуется только реализовать классы для обработки данных (каталог, заказы).
Проблема: если версия библиотеки устарела, может не поддерживать новые версии CommerceML. Рекомендуется тестировать перед использованием.
Как реализовать обмен через SOAP, если 1С предоставляет веб-сервисы?
Некоторые конфигурации 1С имеют встроенные SOAP-сервисы. PHP может выступать в роли клиента, вызывая методы сервиса для получения или отправки данных.
// SOAP клиент для 1С
$wsdl = 'http://1c-server/ws/Exchange1C?wsdl';
$client = new SoapClient($wsdl, [
'login' => 'user',
'password' => 'pass',
]);
try {
$result = $client->getCatalog(['Date' => '2024-01-01']);
// обрабатываем ответ
var_dump($result);
} catch (SoapFault $e) {
echo "Ошибка: " . $e->getMessage();
}
Этот вариант подходит, если 1С явно публикует SOAP-сервисы и требуется выгрузить данные по расписанию.
Ошибки: неверный WSDL, проблемы с аутентификацией, разные схемы XML.
Как организовать обмен без HTTP, используя XML-файлы на FTP или в локальной папке?
В случаях, когда прямое HTTP-соединение невозможно (сетевые ограничения), 1С выгружает файлы в определённую папку, а PHP-скрипт по расписанию (cron) забирает их, обрабатывает и помещает результат.
// скрипт для обработки XML из папки
$files = glob('/exchange/import/*.xml');
foreach ($files as $file) {
$xml = simplexml_load_file($file);
// обработка
// после успеха перемещаем файл
rename($file, '/exchange/processed/'.basename($file));
}
Минус: нет мгновенной обратной связи, требуется настройка планировщика.
Как обмениваться с 1С через REST, если она доработана?
Современные версии 1С могут публиковать REST API через HTTP-сервисы. PHP обращается к эндпоинтам, передавая данные в JSON или XML.
// Пример запроса к REST-сервису 1С
$ch = curl_init('http://1c-server/api/catalog');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'user:pass');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
Этот вариант наиболее гибкий, но требует доработки 1С программистом.
Выбор конкретного подхода зависит от возможностей 1С, требований к синхронизации и инфраструктуры проекта.
Расширенные примеры кода для реализации обмена данными между 1С и PHP с дополнительными возможностями.
Потоковая обработка больших CommerceML-файлов
При объёме данных более 100 МБ стандартные методы (simplexml) потребляют много памяти. Используется XMLReader.
// Обработка CommerceML потоком XMLReader
$reader = new XMLReader();
$reader->open('import.xml');
while ($reader->read()) {
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'Товар') {
$xmlProduct = $reader->readOuterXML();
$product = simplexml_load_string($xmlProduct);
// сохранить товар в БД
echo "Обработан товар: " . $product->Наименование . PHP_EOL;
}
}
$reader->close();
Обработан товар: Стул офисный Обработан товар: Стол письменный ... (всего 10000 записей)
Выгрузка заказов из PHP в 1С (CommerceML)
Генерация XML-файла для отправки в 1С через any способ (HTTP, FTP).
// Генерация CommerceML для документа продажи
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><КоммерческаяИнформация>КоммерческаяИнформация>');
$doc = $xml->addChild('Документ');
$doc->addChild('Ид', 'ORDER-001');
$doc->addChild('Номер', '001');
$doc->addChild('Дата', date('Y-m-d'));
$doc->addChild('ХозОперация', 'Заказ товара');
$sum = $doc->addChild('Сумма', 15000.00);
$sum->addAttribute('Валюта', 'руб');
$products = $doc->addChild('Товары');
$item = $products->addChild('Товар');
$item->addChild('Ид', 'PROD-123');
$item->addChild('ЦенаЗаЕдиницу', 5000);
$item->addChild('Количество', 3);
$item->addChild('Сумма', 15000);
$xml->asXML('/tmp/order-export.xml');
echo 'Файл создан: /tmp/order-export.xml';
Файл создан: /tmp/order-export.xml
Параллельный обмен с несколькими базами 1С через Guzzle
Если нужно одновременно обмениваться данными с несколькими конфигурациями 1С, используется асинхронный HTTP-клиент.
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
$clients = [
['base_uri' => 'http://1c-buh', 'auth' => ['user1', 'pass1']],
['base_uri' => 'http://1c-trade', 'auth' => ['user2', 'pass2']],
];
$requests = function () use ($clients) {
foreach ($clients as $cfg) {
$client = new Client(['base_uri' => $cfg['base_uri']]);
yield new Request('POST', '/exchange', [
'auth' => $cfg['auth'],
'body' => file_get_contents('catalog.xml')
]);
}
};
$pool = new Pool(new Client(), $requests(), [
'concurrency' => 2,
'fulfilled' => function ($response, $index) {
echo "База #$index ответила: " . $response->getBody() . PHP_EOL;
},
'rejected' => function ($reason, $index) {
echo "База #$index ошибка: " . $reason . PHP_EOL;
},
]);
$promise = $pool->promise();
$promise->wait();
База #0 ответила: success База #1 ответила: success
Обработка ошибок и повторные попытки при обмене с 1С
Реализация устойчивого обмена с логированием и автоматическими повторами при временных сбоях.
class ExchangeWithRetry {
private $maxAttempts = 3;
private $delay = 2; // секунды
public function send($url, $xml) {
$attempt = 0;
while ($attempt < $this->maxAttempts) {
$attempt++;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/xml']);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
echo "Успех на попытке $attempt\n";
return $response;
} else {
echo "Ошибка (HTTP $httpCode) на попытке $attempt\n";
if ($attempt < $this->maxAttempts) {
sleep($this->delay);
}
}
}
throw new \RuntimeException('Не удалось отправить данные после '.$this->maxAttempts.' попыток');
}
}
$exchanger = new ExchangeWithRetry();
try {
$exchanger->send('http://1c-server/exchange', '... ');
} catch (Exception $e) {
echo $e->getMessage();
}
Ошибка (HTTP 500) на попытке 1 Ошибка (HTTP 500) на попытке 2 Успех на попытке 3