| 1 |
<?php |
| 2 |
require_once __DIR__ . '/../includes/auth.php'; |
| 3 |
require_once __DIR__ . '/../includes/db.php'; |
| 4 |
require_once __DIR__ . '/../includes/helpers.php'; |
| 5 |
|
| 6 |
require_login(); |
| 7 |
|
| 8 |
// POST-only. |
| 9 |
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { |
| 10 |
http_response_code(405); |
| 11 |
exit('Method not allowed.'); |
| 12 |
} |
| 13 |
csrf_verify(); |
| 14 |
|
| 15 |
/** Recursively remove a directory identified by a path relative to UPLOAD_DIR. */ |
| 16 |
function remove_upload_dir(string $relPath): void |
| 17 |
{ |
| 18 |
$base = realpath(UPLOAD_DIR); |
| 19 |
$dir = realpath(UPLOAD_DIR . '/' . $relPath); |
| 20 |
if ($base === false || $dir === false) { |
| 21 |
return; |
| 22 |
} |
| 23 |
// Safety: never touch anything at or above the uploads root. |
| 24 |
if ($dir === $base || strpos($dir, $base . DIRECTORY_SEPARATOR) !== 0) { |
| 25 |
return; |
| 26 |
} |
| 27 |
$items = new RecursiveIteratorIterator( |
| 28 |
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS), |
| 29 |
RecursiveIteratorIterator::CHILD_FIRST |
| 30 |
); |
| 31 |
foreach ($items as $item) { |
| 32 |
$item->isDir() ? @rmdir($item->getPathname()) : @unlink($item->getPathname()); |
| 33 |
} |
| 34 |
@rmdir($dir); |
| 35 |
} |
| 36 |
|
| 37 |
$type = $_POST['type'] ?? ''; |
| 38 |
|
| 39 |
if ($type === 'repo') { |
| 40 |
$id = (int) ($_POST['id'] ?? 0); |
| 41 |
$repo = get_repository($id); |
| 42 |
if ($repo) { |
| 43 |
remove_upload_dir($repo['slug']); |
| 44 |
delete_repository($id); // cascades file + folder rows |
| 45 |
} |
| 46 |
header('Location: ' . url('/admin/dashboard.php?deleted=1')); |
| 47 |
exit; |
| 48 |
} |
| 49 |
|
| 50 |
if ($type === 'folder') { |
| 51 |
$id = (int) ($_POST['id'] ?? 0); |
| 52 |
$folder = get_folder($id); |
| 53 |
if ($folder) { |
| 54 |
$repo = get_repository((int) $folder['repo_id']); |
| 55 |
$path = delete_folder($id); // removes descendant file + folder rows |
| 56 |
if ($repo && $path !== null) { |
| 57 |
remove_upload_dir($repo['slug'] . '/' . $path); |
| 58 |
} |
| 59 |
if ($repo) { |
| 60 |
header('Location: ' . url('/admin/upload.php?repo=' . urlencode($repo['slug']) . '&deleted=1')); |
| 61 |
exit; |
| 62 |
} |
| 63 |
} |
| 64 |
header('Location: ' . url('/admin/dashboard.php?deleted=1')); |
| 65 |
exit; |
| 66 |
} |
| 67 |
|
| 68 |
if ($type === 'file') { |
| 69 |
$id = (int) ($_POST['id'] ?? 0); |
| 70 |
$file = get_file($id); |
| 71 |
if ($file) { |
| 72 |
$repo = get_repository((int) $file['repo_id']); |
| 73 |
// Delete the file on disk, guarding against traversal. |
| 74 |
$base = realpath(UPLOAD_DIR); |
| 75 |
$full = realpath(UPLOAD_DIR . '/' . $file['filepath']); |
| 76 |
if ($base !== false && $full !== false && strpos($full, $base . DIRECTORY_SEPARATOR) === 0) { |
| 77 |
@unlink($full); |
| 78 |
} |
| 79 |
delete_file($id); |
| 80 |
if ($repo) { |
| 81 |
header('Location: ' . url('/admin/upload.php?repo=' . urlencode($repo['slug']) . '&deleted=1')); |
| 82 |
exit; |
| 83 |
} |
| 84 |
} |
| 85 |
header('Location: ' . url('/admin/dashboard.php?deleted=1')); |
| 86 |
exit; |
| 87 |
} |
| 88 |
|
| 89 |
http_response_code(400); |
| 90 |
exit('Unknown delete type.'); |
| 91 |
|