Апрельские "нешутки", записанные в пятницу не 13-го (продолжение)




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

19 Comments

  1. karpik666

    Хм, А просто условие убрать на полные права и в «иначе» записать

    ПараметрыСеанса.СписокОрганизацийДоступныхДляЧтения = Новый ФиксированныйМассив();
    ПараметрыСеанса.СписокОрганизацийДоступныхДляЗаписи = Новый ФиксированныйМассив();    

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

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

    Reply
  2. cargobird

    (1) karpik666

    не очень страшная история

    Как посмотреть, если пользователь под полными правами не может зайти ни в один журнал документов, ни провести документ из списка….

    все нужно тестировать

    Так все и было протестировано, только под неполными правами) Что так будут вести себя «полные права» ожидалось меньше всего)

    просто условие убрать на полные права

    В итоге да, было убрано условие на полные права ..

    Reply
  3. necropunk

    Да-да-да, знакомый до боли затык. Влипал я так с полными правами тоже…

    Reply
  4. vasyak319

    История на тему «какие траблы могут случиться, если дорабатывать систему, уже доработанную рукожопами». Да, в общем, любые.

    А можно вообще про каждую обнаруженную ошибку статью писать (в принципе, эта статья как раз такая и есть). А можно анекдоты постить. А почему нет, если начисляют по 10 СМ за каждую?

    Reply
  5. cargobird

    (4) vasyak319, в этой статье кроме обнаруженной ошибки (достаточно серьезной, и, наверное, стоящей того, чтобы поделиться), приведен скромный опыт сокращения запроса РЛС путем передачи фиксированного массива в параметр сеанса и кроме того, нашелся сотоварищ по влипанию в подобную ситуацию. А 10 стартмани это скорее приятный бонус, а не цель…

    Reply
  6. vasyak319

    (5) да все влипали. В кучу разных ситуаций, ибо не оскудела земля русская рукожопами. Мне как-то вообще попалась конфа (КАТАП), доработанная платиново-иридиевым эталоном рукожопа.

    Чувак писал что-то вроде:

    Процедура ПриОткрытии()
    ВыбКлиент.Очистить();
    ВЫбКлиент=ВосстановитьЗначение(«Выбклиент_ОтчетПоКлиентам»);
    ВыбКлиент.Очистить();
    Номенклатура=Справочники.ОсобКлиенты.Выбрать(,,,»Наименование УБЫВ»);
    Пока Номенклатура.Следующий() Цикл
    Объект=Номенклатура.Ссылка;
    Клиент=Объект.ПолучитьОбъект();
    Попытка
    ВыбКлиент.Добавить(Клиент.Поставщик);
    Исключение
    КонецПопытки
    КонецЦикла;
    …

    Показать

    ВыбКлиент-список значений на форме отчёта. Уродливые кнопки для его редактирования — всё, как положено. При этом первое, что делала процедура Сформировать — очищала ВыбКлиент и заполняла заново примерно таким же алгоритмом.

    В некоторых документах был булевый реквизит, который на форме документа выглядел флажком с заголовком «Орехова Т.». В процедурах ПередЗаписью проверки типа

    Если ТекущийПользователь.Наименование=»Иванова Света»

    Итэде итэпэ. И что?

    А вы приводите пример заурядной проблемы, причины которой очевидны, способ выяснения проблемных мест очевиден и способ исправления тоже очевиден.

    Reply
  7. karpik666

    (6) vasyak319,

    Если ТекущийПользователь.Наименование=»Иванова Света»

    Видимо в этой организации Иванова Светлана будет работать до победного, а если и уволиться, то в вакансии на ее место будет обязательное требование: Требуется человек с именем «Иванова Света» или изменить на соответствующее в ЗАГС=)

    Reply
  8. cargobird

    (6) vasyak319, боюсь показаться нудным, но способ сокращения запроса РЛС вроде ничего себе так, хотя и не протестирован на производительность)

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

    Скоро напишу «серьезную» статью по РЛС, а тут — извиняйте, ежели чего…

    Reply
  9. karpik666

    (8) ну так форум что ли отменили?

    Reply
  10. cargobird

    (9) karpik666, точно, как-то об этом не подумал)

    Reply
  11. Templ

    (6) vasyak319, (7) karpik666,

    Если ТекущийПользователь.Наименование=»Иванова Света»

    Видимо в этой организации Иванова Светлана будет работать до победного, а если и уволиться, то в вакансии на ее место будет обязательное требование: Требуется человек с именем «Иванова Света» или изменить на соответствующее в ЗАГС=)

    А как надо писать?

    Reply
  12. cargobird

    (11) Templ, как минимум, если конфигурация нетиповая,

    Если РольДоступна(«ИвановаСвета») Тогда … КонецЕсли;

    Тогда пользователю с любым именем можно назначить функционал Светы Ивановой)

    Reply
  13. vasyak319

    (8)

    способ сокращения запроса РЛС вроде ничего себе так

    таки да.

    (11) Templ, зависит от ситуации. В том конкретном случае годилось:

    Если ЭтоРуководительОтделаПродаж() Тогда…

    или:

    Если ОбщегоНазначения.ЕстьПраво(ПланыВидовХарактеристик.ДополнительныеПраваПользователей.ПравоТворитьСЗаказомПокупателяЛюбоеНепотребство) Тогда…

    или даже:

    Если ТекущийПользователь=Константы.ТотЕдинственныйПользовательКоторомуМыРазрешаемУродоватьЗаказКакБогЧерепаху.Получить() Тогда…

    Запомни, Templ, никаких констант в коде! Никогда! Или я приду за тобой… Не, ну почему в этом форуме нет зловещих смайликов? Вообще никаких нету 🙁

    Reply
  14. Templ

    У нас есть вещи и пострашнее констант. Например Запросы в цикле. Соответсвенно тормоза не хилые. (но это не я)

    Reply
  15. alyaev.a.v

    (13) vasyak319, А чем так страшны константы в коде,особенно вне транзакций?

    Reply
  16. vasyak319

    (15) alyaev.a.v, по-моему вы путаете прикладные объекты Константы с термином «константы в коде».

    Reply
  17. alyaev.a.v

    (16) vasyak319, Возможно, я просто подумал коммент про константы относился к «ТекущийПользователь=Константы.ТотЕдинственныйПользовательКоторомуМыРазрешаемУродоватьЗаказ­КакБогЧерепаху.Получить()»

    а похоже он относился «Если ТекущийПользователь.Наименование=»Иванова Света»»,

    попутал 🙂

    Reply
  18. Allexe8.1

    (5)

    опыт сокращения запроса РЛС путем передачи фиксированного массива в параметр сеанса

    Опасная штука. Если массив будет большим, условие (IN) будет выполняться через построчное создание ВТ (сколько элементов массива — столько insert-ов) и левое соединение с ней.

    Reply
  19. cargobird

    (18) Allexe8.1, спасибо за предупреждение, протестирую.

    Предварительно выяснено, что «простые» отчеты из типовой конфигурации формируются со «включенным» РЛС значительно быстрее, чем на стандартных запросах ограничений доступа, проведение документов тоже работает быстро.

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

    Reply

Leave a Comment

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