
本文介绍一种结合 cookie 与 session 的可靠方案,确保每篇文章对每个用户仅统计一次浏览量,避免刷新页面重复计数,提升数据准确性。
本文介绍一种结合 cookie 与 session 的可靠方案,确保每篇文章对每个用户仅统计一次浏览量,避免刷新页面重复计数,提升数据准确性。
在构建内容管理系统(如音乐分享站、博客平台)时,准确统计“独立用户浏览量”至关重要——它直接影响内容热度评估与推荐逻辑。单纯依赖 $_SESSION(如原代码中仅检查 $_SESSION['recent_posts'][$id])存在明显缺陷:每次页面重载或会话重启都会丢失状态,导致重复计数;而仅用 Cookie 又缺乏服务端校验,易被篡改。
✅ 推荐采用 Cookie + Session 协同机制,兼顾客户端持久性与服务端可控性:
- Cookie 标识用户级浏览状态:设置一个长期有效的 Cookie(如30天),记录用户最近浏览的文章 ID;
- Session 辅助临时标记:用于同一会话内快速判断,减少数据库操作;
- 服务端双重校验:仅当 Cookie 未记录当前文章 ID(或记录的是其他文章 ID)时,才执行更新并刷新 Cookie。
以下是优化后的完整实现:
<?php
require_once '../config.php';
// 安全过滤:强制转换为整型,防止 SQL 注入
$id = (int)$_GET['id'];
if ($id <= 0) {
http_response_code(400);
exit('Invalid post ID');
}
$sql = "UPDATE song SET count = count + 1 WHERE id = ?";
$shouldUpdate = false;
// 检查 Cookie 是否已记录该文章 ID
if (!isset($_COOKIE['view_counted'])) {
// 首次访问任意文章 → 记录当前 ID 并更新计数
setcookie('view_counted', $id, time() + (86400 * 30), '/', '', true, true); // HttpOnly + Secure
$shouldUpdate = true;
} elseif ((int)$_COOKIE['view_counted'] !== $id) {
// Cookie 存在但指向其他文章 → 更新为当前 ID 并计数
setcookie('view_counted', $id, time() + (86400 * 30), '/', '', true, true);
$shouldUpdate = true;
}
// 若 Cookie 值等于当前 $id,则跳过更新(已计数)
if ($shouldUpdate) {
// 使用预处理语句防止注入,绑定参数更安全
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);
// 同步更新 Session,便于本会话内快速判断(非必需但可选优化)
if (!isset($_SESSION['recent_posts'])) {
$_SESSION['recent_posts'] = [];
}
$_SESSION['recent_posts'][$id] = 1;
}
?>⚠️ 关键注意事项:
立即学习“PHP免费学习笔记(深入)”;
- 安全性优先:务必使用预处理语句(? 占位符)替代字符串拼接,杜绝 SQL 注入风险;
- Cookie 安全标志:添加 HttpOnly 和 Secure 参数(如示例所示),防止 XSS 窃取;
- ID 类型校验:强制 (int) 转换并验证有效性,避免非法输入;
- 无状态设计:不依赖 Session 存活时间,Cookie 主导长期唯一性判断;
- 扩展建议:如需支持多设备/多账号区分,应升级为基于用户登录态(如 user_id)+ 文章 ID 的组合哈希存储,或引入 Redis 缓存去重。
该方案简洁高效,在绝大多数中小型项目中可直接落地,兼顾准确性、性能与安全性。



















