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

網站流量統計計數器詳細設計與 PHP 實作

     編輯:PHP 綜合知識

設計概述

本文記錄一套完整的網站計數器系統設計,支援頁面級訪問統計、IP 級訪問分析、Session 架構下的獨立訪客識別,並提供報表生成基礎。系統採用 MySQL 儲存,核心包含兩張資料表與一個可複用的 PHP 函式庫 counter.php。

資料庫架構設計

表一:tpCounter(頁面計數表)

欄位名型別說明
idINT(10) AUTO_INCREMENT主鍵序號
pagenameVARCHAR(20)頁面唯一標識,預設為檔案名
countINT(10)累計訪問次數

特殊約定: 站級總訪問數以 pagename='0' 記錄。

表二:tiCounter(IP 計數表)

欄位名型別說明
idINT(10) AUTO_INCREMENT主鍵序號
ipVARCHAR(20)訪客 IP 位址
countINT(10)該 IP 總訪問次數
dateDATETIME最近訪問時間
pagesTEXT歷史訪問頁面 ID 序列,格式:||YYYY-MM-DD HH:MM:SS|pid1|pid2||...

核心業務邏輯

  1. Session 驅動的訪客識別: 每次頁面載入檢查 Session。新訪客(Session 不存在)觸發站級計數 +1 與頁級計數 +1;舊訪客僅頁級計數 +1(刷新亦計)。
  2. 頁面自動註冊: 若 tpCounter 無對應 pagename,自動插入新記錄。
  3. IP 行為追蹤: tiCounter 記錄每個 IP 的訪問次數、最近時間、歷史頁面軌跡(pages 欄位以 | 分隔頁面 ID,雙管線 || 分隔訪問時段)。
  4. Session 生命週期: 瀏覽器關閉導致 Session 銷毀由伺服器自動處理(PHP 預設機制)。

介面規格 (counter.php)

函式功能參數返回值
check_session()檢查/建立 Session,註冊 existing 旗標無Boolean (true=既有, false=新建)
site_count($conn)站級計數(新訪客含 IP 計數)資料庫連線站總訪問數 (int)
page_count($conn, $page_name, $flag=true)頁級計數,可選是否遞增連線, 頁面名, 旗標該頁訪問數 (int)
ip_count($conn)IP 計數與軌跡記錄(需在 page_count 前呼叫)連線IP 訪問數 (int)
show_site_count($num, $len=6, $type=2)顯示計數器(圖形/文字)數值, 長度, 類型直接輸出 HTML

執行流程

0. 權限檢查(防止直接存取 include 檔)
1. 連接資料庫
2. check_session() → 新訪客則 site_count()(內含 ip_count + 頁計數)
3. 顯示站級計數 show_site_count()
4. 若定義 $page_name → page_count() 執行頁級計數
5. 關閉資料庫連線(腳本結束自動)

完整原始碼實作 (counter.php v1.0)

<?php
/** counter.php v1.0 by Amio 2001-5-1
 *  功能:全站/單頁/IP 計數,Session 控制,圖形/文字顯示
 *  使用:各頁面頂部 require 本檔,引用前設定 $inc 變數指向 include 目錄
 */
function check_session() {
    $existing = true;
    session_start();
    if (!isset($_SESSION['existing'])) { // 現代寫法:session_is_registered 已棄用
        $_SESSION['existing'] = true;
        return false;
    }
    return true;
}

