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

PHP 圖片上傳與 ImageMagick 縮圖生成實作指南

     編輯:PHP 綜合知識

為什麼選 ImageMagick?

  • 處理大圖記憶體效率遠優於 GD
  • 支援 200+ 格式(含 HEIC、AVIF、TIFF 多頁)
  • 指令列工具 convert 功能極豐富(銳化、色彩空間、EXIF 處理)
  • 可透過 Imagick PHP 擴充直接呼叫 API,避免 shell_exec 安全風險

環境安裝

# Ubuntu/Debian
apt-get install imagemagick php-imagick

# CentOS/RHEL
yum install ImageMagick ImageMagick-devel
pecl install imagick
echo "extension=imagick.so" > /etc/php.d/imagick.ini

# 驗證
php -r "var_dump(class_exists('Imagick'));"
convert -version

安全上傳與縮圖完整流程

<?php
declare(strict_types=1);

const MAX_SIZE = 5 * 1024 * 1024;           // 5MB
const ALLOWED_MIME = ['image/jpeg', 'image/png', 'image/webp', 'image/gif'];
const UPLOAD_DIR = __DIR__ . '/uploads/';
const THUMB_DIR  = __DIR__ . '/uploads/thumbs/';
const THUMB_WIDTH = 300;

session_start();

// 1. 確保目錄存在且不可直接執行 PHP
foreach ([UPLOAD_DIR, THUMB_DIR] as $dir) {
    if (!is_dir($dir)) mkdir($dir, 0755, true);
    file_put_contents($dir . '.htaccess', 'php_flag engine off');
}

// 2. 處理上傳
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['image'])) {
    $file = $_FILES['image'];
    
    // 基礎驗證
    if ($file['error'] !== UPLOAD_ERR_OK) {
        die(json_encode(['error' => '上傳失敗:' . $file['error']]));
    }
    if ($file['size'] > MAX_SIZE) {
        die(json_encode(['error' => '檔案過大,限制 5MB']));
    }
    
    // MIME 偵測(防止偽裝副檔名)
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime = $finfo->file($file['tmp_name']);
    if (!in_array($mime, ALLOWED_MIME, true)) {
        die(json_encode(['error' => '不支援的圖片格式']));
    }
    
    // 產生安全檔名
    $ext = match ($mime) {
        'image/jpeg' => 'jpg',
        'image/png'  => 'png',
        'image/webp' => 'webp',
        'image/gif'  => 'gif',
    };
    $basename = bin2hex(random_bytes(16));
    $origPath = UPLOAD_DIR . $basename . '.' . $ext;
    $thumbPath = THUMB_DIR . $basename . '_thumb.' . $ext;
    
    // 移動檔案
    if (!move_uploaded_file($file['tmp_name'], $origPath)) {
        die(json_encode(['error' => '儲存失敗']));
    }
    
    // 3. 生成縮圖(使用 Imagick OO 介面)
    try {
        $img = new Imagick($origPath);
        $img->setImageFormat($ext);
        $img->thumbnailImage(THUMB_WIDTH, 0, true);  // 等比縮放
        $img->stripImage();                          // 移除 EXIF/GPS 等敏感資訊
        $img->writeImage($thumbPath);
        $img->destroy();
    } catch (ImagickException $e) {
        error_log("Thumbnail failed: {$e->getMessage()}");
        // 失敗時複製原圖作為備援
        copy($origPath, $thumbPath);
    }
    
    echo json_encode([
        'success' => true,
        'original' => '/uploads/' . basename($origPath),
        'thumbnail' => '/uploads/thumbs/' . basename($thumbPath),
    ]);
    exit;
}
?>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>上傳測試</title></head>
<body>
<form id="up" enctype="multipart/form-data">
  <input type="file" name="image" accept="image/*" required>
  <button>上傳</button>
</form>
<div id="preview"></div>
<script>
document.getElementById('up').onsubmit = async e => {
  e.preventDefault();
  const fd = new FormData(e.target);
  const res = await fetch('', {method:'POST', body:fd}).then(r=>r.json());
  if (res.success) {
    document.getElementById('preview').innerHTML = 
      `<img src="${res.thumbnail}"><br>原圖: <a href="${res.original}" target="_blank">檢視</a>`;
  } else {
    alert(res.error);
  }
};
</script>
</body>
</html>

進階縮圖參數調校

$img->thumbnailImage(300, 300, true);        // 限制長邊 300px,等比
$img->cropThumbnailImage(200, 200);          // 強制裁切為 200x200 正方形
$img->adaptiveResizeImage(300, 200);         // 智慧裁切保留焦點區域
$img->unsharpMask(0.5, 1.0, 1.0, 0.05);      // 銳化補償縮放模糊
$img->setImageCompressionQuality(85);        // JPEG 品質 85%

效能與安全清單

項目建議
記憶體限制php.ini memory_limit 至少 256M;大圖處理可暫時 ini_set('memory_limit', '512M')
執行緒數ImageMagick 多執行緒可能佔滿 CPU,設定 MAGICK_THREAD_LIMIT=1 環境變數
暫存目錄policy.xml 限制 <policy domain="resource" name="tmp" value="1GiB"/>
防止殘留進程使用 Imagick 類別而非 shell_exec('convert ...')
CDN 整合上傳至 S3/OSS 後觸發 Lambda/Function 非同步生成多規格縮圖
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved