功能需求
- 支援循序播放與隨機播放模式
- 循序模式可設定是否循環
- Session 記錄播放進度,刷新頁面續播
- 直接輸出圖片二進位,可用 `
` 嵌入
完整實作
<?php
/**
* 圖片輪播控制器
*
* 使用方式:
* <img src="slider.php?dir=images/&mode=sequential&loop=1">
* <img src="slider.php?dir=banner/&mode=random">
*/
// === 設定區 ===
$config = [
'dir' => $_GET['dir'] ?? 'images/', // 圖片目錄
'mode' => $_GET['mode'] ?? 'sequential', // sequential | random
'loop' => isset($_GET['loop']) ? (bool)$_GET['loop'] : true,
'width' => $_GET['width'] ?? 0, // 0=原始大小
'allowedExt'=> ['jpg', 'jpeg', 'png', 'gif', 'webp'],
];
// 正規化路徑
$config['dir'] = rtrim($config['dir'], '/') . '/';
$fullPath = $_SERVER['DOCUMENT_ROOT'] . '/' . ltrim($config['dir'], '/');
if (!is_dir($fullPath)) {
http_response_code(404);
exit('目錄不存在');
}
session_start();
$sessionKey = 'slider_' . md5($config['dir']);
// 掃描圖片檔案 (快取 1 分鐘)
$cacheKey = 'slider_files_' . md5($fullPath);
$files = $_SESSION[$cacheKey] ?? null;
if ($files === null || time() - ($_SESSION[$cacheKey . '_time'] ?? 0) > 60) {
$files = [];
$dh = opendir($fullPath);
while (($file = readdir($dh)) !== false) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if (in_array($ext, $config['allowedExt'])) {
$files[] = $file;
}
}
closedir($dh);
sort($files); // 檔名排序
$_SESSION[$cacheKey] = $files;
$_SESSION[$cacheKey . '_time'] = time();
}
if (empty($files)) {
http_response_code(404);
exit('無圖片');
}
// === 選擇圖片索引 ===
$count = count($files);
if ($config['mode'] === 'random') {
$index = random_int(0, $count - 1);
} else {
// 循序模式
$current = $_SESSION[$sessionKey] ?? 0;
if ($current >= $count) {
$current = $config['loop'] ? 0 : $count - 1;
}
$index = $current;
// 更新下一張索引
if ($config['loop']) {
$_SESSION[$sessionKey] = ($current + 1) % $count;
} else {
$_SESSION[$sessionKey] = min($current + 1, $count - 1);
}
}
$selectedFile = $files[$index];
$filePath = $fullPath . $selectedFile;
// === 輸出圖片 ===
$mimeTypes = [
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
'webp' => 'image/webp',
];
$ext = strtolower(pathinfo($selectedFile, PATHINFO_EXTENSION));
$mime = $mimeTypes[$ext] ?? 'application/octet-stream';
header("Content-Type: {$mime}");
header('Content-Length: ' . filesize($filePath));
header('Cache-Control: public, max-age=3600'); // 快取 1 小時
header('ETag: "' . md5_file($filePath) . '"');
// 條件請求支援
if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
$etag = '"' . md5_file($filePath) . '"';
if ($_SERVER['HTTP_IF_NONE_MATCH'] === $etag) {
http_response_code(304);
exit;
}
}
readfile($filePath);
前端嵌入範例
<!-- 循序輪播,每次刷新換下一張 -->
<img src="slider.php?dir=slides/&mode=sequential&loop=1"
alt="輪播圖片"
style="max-width:100%; height:auto;">
<!-- 隨機顯示 -->
<img src="slider.php?dir=banner/&mode=random"
alt="隨機橫幅">
<!-- JavaScript 定時切換 (需配合 AJAX 或 iframe) -->
<script>
setInterval(() => {
document.getElementById('slider').src =
'slider.php?dir=slides/&mode=sequential&loop=1&t=' + Date.now();
}, 5000);
</script>
進階擴充建議
- 資料庫儲存圖片資訊 (標題、連結、排序、啟用狀態)
- 加入圖片裁剪/縮圖快取 (Intervention Image)
- 支援 WebP 自動轉換
- 管理後台上傳、拖曳排序、預覽
- CDN 整合:輸出簽名 URL 而非直接 readfile