必须用数据库持久化视频播放进度:建video_playback_records表存user_id、video_id、last_position;CI控制器提供save()和get_last_position()接口;前端用timeupdate节流+fetch上报,禁用缓存防数据陈旧。

怎么用 CodeIgniter 存视频播放进度到数据库
不能只靠 localStorage 或 session,用户换设备、清缓存就丢了。真要持久化,得走数据库 + 前端主动上报。
关键点:不是“自动记录”,而是“用户播放时前端定时发请求,后端存进数据库”。CodeIgniter 本身不提供播放器或监听逻辑,它只负责接收和保存。
- 建一张表,比如
video_playback_records,至少含字段:user_id(需登录)、video_id(唯一标识视频)、last_position(float 类型,单位秒)、updated_at - 控制器里写一个专用接口,例如
Video_progress::save(),用$this->input->post()拿video_id和position,再用$this->db->replace()或先查后更新 - 别用
insert()重复插入,否则一条视频会积累 N 条记录;replace()或upsert(CI 4 支持,CI 3 需手写INSERT ... ON DUPLICATE KEY UPDATE)更稳妥
前端怎么触发 CodeIgniter 的进度保存接口
靠 timeupdate 事件太频繁,直接爆接口。必须节流 + 延迟提交。
示例逻辑(放在视频 <video></video> 标签的 JS 初始化块里):
let saveTimer;
video.addEventListener('timeupdate', () => {
clearTimeout(saveTimer);
saveTimer = setTimeout(() => {
fetch('/index.php/video_progress/save', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: `video_id=${video.dataset.id}&position=${video.currentTime}`
});
}, 3000); // 3 秒内只存最后一次
});
- 务必加
video.dataset.id这类属性传真实video_id,别用 DOM 索引或 URL 参数拼接,易错且不安全 - 如果用了 CSRF 保护(CI 默认开启),
fetch必须带 token,从页面 meta 标签或 hidden input 里取,然后加到body里 - 别在
ended事件里删记录——用户可能拖拽跳过结尾,应由后端根据业务判断是否“真正看完”
怎么让视频加载时自动跳到上次位置
不是前端猜,是后端查完再告诉前端。流程是:页面加载 → 前端发请求问“这个 video_id 我上次看到哪了?” → 后端查库返回 → 前端 video.currentTime = xxx。
- 另写一个接口,如
Video_progress::get_last_position(),接收video_id,返回 JSON:{"position": 127.5} - 前端用
await fetch().then(r => r.json())拿结果,注意等video元素 ready 后再设currentTime,否则无效(可监听loadedmetadata事件) - 如果查不到记录,后端返回
{"position": 0},前端照常设,避免空值报错 - 别把进度数据塞进 HTML 模板里输出(如 PHP
echo到 JS 变量),有 XSS 风险,尤其当video_id来自 URL 参数时
为什么用 CodeIgniter 缓存会干扰播放记录
因为 $this->output->cache(n) 缓存的是整个页面 HTML 输出,包括你用来初始化播放器的 JS 脚本。一旦缓存生效,前端永远拿不到最新进度,全是旧值。
- 所有涉及播放记录读写的接口(
save、get_last_position)必须禁用缓存,哪怕只加一行$this->output->cache(0);也行 - 不要对包含视频页的整个控制器方法开缓存;如果首页有推荐视频列表,可以缓存列表部分,但播放器区域必须动态加载(AJAX 分离)
- 检查
application/cache/目录下是否有对应 URI 的缓存文件,真遇到“改了代码没生效”,先手动删缓存文件
实际最难的不是存和取,而是前后端时间精度对齐、网络失败重试、用户快速拖拽时的位置覆盖逻辑——这些都得在业务层补全,框架只管稳稳接住那一次 POST。


















