ImageMagick 作為強大的圖像處理工具套件,通過命令行 convert 實現高性能、高質量的縮略圖生成,遠超 GD 庫在大圖處理上的內存效率與格式支援。本文提供生產級完整代碼方案。
# CentOS/RHEL
yum install ImageMagick ImageMagick-devel -y
# Ubuntu/Debian
apt-get install imagemagick -y
# 驗證
convert -version
# 輸出包含 Version: ImageMagick 6.x.x-x
<?php
// 配置常量
define('UPLOAD_DIR_LARGE', $_SERVER['DOCUMENT_ROOT'] . '/images/large/');
define('UPLOAD_DIR_THUMB', $_SERVER['DOCUMENT_ROOT'] . '/images/thumb/');
define('CONVERT_CMD', '/usr/bin/convert'); // which convert 確認路徑
define('THUMB_WIDTH', 210); // 目標寬度,高度等比縮放
// 確保目錄存在且可寫
foreach (array(UPLOAD_DIR_LARGE, UPLOAD_DIR_THUMB) as $dir) {
if (!is_dir($dir)) mkdir($dir, 0755, true);
}
if (isset($_POST['submit'])) {
// 1. 基礎驗證
if (!isset($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
die('上傳失敗:' . $_FILES['photo']['error']);
}
$tmpName = $_FILES['photo']['tmp_name'];
if (!getimagesize($tmpName)) {
die('非合法圖片文件');
}
// 2. 安全文件名處理
$origName = basename($_FILES['photo']['name']);
$ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
$allowedExt = array('jpg', 'jpeg', 'png', 'gif', 'webp');
if (!in_array($ext, $allowedExt)) {
die('不支援的圖片格式');
}
$safeName = md5_file($tmpName) . '.' . $ext; // 內容哈希去重 + 保留副檔名
// 3. 移動原圖
$largePath = UPLOAD_DIR_LARGE . $safeName;
if (!move_uploaded_file($tmpName, $largePath)) {
die('原圖保存失敗');
}
@chmod($largePath, 0644);
// 4. 生成縮略圖
$thumbPath = UPLOAD_DIR_THUMB . $safeName;
$cmd = sprintf(
'%s %s -resize %dx %s',
escapeshellarg(CONVERT_CMD),
escapeshellarg($largePath),
THUMB_WIDTH,
escapeshellarg($thumbPath)
);
// -resize 210x 表示寬度 210,高度等比;若需固定尺寸可用 210x150^ -gravity center -extent 210x150
$output = array();
$returnVar = 0;
exec($cmd, $output, $returnVar);
if ($returnVar !== 0) {
error_log("ImageMagick 失敗: cmd=$cmd, output=" . implode("\n", $output));
// 可選:回退 GD 庫生成
}
// 5. 重定向防止重複提交
header('Location: ' . $_SERVER['PHP_SELF']);
exit;
}
// 6. 顯示現有縮略圖列表
$thumbs = glob(UPLOAD_DIR_THUMB . '*.{jpg,jpeg,png,gif,webp}', GLOB_BRACE);
?>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>圖片上傳演示</title></head>
<body>
<form action="" method="post" enctype="multipart/form-data">
<p><input type="file" name="photo" accept="image/*" required></p>
<p><input type="submit" name="submit" value="上傳並生成縮略圖"></p>
</form>
<h3>已生成縮略圖</h3>
<div style="display:flex; flex-wrap:wrap; gap:10px;">
<?php foreach ($thumbs as $thumb): ?>
<img src="<?php echo str_replace($_SERVER['DOCUMENT_ROOT'], '', $thumb); ?>"
style="max-width:210px; border:1px solid #ddd; padding:4px;"
alt="<?php echo basename($thumb); ?>">
<?php endforeach; ?>
</div>
</body>
</html>
| 風險點 | 防護措施 |
|---|---|
| 命令注入 | 所有用戶輸入進入 shell 命令**必須**經 escapeshellarg() 轉義 |
| 文件類型偽裝 | getimagesize() 驗證真實 MIME + 副檔名白名單 |
| 文件名衝突/遍歷 | md5_file() 內容哈希命名 + basename() 防路徑遍歷 |
| 大文件 DoS | 配置 upload_max_filesize、post_max_size、Nginx client_max_body_size |
| 磁盤佔滿 | 定期清理任務、配额監控、異步處理隊列 |
| ImageMagick 漏洞 | 及時更新、policy.xml 限制解碼器(如禁用 PS/EPS/PDF) |
避免 HTTP 請求阻塞於 CPU 密集型圖像處理,提升吞吐與用戶體驗。
-resize 210x # 寬度 210,高度等比
-resize x150 # 高度 150,寬度等比
-resize 210x150! # 強制 210x150,忽略比例(變形)
-resize 210x150^ # 填充模式:短邊縮放至目標,長邊超出
-gravity center -extent 210x150 # 配合 ^ 實現居中裁剪固定尺寸
-quality 85 # JPEG 質量 85%(平衡體積/清晰度)
-strip # 剝離 EXIF/配置文件,減小體積
-auto-orient # 根據 EXIF Orientation 自動旋轉正向
-interlace Plane # 漸進式 JPEG(網頁加載優化)
ImageMagick + PHP 實現圖片上傳縮略圖生成,核心在於:嚴格輸入驗證、安全命令構建、錯誤處理回退、異步架構擴展。生產環境建議結合對象存儲(S3/OSS/COS)+ CDN + 圖片處理服務(Imgix/Thumbor/自建),實現端到端的圖片交付優化。