首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 線上人數統計:檔案屬性 + Session 實現輕量級即時計數

     編輯:PHP 綜合知識

設計思路:以檔案系統為「即時資料庫」

傳統線上人數統計常用資料庫 `UPDATE` 計數器或 Memcached/Redis 原子操作。本文提出**零依賴、極簡部署**方案:

  • 每位訪客建立一個**以 Session ID 命名的空檔案**於 `online/` 目錄。
  • 檔案的 **修改時間 (mtime)** 代表最後活動時間。
  • 掃描目錄,**統計 mtime 在 N 分鐘內的檔案數**即為線上人數。
  • 同步清理逾期檔案,防止目錄膨脹。

完整程式碼 (已修正語法、加強健壯性)

<?php
// online_counter.php
// 置於每頁頂部 include,或納入前端控制器

// 設定
$onlineDir   = __DIR__ . '/online';   // 獨立目錄,避免干擾
$expireMinutes = 1;                   // 逾期分鐘數(可調 5~10 分鐘)
$refreshSeconds = 60 * $expireMinutes; // 前端自動重整間隔

// 1. 確保目錄存在且可寫
if (!is_dir($onlineDir)) {
    @mkdir($onlineDir, 0755, true);
    @chmod($onlineDir, 0755);
}

// 2. 啟動 Session(若未啟動)
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}
$sessionId = session_id();

// 3. 建立/更新當前訪客檔案
$myFile = $onlineDir . '/' . $sessionId;
@touch($myFile); // 建立或更新 mtime 為現在

// 4. 掃描目錄統計線上人數
$onlineCount = 0;
$now = time();
$expireTime = $now - ($expireMinutes * 60);

if ($handle = @opendir($onlineDir)) {
    while (($file = readdir($handle)) !== false) {
        if ($file === '.' || $file === '..') continue;
        $filePath = $onlineDir . '/' . $file;
        // 僅統計一般檔案,排除子目錄
        if (!is_file($filePath)) continue;

        $mtime = @filemtime($filePath);
        if ($mtime !== false && $mtime >= $expireTime) {
            $onlineCount++;
        } else {
            // 逾期檔案立即刪除(掃描順便清理)
            @unlink($filePath);
        }
    }
    closedir($handle);
}

// 5. 輸出結果(可根據需求調整格式)
// 扣除自己?視定義而定。這裡顯示含自己。
header('Content-Type: text/html; charset=utf-8');
echo "當前在線 $onlineCount 人";

// 6. 前端自動重整(簡易輪詢)
echo "";
?>

關鍵技術細節

1. 為什麼用 `touch()` 而非 `fopen/fwrite/fclose`?

  • `touch()` 單一系統呼叫更新 `mtime`(若檔案不存在則建立),原子性較好、程式碼最簡潔。
  • 檔案內容為空,**零磁碟空間佔用**(僅 inode + 目錄項)。

2. Session ID 做檔名的優缺點

3. 競態條件與鎖機制

極高併發下,`opendir`/`readdir` 遍歷中可能有新檔案建立/刪除,導致計數 ±1。可接受誤差。若需嚴格準確:

$lockFile = fopen($onlineDir . '/.lock', 'w');
flock($lockFile, LOCK_EX);
// 掃描與清理...
flock($lockFile, LOCK_UN);
fclose($lockFile);

4. 分散式部署擴展:NFS / GlusterFS / Redis 替代

  • 多台 Web 伺服器共享 `online/` 目錄 → 掛載共享儲存 (NFS/GlusterFS/CEPH),**但檔案鎖在網路檔案系統常不可靠**。
  • 推薦改用 **Redis Sorted Set**:`ZADD online:{date} {timestamp} {session_id}`,`ZREMRANGEBYSCORE` 清理、`ZCARD` 統計,毫秒級、原生分散式、支援集群。

進階功能擴展

顯示線上用戶清單(若 Session 存有用戶資訊)

// 掃描階段額外讀取 Session 檔案 (預設 /var/lib/php/session/sess_{id})
$users = [];
if ($mtime >= $expireTime) {
    $sessFile = session_save_path() . '/sess_' . $file;
    if (is_file($sessFile)) {
        $sessData = @file_get_contents($sessFile);
        if ($sessData) {
            session_decode($sessData); // 解碼到 $_SESSION
            if (!empty($_SESSION['username'])) {
                $users[] = $_SESSION['username'];
            }
        }
    }
}
// 輸出 $users 陣列

統計各頁面線上人數

  • 在每頁記錄 `$_SERVER['REQUEST_URI']` 到 Session。
  • 掃描時聚合統計。

效能基準與適用界限

優點缺點/風險
天然唯一、無需額外產生 IDSession ID 可能被竄改/固定 (Session Fixation),需配合 `session_regenerate_id(true)` 登入時重生
自動綁定瀏覽器關閉失效 (Session Cookie)若用戶禁用 Cookie、使用無痕模式,可能頻繁產生新檔案造成計數偏高
無需資料庫連線高併發 (萬級同時在線) 時目錄掃描 `readdir` 成為瓶頸
同時在線掃描耗時 (SSD)建議方案
< 1,000< 5 ms本方案完美適用
1,000 ~ 10,00010 ~ 50 ms可接受,建議加鎖、增加快取層
10,000 ~ 50,00050 ~ 200 ms建議遷移 Redis Sorted Set
> 50,000> 200 ms必須用 Redis / 專用即時統計服務

部署檢查清單

  1. [ ] `online/` 目錄存在、Web 使用者可讀寫執行 (`chown www-data:www-data online`, `chmod 755`)。
  2. [ ] `session.save_path` 目錄權限正確、定期清理 (GC)。
  3. [ ] `php.ini` 設定 `session.gc_maxlifetime` ≥ 前端重整間隔,避免 Session 早於檔案過期。
  4. [ ] 生產環境關閉 `display_errors`,啟用 `error_log` 記錄異常。
  5. [ ] 監控 `online/` 目錄 inode 使用量 (`df -i`),防止 inode 耗盡。

總結

「檔案 mtime + Session ID」是**最小可行性線上計數器**:零依賴、秒級部署、程式碼 < 30 行、維護成本極低。適合中小型站點、內部系統、快速原型。隨著流量增長,平滑遷移至 **Redis Sorted Set** 或 **專用即時分析系統 (如 ClickHouse、Apache Druid)**,核心邏輯「時間窗口內唯一標識計數」完全可復用。理解此模式,本質是掌握**「以時間為維度的集合運算」**——這正是所有即時統計系統的數學骨架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved