&$images) { $categoryThumbDir = $thumbsDir . '/' . $categoryName; if (!is_dir($categoryThumbDir)) { mkdir($categoryThumbDir, 0775, true); } foreach ($images as &$image) { $sourcePath = $image['abs_path']; $sourceMtime = (int) filemtime($sourcePath); $maxTimestamp = max($maxTimestamp, $sourceMtime); $thumbExt = 'jpg'; $thumbName = pathinfo($image['filename'], PATHINFO_FILENAME) . '.jpg'; $thumbAbsPath = $categoryThumbDir . '/' . $thumbName; $thumbWebPath = 'thumbs/' . rawurlencode($categoryName) . '/' . rawurlencode($thumbName); $needsThumb = !file_exists($thumbAbsPath) || filemtime($thumbAbsPath) < $sourceMtime || $sourceMtime > $lastIndexedTimestamp; if ($needsThumb) { createThumbnail($sourcePath, $thumbAbsPath, THUMB_WIDTH, THUMB_HEIGHT); } $image['thumb_path'] = $thumbWebPath; $image['full_path'] = '?action=image&category=' . rawurlencode($categoryName) . '&file=' . rawurlencode($image['filename']); $image['title'] = titleFromFilename($image['filename']); $image['mtime'] = $sourceMtime; } usort($images, static function (array $a, array $b): int { $bySort = ($a['sort_index'] ?? 0) <=> ($b['sort_index'] ?? 0); if ($bySort !== 0) { return $bySort; } return ($b['mtime'] ?? 0) <=> ($a['mtime'] ?? 0); }); } unset($images, $image); if ($maxTimestamp > $lastIndexedTimestamp) { file_put_contents($lastIndexedFile, (string)$maxTimestamp); } $selectedCategory = isset($_GET['category']) ? trim((string)$_GET['category']) : null; if ($selectedCategory !== null && $selectedCategory !== '' && !isset($categories[$selectedCategory])) { http_response_code(404); $selectedCategory = null; } ?> Фотогалерея

Фотогалерея

Категории и превью обновляются автоматически при каждом открытии страницы

Категории

Пока нет папок с фото. Загрузите файлы в photos/<категория>/ через FTP.

$images): ?> <?= htmlspecialchars($categoryName, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') ?> фото

В этой категории пока нет изображений.

$filename, 'abs_path' => $absPath, 'sort_index' => (int)(($photoSortMap[$entry][$filename] ?? 1000)), ]; } $result[$entry] = $images; } uksort($result, static function (string $a, string $b) use ($categorySortMap): int { $aSort = (int)($categorySortMap[$a] ?? 1000); $bSort = (int)($categorySortMap[$b] ?? 1000); if ($aSort !== $bSort) { return $aSort <=> $bSort; } return strnatcasecmp($a, $b); }); return $result; } function assetUrl(string $relativePath): string { $file = __DIR__ . '/' . ltrim($relativePath, '/'); $v = is_file($file) ? (string)filemtime($file) : (string)time(); return $relativePath . '?v=' . rawurlencode($v); } function loadSortData(string $sortFile): array { if (!is_file($sortFile)) { return ['categories' => [], 'photos' => []]; } $json = file_get_contents($sortFile); if ($json === false || trim($json) === '') { return ['categories' => [], 'photos' => []]; } $data = json_decode($json, true); if (!is_array($data)) { return ['categories' => [], 'photos' => []]; } return [ 'categories' => is_array($data['categories'] ?? null) ? $data['categories'] : [], 'photos' => is_array($data['photos'] ?? null) ? $data['photos'] : [], ]; } function isImage(string $path): bool { $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); return in_array($ext, ['jpg', 'jpeg', 'png', 'webp', 'gif'], true); } function createThumbnail(string $srcPath, string $thumbPath, int $targetWidth, int $targetHeight): void { if (extension_loaded('imagick')) { createThumbnailWithImagick($srcPath, $thumbPath, $targetWidth, $targetHeight); return; } createThumbnailWithGd($srcPath, $thumbPath, $targetWidth, $targetHeight); } function createThumbnailWithImagick(string $srcPath, string $thumbPath, int $targetWidth, int $targetHeight): void { $imagick = new Imagick($srcPath); $imagick->setIteratorIndex(0); $imagick->setImageOrientation(Imagick::ORIENTATION_UNDEFINED); $imagick->thumbnailImage($targetWidth, $targetHeight, true, true); $imagick->setImageFormat('jpeg'); $imagick->setImageCompressionQuality(82); $imagick->writeImage($thumbPath); $imagick->clear(); $imagick->destroy(); } function createThumbnailWithGd(string $srcPath, string $thumbPath, int $targetWidth, int $targetHeight): void { [$srcW, $srcH, $type] = @getimagesize($srcPath) ?: [0, 0, 0]; if ($srcW < 1 || $srcH < 1) { return; } $src = match ($type) { IMAGETYPE_JPEG => @imagecreatefromjpeg($srcPath), IMAGETYPE_PNG => @imagecreatefrompng($srcPath), IMAGETYPE_GIF => @imagecreatefromgif($srcPath), IMAGETYPE_WEBP => function_exists('imagecreatefromwebp') ? @imagecreatefromwebp($srcPath) : null, default => null, }; if (!$src) { return; } $scale = min($targetWidth / $srcW, $targetHeight / $srcH); $dstW = max(1, (int) floor($srcW * $scale)); $dstH = max(1, (int) floor($srcH * $scale)); $dst = imagecreatetruecolor($dstW, $dstH); imagecopyresampled($dst, $src, 0, 0, 0, 0, $dstW, $dstH, $srcW, $srcH); imagejpeg($dst, $thumbPath, 82); imagedestroy($src); imagedestroy($dst); }