Прокси soap-сервер. Когда 1С не может в SOAP




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

18 Comments

  1. savostin.alex

    Можно как службу поднять:

    nssm.exe install web-app «C:Program Files
    odejs
    ode.exe» c:httpindex.js

    Reply
  2. nixel

    (1) предпочитаю такие вещи упаковывать в докер.

    Reply
  3. PLAstic

    А проблема была сложнее, чем просто обернуть наш пакет в soap:envelope? А то я выкрутился, скачав XSD SOAP, подгрузив в 1С и программно обернув достаточно красиво свой пакет в envelope. Про что мне надо почитать, чтобы проникнуться сложностями топикстартера? Мне кажется, хидеры так же добавляются обычным способом…

    1С с жсоном работает просто мерзко, когда пытаешься его сериализовать по XDTO. Попробуйте выгрузить или загрузить пустой массив. Выгрузить — он никак не декларируется, загрузить — натыкаемся на баг платформы с одним только выходом — перезагрузить клиента. Платформенный «ПрочитатьJSON», конечно, парсит уже нормально пустые массивы, но получаем структуру.

    Reply
  4. nixel

    (3) хедеры добавляются не в soap:body, а в soap:headers. В моем случае мне нужно было реализовать ws-addressing и ws-security .X509 гостовскими сертификатами. В итоге body составляет примерно 5 процентов от итогового envelope, все остальное обрабатывалось на стороне прослойки.

    Reply
  5. PLAstic

    (4) Загружаем это в пакет XDTO, видим сразу Envelope:Header. Это не то?

    Вроде похоже. Почитал про WS-addressing, сразу наткнулся на этот пакет. Грузим его в XDTO, добавляем нужные ссылки. Вроде всё?

    Тут в 1.2 и в 7 указаны ссылки на все задействованные пространства имён.

    Reply
  6. nixel

    (5) про ws-security почитайте)

    Reply
  7. nixel

    (5) но вообще любопытная идея — формировать соап сообщение напрямую через xdto. Спасибо, буду иметь ввиду.

    Reply
  8. N!ghtmare

    Еще как вариант,не «за 10 минут конечно», чтобы сохранить возможность валидации пакетов на стороне приемника, в проксе реализовать xslt преобразование. был практический опыт реализации на одном из проектов такой штуки на шарпе для интеграции с SAP PI.

    в целом эта функция(xslt transoform) есть в большинстве esb -ей. и в WSO2 и в MULE. так же поддержка процессоров xslt есть в java и .net , нужно только обернуть и поднять на сервере приложения(Тomcat,IIS)

    И на помечтать… В платформе было бы не плохо не сразу подавать сообщение на валидатор по опубликованному веб-сервису , а добавить возможность провести подготовительную обработку сообщения,дать возможность реализовать прокси внутри. Так же по внешней wsdl ссылке перед отправкой добавить возможность обработки отправляемого сообщения внешнему вебсервису. вот бы зажили тогда….

    Reply
  9. nixel

    (4) и отдельно этот же сервис у меня выступает в роли коллбэка для асинхронного соап обмена с повышенными требованиями по высокой доступности, а 1с с её выводом на обслуживание для обновления тут не подходила.

    В общем… Много было заморочек

    Reply
  10. Fragster

    На хабре есть хорошая статья. Решается на 1с буквально в десяток строк, коотрые можно вынести в общий модуль и переиспользовать https://habr.com/post/313910/

    Reply
  11. DitriX

    когда я столкнулся с этой проблемой — я не думал что это такая трагедия 🙂

    Мы решили эту проблему за 10 минут, причем тупо средствами 1С.

    Тут надо всего лишь понять, что SOAP — это протокол овер http, а это значит, что достаточно использовать http для тех же функций.

    Поэтому просто берем работаем как с обычным SOAP — набираем боди как обычно, потом сериализуем его в xml, потом приклеиваем сверху хеадер и отправляем пост запрос.

    Да, добавилось лишних 20 строк кода, зато четко все на 1С, универсально и без всяких проблем.

    Reply
  12. PLAstic

    (11) Т.е. колхозить потэгово? Я правильно понял?

    Reply
  13. DitriX

    (12) Эммм… Не понял, в смысле — потегово? Делаете все как обчно, но в тот момент когда вы делаете вызов функции соапа — вы просто сериализуете параметры, которые вы бы передавали в соап, и отправляете через http. Ничего тут потегово не надо делать.

    Reply
  14. 987ww765

    (13) Вас не затруднит выложить пример? На словах я так и не догнал ваш вариант решения. Спасибо

    Reply
  15. DitriX

    Простого примера нет, там все раскидано по куче модулей.

    Но в двух словах так:

    1. Получаем через соап опиание xdto

    2. Создаем эти xdto и заполняем все как обычно, как будто мы хотим отправить через соап

    3. Когда собрали все данные — берем этотм xdto пакет и сериализуем в xml

    4. Берем расширение для хрома https://chrome.google.com/webstore/detail/wizdler/oebpmncolmhiapingjaagmapififiakb­ и набиваем тестовые данные

    5. Смотри какой xml надо получить, и то что получили на этапе 3 — приводим к тому, что видим на этапе 4. Обычно — это добавление в начле и вконце тегов всяких. И обязательно смотрим заголовки.

    6. Формируем http запрос, где пихаем заголовки и в тело — вот эту нащшу полученную строку

    7. Получив ответ — десериализуем его, либо просто через фабрику, либо вычленяем тип и через него.

    Reply
  16. webester

    Чего я не понял, так это если вы поднимаете свой сервер который обрабатывает только ваши запросы. Зачем мудрить с передачей параметров? Передавайте нужные данные в теле запроса а уже скриптом пакуйте как надо?

    Reply
  17. user883007

    (11) Добрый день!

    А не могли бы Вы показать на примере более конкретно. Наш сервер не отвечает на HTTP запросы так, как на SOAP.

    Reply
  18. user1250657

    очень помогло, спасибо!

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *