LAN_Portal/files/download.php
2026-10-16 16:22:59 -04:00

35 lines
1.7 KiB
PHP
Executable file

<?php
// The only independently executable feature endpoint. No portal session needed.
require_once __DIR__ . '/common.php';
if (!in_array($_SERVER['REQUEST_METHOD'] ?? '', ['GET', 'HEAD'], true)) {
header('Allow: GET, HEAD'); http_response_code(405); exit;
}
$filesKey = files_string($_GET['files_id'] ?? null);
if (!preg_match('/^[a-f0-9]{32}$/D', $filesKey)) { http_response_code(404); exit('File not found.'); }
$filesStream = null;
try {
$filesLock = files_lock(LOCK_SH);
try {
$filesStore = files_read();
if (!isset($filesStore['items'][$filesKey])) { http_response_code(404); exit('File not found.'); }
$filesItem = $filesStore['items'][$filesKey];
$filesStream = @fopen(__DIR__ . '/data/uploads/' . $filesKey . '.bin', 'rb');
if (!$filesStream) { http_response_code(404); exit('Stored file is missing.'); }
$filesStat = fstat($filesStream);
if (!$filesStat || $filesStat['size'] !== $filesItem['size']) throw new RuntimeException('Stored file size mismatch.');
} finally { flock($filesLock, LOCK_UN); fclose($filesLock); }
} catch (Throwable $filesException) {
if (is_resource($filesStream)) fclose($filesStream);
http_response_code(503); header('Content-Type: text/plain; charset=UTF-8');
exit('File storage is unavailable. Check the portal file-sharing section.');
}
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $filesItem['name'] . '"');
header('Content-Length: ' . $filesItem['size']);
header('X-Content-Type-Options: nosniff');
header('Cache-Control: no-store');
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'GET') {
@set_time_limit(0);
fpassthru($filesStream);
}
fclose($filesStream);