圖片上傳是 Web 應用的基礎功能。本文提供一個完整、安全的 PHP 範例,涵蓋:前端表單、後端驗證、檔案儲存、資料庫記錄路徑、以及前端顯示邏輯。
CREATE TABLE `images` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`filename` VARCHAR(255) NOT NULL COMMENT '原始檔名',
`stored_name` VARCHAR(255) NOT NULL COMMENT '伺服器存儲檔名',
`filepath` VARCHAR(500) NOT NULL COMMENT '相對網站根目錄路徑',
`mime_type` VARCHAR(50) NOT NULL,
`filesize` INT UNSIGNED NOT NULL,
`uploaded_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
<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="photo" accept="image/*" required></label>
<button type="submit">上傳</button>
</form>
<?php
// upload.php
require_once 'db.php'; // PDO 連線
$target_dir = __DIR__ . '/uploads/';
if (!is_dir($target_dir)) mkdir($target_dir, 0755, true);
$allowed_mimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$max_size = 2 * 1024 * 1024; // 2MB
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['photo'])) {
$file = $_FILES['photo'];
// 1. 錯誤檢查
if ($file['error'] !== UPLOAD_ERR_OK) {
die('上傳錯誤代碼: ' . $file['error']);
}
// 2. MIME 型別驗證(使用 finfo 防偽造)
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file['tmp_name']);
if (!in_array($mime, $allowed_mimes, true)) {
die('不支援的檔案類型: ' . $mime);
}
// 3. 大小檢查
if ($file['size'] > $max_size) {
die('檔案過大,限制 2MB');
}
// 4. 產生唯一儲存檔名,防覆蓋與路徑遍歷
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$stored_name = bin2hex(random_bytes(16)) . '.' . strtolower($ext);
$dest_path = $target_dir . $stored_name;
// 5. 移動檔案
if (!move_uploaded_file($file['tmp_name'], $dest_path)) {
die('檔案移動失敗,請檢查目錄權限');
}
// 6. 寫入資料庫
$stmt = $pdo->prepare(
'INSERT INTO images (filename, stored_name, filepath, mime_type, filesize)
VALUES (?, ?, ?, ?, ?)'
);
$relative_path = 'uploads/' . $stored_name;
$stmt->execute([
$file['name'],
$stored_name,
$relative_path,
$mime,
$file['size']
]);
echo '上傳成功!ID: ' . $pdo->lastInsertId();
exit;
}
?>
<?php
// gallery.php
require_once 'db.php';
$stmt = $pdo->query('SELECT id, filepath, filename FROM images ORDER BY uploaded_at DESC');
$images = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>圖片庫</title></head>
<body>
<h1>已上傳圖片</h1>
<div style="display:flex; flex-wrap:wrap; gap:16px;">
<?php foreach ($images as $img): ?>
<figure style="width:200px; text-align:center;">
<img src="<?= htmlspecialchars($img['filepath']) ?>" alt="<?= htmlspecialchars($img['filename']) ?>" style="max-width:100%; height:auto;">
<figcaption><?= htmlspecialchars($img['filename']) ?></figcaption>
</figure>
<?php endforeach; ?>
</div>
</body>
</html>
finfo 檢測真實 MIME,勿信任 $_FILES['type']。uploads/ 目錄設定 php_flag engine off 或放在網站根目錄外,防止腳本執行。php.ini 的 upload_max_filesize、post_max_size 及表單隱藏欄位 MAX_FILE_SIZE。以上範例展示了從零建立一個安全、可維護的 PHP 圖片上傳系統的完整流程。實際部署時,建議再加入圖片壓縮、縮圖生成、CDN 整合等進階功能。