PHP怎么实现视频播放统计_PHP实现视频播放统计方式【统计】

9次阅读

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

PHP怎么实现视频播放统计_PHP实现视频播放统计方式【统计】

为什么直接读取视频文件访问日志不靠谱

很多开发者第一反应是“把 video.mp4 放在 Web 目录下,靠 nginx/apache 日志统计播放次数”,这看似简单,但实际漏统严重:浏览器预加载、CDN 缓存、断点续播、用户拖拽进度条都会触发多次 206 Partial Content 请求,单次播放可能产生 5–20 条日志;而真正完成播放的用户,日志里根本看不出“播完没”。更麻烦的是,日志里没有用户 ID、设备类型、播放时长等业务需要的维度。

php 接收前端播放事件上报(推荐方案)

核心思路:前端在关键节点(开始播放、暂停、结束、异常中断)调用 PHP 接口上报行为,PHP 写入数据库。这样数据可控、可关联用户、可扩展字段。

  • 前端需监听 playpauseendedError 等原生事件,用 fetch()XMLHttpRequest 发送 POST 请求到 PHP 接口
  • PHP 接口(如 /api/log_play.php)需校验 Content-Type: application/json、解析 file_iduser_idEvent"start"/"pause"/"end")、timestampduration(当前已播秒数)
  • 务必加基础防刷:限制同一 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 事件直接当“一次播放”——用户点一下又关掉不算;建议以 endedduration >= total_duration * 0.9 作为有效完成依据

CDN 场景下如何获取真实用户 IP 和地域

如果视频资源走 CDN,且统计要按地域分析,PHP 默认的 $_SERVER['REMOTE_ADDR'] 是 CDN 节点 IP,不是用户真实 IP。

立即学习PHP免费学习笔记(深入)”;

  • 检查 CDN 是否透传真实 IP:常见 Header 有 X-forwarded-ForX-Real-IPCf-Connecting-Ip(Cloudflare)
  • PHP 中应优先取 $_SERVER['HTTP_X_FORWARDED_FOR'](注意该字段可伪造,需结合白名单验证 CDN 回源 IP)
  • 地域识别别用纯 PHP 库(如 geoip 扩展已废弃),改用离线 GeoLite2 City 数据库 + maxmind-db/reader composer 包,查 IP 更准

复杂点在于:播放统计不是“一次请求一个结果”,而是多点埋点+状态补全+业务规则过滤。最容易被忽略的是“用户中途关闭页面导致 ended 事件根本发不出”,必须靠服务端 session 超时机制兜底。

text=ZqhQzanResources