function page_count($connect, $page_name, $flag = true) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $page_name = mysql_real_escape_string($page_name, $connect); // 防注入
    $query = @mysql_query("SELECT id, count FROM tpcounter WHERE pagename='$page_name'", $connect) or die("invalid page query!");
    if (!mysql_num_rows($query)) {
        mysql_query("INSERT INTO tpcounter (pagename, count) VALUES ('$page_name', 1)", $connect) or die("insert page failed");
        $pid = mysql_insert_id($connect);
        $return_num = 1;
    } else {
        $row = mysql_fetch_assoc($query);
        $num = $row['count'];
        $pid = $row['id'];
        if ($flag) $num++;
        mysql_query("UPDATE tpcounter SET count=$num WHERE pagename='$page_name'", $connect) or die("update page failed");
        $return_num = $num;
    }
    // 記錄 IP 訪問頁面軌跡
    if ($flag) {
        $pquery = @mysql_query("SELECT pages FROM ticounter WHERE ip='$ip'", $connect) or die("invalid pages query!");
        if (mysql_num_rows($pquery)) {
            $parray = mysql_fetch_assoc($pquery);
            $pstr = $parray['pages'] . $pid . "|";
            mysql_query("UPDATE ticounter SET pages='$pstr' WHERE ip='$ip'", $connect) or die("update ip failed");
        }
    }
    return $return_num;
}

function ip_count($connect) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $visit_time = date("Y-m-d H:i:s");
    $visit_pages = "||" . $visit_time . "|";
    $ipquery = @mysql_query("SELECT count, pages FROM ticounter WHERE ip='$ip'", $connect) or die("invalid ip query!");
    if (!mysql_num_rows($ipquery)) {
        $pageStr = "|" . $visit_pages;
        mysql_query("INSERT INTO ticounter (ip, count, date, pages) VALUES ('$ip', 1, '$visit_time', '$pageStr')", $connect) or die("insert ip failed");
        return 1;
    } else {
        $parray = mysql_fetch_assoc($ipquery);
        $ipnum = $parray['count'] + 1;
        $pageStr = $parray['pages'] . $visit_pages;
        mysql_query("UPDATE ticounter SET count=$ipnum, date='$visit_time', pages='$pageStr' WHERE ip='$ip'", $connect) or die("update ip failed");
        return $ipnum;
    }
}

function site_count($connect) {
    if (!check_session()) {
        ip_count($connect);
        return page_count($connect, "website", true);
    } else {
        return page_count($connect, "website", false);
    }
}

function displayCount($num) {
    return "countpng.php?count=" . $num;
}

function show_site_count($num, $length = 6, $type = 2) {
    $outStr = str_pad((string)$num, $length, '0', STR_PAD_LEFT);
    if ($type == 1) {
        echo '<img src="' . displayCount($outStr) . '">';
    } else {
        echo $outStr;
    }
}

// 自動執行區塊(需在引用前設定 $inc 非空)
if (!isset($inc)) exit;
$connect = mysql_connect('localhost', 'root', '');
mysql_select_db('damio', $connect);
$sitecount = site_count($connect);
if (isset($page_name)) page_count($connect, $page_name);
?>

現代化改造重點

  • 資料庫層: 全面改用 PDO 預處理語句,消除 SQL 注入風險。
  • Session 管理: 使用 $_SESSION 超全域陣列,配合 session_set_save_handler 可擴展至 Redis/Memcached 叢集。
  • IP 儲存: IPv6 位址長度超過 VARCHAR(20),建議改用 VARBINARY(16) 或 VARCHAR(45)。
  • 效能優化: pages 欄位以 TEXT 追加方式寫入,長期運行會導致行體積膨脹、更新緩慢。建議拆分為獨立的 visit_log 表(ip, page_id, visit_time),並建立索引,利於分析查詢。
  • 計數器顯示: 圖形計數器 countpng.php 可替換為前端 JavaScript 從 API 取得數值後動態渲染,減少伺服器端圖片生成開銷。
  • 併發控制: 高流量下 UPDATE ... SET count=count+1 可能產生競態條件,建議使用資料庫原子操作或 Redis INCR 先行計數,定期持久化落庫。

結語

這套設計在 2001 年屬於較完整的訪問統計方案,涵蓋 Session 隔離、多維度計數、行為軌跡記錄。如今雖然底層技術棧已過時,但其核心邏輯——「以 Session 區分首次/再次訪問、以 IP 追蹤用戶軌跡、多表協同支援報表分析」——在現代分析系統(如 Google Analytics、Matomo)中依然是基石。重構時保留業務邏輯,替換底層儲存與存取層,即可平滑遷移至現代架構。

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