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

PHP 頭像上傳完整實作:從表單驗證到縮圖生成

     編輯:PHP 相關知識

功能需求

  • 支援 JPG、PNG、GIF、BMP 等常見圖片格式
  • 限制檔案大小(預設 2MB)
  • 上傳後自動生成縮圖預覽
  • 檔案命名避免衝突(時間戳 + 隨機字串)
  • 資料夾權限自動建立

前端表單 (upload.html)

<!DOCTYPE html>
<html lang="zh-TW">
<head>
  <meta charset="UTF-8">
  <title>頭像上傳</title>
  <style>
    body { font-family: sans-serif; max-width: 600px; margin: 2rem auto; }
    .preview { max-width: 200px; max-height: 200px; border: 1px solid #ddd; margin-top: 1rem; }
    .error { color: #c62828; font-weight: bold; }
    .success { color: #2e7d32; font-weight: bold; }
  </style>
</head>
<body>
  <h1>上傳頭像</h1>
  <form action="upload.php" method="post" enctype="multipart/form-data">
    <label>
      選擇圖片 (JPG/PNG/GIF/BMP, < 2MB):<br>
      <input type="file" name="avatar" accept="image/jpeg,image/png,image/gif,image/bmp" required>
    </label><br><br>
    <button type="submit">上傳並預覽</button>
  </form>
  <div id="result"></div>
</body>
</html>

後端處理 (upload.php)

<?php
// 設定
$allowedMimes = [
    'image/jpeg', 'image/jpg', 'image/pjpeg',
    'image/png', 'image/x-png',
    'image/gif',
    'image/bmp'
];
$maxSize = 2 * 1024 * 1024; // 2MB
$uploadDir = __DIR__ . '/uploads/avatars/';
$previewRatio = 0.5; // 縮圖比例

// 確保上傳目錄存在
if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

// 處理上傳
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!isset($_FILES['avatar']) || $_FILES['avatar']['error'] !== UPLOAD_ERR_OK) {
        $msg = ['type' => 'error', 'text' => '檔案上傳失敗,錯誤代碼: ' . ($_FILES['avatar']['error'] ?? '未知')];
    } else {
        $file = $_FILES['avatar'];
        
        // 檢查大小
        if ($file['size'] > $maxSize) {
            $msg = ['type' => 'error', 'text' => '檔案過大,限制 2MB'];
        }
        // 檢查 MIME
        elseif (!in_array($file['type'], $allowedMimes, true)) {
            $msg = ['type' => 'error', 'text' => '不支援的檔案類型: ' . htmlspecialchars($file['type'])];
        }
        // 檢查真實圖片內容 (防偽裝)
        elseif (!@getimagesize($file['tmp_name'])) {
            $msg = ['type' => 'error', 'text' => '檔案非有效圖片或已損毀'];
        }
        else {
            // 產生唯一檔名
            $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
            $ext = ($ext === 'jpg') ? 'jpeg' : $ext; // 統一副檔名
            $newName = 'avatar_' . date('YmdHis') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
            $destPath = $uploadDir . $newName;
            
            // 移動檔案
            if (move_uploaded_file($file['tmp_name'], $destPath)) {
                // 生成縮圖資訊
                $imgInfo = getimagesize($destPath);
                $previewW = (int)($imgInfo[0] * $previewRatio);
                $previewH = (int)($imgInfo[1] * $previewRatio);
                
                $msg = [
                    'type' => 'success',
                    'text' => '上傳成功!',
                    'file' => $newName,
                    'path' => $destPath,
                    'url' => 'uploads/avatars/' . $newName,
                    'width' => $imgInfo[0],
                    'height' => $imgInfo[1],
                    'preview_w' => $previewW,
                    'preview_h' => $previewH,
                ];
            } else {
                $msg = ['type' => 'error', 'text' => '檔案儲存失敗,請檢查目錄權限'];
            }
        }
    }
    
    // 輸出 JSON 供 AJAX 使用,或直接顯示
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($msg);
    exit;
}
?>

AJAX 版前端增強 (upload_ajax.html)

<script>
document.querySelector('form').addEventListener('submit', async (e) => {
    e.preventDefault();
    const formData = new FormData(e.target);
    const resultDiv = document.getElementById('result');
    resultDiv.innerHTML = '<p>上傳中...</p>';
    
    try {
        const res = await fetch('upload.php', { method: 'POST', body: formData });
        const data = await res.json();
        
        if (data.type === 'success') {
            resultDiv.innerHTML = `
                <p class="success">${data.text}</p>
                <img src="${data.url}" class="preview" alt="預覽" width="${data.preview_w}" height="${data.preview_h}">
                <p>原始尺寸: ${data.width} x ${data.height}</p>
                <p>檔案名: ${data.file}</p>
            `;
        } else {
            resultDiv.innerHTML = `<p class="error">${data.text}</p>`;
        }
    } catch (err) {
        resultDiv.innerHTML = `<p class="error">網路錯誤: ${err.message}</p>`;
    }
});
</script>

進階功能擴充

  • 圖片裁切:整合 Cropper.js 讓使用者自訂裁切區域
  • 多尺寸縮圖:上傳後同步生成 50x50、100x100、200x200 三種尺寸,適用不同顯示場景
  • 雲端儲存:搭配 AWS S3 / Google Cloud Storage / 阿里云 OSS,將本地檔案同步上傳並回傳 CDN 網址
  • 內容安全掃描:整合 ClamAV 或 Google Cloud Vision API 掃描惡意內容
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved