"Маленькие" неприятности 1С 8.2




Принцип обмена данными из 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='\

27 Comments

  1. maxlab
    Сразу хочу предупредить о «кроссплатформенности» данного продукта — это пока миф. Сервер 1С на Debian 5 вылетает примерно раз в два часа. Может конечно и руки кривые, но на Windows 2003 все работает, причем быстрее.

    На FC8(32bit) работает уже две недели на пару с 8.1

    Reply
  2. awk

    А какая сборка 1С? Вылетала, кстати, когда работали две базы. В одну я переносил из семерки данные, а в другой активно конфигуратором пользовался.

    Reply
  3. Душелов

    >метода «УстановитьСхему» просто нет

    Он есть. Только называется «Вывести»

    Вывести (Put)

    Синтаксис:

    Вывести(<Схема>)

    Параметры:

    <Схема> (обязательный)

    Тип: ГеографическаяСхема. Выводимая схема.

    Описание:

    Выводит в схему данные из макета географической схемы.

    Доступность:

    Сервер, толстый клиент, внешнее соединение.

    Reply
  4. maxlab
    А какая сборка 1С? Вылетала, кстати, когда работали две базы. В одну я переносил из семерки данные, а в другой активно конфигуратором пользовался.

    Сборка такая же — 1С:Предприятие 8.2 (8.2.9.356)

    Reply
  5. DimaP

    Да, «сюрпризы» есть.

    Платформа 8.2.9.356

    Конфа своя

    Почему-то при попытке передать с сервера на веб-клиент маленькую таблицу значений выдаёт ошибку -мол такое нельзя 😥

    &НаКлиенте
    Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    
    Если Объект.IP<>»» Тогда
    Результат= ЗапросПоИП(Объект.IP,Объект.Код);
    Если Результат=0 Тогда
    Отказ=0;
    Иначе
    Предупреждение(«IP «+Объект.IP+» уже используется!»);
    Отказ=1;
    КонецЕсли;
    КонецЕсли; // ip неопределён

    Показать

    &НаСервере
    Функция ЗапросПоИП(IP,Код)
    ЗапросПоIP=Новый Запрос;
    ЗапросПоIP.Текст=»ВЫБРАТЬ
    | ФИОПользователя.IP,
    | ФИОПользователя.Код,
    | ФИОПользователя.Выбыл
    |ИЗ
    | Справочник.ФИОПользователя КАК ФИОПользователя
    |ГДЕ
    | ФИОПользователя.IP = &IP
    | И ФИОПользователя.Код <> &Код
    | И ФИОПользователя.Выбыл = &Ложь»;
    ЗапросПоIP.УстановитьПараметр(«IP»,IP);
    ЗапросПоIP.УстановитьПараметр(«Код»,Код);
    ЗапросПоIP.УстановитьПараметр(«Ложь»,Ложь);
    Результат=ЗапросПоIP.Выполнить().Выгрузить();
    Возврат Результат.Количество();
    КонецФункции // ()

    Показать

    Просто Результат нельзя передать …

    Reply
  6. Душелов

    (5) Я думаю, что стоит прочитать документацию и руководство разработчика. Там черным по белому написано про объекты, которые используются в тонком клиенте.

    В приведенном выше примере эту проверку надо делать в контексте сервера:

    &НаКлиенте
    Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    Отказ = ПроверитьIP();
    КонецЕсли; // ip неопределён

    Зачем нагружать обработкой клиентские машины?

    Reply
  7. awk

    А ещё есть ПередЗаписьюНаСервере()

    и

    ЗапросПоIP=Новый Запрос;

    ЗапросПоIP.Текст=»ВЫБРАТЬ

    | ФИОПользователя.IP,

    | ФИОПользователя.Код,

    | ФИОПользователя.Выбыл

    |ИЗ

    | Справочник.ФИОПользователя КАК ФИОПользователя

    |ГДЕ

    | ФИОПользователя.IP = &IP

    | И ФИОПользователя.Код <> &Код

    | И ФИОПользователя.Выбыл = &Ложь»;

    ЗапросПоIP.УстановитьПараметр(«IP»,IP);

    ЗапросПоIP.УстановитьПараметр(«Код»,Код);

    ЗапросПоIP.УстановитьПараметр(«Ложь»,Ложь);

    Результат=ЗапросПоIP.Выполнить().Выгрузить();

    Возврат Результат.Количество();

    я бы заменил на:

    ЗапросПоIP=Новый Запрос;

    ЗапросПоIP.Текст=»ВЫБРАТЬ

    | ВЫБРАТЬ Первые 1 ФИОПользователя.Ссылка

    |ИЗ

    | Справочник.ФИОПользователя КАК ФИОПользователя

    |ГДЕ

    | ФИОПользователя.IP = &IP

    | И ФИОПользователя.Код <> &Код

    | И ФИОПользователя.Выбыл = &Ложь»;

    ЗапросПоIP.УстановитьПараметр(«IP»,IP);

    ЗапросПоIP.УстановитьПараметр(«Код»,Код);

    ЗапросПоIP.УстановитьПараметр(«Ложь»,Ложь);

    Отказ = Не ЗапросПоIP.Выполнить().Пустой();

    Reply
  8. awk

    dushelov 22.11.2009 10:51:09

    >метода «УстановитьСхему» просто нет

    Он есть. Только называется «Вывести»

    Есть, но приложение уходит в бесконечную рекурсию.

     Карта = БизнессПроцесс.ПолучитьОбъект().ПолучитьКартуМаршрута();
    //ИмяФайла = КаталогВременныхФайлов() + Элементы.ВыполнениеНарядов.ТекущаяСтрока;
    //Карта.Записать(ИмяФайла);
    Схема = Новый ГрафическаяСхема;
    //Схема.Прочитать(ИмяФайла);
    Схема.Вывести(Карта);
    

    Перед тем как написать проверь. (Проверял на тонком клиенте)

    Reply
  9. Душелов

    (8) Если есть возможность, дай свою конфигурацию посмотреть…

    Reply
  10. awk

    Пиши it@selenia.ru… Метода Вывести в Графической схеме нет. Есть в Географической. Я только одного не понимаю, почему 1С-ка зацикливается, вместо вывода ошибки.

    Reply
  11. Душелов

    (10) Отписал…

    Reply
  12. awk

    Отправил :0)

    Reply
  13. Душелов

    (12)

    &НаСервере
    Процедура ПолучитьКарту(БизнессПроцесс)
    Схема = БизнессПроцесс.ПолучитьОбъект().ПолучитьКартуМаршрута();
    КонецПроцедуры
    Reply
  14. awk

    Работает :0)

    Reply
  15. afanasko

    (0) Фиг с ней, с этой схемой! Ты лучше расскажи как конфигуратор на Убунту запустил )))

    Reply
  16. awk

    Virtual box — хорошо виден на скриншоте. На debian lenny и из-под wine заработал. Только вылетает при создании форм. Говорит Ключ защиты больше не доступен. На Ubuntu ключа так и не видит. Интересно кто виноват wine или 1С…

    P.S. 8.1 под wine не вылетает.

    Reply
  17. pron2

    Структура кода должна быть определена не прикладной логикой, а логикой клиент-серверного взаимодействия

    Нужно научиться мыслить клиент-серверной логикой!

    Reply
  18. MSensey

    Для меня один из главных сюрпризов, то что объект не хранится на сервере. При переходе с клиента на сервер объект создается заново.

    При этом заполняется данными которые есть на клиенте. Но ведь на клиенте не все можно хранить. Получается, что нужно использовать временные хранилища. Вобщем гемор.

    Reply
  19. Душелов

    (18) А в чем проблема использования РеквизитФормыВЗначение и ЗначениеВРеквизитФормы ?

    Reply
  20. MSensey

    (19) Поясню на задаче.

    На клиенте пользователь вводит настройки. Потом хочет получить информацию.

    Для этого мы идем на сервер. Получаем данные, по ним формируем информацию и возвращаем ее.

    При этом полученные данные хотелось бы сохранить, чтобы не получать снова.

    В 8.1 для этого мы записывали ее в реквизиты объекта или переменные.

    В 8.2. так делать нельзя, т.к. в первом случае они приедут на клиента, а во втором случае потеряются.

    Reply
  21. extreme

    (16) ключ в 8.2 на ubuntu под wine заставили видеть методом тыка, хотя мистики я не понял: nethasp.ini с прописанным ip менеджера лицензий переложили из 1Cv82/conf/ в 1Cv82/8.2.9.356/bin/conf/ — и заработало сразу.

    До этого стабильно ругался при запуске «Ключ защиты более недоступен»

    Reply
  22. awk

    Я сделал то же самое, но не помогло. Хотя мистики тут нет. Все просто путь поиска файла (nethasp.ini) начинается с каталога программы, потом переходит в каталог программыconf потом смотрит ConfLocation в conf.cfg

    Reply
  23. DimaP

    Общее (видимо для 8.1 и 8.2 +sql), относительно процедур НаКлиенте и НаСервере:

    1) сначала оказывается надо передать управление общему модулю, вот там выполнятся серверные, а в модуле (скажем, объекта) не получается жонглировать взаимными вызовами из НаКлиенте процедур НаСеревер 🙁

    2) отладчик не заходит в серверные процедуры (даже если я выполняю отладку на самом сервере, но это, видимо, никак не влияет и не связано).

    Reply
  24. Душелов

    (23) 1. Ничего не понятно.

    2. Все заходит. В конфигураторе надо еще разрешить отладку.

    И вообще, отлаживать серверные модули лучше в файловом режиме.

    Reply
  25. DimaP

    Разрешена отладка. Ещё сюрприз работы с SQL — это при запуске приложения в режиме отладки оно имеет свойство зависать на этапе заставки и нужно перезапустить всё — это только у меня?

    Reply
  26. Душелов

    (25) Никаких таких проблем не замечено. У нас все работает в промышленной эксплуатации с тонким и веб-клиентом.

    Reply
  27. Елисеева

    Спасибо, помогло 🙂

    Reply

Leave a Comment

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