Быстрый бэкап изменяемых данных




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

24 Comments

  1. retif

    а скорость работы какая?

    10000 позиций — транзакция нажна

    Reply
  2. sokol_6630

    Лучше в excel сохранить и потом при загрузке при помощи метода Range сохранить все нужные данные в Таблицу значений и потом уже из нее восстанавливать нужные данные. А таким методом каждый раз приходится получать область с данными, это не слишком быстро.

    Reply
  3. Lem0n

    ВыгрузкаЗагрузка между идентичными конфигурациями на ИТС

    Reply
  4. davdykin

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

    Reply
  5. PrinzOfMunchen

    Денис, а если просто таблицу значений сохранить в файл через «ЗначениеВСтрокуВнутр»? При восстановлении через «ЗначениеИзСтрокиВнутр» ссылки остаются.

    А есть ещё и сериализация стандартных объектов…

    Но да, можно и так, конечно ))

    Reply
  6. collider

    Способ интересный, но мне кажется, что сложноват. Много надо держать в голове. Проще по журналу транзакций откатить базу на 4 минуты назад.

    Reply
  7. ogroup

    (6) В большинстве случаев, его нет (

    Reply
  8. ogroup

    (1) Алексей, не мерил, но для 2-5 тысяч позиций вполне приемлемая, секунд 12-15.

    Reply
  9. ogroup

    (5) Вся фишка этой штуки в том, что не нужно ничего писать предварительно. в 99% случаев вы пишите запрос в консоли, прежде чем запустить его в работу.

    Reply
  10. PrinzOfMunchen

    (9) Просто добавь в консольку кнопки сохранения/восстановления результатов запроса (таблицы значений). И всё будет работать намного быстрее, чем обход mxl в цикле.

    Reply
  11. webester

    (6)Вместе с со своими изменениями, откатить продажи, уже пробитые в ККМ чеки и созданные кем нибудь элементы справочников. Мои юзеры сразу убивают за такое .

    Reply
  12. collider

    (11) Наверное полагается что то, что автор предложил, будет происходить в

    1. Тестовой базе

    2. Рабочей базе без пользователей (на случай необходимости отката)

    А в рабочей базе и при этом с людьми в ней, я в любом случае не рискнул бы делать подобное. Выгружать в mxl и загружать обратно — это не такая уж и надёжная операция. Однажды что-то упустишь и будешь откатывать к ночному бэкапу продажи, уже пробитые в ККМ, чеки и созданные кем нибудь элементы справочников.

    Reply
  13. webester

    (12)Ну… как то упустил. У меня тестовая база в режиме восстановления «простая». В таком случае да, лог проще откатить.

    Reply
  14. baracuda

    Один вопрос, а что если в запросе была допущена неочевидная ошибка, как часто бывает. Все данные в итоге коту под хвост.

    Очень вредный совет. Как минимум я все равно перед операцией сделал бы бэкап данных.

    Reply
  15. ogroup

    (14) я здесь предполагаю, что запрос, выполняемый в запроснике, и запрос, выполняемый при изменении данных — один и тот же. Пусть даже и с ошибкой, но отработает он одинаково

    Reply
  16. Zhilyakovdr

    Превое. Изменение каких то больших массивов данных чаще всего делают ночью когда база свободна от пользователей.

    Второе. В большинстве фирм которые дорожат своими данными кроме ночных бекапов делаются бекапы логов (у нас в организации каждые 5 минут)

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

    Поднимается бекап на точку с корректными данными и как уже писали выше используется ВыгрузкаЗагрузка между идентичными конфигурациями.

    Если структура изменилась то в том чтобы привести тестовую базу(из бекапа) в соответствие с боевой нет ничего сложного, особенно если вы используете хранилище.

    Но самый лучший способ это не косячить на боевых серверах)))))

    Reply
  17. NN2P

    Бакуп сделал мой день!

    Reply
  18. ture

    (17)

    Что-то мне кажется, что это слишком оптимистично:

    Проще по журналу транзакций откатить базу на 4 минуты назад.

    На заре юности и желторотости, я, к примеру, реально верил в это. Потом разок попробовал… получилось одного журнала почему-то мало. Долго не мог унять негодования. Но звучит то как красиво! — «на 4 минуты назад»

    Жаль, что бакуп так «странно» устроен.

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

    Перед массовым изменениями в боевой базе. 1. Сделать архив. 2. Проверить на копии. 3. Внести изменения.

    Хотя сама по себе идея интересная при тестировании.

    Reply
  20. didkovskij

    как вариант, с помощью обработки «Выгрузка и загрузка данных XML»

    можно универсальной выгрузкой выгрузить данные в xml. Затем откатить простой загрузкой.

    Reply
  21. Angealtor

    Автор скорее всего свое решение предлагает использовать в случаях, когда один из менеджеров компании меняет несколько реквизитов (100-10000) у определенной группы товаров,например, и допускает ошибку. Т.е. способ предназначен преимущественно для справочников.

    Reply
  22. DrAku1a

    Примерно так:

    1. ЗначениеВФайл / ЗначениеИзФайла

    2. ЗначениеВСтрокуВнутр / ЗначениеИзСтрокиВнутр

    3. XML-сериализация (обработка «Выгрузка-загрузка данных в формате XML», вроде есть на ИТС и для 8.2, и для 8.3)

    Reply
  23. Probot1c

    Способ интересный, но я пользуюсь утилитой ежедневного (недельного) копирования БД ..effector saver (если кому понадобится)

    Reply
  24. nsasov

    (21) Самое простое решение, поддерживаю! Но вообще это актуально только при тестировании обработки. На рабочей базе лучше такие изменения делать в монопольном режиме.

    Reply

Leave a Comment

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