feat(galerias): upload several images at once, clear errors and JPEG XL placeholders

This commit is contained in:
andre committed 2026-10-26 13:48:02 +00:00
1 parent 6abc486630
commit 6ac5213624
3 files changed
+55 -17

No files matched your search

+38 -11
View File
@@ -25,12 +25,29 @@ if (isset($_POST['rename'])) {
}
}
// Upload image
if (isset($_FILES['image']) && $_FILES['image']['error'] !== UPLOAD_ERR_NO_FILE) {
// Upload images (several at once: images[])
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['upload'])) {
csrf_check();
$result = db_gallery_image_upload($pdo, $id, $_FILES['image']);
if ($result) session()->setFlashdata('success', 'Imagem carregada.');
else session()->setFlashdata('error', 'Falha no upload. Verifique o formato.');
$files = [];
foreach ((array) ($_FILES['images']['name'] ?? []) as $i => $n) {
if ($_FILES['images']['error'][$i] === UPLOAD_ERR_NO_FILE) continue;
$files[] = ['name' => $n, 'type' => $_FILES['images']['type'][$i], 'tmp_name' => $_FILES['images']['tmp_name'][$i],
'error' => $_FILES['images']['error'][$i], 'size' => $_FILES['images']['size'][$i]];
}
$ok = 0; $failed = [];
foreach ($files as $file) {
if (db_gallery_image_upload($pdo, $id, $file, $why)) $ok++;
else $failed[] = $file['name'] . ' (' . $why . ')';
}
if ($ok) session()->setFlashdata('success', $ok === 1 ? 'Imagem carregada.' : "$ok imagens carregadas.");
if ($failed) session()->setFlashdata($ok ? 'warning' : 'error', 'Não carregadas: ' . implode(', ', $failed) . '.');
if (!$files) session()->setFlashdata('error', 'Escolha pelo menos uma imagem.');
header('Location: ' . base_url('views/admin/galerias/edit.php?id=' . $id));
exit;
}
// Over post_max_size PHP drops the whole body ($_POST and $_FILES empty), so say so instead of doing nothing.
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !$_POST && (int) ($_SERVER['CONTENT_LENGTH'] ?? 0) > 0) {
session()->setFlashdata('error', 'O envio é maior do que o servidor aceita (' . ini_get('post_max_size') . ' no total). Carregue menos imagens de cada vez.');
header('Location: ' . base_url('views/admin/galerias/edit.php?id=' . $id));
exit;
}
@@ -78,14 +95,14 @@ include __DIR__ . '/../../../includes/header.php';
</div></div>
<div class="card shadow-sm mt-3"><div class="card-body">
<h2 class="h6 mb-3">Adicionar imagem</h2>
<h2 class="h6 mb-3">Adicionar imagens</h2>
<form method="POST" enctype="multipart/form-data">
<?= csrf_field() ?>
<div class="mb-3">
<input type="file" class="form-control" name="image" accept=".jpg,.jpeg,.png,.gif,.webp,.jxl,image/jxl">
<div class="form-text">JPG, PNG, GIF, WebP ou JPEG XL (o JPEG XL não é redimensionado e só aparece em browsers que o suportam, como o Safari).</div>
<input type="file" class="form-control" name="images[]" multiple accept=".jpg,.jpeg,.png,.gif,.webp,.jxl,image/jpeg,image/png,image/gif,image/webp,image/jxl">
<div class="form-text">Pode escolher várias. JPG, PNG, GIF, WebP ou JPEG XL, até <?= round(gallery_upload_max_bytes() / 1048576) ?> MB cada (máx. <?= (int) ini_get('max_file_uploads') ?> de cada vez, <?= htmlspecialchars((string) ini_get('post_max_size')) ?> no total).</div>
</div>
<button type="submit" class="btn btn-primary btn-sm"><i class="bi bi-cloud-arrow-up me-1"></i>Carregar</button>
<button type="submit" name="upload" value="1" class="btn btn-primary btn-sm"><i class="bi bi-cloud-arrow-up me-1"></i>Carregar</button>
</form>
</div></div>
</div>
@@ -110,9 +127,19 @@ include __DIR__ . '/../../../includes/header.php';
<?php else: ?>
<div class="row g-2">
<?php foreach ($images as $img): ?>
<?php $rel = 'uploads/gallery/' . $id . '/' . $img['i_file_name']; ?>
<div class="col-6 col-lg-4 position-relative">
<img src="<?= base_url('uploads/gallery/' . $id . '/' . $img['i_file_name']) ?>"
alt="" class="img-thumbnail w-100" style="height:140px;object-fit:cover;" loading="lazy">
<?php if (str_ends_with(strtolower($rel), '.jxl') && img_fallback_rel($rel) === ''): ?>
<?php /* JPEG XL still without its WebP/JPG copy (no decoder on the server yet): most browsers
can't draw it, so show what is stored instead of a blank tile. */ ?>
<div class="img-thumbnail w-100 d-flex flex-column align-items-center justify-content-center text-center small text-body-secondary" style="height:140px;">
<i class="bi bi-file-earmark-image fs-3"></i>
<span class="badge text-bg-secondary my-1">JPEG XL</span>
<span class="text-truncate w-100 px-1" title="<?= htmlspecialchars($img['i_file_name']) ?>"><?= htmlspecialchars($img['i_file_name']) ?></span>
</div>
<?php else: ?>
<?= img_tag($rel, ['alt' => '', 'class' => 'img-thumbnail w-100', 'style' => 'height:140px;object-fit:cover;', 'loading' => 'lazy', 'width' => null]) ?>
<?php endif; ?>
<form method="POST" class="position-absolute top-0 end-0 m-1" onsubmit="return confirm('Remover esta imagem? Fica na lixeira durante 30 dias.')">
<?= csrf_field() ?>
<button class="btn btn-sm btn-danger rounded-circle" name="del_img" value="<?= (int) $img['i_id'] ?>" aria-label="Remover imagem"