<?php // Полная загрузка сервисных книжек, создан 2025-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='\
Есть один маленький и очень тонкий ньюанс:
При использовании временного хранилища с адресом УИД формы, если надо передать больше чем 1 файл, точнее передать потом еще раз передать, то в дело вступает механизм кеширования и результат будет следующий (не знаю починили ли в последних релизах):
Поместили Адрес = ПоместитьВоВременноеХранилище(Файл1,ЭтаФорма.УникальныйИдентификатор)
Метод ПолучитьИзВременногоХранилища(Адрес)
На сервере — Файл 1
На клиенте — Файл 1
следом Адрес = ПоместитьВоВременноеХранилище(Файл2,ЭтаФорма.УникальныйИдентификатор) Форма та же, без переоткрытия
Метод ПолучитьИзВременногоХранилища(Адрес)
На сервере Файл 2
На клиенте Файл 1
При этом где помещаем — клиент или сервер — не важно.
(1) На платформе 8.3.10.2699 провел несколько экспериментов:
Показать
Результат получился вполне ожидаемый, т.е. правильный. Возможно в предыдущих релизах платформы действительно была ошибка, но сейчас она исправлена.
(2)
ПолучитьНаСервере(Адрес1);
Адрес2 = ПоместитьВоВременноеХранилище(«Б», ЭтаФорма.УникальныйИдентификатор);
ПолучитьНаСервере(Адрес2);
Там суть моего посыла была в другом, но по факту да, проверил на текущих релизах, при получении из временного хранилища по адресу формы больше бага нет.
Но я уже привык не доверять этому механизму, ибо в свое время на этом очень сильно обжегся (изменение по одному адресу во временном хранилище)
Интересная и полезная статья, особенно для тех, кто под «нажимом непреодолимой силы» вынужден менять привычные платформы и конфигурации… При переписывании обработок на управляемые формы вопрос корректной работы с файлами обязательно возникает…
(3)
и как выкрутились с адресом во временном хранилище?
Давайте я немного наброшу на вентилятор. А как будет работать Ваша схема с файлами больше 4 Гб?
(6)
Я бы слегка перефразировал вопрос и разбил его на несколько:
1) Как работают с большими файлами платформенные механизмы передачи файлов между клиентом и сервером? Какие есть ограничения для тонкого и веб-клиента? Есть ли зависимость от браузера?
2) Как работают с большими объемами данных механизмы потоков?
Впрочем, мне кажется, что ответы на эти вопросы имеют скорее теоретическое значение, так как если система спроектирована таким образом, что передача больших файлов указанными средствами платформы — штатная функция системы, то это недосмотр проектировщика или архитектора. Все же подобные задачи лучше решать другими средствами, к примеру — FTP. А для «защиты от дурака» достаточно встроить проверку размера файла перед передачей. Да, конечно же не забываем, что на клиенте для этого необходимо использовать асинхронный НачатьПолучениеРазмера
(7)
1) Какая разница как они работают «под капотом»? Во временное хранилище нельзя положить больше 2#k8SjZc9Dxk32 байт. Просто нельзя.
Если Вам сильно интересно, как, возьмите большой файл и посмотрите на дисковую активность в темпах, обещаю понравится.
2) А вот механизм потоков работает просто отлично, он может и небольшими порциями работать через ПотокВПамяти.
(8)
Ну вот вы и сами ответили на свой вопрос, попутно подтвердив мои слова, о том, что при проектировании системы, работающей с большими файлами, нельзя использовать механизмы передачи файлов через временное хранилище. Для этого необходимо использовать другие технологии.
Я конечно не хочу казаться умником, но чем вас не устраивает метод НачатьПомещениеФайла / НачатьПомещениеФайлов ? У вас куча процедур расписана (на мой взгляд совершенно лишних)
я выбираю файлы таким образом:
Показать
(10) Основное отличие моего варианта от Вашего — возможность обработать выбранный пользователем файл до передачи на сервер или получения с сервера. Например: сообщить пользователю «Вы не можете загрузить на сервер файл ‘Игра престолов (все сезоны).mkv'» или «Вы не можете перезаписать файл ‘устав проекта.docx’, выберите другой». Кроме того, в Вашем варианте все заканчивается после получения адреса загруженного файла, в моем — дополнительно описана процедура обработки содержимого с помощью механизма потоков, поэтому и методов в примере больше. Но конечно же, Ваш вариант проще, и может быть вполне применим в большинстве случаев.
(11) при превышении объема файла над размером памяти — система сама выдаст ошибку. Вам останется лишь вывести ее в удобочитаемом виде.
(11) еще можно создать диалог — выбрать и инициализировать файл и получить его размер. Если размер устраивает — передать Диалог дальше в метод получения файла.
(12)
12. Виктор Назаров (androgin) 12.04.18 13:48
(11) при превышении объема файла над размером памяти — система сама выдаст ошибку. Вам останется лишь вывести ее в удобочитаемом виде
А если нам надо ограничить размер файла своим значением, например 10Мб, исходя из своих целей? А если надо наложить условие: можно загружать все файлы, кроме определенных типов? В этих случаях как раз и надо проверить, что выбрал пользователь. Причем сделать это лучше ДО остальных действий по формированию и передаче файла.
(13) Именно такая схема, с отдельным диалогом, и приведена в статье. Я не стал вставлять дополнительные проверки, чтобы не загромождать пример. И, раз уж мы получили имя файла, его и надо передавать в метод передачи файла, а не Диалог.
(15) ну вам виднее. Но я бы так не делал)
(15) вы в своем коде все равно тащите все на сервер — в чем смысл?
вам в любом случае для получения размера сначала придется инициализировать файл, а до этого выбрать его диалогом. Все не удовлетворяющие файлы можно удалить из диалога и передать уже этот диалог в получение файлов.
Использование диалога позволяет применять фильтр!
НЕ?
(17)
Мне кажется в нашем споре каждый имеет в виду что-то свое. Я описываю решение следующей задачи: 1) дать возможность пользователю выбрать файл, 2) проверить, что он выбрал (проверки могут быть самые разные: размер, расширение, каталог), 3) и только если файл удовлетворяет заданным критериям, отправить его на сервер для дальнейшей обработки. В моем примере выбор файла — асинхронный вызов диалога, по его завершению мы получим имя файла, который после всех проверок будем использовать при передачи на сервер. Зачем при передаче на сервер еще раз указывать диалог? Чтобы пользователь два раза выбирал файл? Да, конечно же, можно использовать интерактивный режим вызова метода НачатьПомещениеФайлов без предварительного вызова диалога. Но при этом Вам просто негде будет вставить свои проверки. Единственное что Вы можете — это указать маску допустимых имен файла. Но и в этом случае Вы не сможете задать условие вида: ‘выбрать все файлы, кроме *.exe, *.vbs’. Что касается задачи получения файла с сервера, там ситуация немного иная. Если, как в моем примере, файл не хранится в базе, а формируется каким либо образом — это формирование может занять какое-то время. Тогда, с точки зрения юзабилити, лучше дать возможность выбрать файл для записи, удостовериться что он его выбрал, и выбрал то, что надо, а только потом заниматься длительным формированием файла. При использовании Вашего подхода (т.е. использования диалога выбора при вызове метода передачи) мы сначала затратим время на формирование и сохранение файла во временном хранилище, а только потом будем спрашивать у пользователя куда он хочет его сохранить, и не передумал ли он, «потому что забыл дома флешку».
(18) так вы сами же описываете то, что я и говорю: выбор файла и проверку его ( ваш второй пункт очень странный — расширение и каталог в диалоге выбирается! а размер можно получить после выбора файла или настроить вид диалога — показать там размер).
Это топтание на месте.
Мне вообще непонятно: зачем использовать сервер, если все на клиенте делается: и выбор файла и получение его размера. Только для того, чтобы поиграться с потоком?)))
Можно использовать и не_интерактивный метод выбора (признак такой имеется в методе) и это никак не мешает вставить свои проверки. Фильтр «выбрать все, кроме ххх, ххх» — ну это ж дурость! Создайте необходимые фильтры заранее и пусть пользователь сам выбирает, что ему нужно.
Когда вы тащите хранилище на сервер — вы уже получаете файл!
Вам вообще знакомы клиент-серверные работы с файлами?
Ваш метод, мало того, что получает файл и помещает в хранилище, так вы потом его еще на сервер тащите и там получаете из хранилища!!
Что за абсурд?
Все ваши манипуляции вполне себе на клиенте работают!
(19)
Несмотря на вашу горячность, я надеюсь, что Вы не троллите, а просто невнимательно читаете мои сообщения. Хорошо, давайте возьмем Ваш пример из (10). Добавьте в него возможность загружать любые файлы, кроме потенциально опасных, например *.exe. Нет, это не дурость, подобный функционал есть в системах, построенных на базе БСП, там есть что-то вроде «Запретить загрузку файлов с расширениями». В случае попытки выбрать такой файл добавьте сообщение об этом пользователю. Если у Вас найдется способ сделать это с помощью интерактивного режима метода НачатьПомещениеФайлов без дополнительного вызова диалога, поделитесь. Далее: в моем примере при выборе файла не используется сервер, и конечно же для получения размера файла сервер тоже не нужен. Безусловно, есть задачи, которые можно решить только на клиенте. Но я специально выбрал такую задачу, для которой нужен сервер. Я это подчеркнул в начале статьи. Вы и сами сможете привести примеры таких задач. Вы же согласитесь, что с объектами базы данных можно работать только на сервере? Вот и в моем примере используется запись и чтение объектов ИБ. Может Вы имеете в виду иное — хранение файла целиком в базе данных, в каком-либо реквизите? Это немного другая задача.
(20) «кроме потенциально опасных» — вы вообще читали, что я писал?
вы программист — вам легко это проверить после выбора! Даже если вы не укажете опасное расширение — вы его можете проверить ПОСЛЕ выбора и вывести пользователю сообщение, что «ай-я-яй, такие файлы нельзя выбирать!» и удалить их из выбора. Сложно? НЕТ!
Далее: НачатьПомещениеФайлов с диалогом как раз и контролирует расширения, о чем я вам выше и писал!
«специально выбрал такую задачу, для которой нужен сервер» — именно это и является узким местом! вы тащите все на сервер! а это и есть «очень плохо».
Я же настаиваю, что все операции с проверками делать нужно на клиенте!
(22)
Вы все-таки невнимательно прочитали статью и мои комментарии. Поясню еще раз: на первом шаге мы вызываем диалог выбора файла. При вызове можно указать (как Вы верно говорите) свойства диалога: фильтр, начальный каталог, etc. Результат работы диалога обрабатывается в ОповещениеПослеВыбораФайлаДляЧтения . Здесь мы можем выполнить любые проверки — проверить расширение файла, путь к файлу и так далее. Я не стал загромождать пример, поэтому проверяю только то, что пользователь не отказался от выбора. Если вы посмотрите внимательно, то увидите директиву &НаКлиенте. Это означает, что эти операции будут выполнены на клиенте. С чего Вы взяли, что я делаю это на сервере? Если посмотрите внимательно, то увидите, что у меня ни в одной серверной процедуре нет проверок.
Вы разобрались что происходит в моих серверных методах? А там я делаю то, что можно сделать только на сервере: работаю с данными информационной базы. Для решения поставленной в начале статьи задачи, мне нужно содержимое файла. Вполне логично, что я его получаю из хранилища. Что значат Ваши слова:
«Ваш метод, мало того, что получает файл и помещает в хранилище, так вы потом его еще на сервер тащите и там получаете из хранилища!!
Что за абсурд?
Все ваши манипуляции вполне себе на клиенте работают! «? Как можно после помещения файла во временное хранилище, отдельно его «тащить» на сервер? Какая строчка моего кода заставила Вас так подумать? Как «манипуляции» по созданию объекта и записи его в ИБ «вполне себе на клиенте работают»? Или Вы считаете что таких задач не бывает? Что любые действия с содержимым файлов можно делать на клиенте, потому что на сервере это делать «есть «очень плохо»?
Давайте, чтобы не быть голословным, напишите свой вариант решения рассмотренной в статье задачи и покажите в чем он быстрее / лучше / пригодней для дальнейшей адаптации. Потому что иначе от меня ускользает смысл того, что Вы хотите доказать.
Уже не нужно использовать «СериализаторXDTO»
Работа с файлами (обычная и управляемая форма) все структурировано и используется метод «ЧтениеДанных»!
Наконец написал свою публикацию
с блекджеком и ш……