MAX_FILE_BYTES) { redirectWithStatus('toolarge'); return; } $originalName = (string)($file['name'] ?? 'upload.bin'); $safeOriginal = sanitizeFilename($originalName); try { $hash = bin2hex(random_bytes(16)); } catch (Throwable) { redirectWithStatus('error'); return; } $now = new DateTimeImmutable('now', new DateTimeZone('UTC')); $targetDir = sprintf( '%s/%s/%s/%s/%s', UPLOAD_ROOT, $now->format('Y'), $now->format('m'), $now->format('d'), $hash ); if (!is_dir($targetDir) && !mkdir($targetDir, 0775, true) && !is_dir($targetDir)) { redirectWithStatus('error'); return; } $timestamp = $now->format('U'); $finalName = $timestamp . '-' . $safeOriginal; $targetPath = $targetDir . '/' . $finalName; if (!move_uploaded_file((string)$file['tmp_name'], $targetPath)) { redirectWithStatus('error'); return; } redirectWithStatus('success'); } function handleDelete(): void { $target = $_POST['target'] ?? ''; if (!is_string($target) || $target === '') { redirectWithStatus('delete-invalid'); return; } $relative = sanitizeRelativePath($target); if ($relative === null) { redirectWithStatus('delete-invalid'); return; } $fullPath = UPLOAD_ROOT . '/' . $relative; if (!is_file($fullPath)) { redirectWithStatus('delete-missing'); return; } if (!@unlink($fullPath)) { redirectWithStatus('delete-error'); return; } cleanupEmptyDirectories(dirname($fullPath)); redirectWithStatus('delete-success'); } function sanitizeFilename(string $name): string { $name = trim($name); $name = basename($name); $name = preg_replace('/[\s]+/', '_', $name); $name = preg_replace('/[^A-Za-z0-9._-]/', '', $name) ?? ''; return $name !== '' ? $name : 'file.bin'; } function sanitizeRelativePath(string $path): ?string { $path = trim(str_replace("\0", '', (string)$path)); $path = ltrim($path, '/'); if ($path === '' || str_contains($path, '..')) { return null; } $segments = array_values(array_filter( explode('/', $path), static fn (string $segment): bool => $segment !== '' && $segment !== '.' )); if (count($segments) < 5) { return null; } return implode('/', $segments); } function redirectWithStatus(string $status): void { $redirectTarget = $_POST['redirect_to'] ?? '/admin.php'; $redirectTarget = sanitizeRedirectTarget($redirectTarget); $location = appendStatusParam($redirectTarget, $status); header('Location: ' . $location, true, 302); } function cleanupEmptyDirectories(string $directory): void { $root = realpath(UPLOAD_ROOT); $current = realpath($directory); if ($root === false || $current === false) { return; } while ($current !== $root && $current !== false && str_starts_with($current, $root)) { $items = @scandir($current); if ($items === false || count($items) > 2) { break; } if (!@rmdir($current)) { break; } $current = dirname($current); } } function sanitizeRedirectTarget(string $target): string { $target = trim($target); if ($target === '' || $target[0] !== '/') { return '/admin.php'; } $target = strtok($target, "\r\n"); return $target ?: '/admin.php'; } function appendStatusParam(string $url, string $status): string { $parts = explode('?', $url, 2); $path = $parts[0]; $params = []; if (isset($parts[1])) { parse_str($parts[1], $params); } $params['status'] = $status; $query = http_build_query($params); return $path . ($query !== '' ? '?' . $query : ''); } function gatherUploads(): array { if (!is_dir(UPLOAD_ROOT)) { return []; } $files = []; $flags = FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS; $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(UPLOAD_ROOT, $flags)); $finfo = finfo_open(FILEINFO_MIME_TYPE); foreach ($iterator as $fileInfo) { if (!$fileInfo->isFile()) { continue; } $fullPath = $fileInfo->getPathname(); $relative = ltrim(str_replace('\\', '/', substr($fullPath, strlen(UPLOAD_ROOT))), '/'); $segments = explode('/', $relative); if (count($segments) < 5) { continue; } [$year, $month, $day, $hash] = array_slice($segments, 0, 4); $storedName = end($segments) ?: $fileInfo->getFilename(); $originalName = preg_replace('/^\d{10,}-/', '', $storedName) ?: $storedName; $files[] = [ 'original' => $originalName, 'stored' => $storedName, 'slug' => sprintf('%s/%s/%s/%s', $year, $month, $day, $hash), 'url' => '/files/' . $relative, 'size' => $fileInfo->getSize(), 'mime' => $finfo ? (finfo_file($finfo, $fullPath) ?: 'application/octet-stream') : 'application/octet-stream', 'uploaded_at' => $fileInfo->getMTime(), 'relative' => $relative, ]; } if (is_resource($finfo)) { finfo_close($finfo); } usort( $files, fn (array $a, array $b): int => $b['uploaded_at'] <=> $a['uploaded_at'] ); return $files; } function renderDashboard(array $files, ?string $status): void { $totalSize = array_sum(array_column($files, 'size')); $statusMeta = resolveStatusMessage($status); ?> Send • Admin

Send Admin

Monitor uploads ( files · stored)

No uploads yet.
File Uploaded Size MIME Hash slug Download Delete
Open
['File uploaded successfully.', 'success'], 'missing' => ['No file selected for upload.', 'warning'], 'toolarge' => ['File exceeds the 10 GiB limit.', 'error'], 'error' => ['Unexpected error while handling the upload.', 'error'], 'delete-success' => ['File deleted successfully.', 'success'], 'delete-missing' => ['File was not found or already deleted.', 'warning'], 'delete-error' => ['Unable to delete the requested file.', 'error'], 'delete-invalid' => ['Invalid delete request received.', 'error'], ]; return $map[$status] ?? null; }