Выгружаем в EXCEL с помощью ADO (часть 2)




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

37 Comments

  1. dimaxmaster

    Плюсую, очень полезная вещь. Автор молодец.

    Reply
  2. markers

    Интересно вот, есть ли возможность навести визуальный лоск через ADO (Просто мечтаю..), например там цвета/рамочки/шрифты…

    Надо полагать что нельзя 🙁

    А так выгружать через ADO скажем прайс, а потом по строчке красить и т.д., теряется весь смысл 🙁 Но автору всё-равно спасибо!

    Reply
  3. dav405

    Тут у меня проблема на ту же тему(Jet):

    http://infostart.ru/public/65304/

    Смогли ли победить?

    http://support.microsoft.com/kb/257819/

    A caution about editing Excel data with ADO: When you insert text data into Excel with ADO, the text value is preceded with a single quote. This may cause problems later in working with the new data.

    Короче, не работает….

    Reply
  4. pga_dim

    Спасибо , дай ссылку где у Microsoft синтаксис подсмотреть по командам ADODB и по строке подключения .

    Reply
  5. afanasko

    Хорошая статья!

    У меня получилось сделать апдейт. Использовал следующий синтаксис команды:

    UPDATE [МояТаблица] SET [Символьный] = ‘йцукен’ WHERE [Целый]=1234567

    С удалением данных из таблицы возникнут проблемы. Данный драйвер не поддерживает удаление данных в связанных таблицах. Для удаления данных нужно использовать драйвер Fox Pro.

    Reply
  6. ll13

    (2) Технология ADO универсальна и код под 7.7 можно переписать за 5 минут…

    Reply
  7. ll13

    (3) Визуальный лоск через ADO Вы особо не наведете… технология ADO — это технология работы с базами данных со всеми вытекающими последствиями, достоинствами и недостатками …

    Reply
  8. markers

    (8) Да я знаю, просто мечтаю…. есть просто задача ускорить формирование прайсов с 3-4 минут * 6446 строк * 7 колонок на более быстрое… Более быстрое это ADO, но с оформлением проблемы…

    Сейчас у меня сделано прямое формирование прайс-листов через COM + COMSafetyArrays.

    Reply
  9. ll13

    (5)

    http://support.microsoft.com/kb/316934/ru

    http://www.connectionstrings.com/

    Если что-то интересное найдете непременно напишите мне.

    Reply
  10. v7plus

    Почему в созданной таблице excel стоит ‘ первым символом во всех ячейках, даже в заголовках?

    Reply
  11. ll13

    (11) Потому что у экселя данный символ — это признак символьных данных.

    Reply
  12. v7plus

    Это я знаю. Как его убрать?

    При создании колонок вроде явно пишем

    Column.Type = 202;

    imex = 1;

    в строке соединения нелязя указать.

    Что делать?

    Reply
  13. demonice

    Присоединяюсь к вопросу как убрать «‘»?

    Reply
  14. ll13

    (13),(14) Все символьные типы, провайдер OLEDB предваряет этим знаком (так сказано на сайте microsoft), как от него избавиться я не знаю, если узнаете напишите тут. Но лично мне он никогда не мешал, более того даже в файле эксель который заполняется «вручную» предварять этим знаком символьные данные — хороший тон.

    Reply
  15. rasswet

    с Экселем 2010 не работает.

    строка подключения, которая работает Provider=Microsoft.ACE.OLEDB.12.0;Data Source=E:installExport.xlsx;Extended Properties=»Excel 12.0;HDR=NO;IMEX=1″;

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

    Reply
  16. Makushimo

    (6) afanasko,

    Объясните для тех кто в танке.

    В статье инфа о том, как создать таблицу Ексель и в нее добавить строки,

    и о том, как найти строку и изменить ее.

    а Если нужно добавить строку в существующий лист файла Ексель, то как это сделать?

    Reply
  17. afanasko

    (17) Makushimo,

    Если с помощью АДО, то очевидно, что нужно открыть существующий файл Эксель:

    СтрокаПодключения = »
    |Provider=Microsoft.Jet.OLEDB.4.0;
    |Data Source=»+ИмяФайлаЭксельСуществующий+»;
    |Extended Properties=»»Excel 8.0;HDR=YES»»;»;
    
    Connection = Новый COMОбъект(«ADODB.Connection»);
    
    Connection.ConnectionString = СтрокаПодключения;
    Connection.Open();
    

    Показать

    после этого данные добавляются легко:

    Command = Новый COMОбъект(«ADODB.Command»);
    Command.ActiveConnection = Connection;
    
    Command.CommandText = «INSERT INTO [МояТаблица] (Символьный, Дата, Целый, Дробный) values (‘АБВГДЕЁ’, ’12/4/1955′, ‘1234567’, ‘12345,6789’)»;
    Command.Execute();
    
    Reply
  18. Makushimo

    (18) afanasko,

    Мой код

    Процедура КнопкаВыполнитьНажатие()

    ВыбФайл = «D:МойФайл.xls»;

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

    |Provider=Microsoft.Jet.OLEDB.4.0;

    |Data Source=»+ВыбФайл+»;

    |Extended Properties=»»Excel 8.0;HDR=YES»»;»;

    Connection = Новый COMObject(«ADODB.Connection»);

    Попытка

    Connection.ConnectionString = СтрокаПодключения;

    Connection.Open();

    Исключение

    Сообщить(«Ошибка чтения: «+СокрЛП(ВыбФайл)+» «+ОписаниеОшибки());

    Возврат;

    КонецПопытки;

    Лист = «[Лист1$]»;

    Command = Новый COMObject(«ADODB.Command»);

    Command.ActiveConnection = Connection;

    Command.CommandText = «INSERT INTO «+Лист+»(Поле1, Поле2, Поле3, Поле4) values (‘АБВГДЕЁ’, ‘ввв’, ‘ФАВУ’, ‘ФФФфФФ’)»;

    Command.Execute();

    Connection.Close();

    КонецПроцедуры

    Поле1, Поле2, Поле3, Поле4 — это названия колонок в первой строке листа1

    выдает ошибку:

    {Форма.Форма(233)}: Ошибка при вызове метода контекста (Execute): Произошла исключительная ситуация (Microsoft JET Database Engine): Несоответствие типов данных в выражении условия отбора.

    Command.Execute();

    по причине:

    Произошла исключительная ситуация (Microsoft JET Database Engine): Несоответствие типов данных в выражении условия отбора.

    я явно где-то чего-то недопонял.

    скажите где?

    Reply
  19. afanasko

    (19) Makushimo,

    Данный код у меня работает без проблем. Может ты пытаешься вставить строковые данные в колонки с типом значения «Дата» или «Число»?

    Reply
  20. AlexO

    А почему везде примеры соединения через ADO только для изменений из 1C в Excel?

    и нигде не нашел наоборот — из Excel в 1С. Везде только через Application (OLE).

    А вроде чеерз ADO быстрее работает? Или уже без разницы? например, на загрузке 10 тыс строк.

    (18) по-моему, вот это:

    Extended Properties=»»Excel 8.0…

    обозначает версию Excel, и это Excel 2003 — а какая строка подключения для 2007-2010?

    и где вообще можно подсмотреть строки подключения провайдера?

    Reply
  21. AlexO

    (0) а в чем отличие подключения ADOX или через провайдера DB? по скорости, функциональности, или еще что?

    Reply
  22. AlexO

    +(21) вот нашел (также и для (9) ):

    Why Use ADO?

    The use of ADO to transfer data to or retrieve data from an Excel workbook gives you, the developer, several advantages over Automation to Excel:

    Performance. Microsoft Excel is

    Reply
  23. ll13

    (21) AlexO, Примеров чтения из Excel -> 1С через АДО полным полно.

    Будет время напишу подробную статью посвященную этой теме, которая прольет свет на несколько не очевидных моментов.

    Reply
  24. haous

    Спасибо. Полезные вещи почерпнул для себя.

    Reply
  25. Yury1001

    (0) Большое спасибо, плюсую дважды, первый реально рабочий материал по теме на сайте который позволил в пределах часа написать выгрузку большого объема данных в excel.

    За две минуты обработка добилась ошибки:

    Command.Execute();

    {D:DATABASEВИКОSALES.ERT(ХХ)}: Microsoft JET Database Engine: Переполнение электронной таблицы.

    Но это уже проблема клиента, что у него больше 65536 строк:)))

    Ещё раз мой респект!

    P.S. На 7.7 всё арбайтен, капитально!

    Reply
  26. Yury1001

    (19) Про несоответствие типов добавлю, 1С неявно разделяет число десятичной ТОЧКОЙ, а передавать нужно обязательно ЗАПЯТУЮ, то есть явно Заменой или Форматом, а так же для 1С 8, думаю, нужно убирать разделитель триад (неразрывный пробел по умолчанию).

    Reply
  27. serggo

    Господа, а возможно ли сразу используя ADODB — запрос, прочитать не value из ячеек, а именно текст (Аналог ExDoc.Sheets(1).Cells(а,1).Text)?

    При переборе recorset’a юзаю:

    Пока НЕ RS.EOF() Цикл
    Артикул = RS.Fields(АртНом).value;

    ;

    Естественно, при замене value на text ругается

    Reply
  28. Genneral

    Промучался целый день, пытаясь сделать выгрузку в Excels через «Provider=Microsoft.Jet.OLEDB.4.0» регламентным заданием на стороне сервера 1с, на клиенте работает на сервере нет, и права крутил и что только не делал, оказалось все просто: Клиент 32-бит , Сервер 64-бит, а с 64-бит данный провайдер не работает, вот такой «нюанс».

    Reply
  29. IrinaKostroma

    Народ, а кто-нибудь сталкивался при переносе данных с тем что если в данных есть апостроф

    (например в наименовании товара), то ругается и не грузит данные.

    Если данные без апострофов то все работает нормально…

    Что делать в таких случаях?

    Код такой(часть):

    Command.CommandText = »

    |INSERT INTO [Table] VALUES (‘»+парТаб.КодПоставщика+»‘,'»+парТаб.КодПроизводителя+»‘,'»+парТаб.НаименованиеТовараПоставщика+»‘,'»+парТаб.ЦенаПоставщика+»‘)»;

    Command.Execute();

    Reply
  30. DoctorRoza

    Нужная информация, респект автору. 😉

    Reply
  31. Dim Dimy4

    Тема раскрыта не полностью.

    Попробуйте использовать в Excel именованный диапазон.

    При чтении по диапазонам все путем.

    А вот при записи, если у вас Именованный диапазон это 1 ячейка (и таких диапазонов несколько подряд в столбик).

    Делаешь апдейт через РекордСет этого диапазона. Вместо того что бы обновить значение в ячейке именованного диапазона (адрес !$B$2) он обновляет ячейку в первой строке (с адресом !$B$1). Соответственно обновляешь следующий именованный диапазон (адрес !$B$4) опять обновляется ячейка с адресом (!$B$1).

    Кто с таким сталкивался и как решить?

    Reply
  32. sick_russian

    А не подскажите пример запуска макроса в книге через адо?

    Reply
  33. Kinestetik

    Люди, такая проблема: в процедуре создаётся нетипизованная ТЗ, в которую из EXCEL через ADO выкачиваются данные. Проблема в следующем: есть ячейка с дробным числом: 0,54 — АДО её считывает, в рекордсете она есть, а при попадании в ТЗ -> NULL….

    Файло прикладываю

    Reply
  34. Kinestetik

    Народ, решилось всё. Был запрятан узкий столбец, из за него нулл выходил

    Reply
  35. Dim Dimy4

    (33) Dim Dimy4,

    пришлось делать через объект COMSafeArray

    Reply
  36. artemavrin

    (14) demonice, может кому еще полезно будет, чтоб избавиться от апострофа ‘ в строковых данных необходимо сменить провайдера на Provider=Microsoft.ACE.OLEDB.12.0

    Reply
  37. skyvixen

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

    Reply

Leave a Comment

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