* * Hands the visitor a short-lived presigned URL for the gallery's prebuilt ZIP * and gets out of the way. The transfer runs browser ↔ S3, so a 3 GB archive is * unaffected by the host's 60 s execution limit and stays resumable — this * script only ever sends a redirect. * * An out-of-date archive is refused rather than served, mirroring the disabled * button on the gallery page: a client must not be handed a ZIP that silently * omits the photos uploaded since it was built. * * Every failure looks the same as an unknown gallery, so the endpoint reveals * nothing the visitor does not already know from the link. */ define('SITE_BASE', '../'); require dirname(__DIR__) . '/app/bootstrap.php'; session_boot(); $slug = (string)($_GET['g'] ?? ''); $gallery = $slug !== '' ? gallery_load($slug) : null; $allowed = $gallery !== null && !gallery_is_expired($gallery) && !empty($gallery['downloads_enabled']) && !empty($gallery['archive']['key']) && !archive_is_stale($gallery) // The same per-gallery session unlock the viewer sets. && (empty($gallery['password_hash']) || !empty($_SESSION['gallery_unlocked'][$slug])); if (!$allowed) { http_response_code(404); public_header('Download not available'); echo '

Download not available

' . '

This download does not exist or is not ready yet.

'; public_footer(); exit; } // Short TTL on purpose: the browser only needs the URL long enough to start the // transfer. A GET already in flight is not cut off when the signature expires. redirect(s3_presign_get((string)$gallery['archive']['key'], 900));