Выгружаем в EXCEL с помощью ADO




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?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='\

30 Comments

  1. borman

    Вот здесь можете посмотреть готовую обработку для УТ, которая создает книгу excel со страницами.

    Да простит меня автор за саморекламу 😎 .

    Reply
  2. resear4er@yandex.ru

    Многовато писанины.

    Почему бы не воспользоваться напр. таким кодом для выгрузки данных в excel:

    ИмяФайлаЭксель = «D:Export.xls»;

    Макет = ЭтотОбъект.ПолучитьМакет(«Макет»);

    ТабДок = Новый ТабличныйДокумент;

    // Получаем номенклатуру для выгрузки

    Запрос = Новый Запрос(» ВЫБРАТЬ

    | Номенклатура.Код,

    | Номенклатура.Наименование

    |ИЗ

    | Справочник.Номенклатура КАК Номенклатура»);

    Результат = Запрос.Выполнить().Выбрать();

    Пока Результат.Следующий() Цикл

    строка = Макет.ПолучитьОбласть(«строка»);

    строка.Параметры.Заполнить(результат);

    ТабДок.Вывести(строка);

    КонецЦикла;

    ТабДок.Записать(ИмяФайлаЭксель,ТипФайлаТабличногоДокумента.XLS97);

    Код отработал довольно быстро: 12500 запис. за 12сек.

    Reply
  3. ll13

    (2) А вы попробуйте выполнить свой код на сервере 😉

    А Вы что на все случаи жизни макеты рисуете ?

    Reply
  4. resear4er@yandex.ru

    II13 спасибо за ответ! Теперь понял, где данную статью можно применить. 🙂

    P.S Нет, не на все 🙂

    Reply
  5. dimaxmaster

    Автору огромный +. Не знал «силу маханизма» АDO. Спасибо!

    Reply
  6. dimaxmaster

    Вопрос к автору: выгрузка происходит в строке, т.е. все данные выгружаются как строка. А нет ли возможности выгрузить Число как Число?

    Reply
  7. ll13

    (6) Где-то так :

    Table = Новый COMОбъект(«ADOX.Table»);

    Table.Name = «TestTable»;

    // Допустимые типы

    // adDouble = 5 Значение с плавающей точкой двойной точности

    // adDAte = 7 Дата

    // adCurrency = 6 Денежная сумма

    // adBoolean = 11 Булево

    // adVarWChar = 202 Символьная строка Unicode, заканчивающаяся NULL

    // adLongVarWChar = 203 Длинное строковое значение

    Column = Новый COMОбъект(«ADOX.Column»);

    Column.Name = «МойСтолбец»;

    Column.Type = 5;

    Table.Columns.Append(Column);

    Column = Неопределено;

    Catalog.Tables.Append(Table);

    Reply
  8. dimaxmaster

    (7) Спасибо, все работает

    Reply
  9. Jogeedae

    поясните:

    Command.CommandType = 1;

    Reply
  10. ll13

    (9) Тип передаваемой команды

    1 — текстовая команда SQL

    Ещё может быть хранимая процедура и по-моему таблица(но точно не помню)

    Но с ними не экспериментировал …. если осилите напишите 🙂

    Reply
  11. markers

    (2) Ваш вариант не всегда годен, к примеру проблема с обрезанием кода номенклатуры при сохранении в эксель (обрезает ведущие нули), нельзя сделать ссылку и много ещё чего..

    Reply
  12. Eddmos

    А можно к модулю приблудить позиции

    при выводе из номенклатуры

    штрих код и стоимость товара????

    Возможен ли обратный вариант

    загрузка из Excel в 1С

    например в «Реализация товаров и услуг: продажа» опять же по тем позициям

    код штрих наименование

    спс

    Reply
  13. ll13

    (12)

    А можно к модулю приблудить позиции

    при выводе из номенклатуры

    штрих код и стоимость товара????

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

    Возможен ли обратный вариант

    загрузка из Excel в 1С

    например в «Реализация товаров и услуг: продажа» опять же по тем позициям

    код штрих наименование

    На данном сайте таких обработок целая куча…

    Reply
  14. marku

    Спасибо Автору ll13 💡

    вот еще в сети нашел для 2007:

    Excel 2007 Connection String

    «Provider=Microsoft.ACE.OLEDB.12.0; data source={0}; Extended Properties=»Excel 12.0;HDR=No;IMEX=1;»»;

    СтрокаПодключения = »

    |Provider=Microsoft.ACE.OLEDB.12.0;

    |Data Source=»+ИмяФайлаЭксель+»;

    |Extended Properties=»»Excel 12.0;HDR=No;»»;»;

    Reply
  15. ratinc

    Созданный таким образом файл затем открывается с предупреждением что он повреждён. Если сохранять xlsx то вообще не открывается

    Reply
  16. AlexO

    (14) Наверное, HDR=Yes надо ставить.

    Reply
  17. AlexO

    (14) хотя нет, это не влияет в данном случае (но я до конца не уверен):

    Where «HDR=Yes» means that there is a header row in the cell range

    (or named range), so the provider will not include the first row of the

    selection into the recordset. If «HDR=No», then the provider will include

    the first row of the cell range (or named ranged) into the recordset.

    «Где «HDR=Yes» означает, что на открываемом листе есть строка-заголовок в диапазоне ячеек выбранных данных(или именованном диапазоне), т.о. Подключение не включит первую строку набора в Рекордсет (набор записей или набор данных).

    Если же «HDR=No», то Подключение включит первую строку диапазона ячеек (или именованного диапазона) в Рекордсет.»

    Reply
  18. Unicorn31

    адо использовал раньше для работы с sql базами- работает на ура… как то не приходило в голову , что для 1с можно использовать… спасибо за идею

    Reply
  19. IrinaKostroma

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

    почему то в созданном файле Excel в начале каждого слова в столбце стоит апостроф

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

    Reply
  20. DoctorRoza

    Ох, помогла статья, очень нужная оказалась. 🙂

    Reply
  21. sick_russian

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

    Reply
  22. Dim Dimy4

    Столкнулся с проблемой выгрузки из 1С 8 в Excel по ADO.

    Задача «Выгружать данные в именованный диапазон ячеек», при чём существует несколько именованных диапазонов ячеек. Расположены они разнообразно на листе.

    Пример: заданы несколько именованных диапазонов.

    1. Имя диапазона «Дата», адрес диапазона «A1»;

    2. Имя диапазона «Товар», адрес диапазона «A3:A3000»;

    3. Имя диапазона «Артикул», адрес диапазона «B3:B3000»;

    4. Имя диапазона «Количество», адрес диапазона «C3:C3000»;

    и т.д.

    Делаешь поиск диапазона на листе, находит все ок.

    Делаешь запись в ячейки диапазона значений, пишет. Но проставляет не первую, вторую, третью, т.д. ячейку адреса диапазона , а первую,вторую, третью, т.д. ячейку столбца.

    Например записываешь наименование номенклатуры в диапазон «Товар». Записывается:

    Товар1 вместо ячейки «A3» в ячейку «A1»;

    Товар2 вместо ячейки «A4» в ячейку «A2»;

    Товар3 вместо ячейки «A5» в ячейку «A3»;

    и т.д. Кто сталкивался с такой проблемой и какое решение находили?

    Reply
  23. Ele1234567

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

    Reply
  24. Vodoley

    наткнулся на то, что :

    1. после имени листа ставлю $ иначе не находит

    2. вопрос — как записать в эксель числовые данные так, чтобы он их и принял как числовые (без треугольничков в углах ячейки, мол число отформатировано как текст ??

    Reply
  25. 1801

    Попробовал — работает, переделал этот шаблон под выгрузку регистра накопления «Продажи» в Excel. (Аналитикам так удобней работать с данными, путем построения в Excel сводных таблиц в различных разрезах.) Большое вам спасибо!

    Reply
  26. 1801

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

    Reply
  27. Dim Dimy4

    (22) Dim Dimy4,

    пришлось делать через объект COMSafeArray, поищите информацию.

    Reply
  28. UserPro

    Замечательно. А как картинку выгрузить в Exsel с помощью ADO ???

    Reply
  29. hogik

    (19)

    (26)

    Используйте:

    К=Строка(8)+СтрЗаменить(Выборка.Код,»‘»,»»»);
    Н=Строка(8)+СтрЗаменить(Выборка.Наименование,»‘»,»»»);
    Command.CommandText = «INSERT INTO [Table] VALUES (‘»+К+»‘,'»+Н+»‘)»;
    Command.Execute();
    
    Reply
  30. hogik

    Reply

Leave a Comment

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