JustSuperHuman/CleanPHPGallery

★ 0Forks 0TypeScriptGitHub ↗Compare

README

PHP Astro Gallery

Static Astro shell with PHP endpoints for directory scanning and zip upload. The build output can live in a PHP-served folder such as J:\ads, which maps to https://static.justgains.com/ads.

Commands

bun install
bun run check
bun run build
bun run build:single
bun run deploy

Customization

Edit the variables at the top of src/pages/index.astro to rename the gallery or swap branding defaults:

  • appName: browser title, header name, and default gallery heading.
  • appKicker: small header label above the gallery name.
  • galleryRootLabel: label for the top-level media folder in the browser UI.
  • appDescription: meta description for the generated page.
  • faviconHref: favicon URL or data URI.
  • themeColor: browser theme color.

bun run deploy builds the app, packages dist, and deploys it over SSH using the TekPrepper config at F:\tekprepper.com\.env. The default remote target is:

/home/tekprepp/static.justgains.com/ads

The deploy script replaces generated files (index.html, _astro, api), moves the previous Files Gallery PHP app out of the way, and preserves/creates gallery/ for separately uploaded creative assets.

Override paths when needed:

$env:TEKPREPPER_ENV_FILE="F:\tekprepper.com\.env"
$env:GALLERY_REMOTE_WEBROOT="/home/tekprepp/static.justgains.com/ads"
bun run deploy

Single-file build

bun run build:single

Compiles the entire app into dist-single/index.php — drop that one file into any PHP-served folder next to your creative asset directories and it just works. Details:

  • CSS and JS are inlined into the HTML, so the page loads with zero extra asset requests.
  • Branding values from src/pages/index.astro, including the favicon, are compiled into the single PHP file.
  • The HTML is gzipped at build time and stored as raw bytes after __halt_compiler(), so PHP never parses or compresses it at runtime; clients that accept gzip get the precompressed bytes with an exact Content-Length.
  • A build-hash ETag gives repeat visitors 304 Not Modified responses.
  • The API files are merged into the same file (one opcache entry, no require stat calls) and routed via ?api=gallery.php, ?api=upload.php, etc. The page injects window.GALLERY_API_BASE so the frontend targets that scheme automatically; the regular multi-file build keeps using api/*.php.

dist/ and dist-single/ are generated outputs and are intentionally ignored by Git.

The gallery root resolution is the same as below, except the site root is the folder containing index.php itself.

Verified against the live TekPrepper server (LiteSpeed, PHP 8.1, behind Cloudflare); requires PHP 7.4+. One hosting caveat: if a parent .htaccess sets DirectoryIndex without index.php (the deployed ads app does), the bare folder URL will 403 — either request index.php directly or add DirectoryIndex index.php in the folder. Cloudflare strips the ETag at the edge, which only disables the 304 shortcut; the shell is ~11 KB gzipped either way.

Gallery root

By default the PHP API scans:

  1. gallery-root.txt if present, containing a relative media directory.
  2. gallery/ when it exists, even if it is still empty.
  3. The deployed site root, excluding app directories such as _astro and api.

That fallback keeps existing folders like competitors/ and programs/ visible on J:\ads.

Uploads

The upload form posts a zip to api/upload.php, extracts supported creative files into the requested folder, and deletes the temporary zip. Uploads require the admin token when one is configured.

The gallery previews browser-native images and videos directly, opens PDFs in the full-screen viewer, reads markdown and text files in the document reader (see Documents), and renders format-aware download cards for non-previewable files. The supported library includes common Adobe/Affinity source files, AI, PSD/PSB, EPS/PostScript, InDesign, TIFF and camera-raw formats, CAD/3D files, office documents, fonts, audio, archives, and other production formats. Every listed file has a forced attachment download route, so uncommon extensions do not depend on the web host's MIME configuration.

Large zip uploads show browser transfer progress. After the progress reaches 100%, the dialog switches to a server-side processing state while PHP extracts the archive.

Documents

Markdown and plain-text files open in a built-in reader instead of the media lightbox. Click any .md, .txt, .csv, .json, .yml, .log (and similar) card, or use the Read README.md button that appears when a folder contains a README, index, or about markdown file.

The reader has:

  • A Documents sidebar listing every readable file in the current folder or search result, with a filter box. / focuses it.
  • A Contents outline built from the document's headings, with scroll tracking. Click a heading to jump; heading anchors are linkable.
  • Reading and Source modes, a Wrap toggle for monospace views, A-/A+ text sizing, and per-code-block copy buttons. All three preferences persist.
  • Keyboard control: ←/→ (or j/k) move between documents, +/- resize text, Escape closes.
  • A ?doc=<path> URL parameter, so an open document is linkable and survives back/forward navigation.

Rendering is format-aware:

Format Rendered as
md, markdown, mdx, mkd Full markdown document
csv, tsv Table with quoted fields honoured and numeric columns aligned right
json, yaml, yml, toml, ini, cfg, conf, xml, properties Highlighted code
log, diff, patch, srt, vtt, nfo Monospace, highlighted where applicable
txt, text, rst, adoc Reading column that keeps the file's own line breaks, indentation, and column-aligned blocks

Text cards in the grid show a real excerpt of the file, fetched lazily for only the cards on screen.

Markdown support

The renderer is dependency-free and builds DOM nodes directly — no HTML is ever parsed from a document, so untrusted markdown cannot inject markup or scripts. It covers the CommonMark/GFM subset that documentation actually uses: ATX and setext headings, fenced and indented code with syntax highlighting, nested and lazy lists, task lists, tables with alignment, blockquotes, thematic breaks, emphasis/strong/strikethrough, code spans, images, reference links and definitions, autolinks, entities, hard breaks, and escapes.

Links and images are resolved against the document's own folder:

  • A relative link to another readable document opens it in the reader, including other.md#section anchors.
  • A relative link to any other gallery file opens that file.
  • Relative image paths resolve to the gallery URL for that image.
  • Links to files that are not in the gallery render as plain text, and only http, https, mailto, tel, ftp, and sms URLs are allowed — javascript: and data: links are dropped.

API

api/text.php?path=<relative path> returns the file as JSON:

{ "ok": true, "name": "README.md", "type": "markdown", "size": 1715,
  "bytesRead": 1715, "truncated": false, "content": "# ..." }

Files are read up to 3 MB (GALLERY_TEXT_MAX_BYTES); anything larger comes back with truncated: true and the reader shows a notice pointing at the download. Content is normalized to UTF-8 with LF line endings — BOMs are stripped, UTF-16 and Windows-1252 files are converted, and a multi-byte character cut off by the read limit is trimmed rather than mangled. Add &preview=<bytes> for the short excerpt used by grid cards.

Admin Mode

Click Manage and enter the admin token to enable multi-select, moving, and deleting files. The token is checked by PHP on every write request; the browser only stores it in sessionStorage for the current tab session.

On the deployed server the token is stored outside the web root at:

/home/tekprepp/.ads-gallery-admin-token

bun run deploy creates that file if it is missing and preserves it on later deploys.

Contributors

JustSuperHuman

Issues