PHP 商品浏览记录功能完整教程
本教程将教你如何使用 PHP 和 MySQL 来实现一个常见的电商网站功能:记录并展示用户的商品浏览历史。

(图片来源网络,侵删)
功能目标
- 记录浏览:当用户登录或未登录状态下访问一个商品详情页时,系统会记录这次浏览行为(商品 ID、用户 ID、浏览时间)。
- 展示记录:在用户中心或特定页面,展示该用户最近浏览过的商品列表。
- 去重与排序:同一件商品不会被重复记录多次,并且列表按浏览时间倒序排列,最新的在最前面。
数据库设计
我们需要一个数据表来存储浏览记录,这个表需要记录“谁”在“什么时间”浏览了“哪个”商品。
我们创建一个名为 product_views 的表:
CREATE TABLE `product_views` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `user_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户ID,0表示未登录的访客', `product_id` int(11) NOT NULL COMMENT '商品ID', `viewed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '浏览时间', PRIMARY KEY (`id`), UNIQUE KEY `user_product` (`user_id`,`product_id`), -- 防止同一用户重复记录同一商品 KEY `user_id` (`user_id`), KEY `product_id` (`product_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品浏览记录表';
字段说明:
id: 自增主键,用于唯一标识每条记录。user_id: 记录浏览者的用户 ID,如果用户未登录,我们可以将其设为0或一个固定的访客 ID(如使用session_id),这里我们用0代表未登录用户。product_id: 被浏览的商品 ID。viewed_at: 记录浏览发生的时间戳,我们使用CURRENT_TIMESTAMP让它自动填充。UNIQUE KEY user_product: 这是一个非常重要的索引,它确保了对于同一个user_id和product_id的组合,数据库中只会存在一条记录,这自然实现了“去重”功能。
实现步骤
我们将分三步实现:记录浏览、获取记录、展示记录。

(图片来源网络,侵删)
步骤 1: 记录用户的商品浏览行为
这个逻辑通常放在商品详情页(product.php)。
逻辑:
- 获取当前正在浏览的商品 ID (
product_id)。 - 判断用户是否已登录。
- 已登录:获取其
user_id。 - 未登录:使用一个唯一的标识来代表他,这里我们用
$_SESSION['session_id'](需要先session_start())。
- 已登录:获取其
- 将
user_id(或session_id) 和product_id插入到product_views表中。
代码示例 (product.php):
<?php
session_start(); // 必须在最开始调用
// --- 1. 获取商品ID (通常从URL参数获取,product.php?id=123) ---
$product_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if ($product_id <= 0) {
die('无效的商品ID');
}
// --- 2. 连接数据库 (请替换成你自己的数据库信息) ---
$db_host = 'localhost';
$db_user = 'root';
$db_pass = 'your_password';
$db_name = 'your_database';
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);
if ($conn->connect_error) {
die("数据库连接失败: " . $conn->connect_error);
}
$conn->set_charset("utf8mb4");
// --- 3. 准备数据 ---
// 假设你有一个函数来获取当前登录用户ID
$user_id = isLoggedIn() ? getCurrentUserId() : 0;
// 为了区分未登录用户,我们可以使用 session_id
if ($user_id === 0) {
// 使用 session_id 作为访客的唯一标识
$visitor_id = session_id();
} else {
$visitor_id = $user_id;
}
// --- 4. 插入或更新浏览记录 ---
// 使用 INSERT ... ON DUPLICATE KEY UPDATE 语法
// 如果记录已存在(因为 user_product 是唯一键),它会更新 viewed_at 时间
$sql = "INSERT INTO `product_views` (`user_id`, `product_id`) VALUES (?, ?)
ON DUPLICATE KEY UPDATE `viewed_at` = CURRENT_TIMESTAMP";
$stmt = $conn->prepare($sql);
if ($stmt) {
// 绑定参数
// 'ii' 表示两个参数都是整数
$stmt->bind_param("ii", $visitor_id, $product_id);
// 执行
$stmt->execute();
// 关闭预处理语句
$stmt->close();
}
$conn->close();
// --- 辅助函数 (示例) ---
function isLoggedIn() {
// 这里实现你的登录检查逻辑
// return isset($_SESSION['user_id']);
return false; // 假设当前未登录
}
function getCurrentUserId() {
// 这里实现获取当前用户ID的逻辑
// return $_SESSION['user_id'];
return 1; // 假设用户ID为1
}
// ... 商品详情页的其他代码 ...
?>
代码解析:
ON DUPLICATE KEY UPDATE是 MySQL 的一个非常有用的语法,当INSERT语句因为主键或唯一键冲突(即我们已经记录过这个用户看这个商品)而失败时,它会执行UPDATE操作。- 我们将
viewed_at更新为CURRENT_TIMESTAMP,这意味着即使重复浏览,记录的时间也会刷新为最新的时间,这确保了用户的浏览列表总是反映其最新的兴趣。
步骤 2: 获取用户的浏览记录
这个逻辑通常用于生成用户中心的“浏览历史”模块。
逻辑:
- 获取当前用户的标识(
user_id或session_id)。 - 从
product_views表中查询该用户最近浏览过的商品 ID。 - 为了避免数据量过大,我们只取最近的 N 条记录(10 条)。
- 按浏览时间
viewed_at降序排列。
代码示例 (get_viewed_products.php 或直接在用户中心页面里):
<?php
session_start();
// --- 1. 连接数据库 (同上) ---
$db_host = 'localhost';
$db_user = 'root';
$db_pass = 'your_password';
$db_name = 'your_database';
$conn = new mysqli($db_host, $db_user, $db_pass, $db_name);
if ($conn->connect_error) {
die("数据库连接失败: " . $conn->connect_error);
}
$conn->set_charset("utf8mb4");
// --- 2. 获取用户标识 ---
$user_id = isLoggedIn() ? getCurrentUserId() : 0;
if ($user_id === 0) {
$visitor_id = session_id();
} else {
$visitor_id = $user_id;
}
// --- 3. 查询浏览记录 ---
// 获取最近10条浏览记录的商品ID
$limit = 10;
$sql = "SELECT `product_id` FROM `product_views`
WHERE `user_id` = ?
ORDER BY `viewed_at` DESC
LIMIT ?";
$stmt = $conn->prepare($sql);
if ($stmt) {
// 绑定参数
// 'ii' 表示两个参数都是整数
$stmt->bind_param("ii", $visitor_id, $limit);
$stmt->execute();
$result = $stmt->get_result();
$viewed_product_ids = [];
while ($row = $result->fetch_assoc()) {
$viewed_product_ids[] = $row['product_id'];
}
$stmt->close();
}
$conn->close();
// --- 4. 使用获取到的ID去查询商品详情 ---
// 假设你有一个函数 getProductsByIds() 可以根据ID数组获取商品信息
$viewed_products = [];
if (!empty($viewed_product_ids)) {
// $viewed_products = getProductsByIds($viewed_product_ids); // 调用你的商品查询函数
// 为了演示,我们模拟一些数据
$viewed_products = [
['id' => 101, 'name' => '智能手机 Pro', 'price' => 5999, 'image' => 'phone1.jpg'],
['id' => 85, 'name' => '无线蓝牙耳机', 'price' => 299, 'image' => 'earphone1.jpg'],
['id' => 42, 'name' => '机械键盘', 'price' => 599, 'image' => 'keyboard1.jpg'],
];
}
// ... 现在你可以将 $viewed_products 变量传递给前端模板进行展示 ...
?>
步骤 3: 在前端展示浏览记录
假设你使用的是简单的 PHP 模板引擎(原生 PHP 混合 HTML)。
HTML 模板 (history.php):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">我的浏览历史</title>
<style>
.product-list { display: flex; flex-wrap: wrap; gap: 20px; }
.product-item { border: 1px solid #ccc; padding: 10px; width: 200px; text-align: center; }
.product-item img { max-width: 100%; height: auto; }
</style>
</head>
<body>
<h1>我的浏览历史</h1>
<?php if (!empty($viewed_products)): ?>
<div class="product-list">
<?php foreach ($viewed_products as $product): ?>
<div class="product-item">
<a href="product.php?id=<?php echo $product['id']; ?>">
<img src="images/<?php echo htmlspecialchars($product['image']); ?>" alt="<?php echo htmlspecialchars($product['name']); ?>">
<h3><?php echo htmlspecialchars($product['name']); ?></h3>
<p>¥<?php echo number_format($product['price'], 2); ?></p>
</a>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<p>您还没有浏览过任何商品。</p>
<?php endif; ?>
</body>
</html>
高级优化与最佳实践
处理未登录用户的问题
对于未登录用户,我们使用 session_id 作为标识,但 session_id 在用户关闭浏览器后可能会改变,导致历史记录丢失。
解决方案:
- 方案A(简单):使用长期有效的 Cookie 来生成一个唯一的
visitor_id,并将其与session_id关联。// 在记录浏览前 if (!isset($_COOKIE['visitor_id'])) { $visitor_id = uniqid('vis_', true); // 生成一个唯一的ID setcookie('visitor_id', $visitor_id, time() + 30 * 24 * 60 * 60); // 30天有效期 } else { $visitor_id = $_COOKIE['visitor_id']; } // 使用这个 $visitor_id 去查询和插入 - 方案B(推荐):引导用户注册或登录,当用户未登录时,可以显示“登录后,浏览记录将为您永久保存”的提示,并提供登录入口。
性能优化
-
定期清理数据:浏览记录会无限增长,占用数据库空间,可以设置一个定时任务(如 Cron Job),定期删除超过一定时间(如 90 天)的记录。
-- 删除90天前的所有访客记录 DELETE FROM `product_views` WHERE `user_id` = 0 AND `viewed_at` < DATE_SUB(NOW(), INTERVAL 90 DAY); -- 或者删除所有用户超过180天的记录 DELETE FROM `product_views` WHERE `viewed_at` < DATE_SUB(NOW(), INTERVAL 180 DAY);
-
使用缓存:对于“我的浏览历史”这种不经常变化的数据,可以使用 Redis 或 Memcached 进行缓存,减轻数据库压力。
增强功能
- 合并用户记录:如果用户之前是访客,后来注册了账号,可以将他访客时期的浏览记录合并到新用户 ID 下,这通常需要一个手动触发或注册时自动执行的脚本。
- 分析推荐:基于浏览记录,可以分析用户偏好,实现“猜你喜欢”等个性化推荐功能。
通过以上步骤,你已经成功实现了一个基础的 PHP 商品浏览记录功能。
核心回顾:
- 数据库:设计
product_views表,并用UNIQUE KEY实现去重。 - 记录逻辑:在商品页使用
INSERT ... ON DUPLICATE KEY UPDATE来高效地记录和更新浏览。 - 获取逻辑:在用户中心按
user_id查询并排序,获取最新的商品 ID 列表。 - 展示逻辑:将获取到的商品数据循环渲染到前端页面上。
- 优化:考虑未登录用户、数据清理和性能问题。
这个教程为你提供了一个坚实的基础,你可以根据自己项目的具体需求进行扩展和优化。
