220 lines
6.2 KiB
PHP
220 lines
6.2 KiB
PHP
<?php
|
|
|
|
define('TMP_FILE', __DIR__ . '/backup_tmp.json');
|
|
define('FILES_PER_STEP', 50);
|
|
|
|
// Sprawdzenie czy możemy użyć shell_exec + zip/tar
|
|
function canUseShell() {
|
|
return function_exists('shell_exec') && !in_array('shell_exec', explode(',', ini_get('disable_functions')));
|
|
}
|
|
|
|
function commandAvailable($cmd) {
|
|
$check = shell_exec("command -v $cmd 2>/dev/null");
|
|
return !empty($check);
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
header('Content-Type: application/json');
|
|
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
if ($action === 'init') {
|
|
$filename = 'backup_' . date("Ymd_His");
|
|
$response = ['success' => false];
|
|
|
|
if (canUseShell()) {
|
|
if (commandAvailable('tar')) {
|
|
$tarName = "$filename.tar";
|
|
shell_exec("tar -cf $tarName .");
|
|
if (file_exists($tarName)) {
|
|
$response = [
|
|
'success' => true,
|
|
'method' => 'shell_tar',
|
|
'file' => $tarName
|
|
];
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
} elseif (commandAvailable('zip')) {
|
|
$zipName = "$filename.zip";
|
|
shell_exec("zip -r $zipName . -x '*backup_*.zip' '*.git*' 'node_modules/*' 'vendor/*'");
|
|
if (file_exists($zipName)) {
|
|
$response = [
|
|
'success' => true,
|
|
'method' => 'shell_zip',
|
|
'file' => $zipName
|
|
];
|
|
echo json_encode($response);
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Jeśli nie ma shell_exec lub zip/tar — fallback na ZipArchive krok po kroku
|
|
$zipName = "$filename.zip";
|
|
$zipPath = __DIR__ . '/' . $zipName;
|
|
|
|
$iterator = new RecursiveIteratorIterator(
|
|
new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS)
|
|
);
|
|
|
|
$files = [];
|
|
foreach ($iterator as $file) {
|
|
$path = $file->getPathname();
|
|
if (strpos($path, $zipName) !== false) continue;
|
|
$files[] = $path;
|
|
}
|
|
|
|
$zip = new ZipArchive();
|
|
if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
|
|
echo json_encode(['success' => false, 'message' => 'Nie można utworzyć ZIP']);
|
|
exit;
|
|
}
|
|
$zip->addEmptyDir('__INIT__');
|
|
$zip->close();
|
|
|
|
file_put_contents(TMP_FILE, json_encode([
|
|
'method' => 'php_zip',
|
|
'files' => $files,
|
|
'index' => 0,
|
|
'zipfile' => $zipPath,
|
|
'zipname' => $zipName
|
|
]));
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'method' => 'php_zip'
|
|
]);
|
|
exit;
|
|
}
|
|
|
|
if ($action === 'step') {
|
|
if (!file_exists(TMP_FILE)) {
|
|
echo json_encode(['success' => false, 'message' => 'Brak danych tymczasowych']);
|
|
exit;
|
|
}
|
|
|
|
$data = json_decode(file_get_contents(TMP_FILE), true);
|
|
$files = $data['files'];
|
|
$index = $data['index'];
|
|
$zipfile = $data['zipfile'];
|
|
$zipname = $data['zipname'];
|
|
|
|
$zip = new ZipArchive();
|
|
if ($zip->open($zipfile) !== true) {
|
|
echo json_encode(['success' => false, 'message' => 'Nie można otworzyć ZIP']);
|
|
exit;
|
|
}
|
|
|
|
$end = min($index + FILES_PER_STEP, count($files));
|
|
for ($i = $index; $i < $end; $i++) {
|
|
$filePath = $files[$i];
|
|
if (is_file($filePath)) {
|
|
$localname = substr($filePath, strlen(__DIR__) + 1);
|
|
$zip->addFile($filePath, $localname);
|
|
}
|
|
}
|
|
|
|
$zip->close();
|
|
|
|
$data['index'] = $end;
|
|
file_put_contents(TMP_FILE, json_encode($data));
|
|
|
|
$progress = $end / count($files);
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'method' => 'php_zip',
|
|
'progress' => round($progress * 100, 2),
|
|
'done' => $end >= count($files),
|
|
'zipfile' => $zipname
|
|
]);
|
|
exit;
|
|
}
|
|
}
|
|
?>
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="pl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Backup dynamiczny</title>
|
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
<style>
|
|
#progress-bar {
|
|
width: 100%;
|
|
background-color: #eee;
|
|
border: 1px solid #ccc;
|
|
margin-top: 10px;
|
|
}
|
|
#progress-bar-inner {
|
|
height: 20px;
|
|
width: 0;
|
|
background-color: #4caf50;
|
|
text-align: center;
|
|
color: white;
|
|
line-height: 20px;
|
|
transition: width 0.3s ease;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<h2>Automatyczny backup plików</h2>
|
|
<button id="start-backup">Rozpocznij</button>
|
|
|
|
<div id="progress-bar" style="display:none;">
|
|
<div id="progress-bar-inner">0.00%</div>
|
|
</div>
|
|
|
|
<div id="status"></div>
|
|
|
|
<script>
|
|
$(document).ready(function(){
|
|
let method = '';
|
|
let zipFile = '';
|
|
|
|
$("#start-backup").click(function(){
|
|
$("#status").text("Inicjalizowanie...");
|
|
$("#progress-bar").show();
|
|
$("#progress-bar-inner").css("width", "0%").text("0.00%");
|
|
|
|
$.post("", { action: "init" }, function(res){
|
|
if (!res.success) {
|
|
$("#status").text("Błąd: " + res.message);
|
|
return;
|
|
}
|
|
|
|
method = res.method;
|
|
|
|
if (method === 'shell_tar' || method === 'shell_zip') {
|
|
$("#progress-bar-inner").css("width", "100%").text("100%");
|
|
$("#status").html("✅ Gotowe! <a href='" + res.file + "' download>Pobierz</a>");
|
|
} else if (method === 'php_zip') {
|
|
doStep();
|
|
}
|
|
}, "json");
|
|
});
|
|
|
|
function doStep() {
|
|
$.post("", { action: "step" }, function(res){
|
|
if (res.success && res.method === 'php_zip') {
|
|
let percent = parseFloat(res.progress).toFixed(2);
|
|
$("#progress-bar-inner").css("width", percent + "%").text(percent + "%");
|
|
|
|
if (res.done) {
|
|
$("#status").html("✅ Backup gotowy! <a href='" + res.zipfile + "' download>Pobierz ZIP</a>");
|
|
} else {
|
|
setTimeout(doStep, 300);
|
|
}
|
|
} else {
|
|
$("#status").text("Błąd: " + res.message);
|
|
}
|
|
}, "json");
|
|
}
|
|
});
|
|
</script>
|
|
|
|
</body>
|
|
</html>
|