透過 Apache/Nginx 的 404 錯誤處理機制,將不存在的縮略圖請求導向 PHP 腳本即時生成並快取,實現「按需生成、永久快取」的圖片服務架構。
/image/{name}_w{width}_h{height}.{ext}{name}.{ext},支援 JPEG/PNG/GIF。<?php
// 允許的縮略圖尺寸
$allowedSizes = [
'100_100' => true,
'200_100' => true,
];
$imageRoot = __DIR__ . '/../image/';
// 解析請求檔名
$requestUri = $_SERVER['REQUEST_URI'];
$fileName = basename($requestUri);
// 正則解析:name_w{width}_h{height}.ext
if (!preg_match('/(?P<name>[\w-]+)_w(?P<width>\d+)_h(?P<height>\d+)\.(?P<ext>\w+)/', $fileName, $m)) {
header('HTTP/1.0 404 Not Found');
exit('Invalid thumbnail spec');
}
$sizeKey = $m['width'] . '_' . $m['height'];
if (!isset($allowedSizes[$sizeKey])) {
header('HTTP/1.0 404 Not Found');
exit('Size not allowed');
}
$srcPath = $imageRoot . $m['name'] . '/' . $m['name'] . '.' . $m['ext'];
if (!is_file($srcPath)) {
header('HTTP/1.0 404 Not Found');
exit('Source image not found');
}
// 載入原圖
switch (strtolower($m['ext'])) {
case 'jpg':
case 'jpeg':
$srcImg = imagecreatefromjpeg($srcPath);
break;
case 'png':
$srcImg = imagecreatefrompng($srcPath);
break;
case 'gif':
$srcImg = imagecreatefromgif($srcPath);
break;
default:
header('HTTP/1.0 404 Not Found');
exit('Unsupported format');
}
$srcW = imagesx($srcImg);
$srcH = imagesy($srcImg);
$dstW = (int)$m['width'];
$dstH = (int)$m['height'];
// 等比縮放計算
$ratioSrc = $srcW / $srcH;
$ratioDst = $dstW / $dstH;
if ($ratioSrc > $ratioDst) {
// 原圖較寬:以寬為準
$newW = $dstW;
$newH = (int)($dstW / $ratioSrc);
} else {
// 原圖較高:以高為準
$newH = $dstH;
$newW = (int)($dstH * $ratioSrc);
}
// 建立目標畫布(白底)
$dstImg = imagecreatetruecolor($dstW, $dstH);
$white = imagecolorallocate($dstImg, 255, 255, 255);
imagefilledrectangle($dstImg, 0, 0, $dstW - 1, $dstH - 1, $white);
// 置中貼上縮圖
$offsetX = (int)(($dstW - $newW) / 2);
$offsetY = (int)(($dstH - $newH) / 2);
imagecopyresampled($dstImg, $srcImg, $offsetX, $offsetY, 0, 0, $newW, $newH, $srcW, $srcH);
// 輸出並快取
$cacheDir = $imageRoot . $m['name'] . '/';
$cachePath = $cacheDir . $fileName;
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true);
}
header('Content-Type: image/jpeg');
imagejpeg($dstImg, $cachePath, 90); // 同時存檔
imagejpeg($dstImg, null, 90); // 輸出瀏覽器
imagedestroy($srcImg);
imagedestroy($dstImg);
?>
ErrorDocument 404 /thumbnail.php(或用 mod_rewrite 判斷檔案不存在時導向)。error_page 404 /thumbnail.php; 搭配 try_files。ETag / Last-Modified / Cache-Control 標頭。imagewebp())。