Система для создания бэкапов

07.04.2024

Небольшой скрипт для создания и ротации бэкапов, который забирает файлы с удаленного сервер (php / linux).

Выполняем каждую среду:

 
0 05 * * 3      /usr/bin/php -f /path/to/backupper.php >> /path/to/main.log

Необходимо доставить библиотеку для работы с БД. В composer.json:

 
{
    "require": {
        "oddler/pdo": "^1.8"
    }
}

В консоли

 
composer install

Осноыной скрипт backupper.php:

 
<?php

error_reporting(E_ALL);
ini_set('display_errors', 'On');

define('SO_ROOT', __DIR__);
define('SO_PATH_ARCHIVE', '/backup/files/');
define('SO_PATH_REMOTE_BASE', '/home/bitrix/backup/');
//define('SO_PATH_REMOTE_WORK', SO_PATH_REMOTE_BASE.'test/');
define('SO_PATH_REMOTE_WORK', SO_PATH_REMOTE_BASE.'archive/');
define('SO_REMOTE_HOST', 'bitrix@XXX.YYY.ZZZ.1');
define('SO_INFO_FILE', 'info.json');

class soStatus {
    const newFile  = 0;
    const forDownload   = 1;
    const skipped       = 2;
    const downloaded    = 3;
    const error    = 99;
}

require_once('vendor/autoload.php');

use Oddler\Pdo\DBCore;

class arBackup extends Oddler\Pdo\Table
{
    public $id			    = '';
    public $file_name		= '';
    public $date_start		= '';
    public $date_end		= '';
    public $deleted		    = '';
    public $downloaded		= '';
    public $message		    = '';
    public $crc     	    = '';

    public function __construct(&$oDB = NULL)
    {
        $this->construct('backups', 'id', $oDB);
    }
}

class soMain {

    protected $_db  = null;
    protected $_aRemoteFiles = [];
    protected $_aLastRemoteFile = [];

    public function __construct()
    {
        $DBCore = DBCore::getInstance();
        $this->_db = $DBCore->connect( array(
            'host'     => 'localhost',
            'user'     => 'backupper',
            'password' => 'PASS',
            'database' => 'db_backupper',
            'charset' => 'utf8',
            'database_type' => 'mysql'
        ));
    }

    protected function updateInfo()
    {
        // Запускаем удаленный скрипт, для получения информации
        exec("ssh ".SO_REMOTE_HOST." 'php ".SO_PATH_REMOTE_BASE."/get_info.php'");

        // Скачиваем инфу
        exec('scp -r '.SO_REMOTE_HOST.':'.SO_PATH_REMOTE_BASE.SO_INFO_FILE.' '.SO_ROOT.'/'.SO_INFO_FILE);

        // Получить инфу
        $this->_aRemoteFiles = json_decode(file_get_contents(SO_ROOT.'/'.SO_INFO_FILE));
    }

    public function pullOutLastFile()
    {
        $lastDate = '2000-01-01';
        foreach($this->_aRemoteFiles as $sName => $crc) {
            $date = $this->extractDate($sName);
            if ($lastDate < $date) {
                $lastDate = $date;
                $this->_aLastRemoteFile = [$sName => $crc];
            }
        }
    }

    protected function query($sSQL)
    {
        $this->_db->setQuery($sSQL);
        return $this->_db->query();
    }

    protected function queryAll($sSQL)
    {
        $this->_db->setQuery($sSQL);
        return $this->_db->loadObjectsList();
    }

    protected function queryOne($sSQL)
    {
        $this->_db->setQuery($sSQL);
        return $this->_db->loadObject();
    }

    protected function say($sText)
    {
        echo date('Ymd').': '. $sText."\n";
    }

    protected function extractDate($sText)
    {
        $sPattern  = "|([0-9]{2}).([0-9]{2}).([0-9]{4})|si";
        preg_match_all($sPattern, $sText, $aMatches, PREG_SET_ORDER);

//        echo '<pre>';
//        print_r($aMatches);
//        echo '</pre>';

        return $aMatches[0][3].'-'.$aMatches[0][2].'-'.$aMatches[0][1];

    }

