Когда шаблоны рвутся, или Вывод в Word по-простому




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

15 Comments

  1. palsergeich

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

    От себя могу добавить, один из костылей, мной используемый, замещающий текст в методе find имеет ограничение по количеству символов, обошел через использование буфера обмена, методом find устанавливаю курсор, и туда вставляю из буфера…

    Reply
  2. velll111

    Спасибо, очень интересная статья, Ctrl+C и Ctr+V уже сделал)))

    Reply
  3. Пользователь 1С

    С шаблонами проще текст набивать. Здесь, я так понял, весь текст документа нужно программно добавлять. Возможно, удобно реализовать через чтение внешнего текстового файла с заготовками содержания документа. Ну а в целом, полезная статья, спасибо!

    Reply
  4. AlX0id

    По-настоящему тру было бы собрать docx с нуля как xml-ку ) И не надо было бы этих чудо-ком-объектов с их заморочками с правами и разрядностью..

    Reply
  5. Yashazz

    (4) AlX0id, да, это было бы реально тру. Но даже простейший экселевский файл так собирать нелегко, много малоизвестных граблей (намучился уже с этим), тем более вордовский — тут надо досконально знать внутреннюю структуру. Ну и с картинками неясно — через Base64 их гонять, что ли? Не факт, что получится.

    …а вот интересно, для OpenOffice такое возможно, собрать через xml?

    Reply
  6. AlX0id

    (5)

    С картинками-то как раз все довольно понятно — они просто в отдельной папке хранятся в архиве. А в xml-ке документа описываются элементом <w:drawing>. Что, в общем-то легко проверить, создав элементарный документ и посмотрев, что же лежит в архиве )

    А по поводу малоизведанных граблей — это, конечно, да, без этого вообще никуда )

    Но мне кажется, что задача вполне решаема. по крайней мере, на уровне несложных объектов типа списков, абзацев и т.п. Времени только займет куда как больше, нежели использование чудо-ком-объектов — это точно.

    Reply
  7. madonov

    (4) AlX0id, Да!

    Давайте напишем свой опен офис на языке 1С!

    Начать можно с Word и Excel.

    ЗЫ. Особенно забавно было бы реализовать функционал Access внутри 1С — трушность бы просто зашкалила =)) .

    Reply
  8. Поручик

    (4) В одном нашем проекте есть сборка документа из вороха xml на сервере. И оно работает в нескольких организациях.

    Reply
  9. pro1c@inbox.ru

    Плюсую. Только такое понадобилось, а вы тут как тут!

    Reply
  10. cool.vlad4

    (4) AlX0id, однозначно. в дотнете например это делается достаточно просто (через openxml sdk , плюс есть еще некоторые библиотеки вокруг этого) . жаль только нет такого для 1С . (можно написать компоненту , иметь лишнюю зависимость и лишний гемор при развертывание решения)

    Reply
  11. cool.vlad4

    (4) AlX0id, кстати проблема не столько в правах и заморочках com объектов (это было бы полбеды), сколько в конкретной избыточной и тормозной реализации в офисе. многие вещи делаются через Selection , что тормоз, что тот еще глюк . (попробуйте параллельно при формировании большого документа, работать в другом word-е и при это что-то активно копировать и вставлять)

    Reply
  12. cool.vlad4

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

    Reply
  13. cool.vlad4

    (5)

    …а вот интересно, для OpenOffice такое возможно, собрать через xml?

    естественно. это можно сказать под их некоторым влиянием потом уже микрософт решил реализовывать открытый формат openxml для word/excel и т.д. см https://ru.wikipedia.org/wiki/OpenDocument

    Reply
  14. VladC#

    Автор определённо погорячился, добавив в заголовок фразу «по простому», в чём простота, если код занимает несколько экранов?

    Reply
  15. Yashazz

    (14) VladC#, ну, наверное, в эксплуатации? )))

    …И правда, забавно: привёл, понимаешь, читателям исходник функции, которую 1 раз скопипастить надо, а дальше просто вызывать. Думал, это просто. Но, оказывается, скопипастить — мегасложно. И вызывать потом, следуя нехитрым примерам — архисложно.

    Наверное, я-таки погорячился.

    Reply

Leave a Comment

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