首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 掃描目錄顯示圖片畫廊:opendir、副檔名過濾、CSS 背景圖佈局

     編輯:PHP 相關知識

前言

不使用資料庫、純以檔案系統管理圖片時,opendir() + readdir() 掃描目錄、過濾副檔名、輸出 HTML 是最經典的做法。本文解析一個極簡畫廊實作,採用 CSS 背景圖 background:url() 置中裁切 顯示縮圖,避免 <img> 變形,適合快速部署相簿、作品集或素材庫。

完整程式碼

<?php
$directory = 'gallery'; // 相對路徑
$allowed = ['jpg','jpeg','gif','png'];
$i = 0;

$dh = @opendir($directory) or die("圖片目錄讀取失敗!");

while ($file = readdir($dh)) {
    if ($file==='.' || $file==='..') continue;

    $parts = explode('.', $file);
    $ext = strtolower(array_pop($parts));
    $title = htmlspecialchars(implode('.', $parts)); // 防 XSS

    if (!in_array($ext, $allowed)) continue;

    // 每 4 欄清除右邊距 (配合 CSS float)
    $nomargin = (($i+1) % 4 === 0) ? 'nomargin' : '';

    echo "<div class='pic $nomargin' style='background:url($directory/$file) no-repeat 50% 50%;'>\n";
    echo "  <a href='$directory/$file' title='$title' target='_blank'>$title</a>\n";
    echo "</div>\n";
    $i++;
}
closedir($dh);

配合 CSS (建議內嵌或外部)

<style>
.pic {
    float: left;
    width: 200px; height: 200px;
    margin: 0 20px 20px 0;
    border: 1px solid #ddd;
    background-size: cover;       /* 關鍵:等比填滿並置中裁切 */
    background-position: center;
    background-repeat: no-repeat;
    position: relative;
}
.pic.nomargin { margin-right: 0; }
.pic a {
    display: block; width: 100%; height: 100%;
    color: #fff; text-decoration: none;
    background: rgba(0,0,0,0.5); /* 半透明黑底 */
    opacity: 0; transition: opacity .3s;
    display: flex; align-items: center; justify-content: center;
    font-size: 14px; word-break: break-all; padding: 10px;
}
.pic:hover a { opacity: 1; }
.clear { clear: both; }
</style>

<div class="gallery">
  <?php ...掃描輸出... ?>
  <div class="clear"></div>
</div>

關鍵技術點

技術說明
opendir/readdir/closedir目錄流操作,記憶體效率優於 scandir() (大目錄)
副檔名不區分大小寫strtolower(array_pop(explode('.',$file)))
XSS 防護htmlspecialchars() 處理檔名作為 title/連結文字
CSS 背景圖置中裁切background-size:cover; background-position:center; 完美適配各種比例
懸浮顯示標題opacity 轉場,滑鼠移入顯示檔名
響應式改良改用 display:grid; grid-template-columns: repeat(auto-fill, minmax(200px,1fr)); 取代 float

進階功能擴充

  1. 分頁:計算總數,array_slice($files, $offset, $limit),輸出頁碼連結。
  2. 縮圖快取:首次請求產生 thumbs/ 縮圖 (300×300),後續直接讀取快取,避免大圖下載拖慢頁面。
  3. EXIF 日期排序:exif_read_data($file)['DateTimeOriginal'] 取拍攝時間排序。
  4. Lightbox 放大:引入 lightbox2 或 fslightbox,data-fslightbox="gallery" 即可啟用。
  5. 無限滾動:前端 IntersectionObserver 載入下一頁 JSON,後端回傳檔名陣列。

安全性檢查清單

  • [ ] $directory = realpath($directory) 確保在允許根目錄下,防止路徑遍歷。
  • [ ] 檔名輸出 HTML 皆經 htmlspecialchars()。
  • [ ] 禁止上傳 .php, .phtml, .htaccess 等可執行副檔名。
  • [ ] 目錄權限 0755,檔案 0644,避免 0777。
  • [ ] 若開放上傳,驗證 MIME + 重新命名 + 移除 EXIF。

現代化重構:Laravel + 前端分離

// API Controller
public function index() {
    $dir = storage_path('app/public/gallery');
    $files = collect(glob("$dir/*.{jpg,jpeg,gif,png}", GLOB_BRACE))
        ->map(fn($p) => [
            'url'   => asset('storage/gallery/'.basename($p)),
            'thumb' => asset('storage/gallery/thumbs/'.basename($p)),
            'name'  => basename($p),
            'time'  => filemtime($p),
        ])->sortByDesc('time')->values()->paginate(20);
    return response()->json($files);
}

// Vue 3 + Vite 前端
<script setup>
import { ref, onMounted } from 'vue'
const images = ref([])
async function load(page=1) {
  const res = await fetch(`/api/gallery?page=${page}`)
  images.value.push(...(await res.json()).data)
}
onMounted(() => load())
</script>

<template>
  <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
    <div v-for="img in images" :key="img.url" class="relative aspect-square overflow-hidden rounded">
      <img :src="img.thumb" :alt="img.name" class="w-full h-full object-cover hover:scale-105 transition" loading="lazy">
      <div class="absolute inset-0 bg-black/50 text-white flex items-center justify-center opacity-0 hover:opacity-100 transition">{{ img.name }}</div>
    </div>
  </div>
  <button @click="load(page+1)" v-if="hasMore">載入更多</button>
</template>

小結

這段極簡程式碼展示了 opendir 掃描 → 副檔名過濾 → CSS 背景圖置中裁切 → 浮層顯示標題 的經典畫廊實作。零依賴、單一檔案、即刻可用。現代專案建議採用 前後端分離 + 物件儲存 + CDN 架構,後端只提供 API,前端用 Vue/React + 虛擬滾動實作高效能畫廊。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved