Данные формы и оптимизация обмена с сервером




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

14 Comments

  1. Yashazz

    Да, и понятное дело, что мы на сервер кидаем копию, «слепок» с данных формы, а они сами тихо лежат на клиенте, и если их надо изменить-обработать, то с сервера потом придётся тащщить обратно той же сериализацией и на клиенте обновлять, например, через КопироватьДанныеФормы(Десериализованное,СвоёМестное).

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

    Reply
  2. BabySG

    (0)

    Но в 8.3 нас ждёт неприятный сюрприз: 8.3.4 просто заявляет, что подобные объекты «не могут быть помещены в хранилище», а 8.3.5 громко падает с ошибкой. Скромно осмелюсь полагать, что это просто временная недоработка писателей платформы, ибо если данные можно было передавать в 8.2, то что мешает повторить достигнутое? Поэтому надеюсь, что примерно к 8.3.10 это аккуратно доделают, а не оставят как сейчас и не объявят «фичей», подогнав заумное обоснование.

    Смысл в том, что в 8.2 ОШИБОЧНО разрешалось запихивать подобные данные в хранилище. В 8.2 (ранних версиях) туда можно было еще и COM объект запихнуть.

    А дальше удивлялись — а куда он делся и почему COM не работает 🙂

    Еще есть вариация, когда возвращалось НЕОПРЕДЕЛЕНО (Кстати, разработчики типовых тоже наступили на эти грабли)

    А еще есть ответ от разработчиков, который датируется 2011 годом. Но, как я помню. Вы не участвуете тут https://partners.v8.1c.ru/forum/message/886492#m_886492, поэтому цитата:

    Во временном хранилище могут хранится значения помеченные в синтакс помощнике как «Сериализуется».

    Что, кстати, также описаное в СП для метода ПоместитьВоВременноеХранилище

    Описание:

    Сохраняет сериализуемое значение во временное хранилище.
    Reply
  3. Yashazz

    (2) ОК, была мысль и что «ошибочно разрешили», недопилив концепт, согласен; но почему штатный сериализатор легко справляется без потерь и проблем? Почему нельзя было это же сделать для временного хранилища?

    И кстати, какой криминал в сериализации некоей модели данных, коей являются ДанныеФормы, если там в её реквизитах не болтается ничего предосудительного, а всё сплошь простые типы или ссылки? Неужели это так преступно и жутко?

    Reply
  4. BabySG

    (3) Смысл в том, что данные не «сериализируются» в этом случае, а именно модифицируются.

    Отдаленно можно сравнить с тем, что СправочникОбъект нельзя передать на сервер с клиента (и наоборот), хотя платформа сама-то как-то «понимает», что делать при записи из формы.

    PS. Тут еще такой момент: данные сеанса (а именно в них хранится временное хранилище) могут мигрировать между сервера кластера, и совершенно не факт, что поднятые данные формы будут иметь отношения к какой-либо форме — ее может не быть на другом сервере (например, форма пересоздалась после падения процесса на сервере). Эта же прчина мешает запихать в ВХ COM объект — что делать, если на сервере нет контекста подключения или вообще попали на сервер с Linux?

    PPS. А сама задача предварительной обработки большого массива данных через данные формы — крайне не рекомендуется разработчиками платформы. Крайне негативно влияет на оптимизацию передачи данных (что и видно из статьи). Рекомендуют делать небольшую подготовку и отправлять на сервер для полной обработки. Конечно, не всегда есть возможность отпраить туду все, поэтому приходится в каждом случае придумывать свое решение. Универсального нет (вот у нас есть алгоритм, кторый работает по трем веткам, все зависит от объема данных)

    Reply
  5. Yashazz

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

    И хранилище тут можно лепить привязанное куда угодно, согласен.

    Насчёт COM — тоже абсолютно согласен, очевидные вещи.

    Дык в том и фишка, что я хочу кидать небольшой объём и не тащить контекст. Согласитесь, могут, ещё как могут быть огромные данные, чисто по логике бизнес-задачи, пришедшие с клиента. Тот же COM, или ещё что, и не всегда можно выкрутиться.

    Кстати, до кучи: почему у обычного «ДеревоЗначений» нету метода «Скопировать», не знаете случайно? Только передача по ссылке и фиг сделаешь независимую копию, кроме как построчно…

    Reply
  6. BabySG

    (5) В том случае, если нужно что-то передать с клиента на сервер (например, тот же файл) — то, как раз, его и передаем через хранилище.

    Как вариант, мы можем его обработать на клиенте и создать из оригинального новый уменьшеный и его уже передать на сервер. В этом случае данные формы мы не трогаем, гоняем только то, что сами выбрали.

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

    Reply
  7. Yashazz

    (6) Именно. И задача иногда бывает именно требующая решения тех проблем, о которых я пишу. Например, не можем сразу забросить файл — юзверь хочет сначала посмотреть его содержимое в виде красиво оформленного интерфейса, отметить флажками нужное к обработке, и уж тогда айда на сервер. И бывает, что некоторые операции с клиентскими ипостасями этих интерфейсных объектов требуют втихую некоторым объёмом поработать на сервере.

    Reply
  8. dj_serega

    А если протестить две ТЗ и два ДЗ где будет выигрыш?

    Reply
  9. Yashazz

    (8) Смотря какого они размера. Тут фишка не столько в типе объекта, сколько в его наполнении. Но по моим ощущениям древовидные объекты сериализуются медленнее. В моём примере дерево просто служило эталонной тяжестью, могло ведь быть и строго наоборот — крохотное деревцо и огромная таблица значений.

    Reply
  10. dj_serega

    (9) если я правильно понял то:

    есть 2 ТЗ + 2 ДЗ (по 1000) то один из объектов лучше контекстом обрабатывать?

    Reply
  11. Yashazz

    (10) Если надо обработать 1 из 4 — лучше внеконтекстно. Если 3 из 4 или все — лучше контекстно. Нет однозначного рецепта, всё зависит от наполнения — может, там в ячейках нескольких строк прячутся свои монстры — всякие подтаблицы да массивы, да структуры, да ещё картинки…

    Reply
  12. bonv
    &НаКлиенте
    Процедура СгонятьБезКонтекста(Команда)
    рЗаписьХМЛ=Новый ЗаписьXML;

    В веб-клиенте это не будет работать.

    Reply
  13. Yashazz

    (12) Да. Есть такая печаль. Там останется только моделировать это всякими костылями вроде массивов структур и прочая.

    Reply
  14. PiccaHut001

    (0) «Поэтому надеюсь, что примерно к 8.3.10 это аккуратно доделают, а не оставят как сейчас и не объявят «фичей», подогнав заумное обоснование.» — зря надеетесь, 1с так делают ВСЕГДА

    Reply

Leave a Comment

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