Try to fix uploads
This commit is contained in:
114
setup/index.php
114
setup/index.php
@@ -310,7 +310,7 @@ if (isset($_POST['restore'])) {
|
|||||||
|
|
||||||
$uploadDir = $appRoot . "/uploads";
|
$uploadDir = $appRoot . "/uploads";
|
||||||
|
|
||||||
// Extract inner uploads.zip to staging (with validation & scan report)
|
// 6.a Extract inner uploads.zip to staging (with validation & scan report)
|
||||||
$staging = $appRoot . "/uploads_restoring_" . bin2hex(random_bytes(4));
|
$staging = $appRoot . "/uploads_restoring_" . bin2hex(random_bytes(4));
|
||||||
if (!mkdir($staging, 0700, true)) {
|
if (!mkdir($staging, 0700, true)) {
|
||||||
deleteDir($tempDir);
|
deleteDir($tempDir);
|
||||||
@@ -348,90 +348,65 @@ if (isset($_POST['restore'])) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If inner zip has a single "uploads/" folder, promote its contents
|
// 6.b Determine the actual content root inside staging
|
||||||
$roots = [];
|
// If the inner archive’s top-level is exactly "uploads/", use that; otherwise use staging itself.
|
||||||
|
$contentRoot = $staging;
|
||||||
|
$topEntries = [];
|
||||||
if ($dh = opendir($staging)) {
|
if ($dh = opendir($staging)) {
|
||||||
while (($e = readdir($dh)) !== false) {
|
while (($e = readdir($dh)) !== false) {
|
||||||
if ($e === '.' || $e === '..') continue;
|
if ($e === '.' || $e === '..') continue;
|
||||||
$roots[] = $e;
|
$topEntries[] = $e;
|
||||||
}
|
}
|
||||||
closedir($dh);
|
closedir($dh);
|
||||||
}
|
}
|
||||||
sort($roots);
|
sort($topEntries);
|
||||||
if (count($roots) === 1) {
|
|
||||||
$candidate = $staging . DIRECTORY_SEPARATOR . $roots[0];
|
if (count($topEntries) === 1) {
|
||||||
if (is_dir($candidate)) {
|
$candidate = $staging . DIRECTORY_SEPARATOR . $topEntries[0];
|
||||||
$promoted = $staging . "_promoted";
|
if (is_dir($candidate) && strtolower($topEntries[0]) === 'uploads') {
|
||||||
if (!@rename($candidate, $promoted)) {
|
// Use the "uploads" directory directly without moving/deleting staging yet
|
||||||
// fallback to copy
|
$contentRoot = $candidate;
|
||||||
$rit = new RecursiveIteratorIterator(
|
|
||||||
new RecursiveDirectoryIterator($candidate, FilesystemIterator::SKIP_DOTS),
|
|
||||||
RecursiveIteratorIterator::SELF_FIRST
|
|
||||||
);
|
|
||||||
if (!mkdir($promoted, 0700, true)) {
|
|
||||||
deleteDir($staging);
|
|
||||||
deleteDir($tempDir);
|
|
||||||
die("Failed to create promoted staging directory.");
|
|
||||||
}
|
|
||||||
foreach ($rit as $it) {
|
|
||||||
$rel = substr($it->getPathname(), strlen($candidate) + 1);
|
|
||||||
$dst = $promoted . DIRECTORY_SEPARATOR . $rel;
|
|
||||||
if ($it->isDir()) {
|
|
||||||
if (!is_dir($dst) && !mkdir($dst, 0700, true)) {
|
|
||||||
deleteDir($staging);
|
|
||||||
deleteDir($tempDir);
|
|
||||||
die("Failed to create $dst");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$pdir = dirname($dst);
|
|
||||||
if (!is_dir($pdir) && !mkdir($pdir, 0700, true)) {
|
|
||||||
deleteDir($staging);
|
|
||||||
deleteDir($tempDir);
|
|
||||||
die("Failed to create $pdir");
|
|
||||||
}
|
|
||||||
if (!copy($it->getPathname(), $dst)) {
|
|
||||||
deleteDir($staging);
|
|
||||||
deleteDir($tempDir);
|
|
||||||
die("Failed to copy $rel into promoted staging");
|
|
||||||
}
|
|
||||||
@chmod($dst, 0640);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deleteDir($staging);
|
|
||||||
$staging = isset($promoted) ? $promoted : $staging;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity: staging must contain files
|
// 6.c Sanity check: content root must have files
|
||||||
$hasFiles = false;
|
$hasFiles = false;
|
||||||
$it = new RecursiveIteratorIterator(
|
$ritCheck = new RecursiveIteratorIterator(
|
||||||
new RecursiveDirectoryIterator($staging, FilesystemIterator::SKIP_DOTS)
|
new RecursiveDirectoryIterator($contentRoot, FilesystemIterator::SKIP_DOTS)
|
||||||
);
|
);
|
||||||
foreach ($it as $f) { if ($f->isFile()) { $hasFiles = true; break; } }
|
foreach ($ritCheck as $f) {
|
||||||
|
if ($f->isFile()) { $hasFiles = true; break; }
|
||||||
|
}
|
||||||
if (!$hasFiles) {
|
if (!$hasFiles) {
|
||||||
deleteDir($staging);
|
deleteDir($staging);
|
||||||
deleteDir($tempDir);
|
deleteDir($tempDir);
|
||||||
die("Uploads restore failed: staging is empty (inner uploads.zip may be malformed or fully blocked).");
|
die("Uploads restore failed: extracted content is empty (inner uploads.zip may be malformed or fully blocked).");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- DELETE existing /uploads first, then REPLACE with staging ---
|
// 6.d Remove current /uploads and replace with restored content
|
||||||
if (is_dir($uploadDir)) {
|
if (is_dir($uploadDir)) {
|
||||||
deleteDir($uploadDir, $appRoot); // guarded delete (under app root)
|
deleteDir($uploadDir, $appRoot); // guarded delete under app root
|
||||||
}
|
}
|
||||||
if (!@rename($staging, $uploadDir)) {
|
|
||||||
// fallback: copy
|
// If contentRoot IS the staging root, try a simple rename
|
||||||
|
$renameSource = ($contentRoot === $staging) ? $staging : $contentRoot;
|
||||||
|
$renameOk = @rename($renameSource, $uploadDir);
|
||||||
|
|
||||||
|
// If we used the child "uploads" dir as contentRoot, staging still exists with an empty top; clean it later
|
||||||
|
if (!$renameOk) {
|
||||||
|
// Fallback: copy tree
|
||||||
if (!mkdir($uploadDir, 0750, true)) {
|
if (!mkdir($uploadDir, 0750, true)) {
|
||||||
deleteDir($staging);
|
deleteDir($staging);
|
||||||
deleteDir($tempDir);
|
deleteDir($tempDir);
|
||||||
die("Failed to create uploads directory for placement.");
|
die("Failed to create uploads directory for placement.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$rit = new RecursiveIteratorIterator(
|
$rit = new RecursiveIteratorIterator(
|
||||||
new RecursiveDirectoryIterator($staging, FilesystemIterator::SKIP_DOTS),
|
new RecursiveDirectoryIterator($contentRoot, FilesystemIterator::SKIP_DOTS),
|
||||||
RecursiveIteratorIterator::SELF_FIRST
|
RecursiveIteratorIterator::SELF_FIRST
|
||||||
);
|
);
|
||||||
foreach ($rit as $it) {
|
foreach ($rit as $it) {
|
||||||
$rel = substr($it->getPathname(), strlen($staging) + 1);
|
$rel = substr($it->getPathname(), strlen($contentRoot) + 1);
|
||||||
$dst = $uploadDir . DIRECTORY_SEPARATOR . $rel;
|
$dst = $uploadDir . DIRECTORY_SEPARATOR . $rel;
|
||||||
if ($it->isDir()) {
|
if ($it->isDir()) {
|
||||||
if (!is_dir($dst) && !mkdir($dst, 0750, true)) {
|
if (!is_dir($dst) && !mkdir($dst, 0750, true)) {
|
||||||
@@ -457,17 +432,26 @@ if (isset($_POST['restore'])) {
|
|||||||
@chmod($dst, 0640);
|
@chmod($dst, 0640);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If we copied only the inner "uploads" folder, we still need to clean the top-level staging
|
||||||
|
deleteDir($staging);
|
||||||
|
} else {
|
||||||
|
// rename succeeded; if we renamed the child "uploads", the original staging still exists – clean it
|
||||||
|
if ($contentRoot !== $staging) {
|
||||||
deleteDir($staging);
|
deleteDir($staging);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify uploads has files
|
// 6.e Verify uploads now has files and report counts
|
||||||
$okFiles = false;
|
$fileCount = 0; $dirCount = 0;
|
||||||
$it2 = new RecursiveIteratorIterator(
|
$ritVerify = new RecursiveIteratorIterator(
|
||||||
new RecursiveDirectoryIterator($uploadDir, FilesystemIterator::SKIP_DOTS)
|
new RecursiveDirectoryIterator($uploadDir, FilesystemIterator::SKIP_DOTS),
|
||||||
|
RecursiveIteratorIterator::SELF_FIRST
|
||||||
);
|
);
|
||||||
foreach ($it2 as $f) { if ($f->isFile()) { $okFiles = true; break; } }
|
foreach ($ritVerify as $it) {
|
||||||
if (!$okFiles) {
|
if ($it->isDir()) $dirCount++;
|
||||||
deleteDir($uploadDir);
|
else $fileCount++;
|
||||||
|
}
|
||||||
|
if ($fileCount === 0) {
|
||||||
deleteDir($tempDir);
|
deleteDir($tempDir);
|
||||||
die("Uploads replace failed: resulting directory is empty.");
|
die("Uploads replace failed: resulting directory is empty.");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user