Произвольный код в фоновом режиме




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

42 Comments

  1. Infactum

    Чем типовые механизмы БСП не угодили? Там еще и контроль доступа для фонового задания задействовать можно будет.

    Reply
  2. nikita0832

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

    Reply
  3. RocKeR_13

    (2) вот здесь-то смотрели?)

    Reply
  4. nikita0832

    (3) о да, она даже у меня в закладках есть) там есть привязка к «ИмяМодуля.ИмяЭкспортнойПроцедуры», ещё и замена общей формы, а задача — реализовать без изменения конфигурации.

    Reply
  5. Malfarion

    (4) Привет, не пробовал такой хак пройдет аудит на Fresh ? С учетом того что обработка во внешних, из файла понятно что не возьмет.

    Reply
  6. nikita0832

    (5) Нет, не пробовал, попробуй — нам расскажешь.

    Reply
  7. Malfarion

    Разобрался =)

    Reply
  8. asved.ru

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

    Reply
  9. nikita0832

    (8) Да, контекст в этом случае конечно отвалится. Я вообще вызываю процедуру из модуля объекта этой внешней обработки и туда передаю все что нужно. Рабочий пример если интересно здесь — https://infostart.ru/public/585055/ это по сути мой рабочий инструмент.

    Reply
  10. paybaseme

    Спасибо! Утащил к себе.

    Reply
  11. Xershi
    Reply
  12. nikita0832

    (11)Да, ПрогрессОбработки и ИдентификаторЗадания надо добавлять на форму, это стоило указать хотя мне и казалось чем-то само собой разумеющимся. Имя файла проще всего получить через функцию

    РеквизитФормыВЗначение(«Объект»).ИспользуемоеИмяФайла;

    Ошибка при сохранении связана с безопасным режимом, если у Вас полные права, то такой проблемы не возникает.

    Чтобы не выводить прогресс через состояние для ПрогрессОбработки сделайте Элемент с видом Поле индикатора. СтруктураПараметров — понятное дело ваша, там параметры для процедуры, которую будем запускать. Для простоты можно сделать просто процедуру типа

    Процедура ДлительнаяОперация(Параметры)
    Выполнить(Параметры.Код);
    КонецПроцедуры
    

    и на самой форме

    СтруктураПараметров = Новый Структура(«Код»,Код); //Код из реквизита формы
    

    но это совсем упрощенно

    Reply
  13. Xershi

    (12) выход вывод прогресса это не типовой функционал БСП, а нарисованная форма / элемент в обработке. Плюс как я понял нужно делать в логике длительной операции вызов процедуры:

    ДлительныеОперации.СообщитьПрогресс(Окр(ПроцентВыполнения, 0), Описание);

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

    Reply
  14. Franchiser

    Если на форме обработки идёт прогресс, у тебя остаются кликабельными кнопки и остаётся возможность менять реквизиты у пользователя в процессе выполнения длительной операции, или ты это запрещаешь?

    Reply
  15. Franchiser

    До конца не понятно какие процедуры используются, т.к. указаны части кода из процедур, можешь привести код всех процедур полностью?

    Reply
  16. Franchiser

    (11) для чего проверяется сообщение на фигурную скобку?

    Reply
  17. Xershi

    (16) когда длительная операция возвращает результат, то он в хмл, вот автор это и проверяет!

    Reply
  18. nikita0832

    (14) менять реквизиты на ходу не получится, только перезапускать сеанс или мутить хранилище со значениями реквизитов и получать их в цикле. Тут надо понимать, что выполнение кода — это уже отдельный сеанс, основной сеанс о нем знает по идентификатору, а второй сеанс о первом не знает впринципе. Как я уже говорил пример где это работает здесь: https://infostart.ru/public/585055/ кода много в итоге, не уверен что Вам все нужно.

    Reply
  19. vadim1011985
    Reply
  20. Franchiser

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

    В этом случае же есть недостатки:

    1. Нужно постоянно во все свои доработки вносить намыорму прогресс и код для фонового задания

    2. Когда пользователь запустил длительный процесс, он может в форме продолжать что-то творить , т.к. она осталась не заблокированной.

    Мне кажется удобнее когда форма прогресса открывактся отдельно с блокированием прогоесса.

    P.s. Обработку посмотреть не могу, нет см.

    Reply
  21. nikita0832

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

    Reply
  22. compaud
    Reply
  23. vadim1011985

    (22) У Вас дополнительная внешняя обработка ?

    Reply
  24. compaud

    (23) да, в этом и смысл. В одну все поместить так понимаю нельзя. Ну хоть в 2

    Reply
  25. vadim1011985

    Почему нельзя ? Все можно . Вам просто надо все сделать правильно.

    1) добавить 2 ключевых параметра Идентификатор команды — тип строка и ДополнительнаяОбработкаСсылка с типом Справочник ссылка Дополительные внешние отчеты и обработки

    2) в модуле формы создать команду которая будет запускать длительную операцию ( но это не сама длительная операция ) см мой 19 ответ в этой теме процедура ЗагрузитьИЗаписать только надо будет заменит ВыполнитьКомандуВФоне на ДлительныеОперацииКлиент.ВыполнитьКомандуВФоне

    3) В модуле объекта пишешь функцию регистрации внешней обработки (сведения о внешней обработке )

    И добавляешь процедуру ВыполнитьКоманду ( ИдентификаторКоманды,Параметрывыполнения) — тут могу ошибиться как звучит второй параметр , в которой реализуешь свою длительную операцию

    Вот и все

    Reply
  26. nikita0832

    (25) Зачем регистрировать? то есть можно и регистрировать, но идея в том что БСП-шная процедура ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки открывает обработку просто как внешний файл и выполняет экспортную процедуру из её модуля. Команда здесь тоже не нужна, хотя наверное и через неё можно.

    Reply
  27. vadim1011985

    (26) я описал типовой механизм вызова длительной операции из внешней обработки как это рекомендует 1с.

    Просто не понимаю зачем такие сложности получить обработку — передать на сервер и т.д. и т.п. Если есть внешняя обработка код которой нужно выполнить в фоне то это делается просто

    Плюс вам писали про стандартные методы БСП и Вы сказали что Вам не нравится что нет идентификатора задания и котик вам не нравится и хотелось бы получать прогресс , но как я Вам уже отвечал это все решаемо , как раз Ваша статья на ряду с другими на эту тему натолкнула меня на мысль написать свою хотя она повторят то чт оо чем я писал тут выше

    Reply
  28. victor_k

    Спасибо! Разобрался, использую

    Reply
  29. EvgenS

    Я то то не так понял или фоновое задание которое будет выполняться должно располагаться в конфигурации, а не в обработке?

    Reply
  30. nikita0832

    (29)в обратотке, в модуле объекта. В конфигурации должна быть БСП с методом ДлительныеОперации.ЗапуститьВыполнениеВФоне.

    Reply
  31. km_if

    (19) На БСП 3 также пытался сделать, не передаются некоторые параметры, пишет «Параметры не могут быть сериализованы».

    Строки и числа передаются в ПараметрыКоманды, а что посложнее можно запихать в эти параметры, но выскакивает ошибка.

    Кроме того, без БСП процедуры и функции в модуле объекта видят реквизиты объекта, а если запускать через длительную операцию, то ничего не видят — все значения пустые.

    Непонятно как этим пользоватся, как сложные типы данных передавать для выполнения в длительную операцию на БСП 3?

    Reply
  32. km_if

    (30)



    ПараметрыКоманды.Вставить(«Каталог», Объект.Каталог);

    //ПараметрыКоманды.Вставить(«Объект»,Объект);

    ПараметрыКоманды.Вставить(«ТипЗагрузкиДокументов»,Объект.ТипЗагрузкиДокументов);

    ПараметрыКоманды.Вставить(«НачПериода»,Объект.НачПериода);

    ПараметрыКоманды.вставить(«КонПериода»,Объект.КонПериода);



    Можно ли в этих параметрах передавать что то сложнее чем число или сторку? Хотел бы передать ТЗ и КомпановщикНастроек.

    Reply
  33. vadim1011985

    (32) что мешает поместить тз во временное хранилище , и через параметры передать адрес

    Reply
  34. km_if

    (33)Насколько понял, создается другой сеанс для длительной операции. Поэтому переменная во временном хранилище, созданном в другом сеансе наверно видна не будет. А передать ее стандартным способом не получается, потому что она не сериализируется.

    Reply
  35. vadim1011985

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

    Reply
  36. km_if

    (35) До передачи в ПараметрыКоманды попробывал поместить:

    АдресВХранилищеОтборы = ПоместитьВоВременноеХранилище(Объект.Отборы, Новый УникальныйИдентификатор);

    Отборы — реквизит объекта внешней обработки, тип «КомпоновщикНастроекКомпоновкиДанных»

    «Ошибка при выполнении запроса POST к ресурсу /e1cib/files/9ead0971-78e9-4061-8983-34f3c58b5395:

    Переданное значение не может быть помещено во временное хранилище».

    Reply
  37. km_if

    (35)Попробывал даже вот так — https://forum.infostart.ru/forum9/topic118827/

    В процедуре формы оборачивал нужную переменную в структуру, а потом помещал в хранилище.

    При попытке получить переменные в «Процедура ВыполнитьКоманду» из временного хранилища по переданным адресам ничего нет.

    Reply
  38. vadim1011985

    (37) Смотрите — основная проблема у вас в том что вы хотите передать то , что не может быть передано с клиента на сервер, ТЗ например таким способом передать можно

    Reply
  39. km_if

    (38) ТЗ через временное хранилище тоже пустая.

    Получается варианта два — либо я неправильно передаю, либо это вообще передавать не нужно.

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

    Как можно обойтись без этого?

    Reply
  40. user1095593

    nikita0832, ты можешь сбросить сам файл обработки? Уже два дня мучаюсь не могу толком разобраться… везде только обрывки кода или разные способы, которые не получается довести до ума… Очень хочу с этим разобраться.

    Reply
  41. nikita0832

    (40)ответил в личку

    Reply
  42. cyborg55

    nikita0832, а можно мне тоже пример файла обработки, пжт

    Reply

Leave a Comment

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