在PHP开发中,统计网站访问量或活动参与人数时,我们常常只希望同一个浏览器会话被计算一次。如果直接每次请求都加一,用户刷新几次数据就失真了。借助session可以很自然地标记“是否已经统计过”。

实现原理
当用户第一次访问页面时,服务端会分配一个session,我们可以在session里放一个标识,比如counted。如果标识不存在,说明是首次会话,此时执行计数并写入标识;后续请求发现标识已存在,就跳过计数。
基础代码示例
下面是一段最简洁的实现,把计数写在文件里做演示:
<?php
session_start();
// 计数文件路径
$file = __DIR__ . '/count.txt';
// 如果是首次会话
if (!isset($_SESSION['counted'])) {
// 读取原数字
$num = (int)@file_get_contents($file);
$num++;
file_put_contents($file, $num);
// 标记已计数
$_SESSION['counted'] = true;
}
echo '当前总首次会话数:' . (int)@file_get_contents($file);
?>
封装成函数
为了在项目里复用,可以写成一个函数:
<?php
session_start();
function count_first_session($file) {
if (isset($_SESSION['counted'])) {
return (int)@file_get_contents($file);
}
$num = (int)@file_get_contents($file);
$num++;
file_put_contents($file, $num);
$_SESSION['counted'] = true;
return $num;
}
$total = count_first_session(__DIR__ . '/count.txt');
echo '总首次会话数:' . $total;
?>
注意事项
- 必须在使用session前调用session_start(),且之前不能有输出。
- 如果用户清空浏览器cookie或开无痕窗口,session会丢失,会被重新计数,这是正常现象。
- 高并发场景建议用数据库或Redis代替文件,避免读写冲突。
使用数据库的实现思路
如果是多用户系统,可以用数据表存总次数,首次会话时执行UPDATE语句加一。核心判断逻辑仍然是检查$_SESSION['counted']是否存在。
<?php
session_start();
$pdo = new PDO('mysql:host=127.0.0.1;dbname=test', 'root', '');
if (!isset($_SESSION['counted'])) {
$pdo->exec('UPDATE stats SET total = total + 1 WHERE id = 1');
$_SESSION['counted'] = true;
}
$row = $pdo->query('SELECT total FROM stats WHERE id = 1')->fetch();
echo '总首次会话数:' . $row['total'];
?>
只要抓住“session标记首次”这个核心,无论用文件、数据库还是缓存,都能稳定实现仅首次会话计数。