Generate real resized thumbnails for image attachments (#98)
Lint / PHP (phpcs PSR-12) (push) Successful in 17s
Lint / JS (eslint) (push) Successful in 7s
Lint / PHP requirements (version + extensions) (push) Successful in 20s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Successful in 1m8s
Lint / Deploy (push) Successful in 2s
Lint / PHP (phpcs PSR-12) (push) Successful in 17s
Lint / JS (eslint) (push) Successful in 7s
Lint / PHP requirements (version + extensions) (push) Successful in 20s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Successful in 1m8s
Lint / Deploy (push) Successful in 2s
The attachment grid's <img> thumbnail pointed at the same download_attachment.php URL as the full-size original, so previewing a multi-MB photo attachment cost a full multi-MB download just to render a small grid preview. loading="lazy" only deferred off-screen images; it never reduced per-image transfer size. Generate a resized JPEG thumbnail (longest side capped at 300px) via GD at upload time, from the same metadata-stripped image stripImageMetadata() already produces, reusing its decompression-bomb guard (~40MP decode cap). Store the thumbnail's filename in a new nullable ticket_attachments. thumbnail_filename column (migration 005); NULL means no thumbnail exists (non-image, GD unavailable, or an attachment predating this change) and callers fall back to the full-size original. download_attachment.php serves the thumbnail when requested via ?thumb=1 and one exists, falling back to the original otherwise. The attachments grid now requests thumb=1 for its <img> preview; the lightbox link is unchanged and still opens the full-size original. delete_attachment.php removes the thumbnail file alongside the original, and cleanup_orphan_uploads.php's orphan lookup now also matches thumbnail_filename so generated thumbnails aren't swept up as orphans. Verified against real MariaDB + GD: a 1600x1200 test JPEG produced a 300x225 thumbnail at ~1.8KB vs. the 52KB original (~29x smaller); confirmed the serving logic picks the thumbnail for image attachments with one, falls back to the original for a non-image attachment even when thumb=1 is requested, and that the updated orphan-cleanup lookup matches both the original and thumbnail filename (and correctly finds neither for an unrelated filename). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0117oBw2jN4kALYeS8HPq4zV
This commit is contained in:
+7
-2
@@ -1238,10 +1238,15 @@ function renderAttachments(attachments, append, hasMore) {
|
||||
const uploadDate = `<span class="ts-cell" data-ts="${lt.escHtml(att.uploaded_at)}" title="${lt.escHtml(uploadDateFormatted)}">${lt.time.ago(att.uploaded_at)}</span>`;
|
||||
|
||||
const isImage = /^image\//i.test(att.mime_type || '');
|
||||
const imgUrl = `/api/download_attachment.php?id=${att.attachment_id}&inline=1`;
|
||||
const imgUrl = `/api/download_attachment.php?id=${att.attachment_id}&inline=1`;
|
||||
// Grid preview requests the resized thumbnail (server falls back to the
|
||||
// full-size original for attachments with none, e.g. uploaded before
|
||||
// thumbnail generation existed); the lightbox link stays on the
|
||||
// full-size original since that's what it displays when opened.
|
||||
const thumbUrl = `${imgUrl}&thumb=1`;
|
||||
const iconHtml = isImage
|
||||
? `<a href="${imgUrl}" class="lt-lightbox-trigger" data-lightbox="ticket-attachments" title="${lt.escHtml(att.original_filename)}">
|
||||
<img src="${imgUrl}" alt="${lt.escHtml(att.original_filename)}" class="attachment-thumb" loading="lazy">
|
||||
<img src="${thumbUrl}" alt="${lt.escHtml(att.original_filename)}" class="attachment-thumb" loading="lazy">
|
||||
</a>`
|
||||
: `<div class="attachment-icon">${lt.escHtml(att.icon || '[ f ]')}</div>`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user