141 lines
4.2 KiB
PHP
141 lines
4.2 KiB
PHP
<?php
|
|
require_once __DIR__ . '/../includes/config.php';
|
|
|
|
class Backup {
|
|
private $backup_path;
|
|
private $db_config;
|
|
|
|
public function __construct() {
|
|
$this->backup_path = __DIR__ . '/../backups';
|
|
if (!file_exists($this->backup_path)) {
|
|
mkdir($this->backup_path, 0755, true);
|
|
}
|
|
|
|
$this->db_config = [
|
|
'host' => DB_SERVER,
|
|
'user' => DB_USERNAME,
|
|
'pass' => DB_PASSWORD,
|
|
'name' => DB_NAME
|
|
];
|
|
}
|
|
|
|
public function createBackup() {
|
|
$timestamp = date('Y-m-d_H-i-s');
|
|
$backup_file = $this->backup_path . '/backup_' . $timestamp;
|
|
|
|
// Backup database
|
|
$this->backupDatabase($backup_file . '.sql');
|
|
|
|
// Backup files
|
|
$this->backupFiles($backup_file . '.zip');
|
|
|
|
// Clean old backups (keep last 5)
|
|
$this->cleanOldBackups();
|
|
|
|
return true;
|
|
}
|
|
|
|
private function backupDatabase($file) {
|
|
$command = sprintf(
|
|
'mysqldump --host=%s --user=%s --password=%s %s > %s',
|
|
escapeshellarg($this->db_config['host']),
|
|
escapeshellarg($this->db_config['user']),
|
|
escapeshellarg($this->db_config['pass']),
|
|
escapeshellarg($this->db_config['name']),
|
|
escapeshellarg($file)
|
|
);
|
|
|
|
exec($command, $output, $return_var);
|
|
if ($return_var !== 0) {
|
|
throw new Exception('Database backup failed');
|
|
}
|
|
}
|
|
|
|
private function backupFiles($file) {
|
|
$root_path = __DIR__ . '/..';
|
|
$exclude_dirs = ['backups', 'cache', 'logs', 'vendor'];
|
|
|
|
$zip = new ZipArchive();
|
|
if ($zip->open($file, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
|
throw new Exception('Cannot create zip file');
|
|
}
|
|
|
|
$files = new RecursiveIteratorIterator(
|
|
new RecursiveDirectoryIterator($root_path),
|
|
RecursiveIteratorIterator::LEAVES_ONLY
|
|
);
|
|
|
|
foreach ($files as $name => $file) {
|
|
if ($file->isDir()) {
|
|
continue;
|
|
}
|
|
|
|
$filePath = $file->getRealPath();
|
|
$relativePath = substr($filePath, strlen($root_path) + 1);
|
|
|
|
// Skip excluded directories
|
|
$skip = false;
|
|
foreach ($exclude_dirs as $exclude) {
|
|
if (strpos($relativePath, $exclude . '/') === 0) {
|
|
$skip = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$skip) {
|
|
$zip->addFile($filePath, $relativePath);
|
|
}
|
|
}
|
|
|
|
$zip->close();
|
|
}
|
|
|
|
private function cleanOldBackups($keep = 5) {
|
|
$files = glob($this->backup_path . '/*');
|
|
usort($files, function($a, $b) {
|
|
return filemtime($b) - filemtime($a);
|
|
});
|
|
|
|
if (count($files) > $keep) {
|
|
for ($i = $keep; $i < count($files); $i++) {
|
|
unlink($files[$i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public function restore($backup_date) {
|
|
$sql_file = $this->backup_path . '/backup_' . $backup_date . '.sql';
|
|
$zip_file = $this->backup_path . '/backup_' . $backup_date . '.zip';
|
|
|
|
if (!file_exists($sql_file) || !file_exists($zip_file)) {
|
|
throw new Exception('Backup files not found');
|
|
}
|
|
|
|
// Restore database
|
|
$command = sprintf(
|
|
'mysql --host=%s --user=%s --password=%s %s < %s',
|
|
escapeshellarg($this->db_config['host']),
|
|
escapeshellarg($this->db_config['user']),
|
|
escapeshellarg($this->db_config['pass']),
|
|
escapeshellarg($this->db_config['name']),
|
|
escapeshellarg($sql_file)
|
|
);
|
|
|
|
exec($command, $output, $return_var);
|
|
if ($return_var !== 0) {
|
|
throw new Exception('Database restore failed');
|
|
}
|
|
|
|
// Restore files
|
|
$zip = new ZipArchive();
|
|
if ($zip->open($zip_file) !== true) {
|
|
throw new Exception('Cannot open backup archive');
|
|
}
|
|
|
|
$zip->extractTo(__DIR__ . '/..');
|
|
$zip->close();
|
|
|
|
return true;
|
|
}
|
|
}
|