| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 |
- <?php
- /**
- * Client gallery viewer: /gallery/?g=<slug>
- *
- * - Unknown or expired galleries show the same neutral "not available" page.
- * - Password-protected galleries show a password form; a successful unlock
- * is remembered in the session for that gallery only.
- * - Thumbnails and full-res originals are loaded by the browser directly
- * from S3 via short-lived presigned URLs.
- *
- * This is the only public page outside the document root, hence SITE_BASE:
- * the shared partials prefix their asset and nav links with it.
- */
- define('SITE_BASE', '../');
- require dirname(__DIR__) . '/app/bootstrap.php';
- session_boot();
- $slug = (string)($_GET['g'] ?? '');
- $gallery = $slug !== '' ? gallery_load($slug) : null;
- if ($gallery === null || gallery_is_expired($gallery)) {
- http_response_code(404);
- public_header('Gallery not available');
- echo '<div class="gate"><div class="gate-card"><h1>Gallery not available</h1>'
- . '<p class="page-sub">This gallery does not exist or is no longer online.</p></div></div>';
- public_footer();
- exit;
- }
- $needsPassword = !empty($gallery['password_hash']);
- $unlocked = !$needsPassword || !empty($_SESSION['gallery_unlocked'][$slug]);
- if ($needsPassword && !$unlocked && $_SERVER['REQUEST_METHOD'] === 'POST') {
- csrf_verify();
- if (password_verify((string)($_POST['password'] ?? ''), $gallery['password_hash'])) {
- $_SESSION['gallery_unlocked'][$slug] = true;
- redirect('./?g=' . rawurlencode($slug));
- }
- $error = 'Wrong password.';
- }
- if ($needsPassword && !$unlocked) {
- public_header(e($gallery['title']));
- ?>
- <div class="gate"><div class="gate-card">
- <h1><?= e($gallery['title']) ?></h1>
- <?php if (!empty($error)): ?><div class="flash flash-error"><?= e($error) ?></div><?php endif; ?>
- <form method="post">
- <?= csrf_field() ?>
- <label for="pw">Password</label>
- <input type="password" id="pw" name="password" autofocus autocomplete="off">
- <button type="submit">Open gallery</button>
- </form>
- </div></div>
- <?php
- public_footer();
- exit;
- }
- public_header(e($gallery['title']));
- ?>
- <main class="page">
- <div class="page-head">
- <div>
- <h1 class="page-title"><?= e($gallery['title']) ?></h1>
- <p class="page-sub">
- <?= count($gallery['images'] ?? []) ?> photos
- <?php if (!empty($gallery['expires_at'])): ?>
- · available until <?= e($gallery['expires_at']) ?>
- <?php endif; ?>
- </p>
- </div>
- <?php if (!empty($gallery['downloads_enabled'])): ?>
- <?php
- // Outside .grid on purpose: assets/site.js binds the lightbox to
- // every <a> inside the grid and would swallow this link's click.
- $archive = $gallery['archive'] ?? null;
- ?>
- <?php if ($archive !== null && !archive_is_stale($gallery)): ?>
- <a class="btn btn-ghost page-action" href="download.php?g=<?= e(rawurlencode($slug)) ?>">
- Download all · <?= e(human_bytes((int)$archive['size'])) ?>
- </a>
- <?php else: ?>
- <span class="btn btn-ghost btn-disabled page-action"
- title="The zip archive is outdated and is being recreated. This can take up to an hour — please check back later.">
- Download all
- </span>
- <?php endif; ?>
- <?php endif; ?>
- </div>
- <div class="grid">
- <?php foreach ($gallery['images'] ?? [] as $img): ?>
- <a href="<?= e(s3_presign_get($img['key'])) ?>">
- <img src="<?= e(s3_presign_get($img['thumb'] ?? $img['key'])) ?>"
- alt="<?= e($img['name'] ?? '') ?>" loading="lazy">
- </a>
- <?php endforeach; ?>
- </div>
- </main>
- <?php public_footer(); ?>
|