Загрузка из Excel (без использования com-объектов, без установленного Excel)




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

26 Comments

  1. DJDUH

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

    Reply
  2. Смешной 1С

    (1) Спасибо за замечание. Действительно, работало некорректно, выводило все в одну Таблицу.

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

    Reply
  3. neuro88

    (1) на каждый лист будет создана новая область. так что использовать можно.

    Reply
  4. ifal

    Так это уже как пару лет, если не ошибаюсь.

    Reply
  5. Смешной 1С

    (4) Да, это появилось в платформе 8.3.12.

    Reply
  6. ifal
  7. Смешной 1С

    (6) Да, с платформы 8.3.10 можно считывать отдельные листы файла EXCEL.

    Но многие до сих почему-то через COM читают.

    Reply
  8. ifal

    (7) не всегда корректно 1с считывает, особенно если с openoffice сохраняли.

    Reply
  9. AlexeyPapanov

    Существенное неудобство такого метода в том, что он доступен только в толстом клиенте.

    Reply
  10. Смешной 1С

    (9) В тонком и веб-клиенте также отлично работает

    Reply
  11. Смешной 1С

    (10) Веб клиент

    Reply
  12. AlexeyPapanov

    (11) Ничего не понимаю.

    Может мы о разных вещах говорим?

    Открываю СП по методу ТабличныйДокумент.Прочитать() и вижу

    Доступность:

    Сервер, толстый клиент, внешнее соединение, мобильное приложение(сервер).

    Я скачаю Вашу обработку и проверю.

    Reply
  13. AlexeyPapanov

    (12) Все, увидел. Вы файл на сервере читаете.

    Reply
  14. Смешной 1С

    (13) да, это и логично. Такие задачи как раз и должны на сервере выполняться.

    Reply
  15. AlexeyPapanov

    (14) Чтение файла с клиентской машины? Наоборот, там где можно сделать на клиенте, так и надо делать. А Вам приходится гонять файл с клиента на сервер. На одном компе разницы юзер не ощутит, но концепция работы с УФ подразумевает другой подход как мне кажется.

    Reply
  16. Смешной 1С

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

    Reply
  17. acanta

    А если файл екселе открыт, редактируется одновременно несколькими пользователями запаролен и защищен от редактирования в нескольких местах, тогда как?

    Reply
  18. AlexeyPapanov

    (16) передача файла на сервер в Вашем случае вынужденная, а не необходимая.

    постобработка данных конечно будет на сервере — ежу понятно.

    в любом случае, этот вариант имеет место быть. не у всех, к примеру, есть Excel.

    Reply
  19. Смешной 1С

    (17) Не приходилось иметь дело с такими условиями, нужно эксперементировать

    Reply
  20. TreeDogNight

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

    Reply
  21. starik-2005

    (5) с 8.3.12 можно записывать экс5ль в несколько листов — я об этом писал как-то: https://infostart.ru/public/979007/

    Reply
  22. logarifm

    (20)64 -битными клиентами для больших фалов надо пользоваться!

    Reply
  23. nikita0832
    Также в обработке написан разбор считываемых данных и преобразование их в таблицу значений для дальнейшей обработки.

    — это же через построитель запроса делается? Там хорошо что таблица сразу типизированная, можно её в запрос. Но сложные 2 и более этажные шапки не читаются. я обходил такой косяк дописывая заголовки на основании заголовков выше и урезая область чтения сверху (реализовано тут). Ну и редактор запроса и кода с сохранением этого в файлы .q1c тоже в наличии. Еще у экселя часто косяк с типами бывает, не всегда точно можно сказать какой тип в колонке прочитается, к счастью в консоли типы колонок на лету меняются. И есть неисправимый косяк с типами дата — когда указано время без даты меньше чем 01:36, при этом тип — дата, даты определяются косячно, поэтому время без даты лучше читать как строку.

    Reply
  24. starik-2005

    (22) не надо пользоваться 1С для больших файлов вообще — он для этого не предназначен )))

    Reply
  25. v25i85

    чёт все забыли, что кроме эксель есть и txt — более компактное решение для переноса данных.

    Reply
  26. starik-2005

    (25)

    чёт все забыли, что кроме эксель есть и txt — более компактное решение для переноса данных.

    С учетом того, что последний Эксель — это запакованный XML, то что-то как-то утверждение мне, лично, кажется слабоватым. А для компактности вообще есть HTTP-сервисы — там хоть в protobuf можно данные передавать — уж куда компактнее (хотя тоже не молодое решение — еще в паскале были типизированные файлы, куда можно было гнать поток типа RECORD — как раз бинарник с описанными в типе данными).

    Reply

Leave a Comment

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