分享一个基于 PHP+MySQL 的简易商品评论系统实现方案

135 阅读4分钟

以下是一个基于 PHP+MySQL 的简易电商商品评论系统实现方案,包含数据库设计、API 接口及前端展示代码:

一、数据库设计(MySQL)

-- 商品表
CREATE TABLE `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL COMMENT '商品名称',
  `price` decimal(10,2) NOT NULL COMMENT '价格',
  `category_id` int(11) DEFAULT NULL COMMENT '分类ID',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
);

-- 评论表
CREATE TABLE `product_reviews` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `product_id` int(11) NOT NULL COMMENT '商品ID',
  `user_id` int(11) DEFAULT NULL COMMENT '用户ID(可为空,匿名用户)',
  `user_name` varchar(100) DEFAULT NULL COMMENT '用户名(匿名时显示)',
  `content` text NOT NULL COMMENT '评论内容',
  `rating` tinyint(1) NOT NULL COMMENT '评分(1-5星)',
  `status` tinyint(1) DEFAULT 1 COMMENT '状态(0=待审核,1=已通过,2=已拒绝)',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_product_id` (`product_id`),
  KEY `idx_status` (`status`)
);

-- 评论图片表
CREATE TABLE `review_images` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `review_id` int(11) NOT NULL COMMENT '评论ID',
  `image_url` varchar(255) NOT NULL COMMENT '图片URL',
  `sort` int(11) DEFAULT 0 COMMENT '排序',
  PRIMARY KEY (`id`),
  KEY `idx_review_id` (`review_id`)
);

二、PHP 后端实现

1. 数据库连接(db_connect.php)

<?php
$host = 'localhost';
$dbname = 'ecommerce';
$username = 'root';
$password = 'password';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
    die("数据库连接失败: " . $e->getMessage());
}

2. 获取商品评论 API(get_reviews.php)

<?php
require 'db_connect.php';

// 参数验证
$product_id = isset($_GET['product_id']) ? intval($_GET['product_id']) : 0;
$page = isset($_GET['page']) ? intval($_GET['page']) : 1;
$page_size = isset($_GET['page_size']) ? min(intval($_GET['page_size']), 100) : 20;

if (!$product_id) {
    die(json_encode(['code' => 400, 'message' => '缺少商品ID']));
}

