提交的代碼片段暴露了多個典型錯誤:
enctype="multipart/form-data":導致 $_FILES 為空,文件無法上傳。$_POST['pic'] 獲取文件信息:文件上傳數據只存在 $_FILES 超全局變量中。'./Users/e-bag4/Desktop' 在生產環境必定失效,且存在目錄遍歷風險。values('$path') 直接拼接變量,極易遭受 SQL 注入攻擊。<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="pic" accept="image/*" required>
<input type="submit" value="上傳">
</form>
<?php
require_once 'db.php'; // 返回 PDO 實例 $pdo
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['pic'])) {
$file = $_FILES['pic'];
// 基礎驗證
if ($file['error'] !== UPLOAD_ERR_OK) {
die('上傳錯誤代碼:' . $file['error']);
}
$allowedMimes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
if (!in_array($mime, $allowedMimes)) {
die('只允許上傳 JPG/PNG/GIF/WebP 圖片');
}
if ($file['size'] > 5 * 1024 * 1024) { // 5MB
die('文件大小超過 5MB 限制');
}
// 讀取二進制內容
$blobData = file_get_contents($file['tmp_name']);
if ($blobData === false) {
die('讀取臨時文件失敗');
}
// 入庫:使用預處理語句綁定 BLOB
try {
$sql = "INSERT INTO e_user (pic, mime_type, original_name, upload_time) VALUES (?, ?, ?, NOW())";
$stmt = $pdo->prepare($sql);
// PDO::PARAM_LOB 告訴驅動這是大對象
$stmt->bindValue(1, $blobData, PDO::PARAM_LOB);
$stmt->bindValue(2, $mime);
$stmt->bindValue(3, basename($file['name']));
$stmt->execute();
echo "上傳成功!ID: " . $pdo->lastInsertId();
} catch (PDOException $e) {
error_log($e->getMessage());
echo "數據庫寫入失敗,請稍後重試";
}
}
?>
CREATE TABLE e_user (
id INT AUTO_INCREMENT PRIMARY KEY,
pic LONGBLOB NOT NULL, -- 存儲二進制,LONGBLOB 支持 4GB
mime_type VARCHAR(50) NOT NULL, -- 圖片 MIME 類型,用於輸出時設置 Content-Type
original_name VARCHAR(255), -- 原始文件名
upload_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
若文件超過 PHP memory_limit,直接 file_get_contents 會 OOM。可採用流式寫入:
$stmt->bindParam(1, $fp, PDO::PARAM_LOB);
$fp = fopen($file['tmp_name'], 'rb');
$stmt->execute();
fclose($fp);
生產環境建議:文件落地磁盤/對象存儲,數據庫僅存儲元數據(路徑、Hash、大小),通過 CDN 分發,極大降低 DB 壓力。
文件上傳入 BLOB 的核心要點:表單 enctype、$_FILES 使用、MIME/大小驗證、PDO::PARAM_LOB 綁定、預處理語句防注入。切勿存絕對路徑,切勿拼接 SQL。