Контроль места под резервные копии, с автоматическим удалением файлов при нехватке, с оповещением




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

8 Comments

  1. hercares

    Есть возможность реализовать использование, к примеру, viber бот вместо email, который можно заметить несвоевременно?

    Reply
  2. user1162240

    А не легче все реализовать через батники и Планировщик заданий операционной системы?

    Reply
  3. iones

    (2)Если же вы можете все данные функции реализовать bat-файлом. Пожалуйста!

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

    Reply
  4. iones

    (1)В качестве оповещения, можно прикрутить все что угодно.

    Reply
  5. hercares

    ИМХО, вариант с оповещением на email кажется архаичным и не оперативным. Но да, вы правы, можно прикрутить

    Reply
  6. iones

    (5)Где как. В нашей организации в обязательном порядке должен быть запущен почтовый клиент, с оповещением поверх всех окон. Нас это как раз устраивает. А остальное закрыто (соц.сети, viber, whatsapp, skype и т.п.)

    Учту пожелания на будущие версии.

    Reply
  7. CyberMuesli

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

    Продуктив: база 100Гб, размер полного бэкапа 20Гб, посекундный restore — на два два месяца назад, хранение: часовой диф — 4 часа, ежедневные копии — 2 дня, еженедельные — месяц, ежемесячные — год. Итого 400Гб. Какая еще нехватка места? Какой размер современных СХД?

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

    В RTO 1 час укладываемся с запасом.

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

    Т.к. они жестоко режутся при передаче, их размеры по 10…30Гб, общий объем 800 Гб. Схема бэкапа — месяц посекундного отката каждой базы, до двух месяцев — restore на точки восстановления, в качестве ежедневных и еженедельных копий выступают дифы, что на порядок снижает необходимое место. Итого размер бэкапов двух сред — 700 Гб.

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

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

    P.S. с удивлением узнал, что инфостарт заменяет в сообщениях слово от-кат на звездочку. ))

    Reply
  8. iones

    (7) Читайте сообщение (3)

    Перед тем как плеваться и осуждать. Это реализация контроля средствами 1С. Да, есть еще сотня другая вариантов решения. Не претендует на уникальность.

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

    Код ниже:

    Const ForReading = 1
    Const ForWriting = 2
    Const tFolder = «d:log»
    Const tFileName = «log.txt»
    
    set objFSO=CreateObject («Scripting.FileSystemObject»)
    
    Set objFile = objFSO.OpenTextFile(tFolder & tFileName, ForWriting)
    sText = «disks»
    objFile.WriteLine sText
    objFile.Close
    
    strComputer = «my_comp_name»
    Set objWMIService = GetObject(«winmgmts:\» & strComputer & »
    ootcimv2″)
    Set colDiskDrives = objWMIService.ExecQuery(«SELECT * FROM Win32_DiskDrive»)
    
    For Each objDrive In colDiskDrives
    strDeviceID = Replace(objDrive.DeviceID, «», «\»)
    Set colPartitions = objWMIService.ExecQuery («ASSOCIATORS OF {Win32_DiskDrive.DeviceID=»»» & strDeviceID & «»»} WHERE AssocClass = » & «Win32_DiskDriveToDiskPartition»)
    For Each objPartition In colPartitions
    Set colLogicalDisks = objWMIService.ExecQuery («ASSOCIATORS OF {Win32_DiskPartition.DeviceID=»»» & objPartition.DeviceID & «»»} WHERE AssocClass = » & «Win32_LogicalDiskToPartition»)
    For Each objLogicalDisk In colLogicalDisks
    Set colDisks = objWMIService.ExecQuery («Select * from Win32_LogicalDisk Where DeviceID = ‘» & objLogicalDisk.DeviceID & «‘»)
    For Each objDisk in colDisks
    
    Set objFile = objFSO.OpenTextFile(tFolder & tFileName, ForReading)
    sFileText = objFile.ReadAll
    objFile.Close
    
    Set objFile = objFSO.OpenTextFile(tFolder & tFileName, ForWriting)
    
    objFile.WriteLine sFileText & objLogicalDisk.DeviceID & » — » & objDisk.FreeSpace & » byte»
    objFile.Close
    
    Next
    Next
    Next
    Next

    Показать

    Reply

Leave a Comment

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