本文目录导读:

实现PHP项目的商品评价功能,通常需要包含数据库设计、后端接口、前端展示以及安全校验四个核心部分。
下面是一个基于 MySQL + PHP 的经典实现方案,适用于大多数电商项目。
第一步:数据库设计
你需要至少两张表:orders(订单)和 reviews(评价)。
订单商品关联表(用于验证购买资格)
CREATE TABLE `order_items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order_id` int(11) NOT NULL, `product_id` int(11) NOT NULL, `user_id` int(11) NOT NULL, `is_reviewed` tinyint(1) DEFAULT 0, -- 0未评价,1已评价 PRIMARY KEY (`id`) );
评价主表
CREATE TABLE `reviews` ( `id` int(11) NOT NULL AUTO_INCREMENT, `product_id` int(11) NOT NULL, `user_id` int(11) NOT NULL, `order_id` int(11) NOT NULL, `rating` tinyint(1) NOT NULL, -- 评分(1-5星) `content` text, -- 评价内容 `images` json DEFAULT NULL, -- 评价图片(JSON数组) `status` tinyint(1) DEFAULT 1, -- 1显示,0隐藏(审核) `created_at` datetime DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `unique_user_product_order` (`user_id`,`product_id`,`order_id`), -- 防止重复评价 INDEX `idx_product_rating` (`product_id`, `rating`) );
第二步:后端PHP接口(核心逻辑)
提交评价(需要登录 + 购买验证)
<?php
// submit_review.php
session_start();
require_once 'db.php'; // 数据库连接
// 1. 验证用户登录
if (!isset($_SESSION['user_id'])) {
echo json_encode(['code' => 401, 'msg' => '请先登录']);
exit;
}
$user_id = $_SESSION['user_id'];
$product_id = intval($_POST['product_id']);
$order_id = intval($_POST['order_id']);
$rating = intval($_POST['rating']);
$content = trim($_POST['content']);
// 2. 参数校验
if ($rating < 1 || $rating > 5) {
echo json_encode(['code' => 400, 'msg' => '评分范围1-5']);
exit;
}
if (mb_strlen($content) < 10 || mb_strlen($content) > 500) {
echo json_encode(['code' => 400, 'msg' => '评价内容10-500字']);
exit;
}
// 3. 验证购买资格(检查订单商品表)
$stmt = $pdo->prepare("SELECT id FROM order_items
WHERE user_id = ? AND product_id = ? AND order_id = ? AND is_reviewed = 0");
$stmt->execute([$user_id, $product_id, $order_id]);
if (!$stmt->fetch()) {
echo json_encode(['code' => 403, 'msg' => '未购买该商品或已评价']);
exit;
}
// 4. 处理图片上传(可选)
$images = [];
if (!empty($_FILES['images'])) {
$allowed = ['image/jpeg', 'image/png', 'image/webp'];
foreach ($_FILES['images']['tmp_name'] as $key => $tmp_name) {
if ($_FILES['images']['error'][$key] === 0) {
if (!in_array($_FILES['images']['type'][$key], $allowed)) {
continue;
}
$filename = uniqid() . '.' . pathinfo($_FILES['images']['name'][$key], PATHINFO_EXTENSION);
move_uploaded_file($tmp_name, 'uploads/reviews/' . $filename);
$images[] = $filename;
}
}
}
// 5. 开启事务,写入评价 + 更新订单状态
$pdo->beginTransaction();
try {
// 写入评价
$stmt = $pdo->prepare("INSERT INTO reviews (product_id, user_id, order_id, rating, content, images)
VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$product_id, $user_id, $order_id, $rating, $content, json_encode($images)]);
// 更新订单商品状态为已评价
$stmt = $pdo->prepare("UPDATE order_items SET is_reviewed = 1
WHERE user_id = ? AND product_id = ? AND order_id = ?");
$stmt->execute([$user_id, $product_id, $order_id]);
$pdo->commit();
echo json_encode(['code' => 200, 'msg' => '评价成功']);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['code' => 500, 'msg' => '评价提交失败']);
}
获取商品评价列表
<?php
// get_reviews.php
$product_id = intval($_GET['product_id']);
$page = intval($_GET['page'] ?? 1);
$page_size = 10;
$offset = ($page - 1) * $page_size;
$stmt = $pdo->prepare("SELECT r.*, u.username, u.avatar
FROM reviews r
JOIN users u ON r.user_id = u.id
WHERE r.product_id = ? AND r.status = 1
ORDER BY r.created_at DESC
LIMIT $offset, $page_size");
$stmt->execute([$product_id]);
$reviews = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 统计评分分布
$stmt_rating = $pdo->prepare("SELECT rating, COUNT(*) as count
FROM reviews
WHERE product_id = ? AND status = 1
GROUP BY rating");
$stmt_rating->execute([$product_id]);
$rating_stats = $stmt_rating->fetchAll(PDO::FETCH_KEY_PAIR);
echo json_encode([
'list' => $reviews,
'rating_stats' => $rating_stats,
'total' => count($reviews)
]);
第三步:前端HTML + JavaScript(示例)
<!-- 评价表单 -->
<form id="reviewForm" enctype="multipart/form-data">
<input type="hidden" name="product_id" value="123">
<input type="hidden" name="order_id" value="456">
<div class="star-rating">
<span data-value="1">★</span>
<span data-value="2">★</span>
<span data-value="3">★</span>
<span data-value="4">★</span>
<span data-value="5">★</span>
<input type="hidden" name="rating" id="ratingInput">
</div>
<textarea name="content" placeholder="分享您的使用感受(10-500字)"></textarea>
<input type="file" name="images[]" multiple accept="image/*">
<button type="submit">提交评价</button>
</form>
<script>
document.getElementById('reviewForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('submit_review.php', {
method: 'POST',
body: formData
})
.then(res => res.json())
.then(data => {
if (data.code === 200) {
alert('评价成功');
location.reload();
} else {
alert(data.msg);
}
});
});
// 星星选择逻辑(简化)
document.querySelectorAll('.star-rating span').forEach(span => {
span.addEventListener('click', function() {
document.getElementById('ratingInput').value = this.dataset.value;
});
});
</script>
第四步:扩展功能与注意事项
-
评价审核
- 新增
reviews.status字段(0=待审核,1=通过,2=拒绝) - 后台管理员审核后更新状态
- 新增
-
回复评价
- 新增
review_replies表,关联reviews.id - 商家回复显示在评价下方
- 新增
-
追评功能
- 允许用户在一定时间内追加评价
- 在
reviews表中增加additional_content和additional_time字段
-
性能优化
- 为
product_id和created_at建立复合索引 - 商品详情页缓存评价总数和平均分(Redis 或文件缓存)
- 为
-
安全注意事项
- 使用
htmlspecialchars()防止XSS攻击 - 对图片进行压缩和重命名,防止恶意文件上传
- 限制同一用户对一个商品的评价次数(通过唯一索引实现)
- 使用
-
SEO优化
- 建议使用
<div>包裹,不要直接输出用户输入内容 - 评价列表建议使用服务端渲染或预渲染
- 建议使用
如果使用框架(ThinkPHP / Laravel)
ThinkPHP 6 示例:
// 评价提交
public function submit(Request $request)
{
$data = $request->validate([
'product_id' => 'required|integer',
'order_id' => 'required|integer',
'rating' => 'required|integer|between:1,5',
'content' => 'required|length:10,500',
]);
// 使用事务
Db::transaction(function () use ($data) {
// 写入评价
Review::create($data);
// 更新订单状态
OrderItem::where(...)->update(['is_reviewed' => 1]);
});
}
Laravel 示例:
// 使用 Eloquent ORM + 事件
public function store(ReviewRequest $request)
{
$review = auth()->user()->reviews()->create($request->validated());
// 触发事件(更新商品评分缓存)
event(new ProductReviewed($review));
}
评价功能的核心逻辑:验证身份 → 校验购买资格 → 写入评价 → 更新订单状态,实际项目中建议根据上述结构逐步完善,注意防刷(唯一索引)、审核(状态字段)和性能(缓存与索引)三个关键点。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播