Ликбез 7.7: Инициализация переменных во внешнем отчете.




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

17 Comments

  1. Арчибальд

    Для новичков 😐

    Reply
  2. hogik

    (0)

    Лишний текст: «пКолСсылок=0» 😉

    глОтчетСоСсылками(пФайл, СписПар=»», п1=»», п2=»», п3=»»,…, пN=»»)



    СписПар.ВставитьЗначение(1,п1);

    СписПар.ВставитьЗначение(2,п2);

    СписПар.ВставитьЗначение(3,п3);



    СписПар.ВставитьЗначение(N,пN);

    Reply
  3. Арчибальд

    (2) пКолСсылок — это не количество параметров, а именно количество «ссылочных» параметров, т.е. которые будут изменяться внешним отчетом. Вставить, конечно, можно и так. Но получить потом значения для присвоения — по количеству.

    Reply
  4. hogik

    (3)

    Угу. 😉

    А которые НЕ будут меняться надо класть в «СписПар» после трех первых?

    Думаю, и текст «СписПар=»»,» лишний…

    Reply
  5. Арчибальд

    (4) Большое количество существующих внешних отчетов получают в качестве «аргумента» именно список значений — например, стандартные ВПФ, помощники заполнения документов и т.п. И если я захочу в готовом отчете что-то дополнительно сделать, мне не придется ничего разрушать.

    Кстати, из такой хотелки и появилась эта процедурка, реально встроенная в одну заказанную мне конфу.

    Reply
  6. hogik

    (5) «…в готовом отчете…не придется ничего разрушать»

    А цель «Ликбеза»: «Формировать список значений парамеров, передавать его, получать значения…». Не понимаю. Жарко у нас… 😉

    Процедура глОтчетСоСсылками(пФайл, п1=»», п2=»», п3=»») Экспорт
    Перем СписПар, лИмя;
    Если ПустаяСтрока(пФайл) = 1 Тогда
    Сообщить(«Не задано имя файла отчета!»);
    Возврат;
    КонецЕсли;
    Если ФС.СуществуетФайл(пФайл) = 0 Тогда
    Сообщить(«Не найден файл «+пФайл+» !»);
    Возврат;
    КонецЕсли;
    СписПар = СоздатьОбъект(«СписокЗначений»);
    СписПар.ВставитьЗначение(1,п1);
    СписПар.ВставитьЗначение(2,п2);
    СписПар.ВставитьЗначение(3,п3);
    ОткрытьФормуМодально(«Отчет», СписПар, пФайл);
    п1 = СписПар.ПолучитьЗначение(1,лИмя);
    п2 = СписПар.ПолучитьЗначение(2,лИмя);
    п3 = СписПар.ПолучитьЗначение(3,лИмя);
    КонецПроцедуры

    Показать

    Reply
  7. hogik

    (0)»…ибо не только ссылки, как правило, должны передаваться в отчет…»

    Да, надо передавать список и сразу затирать его другими параметрами… 😉

    Reply
  8. hogik

    (0)

    Александр.

    Жара у нас спала? 😉

    Задаю вопрос.

    В Вашем первом тексте смысл — поставить параметры-ссылки в начало списка «СписПар», а все остальные параметры-значения поместить в этот список заранее (и потом сдвинуть к концу списка), и тем самым «запретить» их изменение во «внешнем отчете»? Тогда — да. Всё верно. Хотя, думаю, и не имеет большого смысла, т.к. «внешний отчет» всегда должен точно «знать» порядок параметров и «понимать» их смысл в части возможности возвращаемого значения. Ну, а если «внешний отчет» это не «понимает», то это уже к доктору… Или к тексту из (6) сообщения.

    Reply
  9. Арчибальд

    (8) Ну да, такой смысл я и вкладывал. В особенности, с учетом того, что во внешних «стандартных» отчетах манипуляция параметрами происходит по именам, а не по позициям (Установить/Получить).

    Поясню еще свою позицию насчет количества ссылок. В давние Фортрановские времена слиталось опасным обращаться к процедуре с числовым литералом в качестве параметра, поскольку некоторые трансляторы все литералы превращали в константы и передавали их адреса. В результате после вызова SQRT(3) далее можно получить 2*3 = стеариновая свечка. По слухам, из-за подобной ситуации упал Апполон-10 (по другим источникам — из-за точки вместо запятой в операдоре DO).

    Так что у меня присутствует генетическое неприятие записи результата «в никуда». Да и по Клипперной практике — удобно первым параметром процедуры/функции всегда иметь количество аргументов 🙂

    Reply
  10. hogik

    (9)

    Вот теперь «Ликбез 7.7» «Для новичков» удался. 🙂

    Только, думаю, новички уже не начинают программировать со среды «1С 7.7».

    Да и про «Клиппер» с Фортраном уже не знают…

    Reply
  11. Арчибальд

    (10)

    Да и про «Клиппер» с Фортраном уже не знают…

    В этом и беда их. Абсолютная зашоренность. Новую платформу считают неким прорывом — это при том, что в программировании с 85 года («японский вызов — 6 поколение») ничего нового не произошло.

    Reply
  12. ne_en

    Пример как я обычно поступаю:

    // Запросим пароль
    Параметры=СоздатьОбъект(«СписокЗначений»);
    Параметры.Установить(«Статус»,»Отмена»);
    Параметры.Установить(«Пароль»,»»);
    Параметры.Установить(«ЗаголовокОкна»,»Пароль на запрет отрицательных остатков по складу»);
    ОткрытьФормуМодально(«Обработка.ВводПароля»,Параметры);
    Если Параметры.Получить(«Статус»)=»ОК» Тогда
    Если Параметры.Получить(«Пароль»)<>»123456789″ Тогда
    СтатусВозврата(0);
    Предупреждение(«Изменения не записаны, изменен параметр разрешения отрицательных остатков по складу. Неправильный пароль.»,20)
    КонецЕсли
    Иначе
    Предупреждение(«Изменения не записаны, изменен параметр разрешения отрицательных остатков по складу. Не введен пароль.»,20)
    КонецЕсли

    Показать

    А в обработке (универсальная форма ввода пароля)

    Перем Параметры;
    
    //*******************************************
    Процедура Отменить()
    Параметры.Установить(«Статус»,»Отмена»);
    Параметры.Установить(«Пароль»,»»);
    СтрокаДействийФормы=»#Закрыть»;
    КонецПроцедуры
    
    //*******************************************
    Процедура Выполнить()
    Параметры.Установить(«Статус»,»ОК»);
    Параметры.Установить(«Пароль»,Пароль);
    СтрокаДействийФормы=»#Закрыть»;
    КонецПроцедуры
    
    //*******************************************
    Процедура ПриОткрытии()
    Параметры=Форма.Параметр;
    Если ПустоеЗначение(Параметры)=1 Тогда
    СтатусВозврата(0);
    Возврат
    КонецЕсли;
    Если ТипЗначенияСтр(Параметры)<>»СписокЗначений» Тогда
    СтатусВозврата(0);
    Возврат
    КонецЕсли;
    ЗаголовокОкна=Параметры.Получить(«ЗаголовокОкна»);
    Если ПустоеЗначение(ЗаголовокОкна)=1 Тогда
    ЗаголовокОкна=»Ввод пароля»
    КонецЕсли;
    Форма.Заголовок(ЗаголовокОкна,0)
    КонецПроцедуры

    Показать

    Так же я поступаю при вызове отчетов и обработок. Все просто и глобальную процедуру(функцию) можно нарисовать на раз два… Но надо ли оно…

    Reply
  13. Арчибальд

    (12) Я когда пишу конфу «с нуля», начинаю с полудюжины любимых глобальных процедур, одна из которых — глВычислитьВнешний. Гораздо меньше одинаковых кусков писать приходится.

    Reply
  14. sss999

    Рассказ про апплон кончно скрасил статью),вот интересно а какие параметры передаете,что так ускоряет работу?единственно такой отчет не буде работать в друой конфигурации.

    Reply
  15. Арчибальд

    (14) Это не отчет, а добавочка к глобальному модулю, которую полезно иметь при расширении функционала внешними отчетами с «перекрестными» вызовами.

    Reply
  16. ne_en

    (15) Посмотрел свои внешние отчеты с «перекрестными» вызовавами… В подавляющем большинстве случаев не обхожусь я тремя параметрами (ну это мелочи, но до коих пор расширять то список параметров…), а при выходе из обработки, чаще всего нужно для начала проанализировать один параметр (иногда два), что бы уже не получать значения остальных. При вот такой «глобализации» же приходится сначала получить значения всех параметров (даже тех, что не рассчитывались, а это бывают и списки и таблицы данных), а только после этого выяснять, нужно ли чего-то с ними делать или у обработки был отказ (ошибочные параметры/данные или пользователь отказался от каких-то действий). А ещё часть параметров нужно передать только туда, а обратно они не нужны (ну взять хотя бы ДатаНачала, ДатаКонца, а круче ТаблМПЗ), при этом на все эти возвраты требуется расходование процессорного времени и иногда значительного, а на сервере терминалов где одновременно может работать пара-тройка десятков пользователей такие вещи уже имеют значение. Вот всем этим (особенно экономией процессорных мощностей) и обусловлен мой выбор «индивидуального подхода» при передаче и получении параметров в отчеты и обработки, при этом совершенно не сложно заниматься копипастингом или создать шаблон(ы).

    Выше сказанное не означает, что Ваш алгоритм непригоден, для него есть своя ниша функционала, и в небольших организациях, где работает не много пользователей, такой расход процресурсов не будет играть существенной роли, заставляющей раньше переходить на более дорогие сервера или даже на распределение нагрузки между несколькими серверами (и более «крутого» админа) для комфортной работы с базой данных.

    Пожалуй я поддержу автора, но с оговоркой, что использование его ограниченно в связи с часто нерациональным использованием процресурсов.

    Reply
  17. Арчибальд

    (16) Отличный комментарий. Подписуюсь под каждым словом. Особенно

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

    У меня, на самом деле, в глобальнмке стоит функция, выдающая результат работы внешнего отчета, и до прошлого года ее (т.е. одного результата) хватало.

    И, конечно же, использование внешних отчетов вместо внутренних процедур/функций жрет ресурсов немерено…

    Reply

Leave a Comment

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