Refactor Restore ITFlow Backup code in setup to utilize Sys Temp Directory

This commit is contained in:
johnnyq
2025-06-19 00:26:23 -04:00
parent 79d0fd28b0
commit 498e86aa7a

View File

@@ -125,8 +125,11 @@ if (isset($_POST['add_database'])) {
} }
<?php
if (isset($_POST['restore'])) { if (isset($_POST['restore'])) {
// === 1. Validate uploaded file ===
if (!isset($_FILES['backup_zip']) || $_FILES['backup_zip']['error'] !== UPLOAD_ERR_OK) { if (!isset($_FILES['backup_zip']) || $_FILES['backup_zip']['error'] !== UPLOAD_ERR_OK) {
die("No backup file uploaded or upload failed."); die("No backup file uploaded or upload failed.");
} }
@@ -137,31 +140,41 @@ if (isset($_POST['restore'])) {
die("Only .zip files are allowed."); die("Only .zip files are allowed.");
} }
// Save uploaded file temporarily // === 2. Move to secure temp location ===
$backupZip = "restore_" . time() . ".zip"; $tempZip = tempnam(sys_get_temp_dir(), "restore_");
if (!move_uploaded_file($file["tmp_name"], $backupZip)) { if (!move_uploaded_file($file["tmp_name"], $tempZip)) {
die("Failed to save uploaded backup file."); die("Failed to save uploaded backup file.");
} }
$zip = new ZipArchive; $zip = new ZipArchive;
if ($zip->open($backupZip) !== TRUE) { if ($zip->open($tempZip) !== TRUE) {
unlink($backupZip); unlink($tempZip);
die("Failed to open backup zip file."); die("Failed to open backup zip file.");
} }
// Extract to a temp directory // === 3. Zip-slip protection and extract to unique dir ===
$tempDir = "restore_temp_" . time(); $tempDir = sys_get_temp_dir() . "/restore_temp_" . uniqid();
mkdir($tempDir); mkdir($tempDir, 0700, true);
for ($i = 0; $i < $zip->numFiles; $i++) {
$stat = $zip->statIndex($i);
if (strpos($stat['name'], '..') !== false) {
$zip->close();
unlink($tempZip);
die("Invalid file path in ZIP.");
}
}
if (!$zip->extractTo($tempDir)) { if (!$zip->extractTo($tempDir)) {
$zip->close(); $zip->close();
unlink($backupZip); unlink($tempZip);
die("Failed to extract backup contents."); die("Failed to extract backup contents.");
} }
$zip->close();
unlink($backupZip);
// === 1. Restore SQL Dump === $zip->close();
unlink($tempZip);
// === 4. Restore SQL ===
$sqlPath = "$tempDir/db.sql"; $sqlPath = "$tempDir/db.sql";
if (file_exists($sqlPath)) { if (file_exists($sqlPath)) {
mysqli_query($mysqli, "SET foreign_key_checks = 0"); mysqli_query($mysqli, "SET foreign_key_checks = 0");
@@ -171,24 +184,27 @@ if (isset($_POST['restore'])) {
} }
mysqli_query($mysqli, "SET foreign_key_checks = 1"); mysqli_query($mysqli, "SET foreign_key_checks = 1");
// Use env var to avoid exposing password
putenv("MYSQL_PWD=$dbpassword");
$command = sprintf( $command = sprintf(
'mysql -h%s -u%s -p%s %s < %s', 'mysql -h%s -u%s %s < %s',
escapeshellarg($dbhost), escapeshellarg($dbhost),
escapeshellarg($dbusername), escapeshellarg($dbusername),
escapeshellarg($dbpassword),
escapeshellarg($database), escapeshellarg($database),
escapeshellarg($sqlPath) escapeshellarg($sqlPath)
); );
exec($command, $output, $returnCode); exec($command, $output, $returnCode);
if ($returnCode !== 0) { if ($returnCode !== 0) {
deleteDir($tempDir);
die("SQL import failed. Error code: $returnCode"); die("SQL import failed. Error code: $returnCode");
} }
} else { } else {
deleteDir($tempDir);
die("Missing db.sql in the backup archive."); die("Missing db.sql in the backup archive.");
} }
// === 2. Restore Upload Folder === // === 5. Restore uploads directory ===
$uploadDir = __DIR__ . "/uploads/"; $uploadDir = __DIR__ . "/uploads/";
$uploadsZip = "$tempDir/uploads.zip"; $uploadsZip = "$tempDir/uploads.zip";
@@ -196,42 +212,51 @@ if (isset($_POST['restore'])) {
$uploads = new ZipArchive; $uploads = new ZipArchive;
if ($uploads->open($uploadsZip) === TRUE) { if ($uploads->open($uploadsZip) === TRUE) {
// Clean existing uploads // Clean existing uploads
foreach (glob($uploadDir . '*') as $item) { foreach (new RecursiveIteratorIterator(
if (is_dir($item)) { new RecursiveDirectoryIterator($uploadDir, FilesystemIterator::SKIP_DOTS),
array_map('unlink', glob("$item/*")); RecursiveIteratorIterator::CHILD_FIRST
rmdir($item); ) as $item) {
} else { $item->isDir() ? rmdir($item) : unlink($item);
unlink($item);
}
} }
$uploads->extractTo($uploadDir); $uploads->extractTo($uploadDir);
$uploads->close(); $uploads->close();
} else { } else {
deleteDir($tempDir);
die("Failed to open uploads.zip in backup."); die("Failed to open uploads.zip in backup.");
} }
} else { } else {
deleteDir($tempDir);
die("Missing uploads.zip in the backup archive."); die("Missing uploads.zip in the backup archive.");
} }
// === 3. Read version.txt (optional log/display) // === 6. Read version.txt (optional display/logging) ===
$versionTxt = "$tempDir/version.txt"; $versionTxt = "$tempDir/version.txt";
if (file_exists($versionTxt)) { if (file_exists($versionTxt)) {
$versionInfo = file_get_contents($versionTxt); $versionInfo = file_get_contents($versionTxt);
// You could log it, show it, or ignore it logAction("Backup Restore", "Version Info", $versionInfo);
// e.g. logAction("Backup Restore", "Version Info", $versionInfo);
} }
// Cleanup temp restore directory // === 7. Clean up temp dir ===
array_map('unlink', glob("$tempDir/*")); function deleteDir($dir) {
rmdir($tempDir); if (!is_dir($dir)) return;
$items = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($items as $item) {
$item->isDir() ? rmdir($item) : unlink($item);
}
rmdir($dir);
}
deleteDir($tempDir);
// === 4. Final Setup Stages === // === 8. Optional: finalize setup flag ===
$myfile = fopen("config.php", "a"); $myfile = fopen("config.php", "a");
$txt = "\$config_enable_setup = 0;\n\n"; fwrite($myfile, "\$config_enable_setup = 0;\n\n");
fwrite($myfile, $txt);
fclose($myfile); fclose($myfile);
// === 9. Done ===
$_SESSION['alert_message'] = "Full backup restored successfully."; $_SESSION['alert_message'] = "Full backup restored successfully.";
header("Location: login.php"); header("Location: login.php");
exit; exit;