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

PHP 圖片上傳完整實現:前端表單、後端驗證、隨機命名、多尺寸生成

     編輯:PHP 綜合知識

前端表單

<form action="upload.php" method="post" enctype="multipart/form-data">
    <input type="hidden" name="MAX_FILE_SIZE" value="2097152"> <!-- 2MB,僅客戶端提示 -->
    <label>選擇圖片:<input type="file" name="image" accept="image/*" required></label>
    <button type="submit">上傳</button>
</form>

後端核心處理

<?php
// 配置
const UPLOAD_DIR = __DIR__ . '/uploads/';
const MAX_SIZE = 2 * 1024 * 1024; // 2MB
const ALLOWED_MIME = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
const ALLOWED_EXT = ['jpg', 'jpeg', 'png', 'gif', 'webp'];

// 確保目錄存在
if (!is_dir(UPLOAD_DIR)) mkdir(UPLOAD_DIR, 0755, true);

$file = $_FILES['image'] ?? null;
if (!$file || $file['error'] !== UPLOAD_ERR_OK) {
    exit(json_encode(['code'=>1, 'msg'=>'上傳失敗或無文件']));
}

// 1. 大小檢查
if ($file['size'] > MAX_SIZE) {
    exit(json_encode(['code'=>2, 'msg'=>'文件過大']));
}

// 2. MIME 檢查(需 fileinfo 擴展)
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
if (!in_array($mime, ALLOWED_MIME, true)) {
    exit(json_encode(['code'=>3, 'msg'=>'類型不允許']));
}

// 3. 擴展名檢查
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, ALLOWED_EXT, true)) {
    exit(json_encode(['code'=>4, 'msg'=>'擴展名不允許']));
}

// 4. 圖片完整性驗證
$imgInfo = getimagesize($file['tmp_name']);
if (!$imgInfo) {
    exit(json_encode(['code'=>5, 'msg'=>'非有效圖片']));
}

// 5. 生成安全文件名
$filename = bin2hex(random_bytes(16)) . '.' . $ext;
$dest = UPLOAD_DIR . $filename;

// 6. 移動文件
if (!move_uploaded_file($file['tmp_name'], $dest)) {
    exit(json_encode(['code'=>6, 'msg'=>'保存失敗']));
}

// 7. 生成縮略圖(可選)
$thumbs = [];
foreach ([['w'=>150,'h'=>150,'suf'=>'_thumb'], ['w'=>800,'h'=>600,'suf'=>'_large']] as $spec) {
    $thumbPath = UPLOAD_DIR . pathinfo($filename, PATHINFO_FILENAME) . $spec['suf'] . '.' . $ext;
    if (make_thumb($dest, $thumbPath, $spec['w'], $spec['h'])) {
        $thumbs[$spec['suf']] = $thumbPath;
    }
}

// 8. 返回結果
echo json_encode([
    'code' => 0,
    'msg' => '成功',
    'data' => [
        'original' => $dest,
        'url' => '/uploads/' . $filename,
        'thumbs' => $thumbs,
        'width' => $imgInfo[0],
        'height' => $imgInfo[1],
        'mime' => $mime,
    ]
]);

// 通用縮略函數
function make_thumb(string $src, string $dst, int $maxW, int $maxH, int $quality = 90): bool {
    list($w, $h, $type) = getimagesize($src);
    if (!$w || !$h) return false;

    $scale = min($maxW/$w, $maxH/$h);
    if ($scale >= 1) return copy($src, $dst);

    $nw = (int)($w * $scale);
    $nh = (int)($h * $scale);

    $create = ['', 'imagecreatefromgif', 'imagecreatefromjpeg', 'imagecreatefrompng', '', '', '', 'imagecreatefromwebp'][$type] ?? 'imagecreatefromjpeg';
    $save = ['', 'imagegif', 'imagejpeg', 'imagepng', '', '', '', 'imagewebp'][$type] ?? 'imagejpeg';

    $srcIm = $create($src);
    $dstIm = imagecreatetruecolor($nw, $nh);
    // 保持透明度
    if (in_array($type, [1,3,7])) {
        imagecolortransparent($dstIm, imagecolorallocatealpha($dstIm, 0,0,0,127));
        imagealphablending($dstIm, false);
        imagesavealpha($dstIm, true);
    }
    imagecopyresampled($dstIm, $srcIm, 0,0,0,0, $nw, $nh, $w, $h);
    $result = $save($dstIm, $dst, $quality);
    imagedestroy($srcIm); imagedestroy($dstIm);
    return $result;
}
?>

安全檢查清單

檢查點實現方式
文件大小MAX_FILE_SIZE + 服務端 $file['size']
MIME 類型finfo_file() 讀取文件頭,不信任 $_FILES['type']
擴展名pathinfo + 白名單
圖片完整性getimagesize() 解碼驗證
文件名安全random_bytes(16) + 原擴展名,無用戶可控部分
存儲路徑非 Web 可訪問目錄,或 Nginx/Apache 禁用腳本執行
權限控制目錄 0755,文件 0644,上傳用戶與 Web 用戶分離
並發安全random_bytes 極低碰撞概率,或加 flock 鎖

進階:分片上傳/斷點續傳

  • 前端:Uppy / Plupload / WebUploader
  • 後端:接收分片 → 臨時目錄 → 全部分片到齊 → 合併 → 驗證 → 入庫
  • 大文件建議對接 OSS/S3/MinIO 直傳,應用服務器不經流量
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved