如何使用PHP将多组文本与图片上传至MySQL数据库?
实现动态文本+图片交替的选择题内容方案(PHP+MySQL)
一、数据库设计
采用双表关联存储,适配任意数量的文本/图片组合:
问题主表
questions字段名 类型 说明 id INT(11) 主键,自增 title VARCHAR(255) 题目标题 created_at DATETIME 创建时间(可选) 问题内容项表
question_content字段名 类型 说明 id INT(11) 主键,自增 question_id INT(11) 外键,关联questions.id type ENUM('text','image') 内容类型:文本/图片 content TEXT 文本内容或图片路径 sort_order INT(11) 排序值,保证内容顺序
二、前端实现:动态内容块+图片上传
核心是做可动态增删的内容块,支持文本输入、图片拖放/粘贴上传。
1. HTML结构
<form id="question-form" method="POST" action="save-question.php"> <div> <label>题目标题:</label> <input type="text" name="title" required> </div> <div id="content-container"> <!-- 默认初始内容块 --> <div class="content-block" data-order="0"> <select class="content-type" name="content_type[]" required> <option value="text">文本</option> <option value="image">图片</option> </select> <textarea class="text-content" name="text_content[]" placeholder="输入文本内容"></textarea> <div class="image-upload-area" style="display: none; border: 1px dashed #ccc; padding: 20px; margin: 10px 0;"> <p>拖放图片到这里,或直接粘贴图片</p> <img class="preview-image" src="" style="max-width: 300px; display: none;" /> <input type="hidden" class="image-path" name="image_path[]" /> </div> <button type="button" class="remove-block">删除</button> </div> </div> <button type="button" id="add-block">添加内容块</button> <button type="submit">保存题目</button> </form>
2. JavaScript逻辑
处理动态块增删、类型切换、图片上传:
// 内容类型切换 document.addEventListener('change', function(e) { if (e.target.classList.contains('content-type')) { const block = e.target.closest('.content-block'); const textArea = block.querySelector('.text-content'); const imageArea = block.querySelector('.image-upload-area'); if (e.target.value === 'text') { textArea.style.display = 'block'; imageArea.style.display = 'none'; textArea.setAttribute('required', true); block.querySelector('.image-path').removeAttribute('required'); } else { textArea.style.display = 'none'; imageArea.style.display = 'block'; textArea.removeAttribute('required'); block.querySelector('.image-path').setAttribute('required', true); } } }); // 添加新内容块 document.getElementById('add-block').addEventListener('click', function() { const container = document.getElementById('content-container'); const lastBlock = container.querySelector('.content-block:last-child'); const newOrder = parseInt(lastBlock.dataset.order) + 1; const newBlock = lastBlock.cloneNode(true); newBlock.dataset.order = newOrder; // 清空内容 newBlock.querySelector('.text-content').value = ''; newBlock.querySelector('.image-path').value = ''; newBlock.querySelector('.preview-image').src = ''; newBlock.querySelector('.preview-image').style.display = 'none'; container.appendChild(newBlock); }); // 删除内容块 document.addEventListener('click', function(e) { if (e.target.classList.contains('remove-block')) { const blocks = document.querySelectorAll('.content-block'); if (blocks.length > 1) { e.target.closest('.content-block').remove(); // 更新剩余块排序值 blocks.forEach((block, index) => block.dataset.order = index); } } }); // 拖放图片上传 document.addEventListener('dragover', function(e) { const uploadArea = e.target.closest('.image-upload-area'); if (uploadArea) { e.preventDefault(); uploadArea.style.backgroundColor = '#f0f0f0'; } }); document.addEventListener('dragleave', function(e) { const uploadArea = e.target.closest('.image-upload-area'); if (uploadArea) { uploadArea.style.backgroundColor = 'transparent'; } }); document.addEventListener('drop', function(e) { const uploadArea = e.target.closest('.image-upload-area'); if (uploadArea) { e.preventDefault(); uploadArea.style.backgroundColor = 'transparent'; const file = e.dataTransfer.files[0]; if (file && file.type.startsWith('image/')) { uploadImage(file, uploadArea.closest('.content-block')); } } }); // 粘贴图片上传 document.addEventListener('paste', function(e) { const activeArea = document.querySelector('.image-upload-area[style*="display: block"]'); if (activeArea) { const items = e.clipboardData.items; for (let item of items) { if (item.type.startsWith('image/')) { const file = item.getAsFile(); uploadImage(file, activeArea.closest('.content-block')); break; } } } }); // 图片上传函数 function uploadImage(file, block) { const formData = new FormData(); formData.append('image', file); fetch('upload-image.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { block.querySelector('.image-path').value = data.path; const preview = block.querySelector('.preview-image'); preview.src = data.path; preview.style.display = 'block'; } else { alert(data.message); } }) .catch(error => alert('上传失败:' + error.message)); }
三、后端PHP实现
1. 图片上传处理脚本 upload-image.php
<?php header('Content-Type: application/json'); if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_FILES['image'])) { echo json_encode(['success' => false, 'message' => '无效请求']); exit; } // 配置 $targetDir = 'uploads/'; $allowedTypes = ['image/jpeg', 'image/png', 'image/gif']; $maxSize = 5 * 1024 * 1024; // 5MB // 创建上传目录 if (!is_dir($targetDir)) { mkdir($targetDir, 0755, true); } // 校验文件 $file = $_FILES['image']; if (!in_array($file['type'], $allowedTypes)) { echo json_encode(['success' => false, 'message' => '仅支持JPG/PNG/GIF格式']); exit; } if ($file['size'] > $maxSize) { echo json_encode(['success' => false, 'message' => '文件大小不能超过5MB']); exit; } if ($file['error'] !== UPLOAD_ERR_OK) { echo json_encode(['success' => false, 'message' => '文件上传错误']); exit; } // 生成唯一文件名 $fileName = uniqid('img_') . '.' . pathinfo($file['name'], PATHINFO_EXTENSION); $targetPath = $targetDir . $fileName; // 保存文件 if (move_uploaded_file($file['tmp_name'], $targetPath)) { echo json_encode(['success' => true, 'path' => $targetPath]); } else { echo json_encode(['success' => false, 'message' => '文件保存失败']); } ?>
2. 题目保存脚本 save-question.php
<?php header('Content-Type: application/json'); // 数据库连接(替换为你的配置) $conn = new mysqli('localhost', 'your_username', 'your_password', 'your_database'); if ($conn->connect_error) { echo json_encode(['success' => false, 'message' => '数据库连接失败']); exit; } // 接收表单数据 $title = trim($_POST['title'] ?? ''); $contentTypes = $_POST['content_type'] ?? []; $textContents = $_POST['text_content'] ?? []; $imagePaths = $_POST['image_path'] ?? []; // 校验标题 if (empty($title)) { echo json_encode(['success' => false, 'message' => '题目标题不能为空']); exit; } // 插入题目主表 $stmt = $conn->prepare("INSERT INTO questions (title, created_at) VALUES (?, NOW())"); $stmt->bind_param("s", $title); if (!$stmt->execute()) { echo json_encode(['success' => false, 'message' => '保存题目失败']); $stmt->close(); $conn->close(); exit; } $questionId = $stmt->insert_id; $stmt->close(); // 插入内容项 foreach ($contentTypes as $index => $type) { $content = ($type === 'text') ? trim($textContents[$index] ?? '') : trim($imagePaths[$index] ?? ''); if (empty($content)) { echo json_encode(['success' => false, 'message' => '内容不能为空']); $conn->close(); exit; } $stmt = $conn->prepare("INSERT INTO question_content (question_id, type, content, sort_order) VALUES (?, ?, ?, ?)"); $stmt->bind_param("issi", $questionId, $type, $content, $index); if (!$stmt->execute()) { echo json_encode(['success' => false, 'message' => '保存内容失败']); $stmt->close(); $conn->close(); exit; } $stmt->close(); } $conn->close(); echo json_encode(['success' => true, 'question_id' => $questionId]); ?>
四、内容渲染
从数据库读取题目和内容,按顺序渲染:
<?php // 数据库连接(替换为你的配置) $conn = new mysqli('localhost', 'your_username', 'your_password', 'your_database'); $questionId = $_GET['id'] ?? 0; if (!$questionId) { die('无效的题目ID'); } // 查询题目标题 $stmt = $conn->prepare("SELECT title FROM questions WHERE id = ?"); $stmt->bind_param("i", $questionId); $stmt->execute(); $result = $stmt->get_result(); $question = $result->fetch_assoc(); $stmt->close(); // 查询内容项(按排序顺序) $stmt = $conn->prepare("SELECT type, content FROM question_content WHERE question_id = ? ORDER BY sort_order ASC"); $stmt->bind_param("i", $questionId); $stmt->execute(); $contentItems = $stmt->get_result()->fetch_all(MYSQLI_ASSOC); $stmt->close(); $conn->close(); ?> <!DOCTYPE html> <html> <head> <title><?php echo htmlspecialchars($question['title']); ?></title> </head> <body> <h1><?php echo htmlspecialchars($question['title']); ?></h1> <div class="question-content"> <?php foreach ($contentItems as $item): ?> <?php if ($item['type'] === 'text'): ?> <p><?php echo nl2br(htmlspecialchars($item['content'])); ?></p> <?php else: ?> <img src="<?php echo htmlspecialchars($item['content']); ?>" alt="题目图片" style="max-width: 100%; margin: 10px 0;"> <?php endif; ?> <?php endforeach; ?> </div> </body> </html>
关键注意事项
- 安全防护:
- 图片上传时严格校验文件类型、大小,防止恶意文件上传
- 输出内容时用
htmlspecialchars()转义,避免XSS攻击 - 数据库操作使用预处理语句,防止SQL注入
- 兼容性:
- 粘贴图片功能需测试主流浏览器(Chrome、Firefox、Edge)
- 拖放事件需阻止默认行为,避免页面跳转
- 优化建议:
- 可添加图片压缩处理,减少存储占用
- 内容块可增加上下移动按钮,调整排序顺序
内容的提问来源于stack exchange,提问作者Francois van Ellinckhuyzen
相关产品推荐
相关产品推荐

