直接读取视频文件访问日志不靠谱,因预加载、CDN缓存、断点续播等会产生大量206请求,单次播放可能记录5–20条日志,且无法识别是否播完,也缺乏用户ID、设备、时长等业务维度。

为什么直接读取视频文件访问日志不靠谱
很多开发者第一反应是“把 video.mp4 放在 Web 目录下,靠 Nginx/Apache 日志统计播放次数”,这看似简单,但实际漏统严重:浏览器预加载、CDN 缓存、断点续播、用户拖拽进度条都会触发多次 206 Partial Content 请求,单次播放可能产生 5–20 条日志;而真正完成播放的用户,日志里根本看不出“播完没”。更麻烦的是,日志里没有用户 ID、设备类型、播放时长等业务需要的维度。
用 PHP 接收前端播放事件上报(推荐方案)
核心思路:前端在关键节点(开始播放、暂停、结束、异常中断)调用 PHP 接口上报行为,PHP 写入数据库。这样数据可控、可关联用户、可扩展字段。
- 前端需监听
play、pause、ended、error等原生事件,用fetch()或XMLHttpRequest发送 POST 请求到 PHP 接口 - PHP 接口(如
/api/log_play.php)需校验Content-Type: application/json、解析file_id、user_id、event("start"/"pause"/"end")、timestamp、duration(当前已播秒数) - 务必加基础防刷:限制同一
user_id+file_id在 1 秒内只记 1 条start;对end事件可设最低时长阈值(如 ≥ 30 秒才算有效播放)
$_POST = json_decode(file_get_contents('php://input'), true);
if (!isset($_POST['file_id'], $_POST['user_id'], $_POST['event'])) {
http_response_code(400);
exit;
}
// 示例:写入 MySQL(请用 PDO 预处理防注入)
$stmt = $pdo->prepare("INSERT INTO video_logs (file_id, user_id, event, timestamp, duration) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$_POST['file_id'], $_POST['user_id'], $_POST['event'], time(), (int)$_POST['duration'] ?? 0]);怎么避免重复统计和漏统计
真实场景中,用户切后台、网络中断、页面刷新都会导致事件丢失或错乱。不能只依赖前端上报。
-
服务端兜底:对每个
file_id+user_id维护一个临时状态表(如video_play_sessions),记录started_at时间;若 10 分钟内无end上报,定时任务扫描并标记为“未完成” -
前端防重:用
sessionStorage存一个唯一session_id,每次上报带上;PHP 接口检查该session_id是否已记录过start,避免刷新页面重复计数 -
区分“播放”和“完成”:不要把
play事件直接当“一次播放”——用户点一下又关掉不算;建议以ended或duration >= total_duration * 0.9作为有效完成依据
CDN 场景下如何获取真实用户 IP 和地域
如果视频资源走 CDN,且统计要按地域分析,PHP 默认的 $_SERVER['REMOTE_ADDR'] 是 CDN 节点 IP,不是用户真实 IP。
千博企业网站管理系统主要面向大中型企业电子商务网站的构建与运营管理进行设计研发,拥有极为灵活的产品架构、极强的可扩展性与可伸缩性,可广泛适合于新闻资讯门户、企业内部知识门户、报社/杂志阅读、影音资讯、视频音频在线播放、法律顾问、政务公开、企业办公信息化等网络业务管理平台的建设,最大限度地满足客户现今乃至未来的应用需求。借助于千博企业网站管理系统极强的灵活性和便捷的可扩展性,企业级客户能够迅速流畅的
立即学习“PHP免费学习笔记(深入)”;
- 检查 CDN 是否透传真实 IP:常见 Header 有
X-Forwarded-For、X-Real-IP、Cf-Connecting-Ip(Cloudflare) - PHP 中应优先取
$_SERVER['HTTP_X_FORWARDED_FOR'](注意该字段可伪造,需结合白名单验证 CDN 回源 IP) - 地域识别别用纯 PHP 库(如
geoip扩展已废弃),改用离线 GeoLite2 City 数据库 +maxmind-db/readerComposer 包,查 IP 更准
复杂点在于:播放统计不是“一次请求一个结果”,而是多点埋点+状态补全+业务规则过滤。最容易被忽略的是“用户中途关闭页面导致 ended 事件根本发不出”,必须靠服务端 session 超时机制兜底。










