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

PHP + Nginx 動態圖片裁剪方案:Imagick 實現、Nginx 快取穿透防護與瀏覽器快取優化

     編輯:PHP 相關知識

動態圖片裁剪是門戶網站、電商平台的剛需:上傳原圖,按需生成各種規格(縮略圖、列表圖、詳情圖),避免預生成佔用儲存空間。本文提供基於 Imagick + Nginx `try_files` 的高效能方案,含等比縮放、裁剪模式、靜態化落地、瀏覽器快取頭優化。

一、整體架構

用戶請求 → Nginx (try_files 靜態檔案) → 命中直接返回
                    ↓ 未命中
              Rewrite 到 PHP 裁剪腳本
                    ↓ 生成並保存到靜態路徑
              返回圖片 + 快取頭
                    ↓ 後續請求直接命中 Nginx 靜態檔案

二、PHP 裁剪腳本 resize.php

<?php
/**
 * 高效能動態圖片裁剪
 * 依賴:php-imagick 擴展
 * URL 範例:/s/www/300x200-2/uploadfile/helloworld.png
 * Nginx Rewrite:^([^.]*)/s/(.*)/(\d+)x(\d+)-(\d+)/(.*)$ $1/s/resize.php?site=$2&width=$3&height=$4&mode=$5&path=$6
 */

ini_set('memory_limit', '80M');

// 參數獲取與驗證
$path = trim($_GET['path'] ?? '');
$mode = intval($_GET['mode'] ?? 0);
$site = trim($_GET['site'] ?? '');
$width = intval($_GET['width'] ?? 0);
$height = intval($_GET['height'] ?? 0);

$siteMap = [
    'www' => '/mnt/webroot/www/',
    'cdn' => '/mnt/webroot/cdn/',
];

if (!isset($siteMap[$site]) || $mode < 0 || $mode > 3 || $width <= 0 || $height <= 0) {
    http_response_code(400);
    exit('Bad Request');
}

$origFile = $siteMap[$site] . $path;
if (!file_exists($origFile)) {
    http_response_code(404);
    exit('Not Found');
}

// 輸出路徑:/var/www/html/s/www/300x200-2/uploadfile/helloworld.png
$scriptDir = dirname(__FILE__);
$savePath = "{$scriptDir}/{$site}/{$width}x{$height}-{$mode}/{$path}";
$saveDir = dirname($savePath);
if (!is_dir($saveDir)) {
    mkdir($saveDir, 0755, true);
}

// 核心裁剪邏輯
$image = new Imagick($origFile);
[$origW, $origH] = [$image->getImageWidth(), $image->getImageHeight()];

$targetW = $width;
$targetH = $height;
$newW = $targetW;
$newH = $targetH;

if ($mode === 0) {
    // 模式 0:等比縮放(含長邊限制)
    $newH = $origH * $newW / $origW;
    if ($newH > $targetH) {
        $newW = $origW * $targetH / $origH;
        $newH = $targetH;
    }
} elseif ($mode === 2) {
    // 模式 2:填充裁剪(類似 CSS object-fit: cover)
    $targetRatio = $targetW / $targetH;
    $origRatio = $origW / $origH;
    if ($targetRatio > $origRatio) {
        // 目標更寬 → 裁剪高度
        $trimH = $origH - ($origW / $targetRatio);
        $image->cropImage($origW, $origH - $trimH, 0, $trimH / 2);
    } else {
        // 目標更高 → 裁剪寬度
        $trimW = $origW - ($origH * $targetRatio);
        $image->cropImage($origW - $trimW, $origH, $trimW / 2, 0);
    }
}
// 模式 1、3 可擴展:固定寬/高、智慧裁剪等

$image->resizeImage($newW, $newH, Imagick::FILTER_LANCZOS, 1);
$image->writeImage($savePath);

// 輸出圖片 + 快取頭
header('Content-Type: image/jpeg');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: public, max-age=2592000'); // 30 天
echo file_get_contents($savePath);

// 遞迴建立目錄輔助函數
function wpx_mkdir($dir, $mode = 0755) {
    return is_dir($dir) || mkdir($dir, $mode, true);
}

三、Nginx 配置核心

server {
    listen 80;
    server_name img.example.com;
    root /var/www/html; # PHP 腳本與生成靜態檔同根目錄

    location /s {
        # 關鍵:先嘗試靜態檔案,不存在才交給 PHP
        try_files $uri $uri/ @imagick;
    }

    location @imagick {
        rewrite ^([^.]*)/s/(.*)/(\d+)x(\d+)-(\d+)/(.*)$ $1/s/resize.php?site=$2&width=$3&height=$4&mode=$5&path=$6 last;
    }

    location ~ \.php$ {
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # 靜態資源長期快取
    location ~* \.(jpg|jpeg|png|gif|webp|css|js)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

四、關鍵優化細節

  1. Last-Modified + If-Modified-Since:PHP 輸出 Last-Modified,Nginx 靜態檔自動支援。瀏覽器二次請求返回 304 Not Modified,零流量傳輸圖片數據。
  2. Imagick 記憶體限制:ini_set('memory_limit', '80M') 防止大圖 OOM。
  3. 濾鏡選擇:FILTER_LANCZOS(Lanczos 重採樣)品質最佳,速度次之;縮略圖可用 FILTER_TRIANGLE 提速。
  4. 格式統一輸出 JPEG:統一 Content-Type: image/jpeg,簡化快取鍵;原圖 PNG/GIF 透明度場景需保留格式則另行判斷。
  5. 防盜鏈:Nginx `valid_referers` + `if ($invalid_referer) { return 403; }`。
  6. CDN 友好:生成靜態檔後,CDN 節點直接快取,回源壓力極低。

五、模式擴展建議

Mode名稱CSS 類比場景
0等比縮放object-fit: contain完整展示、不裁剪
1固定寬度等比width: 300px; height: auto列表流、卡片
2填充裁剪object-fit: cover封面、Banner、頭像
3智慧裁剪—人臉識別、主體區域保留

六、總結

「Nginx 靜態優先 + PHP 動態生成 + 瀏覽器/CDN 多層快取」是動態圖片處理的黃金架構。Imagick 提供專業級圖片處理能力,配合合理的 URL 設計與快取策略,可支撐日均億級圖片請求。核心原則:**生成一次,快取永久,靜態化落地,動態請求極少**。

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