PHP 商品浏览记录功能完整教程

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

php商品浏览记录教程
(图片来源网络,侵删)

功能目标

  1. 记录浏览:当用户登录或未登录状态下访问一个商品详情页时,系统会记录这次浏览行为(商品 ID、用户 ID、浏览时间)。
  2. 展示记录:在用户中心或特定页面,展示该用户最近浏览过的商品列表。
  3. 去重与排序:同一件商品不会被重复记录多次,并且列表按浏览时间倒序排列,最新的在最前面。

数据库设计

我们需要一个数据表来存储浏览记录,这个表需要记录“谁”在“什么时间”浏览了“哪个”商品。

我们创建一个名为 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_idproduct_id 的组合,数据库中只会存在一条记录,这自然实现了“去重”功能。

实现步骤

我们将分三步实现:记录浏览、获取记录、展示记录。

php商品浏览记录教程
(图片来源网络,侵删)

步骤 1: 记录用户的商品浏览行为

这个逻辑通常放在商品详情页(product.php)。

逻辑:

  1. 获取当前正在浏览的商品 ID (product_id)。
  2. 判断用户是否已登录。
    • 已登录:获取其 user_id
    • 未登录:使用一个唯一的标识来代表他,这里我们用 $_SESSION['session_id'](需要先 session_start())。
  3. 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: 获取用户的浏览记录

这个逻辑通常用于生成用户中心的“浏览历史”模块。

逻辑:

  1. 获取当前用户的标识(user_idsession_id)。
  2. product_views 表中查询该用户最近浏览过的商品 ID。
  3. 为了避免数据量过大,我们只取最近的 N 条记录(10 条)。
  4. 按浏览时间 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 商品浏览记录功能。

核心回顾:

  1. 数据库:设计 product_views 表,并用 UNIQUE KEY 实现去重。
  2. 记录逻辑:在商品页使用 INSERT ... ON DUPLICATE KEY UPDATE 来高效地记录和更新浏览。
  3. 获取逻辑:在用户中心按 user_id 查询并排序,获取最新的商品 ID 列表。
  4. 展示逻辑:将获取到的商品数据循环渲染到前端页面上。
  5. 优化:考虑未登录用户、数据清理和性能问题。

这个教程为你提供了一个坚实的基础,你可以根据自己项目的具体需求进行扩展和优化。