Передача файла с клиента на сервер и с сервера на клиент. Управляемые формы




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

20 Comments

  1. Dream_kz

    Очередной велосипед из серии: «не нашел, сделал свой».

    https://infostart.ru/public/584472/

    https://infostart.ru/public/669204/

    https://infostart.ru/public/409865/

    https://infostart.ru/public/812886/

    ну и т.д.

    Reply
  2. androgin

    какой треш!!!

    Это ж надо так размазать обычное получение файла ))

    Reply
  3. milkers

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

    Reply
  4. milkers

    (3) Если Вы считаете, что здесь много лишнего, то буду только рад Вашим подсказкам.

    Reply
  5. Diagnostiks

    Простую передачу файла на сервер и обратно превратили прям в «никогда такого не было, и вот опять». Очередной велосипед.

    Reply
  6. milkers

    (6) Я бы и сам был бы рад сократить код. К сожалению, нужно учитывать кучу вещей, таких как асинхронное взаимодействие, удаление временных файлов за собой, возможность сохранения имени файла в настройках и т.д. Плюс желательно сделать его легко переносимым из одной обработки в другую, ну и по возможности читаемым. Делал для себя, чтобы разобраться с этим один раз и больше не тратить времени. Еще один строительный кубик в коллекцию, чтобы быстрее писать код. Если понравится кому-то еще я только за.

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

    Reply
  7. Xershi

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

    Reply
  8. Diagnostiks
    Делал для себя, чтобы разобраться с этим один раз и больше не тратить времени

    Странно, всегда думал, что программисты это не «тупой» народ (скопировал, вставил), а творческий, да и что там писать, экономия времени минут 5-10 максимум.

    Reply
  9. milkers

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

    Reply
  10. Diagnostiks

    Отлично. Но тогда все Ваши «шаблоны» кода надо где-то централизовано хранить. А можно сделать проще — шаблоны текста сделать уж тогда.

    Reply
  11. androgin

    (7) НачатьПомещениеФайлов — тут и асинхрон и временное хранилище и имена файлов и даже можно открыть с помощью диалога и фильтрами расширений

    Reply
  12. kadild

    Используйте НачатьПомещениеФайлов и читайте напрямую из двоичных данных без создания временных файлов (8.3.9).

    Функционал в пару строк у вас превратился в лапшу с кучей процедур.

    В целом хорошо, что делитесь информацией.

    Reply
  13. kadild

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

    Reply
  14. milkers

    (13) Разговор был бы предметнее, если бы вы привели рабочий вариант кода. Если он окажется лучше, я только рад буду использовать Ваш вариант.

    Reply
  15. milkers

    (0) Более укороченный вариант кода, спасибо kadild , через НачатьПомещениеФайлов

    Reply
  16. МимохожийОднако

    (13) Сбрось сюда примерчик

    Reply
  17. shard

    хочу дополнить: при чтении табличного документа из файлов xls, xlsx, ods при получении имени временного файла указывать расширение обязательно, иначе будет «Ошибка при выполнении файловой операции»

    &НаКлиенте
    Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначенияМассив) Экспорт
    ДиалогФыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    
    ДиалогФыбораФайла.Фильтр                      = «Файл Excel (*.xls, *.xlsx)|*.xls?»;
    ДиалогФыбораФайла.Заголовок                   = «Выберите файл для загрузки данных»;
    ДиалогФыбораФайла.ПредварительныйПросмотр     = Ложь;
    ДиалогФыбораФайла.ИндексФильтра               = 0;
    ДиалогФыбораФайла.ПроверятьСуществованиеФайла = Истина;
    
    НачатьПомещениеФайла(Новый ОписаниеОповещения(«ВыполнитьЗагрузку»,ЭтаФорма),,ДиалогФыбораФайла,истина,УникальныйИдентификатор);
    КонецПроцедуры
    
    &НаКлиенте
    Процедура ВыполнитьЗагрузку(Результат,Адрес,ВыбранноеИмяФайла,ДополнительныеПараметры) Экспорт
    Если Не Результат Тогда
    Возврат;
    КонецЕсли;
    
     Расширение=СтрЗаменить(ВыбранноеИмяФайла,».»,Символы.ПС);
    Расширение=СтрПолучитьСтроку(Расширение,СтрЧислоСтрок(Расширение));
    ЗагрузитьНаСервере(Адрес,Расширение);
    //Сообщить(«Завершили»);
    КонецПроцедуры
    
    &НаСервереБезКонтекста
    Процедура ЗагрузитьНаСервере(Знач Адрес,Расширение)
    ФайлВременногоХранилища=ПолучитьИзВременногоХранилища(Адрес);
    ИмяФайла=ПолучитьИмяВременногоФайла(Расширение);
    ФайлВременногоХранилища.Записать(ИмяФайла);
    УдалитьИзВременногоХранилища(Адрес);
    MXL=Новый ТабличныйДокумент;
    MXL.Прочитать(ИмяФайла);
    УдалитьФайлы(ИмяФайла);
    КонецПроцедуры

    Показать

    Reply
  18. makfromkz

    (15) Присоединяюсь , (13) мог бы показать кошерный код.

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

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

    Reply
  19. gubanoff

    (0) помогло, хороший пример для быстрого старта!

    Reply

Leave a Comment

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