最轻量在线人数统计需用flock()加锁配合时间戳会话列表:每条记录为“session_id|timestamp”,按5分钟有效期过滤,追加写入并每次统计前清理过期项,避免竞态与僵尸用户。

直接用文件存在线人数,PHP 里最轻量、最可控的方式就是靠 flock() + file_get_contents()/file_put_contents() 配合时间戳清理,别碰 session 或数据库——小项目够用,大并发会丢数。
为什么不能直接 file_get_contents() 后 ++ 再写回去?
因为 PHP 多进程/多请求下没有原子性:两个请求几乎同时读到 “12”,各自加 1 写回,结果还是 “13” 而不是 “14”。必须加锁。
-
flock($fp, LOCK_EX)是唯一靠谱的跨请求互斥手段,file_put_contents(..., LOCK_EX)只对写入本身加锁,不保证读-改-写整个流程安全 - 文件句柄得保持打开状态直到解锁,不能
fopen → fread → fclose → fopen → fwrite → fclose,中间断开就失去锁 - 锁文件建议单独用一个(比如
online.lock),和计数文件(online.count)分开,避免读写冲突
怎么存才方便判断“是否在线”?
纯数字计数器只能告诉你“此刻有多少人”,但无法区分是真实活跃用户还是卡着页面没关的僵尸。所以得存带时间戳的会话列表,再按有效期过滤。
- 每条记录格式:
session_id|timestamp,例如abc123|1717025688 - 在线判定标准:当前时间减去 timestamp ≤ 300(5 分钟),超时就剔除
- 用
file_put_contents($file, $line . "\n", FILE_APPEND | LOCK_EX)追加,比全量重写更轻量 - 清理逻辑必须每次统计前执行,否则文件越滚越大,
file()读取变慢
实际代码里要注意哪些坑?
看似几行的事,错一个点就导致计数虚高或归零。
- PHP CLI 和 Web SAPI 的
session_id()行为不同,Web 环境务必先session_start()再取session_id() -
file()读取后每行末尾带\n,trim()必须做,否则explode('|', $line)可能分出空数组 - 写入前检查磁盘空间和文件权限:
is_writable(dirname($file)),否则静默失败 - 不要用
time() - $ts > 300判断过期,而要用$ts ,避免整数溢出或负值误判
性能和可靠性边界在哪?
这个方案撑不住每秒 10+ 请求的持续写入。锁文件会成瓶颈,flock() 在 NFS 或某些容器文件系统上可能失效。
- 单机日活
- 一旦发现
flock()返回false频率升高,说明锁争抢严重,得切 Redis - 别把计数逻辑塞进每个页面顶部——提取成独立
get_online_count()函数,用 APCu 缓存 10 秒结果,减轻 I/O 压力
文件路径、锁机制、过期策略这三块,少处理一块,统计就不可信。尤其是时间戳校验,本地服务器时间和 PHP date_default_timezone_set() 不一致时,会批量误删“在线”记录。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