    protected function syncDB()
    {
        foreach($this->_aRemoteFiles as $sName => $crc) {

            $this->say($sName);

            $sSQl = 'SELECT count(*) AS c FROM backups WHERE `file_name` = "'.$sName
                .'" AND deleted = 0 AND downloaded > ' . soStatus::forDownload;

            $oRes = $this->queryOne($sSQl);

//            $this->say($sSQl);
//            $this->say($oRes->c);

            if (!$oRes->c) {
                $oBackup = new arBackup();
//                $oBackup = new stdClass();
                $oBackup->file_name = $sName;
                $oBackup->crc = $crc;
                $oBackup->date_start = $this->extractDate($sName);
                // MONTH WEEK
                $oBackup->date_end = date('Y-m-d', strtotime('+3 WEEK', strtotime($oBackup->date_start)));
                $oBackup->deleted = 0;

                if (key($this->_aLastRemoteFile) == $sName) {
                    $oBackup->downloaded = soStatus::forDownload;
                } else {
                    $oBackup->downloaded = soStatus::skipped;
                }

                $oBackup->message = '';

                $oBackup->save();
            }
        }
    }

    // Скачиваем файлы которых нет
    protected function downloadNew()
    {
        $aRes = $this->queryAll('SELECT id FROM backups WHERE deleted = 0 AND downloaded = ' . soStatus::forDownload);

        if (count($aRes)) {
            foreach($aRes as $oRow) {
                $oBackup = new arBackup();
                $oBackup->load($oRow->id);
                $sFile = SO_PATH_ARCHIVE.'/'.$oBackup->file_name;
                exec('scp -r '.SO_REMOTE_HOST.':'.SO_PATH_REMOTE_WORK.$oBackup->file_name.' '.$sFile);

                // Проверяем md5
                if(!md5_file($sFile) == $oBackup->crc) {
                    $sTMP7 = 'md5_error';
                    file_get_contents('http://api.oddler.ru/tools/?task=telegram&message='.$sTMP7.'&token=123');
                    $oBackup->message = 'crcError';
                    $oBackup->downloaded = soStatus::error;
                } else {
                    $oBackup->downloaded = soStatus::downloaded;
                }

                $oBackup->save();
            }
        } else {
            $this->say('Nothing to download');
        }

    }

    protected function deleteOld()
    {
        $aRes = $this->queryAll('SELECT id FROM backups WHERE downloaded  = '.soStatus::downloaded.' AND deleted = 0 AND date_end <= "'.date('Y-m-d').'"');
        foreach($aRes as $oRow) {
            $oBackup = new arBackup();
            $oBackup->load($oRow->id);
            $sFile = SO_PATH_ARCHIVE.'/'.$oBackup->file_name;

            $this->say('Unlink: ' . $sFile);
            unlink($sFile);

            $oBackup->deleted = 1;

            $oBackup->save();


//            $sTMP7 = 'time_2_remove';
//            file_get_contents('http://api.oddler.ru/tools/?task=telegram&message='.$sTMP7.'&token=123');
        }
    }

    public function run()
    {
        $bClear = false;
//        $bClear = true;

        if ($bClear) {
            $this->query('TRUNCATE backups');
        } else {
            $this->updateInfo();

            $this->pullOutLastFile();

//!            $this->query('TRUNCATE backups');

            $this->syncDB();

////        $aRes = $this->queryAll('SELECT * FROM backups');
////        print_r($aRes);

            $this->downloadNew();

            // Удаляем старые файлы
            $this->deleteOld();
        }
    }
}

$soMain = new soMain();
$soMain->run();

Скрипт для удаленного сервера get_info.php

 
<?php

$bDebug = false;

$aResult = [];

$sBasePath = __DIR__;

if ($bDebug) {
    $sPath = $sBasePath.'/test/';
} else {
    $sPath = $sBasePath.'/archive/';
}

$results = glob($sPath.'*.tar.gz');

foreach ($results as $result) {
    $result = str_replace($sPath, '', $result);

    if ($bDebug) {
        $aResult[$result] = 'MD5';
    } else {
        $aResult[$result] = md5_file($sPath.$result);
    }
}

if ($bDebug) {
    print_r($aResult);
}

//print_r($aResult);

file_put_contents($sBasePath.'/info.json', json_encode($aResult));[


Категории: PHP, Linux, Script / Tool
Пометки: backupper
Яндекс.Метрика