Асинхронный обмен данными с JavaScript (и не только) без потерь




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

23 Comments

  1. VitaliyCeban

    Учитывая что событие ПриНажатии может быть пропущено, и оно могло быть последним (не поможет обработка предыдущих событий при следующем ПриНажатии, так как его не будет), то относительная гарантия доставки, в итоге, достигается исключительно за счет следующего кода?

    &НаКлиенте
    Процедура ПриОткрытии(Отказ)
    ПодключитьОбработчикОжидания(«ПолучитьИОбработатьДанные»,1);
    КонецПроцедуры

    Относительная, потому что форма может быть закрыта до очередного срабатывания таймера, впрочем, это я уже утрирую )

    В любом случае, решение интересное, и существенно лучше его отсутствия, спасибо.

    Reply
  2. igo1

    вообще вот пример как работать без обработчика ожидания, можно просто вызвать событие «нажатие», и передать туда данные

    http://infostart.ru/public/338126/

    Reply
  3. VitaliyCeban

    (2) Прочитайте более внимательно начало этой публикации.

    можно просто вызвать

    оно то можно, только есть ненулевая вероятность что в 1С событие ПриНажатии вызвано НЕ будет.

    Эту проблему и призвана решить данная публикация.

    Reply
  4. Alxby

    (3) Спасибо, опередили с ответом:)

    Reply
  5. Alxby

    (1) Да, при закрытии формы мы можем потерять последние события. Но нам никто не мешает перед закрытием формы их все-таки принудительно получить. К тому же, как мне кажется, основное применение JavaScript — визуальные компоненты интерфейса, данные которых вряд ли нужны после закрытия формы.

    Reply
  6. herfis

    «события на вебстранице возникают асинхронно, форма 1С, в общем случае, может какие-то из виртуальных кликов пропустить»

    Поясните. По какой причине 1С может пропустить клики. И в каких случаях. Где можно об этом почитать в подробностях.

    В документации по «ПриНажатии» ничего такого нет. Т.е. предполагается, что ловиться должны все события.

    «события на вебстранице возникают асинхронно» — ну и что с того?

    Reply
  7. herfis

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

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

    Reply
  8. VitaliyCeban

    (7) Поинтересуйтесь у http://infostart.ru/profile/52749/

    Самому не приходило сталкиваться с проблемой, но не доверять Евгению, учитывая созданные им решения, у меня оснований нет.

    Reply
  9. Alxby

    (7) Как бы то ни было, основной целью написания статьи было не решение конкретной проблемы, указанной в примере, а описание способа решения подобных ей проблем, не обязательно связанных с взаимодействием с JavaScript.

    Reply
  10. herfis

    (8) ИМХО, если 1С не делает пропусков, скажем, при нескольких событиях HTML с интервалом 1ms, когда в 1С каждое обрабатывается к примеру 5ms (т.е. какая-то очередь все-таки есть), то для большинства практических задач нет смысла обслуживать свою очередь событий. Когда возникнет практическая задача — поставлю эксперимент, раз тут занимаются решением проблем о которых знают по-наслышке.

    Задачи Евгения, насколько я понимаю, достаточно специфичны.

    Reply
  11. herfis

    (9) Соглашусь. Статью плюсанул.

    Сначала зацепился за то, что queueHead пишется из двух процессов (при сбросе очереди), но получается что сброс невозможен одновременно с обработкой события в 1С. Остроумное решение проблемы мьютексов при условии частого обнуления очереди.

    Reply
  12. Alxby

    (11)Здесь нелишним будет упомянуть, что в JavaScript оператор присваивания имеет ассоциативность справа налево, и

    queueHead = queueTail = -1;

    эквивалентно

    queueTail = -1;

    queueHead = -1;

    что гарантирует: в процессе обнуления queueHead будет не меньше queueTail и чтение из очереди невозможно.

    Reply
  13. igo1

    (3) не встречал таких проблем с пропуском нажатий, но в таком случае я бы решал задачу немного иначе, реализовав гарантированную доставку.

    Reply
  14. Alxby

    (13) У меня тоже была идея реализовать механизм, похожий на работу TCP (правда для решения другой задачи). Может быть напишете статью о своем варианте?

    Reply
  15. herfis

    (13) Каким именно образом и чем он лучше? Статья ведь как раз и рассматривает вариант реализации гарантированной доставки.

    Reply
  16. pbazeliuk

    (15) Термин «гарантированная доставки» здесь не применим. Объекты жестко связаны, они не могут отдельно работать друг от друга, нет восстановления состояния, например, после падения кластера 1С.

    В этом случае, решена проблема пропускания «кликов».

    Reply
  17. herfis

    (16) Вы пытаетесь сказать, что под термин «гарантированная доставка» подходят только внешние сервисы очередей? Не думаю, что в (13) именно это подразумевалось 🙂

    В нашем случае «гарантированность» имеет смысл только в рамках жизненного цикла формы.

    Reply
  18. pbazeliuk

    (17) Сервис очередей не упоминал вроде как. Термин «гарантированная доставка» не должен зависеть от контекста и он не применим точно здесь. Правильней назвать это «fire-and-forget».

    Reply
  19. igo1

    (9) Статья очень полезная, вы не расстраивайтесь. Гора комментариев как раз об этом и говорит.

    Reply
  20. infostart user

    какая боль ;(

    Reply
  21. herfis

    (18)

    Термин «гарантированная доставка» не должен зависеть от контекста и он не применим точно здесь

    Ок. Раз не должен зависеть от контекста, то вы подразумеваете его исчерпывающее определение. Дайте ссылочку, плиз. Я такого не нашел.

    Везде зависит от контекста. Например, как по вашему — TCP обеспечивает «гарантированную доставку» или нет?

    Reply
  22. pbazeliuk

    (21) Он обеспечивает надежную передачу данных, но «негарантированную». Термин «гарантированная доставка» появился как описание паттерна. Действительно, пример, который не связан с очередями, сложно найти.

    Reply
  23. vaxhab

    +

    Reply

Leave a Comment

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