// 查询评论
$offset = ($page - 1) * $page_size;
$stmt = $pdo->prepare("
    SELECT r.*, GROUP_CONCAT(i.image_url) as images 
    FROM product_reviews r 
    LEFT JOIN review_images i ON r.id = i.review_id 
    WHERE r.product_id = ? AND r.status = 1 
    GROUP BY r.id 
    ORDER BY r.created_at DESC 
    LIMIT ? OFFSET ?
");
$stmt->execute([$product_id, $page_size, $offset]);
$reviews = $stmt->fetchAll(PDO::FETCH_ASSOC);

// 处理图片
foreach ($reviews as &$review) {
    $review['images'] = $review['images'] ? explode(',', $review['images']) : [];
}

// 返回结果
echo json_encode([
    'code' => 200,
    'data' => $reviews,
    'page' => $page,
    'page_size' => $page_size,
    'total' => $pdo->query("SELECT COUNT(*) FROM product_reviews WHERE product_id = $product_id AND status = 1")->fetchColumn()
]);

3. 提交评论 API(submit_review.php)

<?php
require 'db_connect.php';

// 参数验证
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
$user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0;
$user_name = isset($_POST['user_name']) ? htmlspecialchars($_POST['user_name']) : '匿名用户';
$content = isset($_POST['content']) ? htmlspecialchars($_POST['content']) : '';
$rating = isset($_POST['rating']) ? min(max(intval($_POST['rating']), 1), 5) : 5;

if (!$product_id || empty($content)) {
    die(json_encode(['code' => 400, 'message' => '参数不完整']));
}

// 插入评论
$stmt = $pdo->prepare("
    INSERT INTO product_reviews (product_id, user_id, user_name, content, rating, status)
    VALUES (?, ?, ?, ?, ?, 0)
");
$stmt->execute([$product_id, $user_id, $user_name, $content, $rating]);
$review_id = $pdo->lastInsertId();

// 处理图片上传(示例代码,实际需处理文件上传逻辑)
if (isset($_FILES['images']) && $_FILES['images']['error'][0] === 0) {
    foreach ($_FILES['images']['tmp_name'] as $key => $tmp_name) {
        $image_path = '/uploads/reviews/' . uniqid() . '.jpg';
        move_uploaded_file($tmp_name, __DIR__ . $image_path);
        
        $pdo->prepare("
            INSERT INTO review_images (review_id, image_url, sort)
            VALUES (?, ?, ?)
        ")->execute([$review_id, $image_path, $key]);
    }
}

echo json_encode(['code' => 200, 'message' => '评论提交成功,等待审核']);

三、前端展示(HTML+JavaScript)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>商品评论</title>
    <style>
        .review-list {
            max-width: 800px;
            margin: 0 auto;
        }
        .review-item {
            border-bottom: 1px solid #eee;
            padding: 15px 0;
        }
        .review-header {
            display: flex;
            justify-content: space-between;
            margin-bottom: 10px;
        }
        .review-rating {
            color: #ff9900;
        }
        .review-images {
            display: flex;
            gap: 10px;
            margin-top: 10px;
        }
        .review-images img {
            max-height: 100px;
            border-radius: 4px;
        }
        .review-form {
            margin-top: 30px;
            padding: 20px;
            background-color: #f9f9f9;
            border-radius: 8px;
        }
        .rating-stars {
            font-size: 24px;
            color: #ccc;
            cursor: pointer;
        }
        .rating-stars .star.active {
            color: #ff9900;
        }
    </style>
</head>
<body>
    <div class="review-list">
        <h2>商品评论</h2>
        <div id="reviews-container"></div>
        
        <div class="review-form">
            <h3>发表评论</h3>
            <div class="rating-stars">
                <span class="star" data-rating="1"></span>
                <span class="star" data-rating="2"></span>
                <span class="star" data-rating="3"></span>
                <span class="star" data-rating="4"></span>
                <span class="star" data-rating="5"></span>
                <input type="hidden" id="rating" value="5">
            </div>
            <textarea id="review-content" placeholder="请输入评论内容" rows="4" style="width: 100%; margin: 10px 0;"></textarea>
            <input type="file" id="review-images" multiple accept="image/*">
            <button id="submit-review">提交评论</button>
        </div>
    </div>

    <script>
        const productId = 123; // 替换为实际商品ID
        let currentPage = 1;

        // 加载评论
        function loadReviews(page = 1) {
            fetch(`get_reviews.php?product_id=${productId}&page=${page}`)
                .then(response => response.json())
                .then(data => {
                    renderReviews(data.data);
                    currentPage = page;
                })
                .catch(error => console.error('加载评论失败:', error));
        }

        // 渲染评论
        function renderReviews(reviews) {
            const container = document.getElementById('reviews-container');
            container.innerHTML = '';

            if (reviews.length === 0) {
                container.innerHTML = '<p>暂无评论</p>';
                return;
            }

            reviews.forEach(review => {
                const reviewEl = document.createElement('div');
                reviewEl.className = 'review-item';
                reviewEl.innerHTML = `
                    <div class="review-header">
                        <span>${review.user_name}</span>
                        <span class="review-rating">${'★'.repeat(review.rating)}</span>
                    </div>
                    <p>${review.content}</p>
                    <div class="review-date">${review.created_at}</div>
                    ${review.images.length > 0 ? `
                        <div class="review-images">
                            ${review.images.map(img => `<img src="${img}" alt="评论图片">`).join('')}
                        </div>
                    ` : ''}
                `;
                container.appendChild(reviewEl);
            });
        }

        // 评分选择
        document.querySelectorAll('.rating-stars .star').forEach(star => {
            star.addEventListener('click', () => {
                const rating = parseInt(star.getAttribute('data-rating'));
                document.getElementById('rating').value = rating;
                
                document.querySelectorAll('.rating-stars .star').forEach(s => {
                    if (parseInt(s.getAttribute('data-rating')) <= rating) {
                        s.classList.add('active');
                    } else {
                        s.classList.remove('active');
                    }
                });
            });
        });

        // 提交评论
        document.getElementById('submit-review').addEventListener('click', () => {
            const content = document.getElementById('review-content').value.trim();
            const rating = document.getElementById('rating').value;
            const images = document.getElementById('review-images').files;

            if (!content) {
                alert('请输入评论内容');
                return;
            }

            const formData = new FormData();
            formData.append('product_id', productId);
            formData.append('content', content);
            formData.append('rating', rating);
            
            for (let i = 0; i < images.length; i++) {
                formData.append('images[]', images[i]);
            }

            fetch('submit_review.php', {
                method: 'POST',
                body: formData
            })
            .then(response => response.json())
            .then(data => {
                alert(data.message);
                if (data.code === 200) {
                    document.getElementById('review-content').value = '';
                    document.getElementById('review-images').value = '';
                }
            })
            .catch(error => console.error('提交评论失败:', error));
        });

        // 初始化加载
        loadReviews();
    </script>
</body>
</html>

四、部署与优化建议

  1. 安全优化

    • 使用 PDO 预处理语句防止 SQL 注入
    • 对用户输入进行 XSS 过滤
    • 图片上传需验证文件类型和大小
  2. 性能优化

    • 添加数据库索引(如评论表的 product_id 和 status
    • 评论列表采用分页加载
    • 图片使用 CDN 加速
  3. 功能扩展

    • 添加评论审核机制
    • 支持评论点赞 / 踩功能
    • 实现评论分类筛选(好评 / 中评 / 差评)
  4. 用户体验

    • 添加评论加载动画

    • 实现评论提交成功提示

    • 支持图片预览功能

此方案提供了电商评论系统的基础架构,可根据实际需求进行扩展和优化。编辑分享