网页浏览量

首页 博客

时间:2025年2月27日 浏览量:Loading…

一直以来,想给网页加上一个浏览量统计访问次数,正好今天小朋友忙着画画,自己抽时间来完成这个事情。这里想通过一个网页浏览量统计系统,并通过数据库MySQL来实现存储和读取。

数据库创建

简单的网页可能只需要统计访问量。若是想对访问量做进一步分析,可以存储更多的信息,比如访问IP地址、客户端、HTTP来源等。以下是创建表格的shema文件create_tables.sql

-- Table to store aggregated page view data; create this table first --
CREATE TABLE page_views (
    page_url VARCHAR(255) NOT NULL PRIMARY KEY, -- unique url
    view_count INT DEFAULT 0, -- total view count
    unique_ip_count INT DEFAULT 0, -- unique ip count
    unique_user_agent_count INT DEFAULT 0, -- browser, device, OS, engine, etc.
    unique_referrer_count INT DEFAULT 0, -- HTTP Referer
    last_view TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Table to store unique IP addresses per page --
CREATE TABLE page_view_ips (
    page_url VARCHAR(255) NOT NULL, -- page url
    ip_address VARCHAR(45) NOT NULL, -- unique IP address
    view_count INT DEFAULT 1, -- number of views from an IP
    PRIMARY KEY (page_url, ip_address), -- ensures each IP is only stored once per page
    FOREIGN KEY (page_url) REFERENCES page_views(page_url) ON DELETE CASCADE -- deletes IP records if the page is removed
);

-- Table to store unique User-Agent views with a count --
CREATE TABLE page_view_user_agents (
    page_url VARCHAR(255) NOT NULL, -- Page URL
    user_agent VARCHAR(255) NOT NULL, -- Unique User-Agent string
    view_count INT DEFAULT 1, -- Number of views from this User-Agent
    PRIMARY KEY (page_url, user_agent), -- Prevents duplicate entries per page
    FOREIGN KEY (page_url) REFERENCES page_views(page_url) ON DELETE CASCADE -- Cascades deletion
);

-- Table to store unique Referrer views with a count --
CREATE TABLE page_view_referrers (
    page_url VARCHAR(255) NOT NULL, -- Page URL
    referrer VARCHAR(255) NOT NULL, -- Unique Referrer URL
    view_count INT DEFAULT 1, -- Number of views from this Referrer
    PRIMARY KEY (page_url, referrer), -- Prevents duplicate entries per page
    FOREIGN KEY (page_url) REFERENCES page_views(page_url) ON DELETE CASCADE -- Cascades deletion
);

在MySQL运行的情况下,执行:

mysql -u your_username -p -D your_database_name < create_tables.sql

PHP处理页面

这里创建了一个PHP处理页面文件track_views.php,以便获取当前URL、检查更新数据库、并返回浏览量。同时,为了避免一些重复统计,对可能的同一访问做了限制。

<?php

// ======== Configurations ========

$rate_limit_time = 60; // seconds per request from the same IP + User-Agent

// ======== Database connection ========

$env = parse_ini_file('/var/www/config/.env');
$servername = $env['DB_HOST'];
$username = $env['DB_USER'];
$password = $env['DB_PASSWORD'];
$dbname = $env['DB_NAME'];

$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// ======== Communicate with database  ========

session_start(); // Use session to store rate-limit cache

// Detect the correct page URL:
if (isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER'])) {
    $page_url = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_PATH); // Get the referring page path
} else {
    $page_url = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); // Get the current PHP file path
}

// Ensure the page_url always starts with a single leading slash
$page_url = '/' . ltrim($page_url, '/');

// Include the full domain in the page URL
$page_url = $_SERVER['HTTP_HOST'] . $page_url;

$page_url = $conn->real_escape_string($page_url); // Prevent SQL injection

// Get user details
$ip_address = $_SERVER['REMOTE_ADDR'] === '::1' ? '127.0.0.1' : $_SERVER['REMOTE_ADDR'];
$ip_address = $conn->real_escape_string($ip_address);

$user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $conn->real_escape_string($_SERVER['HTTP_USER_AGENT']) : 'Unknown';
$referrer = isset($_SERVER['HTTP_REFERER']) ? $conn->real_escape_string($_SERVER['HTTP_REFERER']) : '';

$hash_key = md5($ip_address . $user_agent); // Create a unique hash for the user

// ======== Fetch Latest View Count Before Rate Limiting ========
$result = $conn->query("SELECT view_count FROM page_views WHERE page_url = '$page_url'");
$row = $result->fetch_assoc();
$current_view_count = $row ? $row['view_count'] : 1;

// ======== Rate Limiting (Prevent Excessive DB Writes) ========

if (isset($_SESSION['last_request'][$hash_key]) && (time() - $_SESSION['last_request'][$hash_key]) < $rate_limit_time) {
    echo $current_view_count;
    $conn->close();
    exit();
}
$_SESSION['last_request'][$hash_key] = time(); // Update last request timestamp

// ======== Database Update ========

$conn->begin_transaction();

// -- Update Total View Count --
$conn->query("
    INSERT INTO page_views (page_url, view_count)
    VALUES ('$page_url', 1)
    ON DUPLICATE KEY UPDATE view_count = view_count + 1
");

// -- Update Unique IP Count --

$conn->query("
    INSERT INTO page_view_ips (page_url, ip_address, view_count)
    VALUES ('$page_url', '$ip_address', 1)
    ON DUPLICATE KEY UPDATE view_count = view_count + 1
");

// Increment unique IP count only for first-time visits
$conn->query("
    UPDATE page_views 
    SET unique_ip_count = unique_ip_count + 1 
    WHERE page_url = '$page_url' 
    AND NOT EXISTS (SELECT 1 FROM page_view_ips WHERE page_url = '$page_url' AND ip_address = '$ip_address')
");

// -- Update Unique User-Agent Count --

$conn->query("
    INSERT INTO page_view_user_agents (page_url, user_agent, view_count)
    VALUES ('$page_url', '$user_agent', 1)
    ON DUPLICATE KEY UPDATE view_count = view_count + 1
");

// Increment unique user-agent count only for first-time visits
$conn->query("
    UPDATE page_views 
    SET unique_user_agent_count = unique_user_agent_count + 1 
    WHERE page_url = '$page_url' 
    AND NOT EXISTS (SELECT 1 FROM page_view_user_agents WHERE page_url = '$page_url' AND user_agent = '$user_agent')
");

// -- Update Unique Referrer Count --
if (!empty($referrer)) {
    $conn->query("
        INSERT INTO page_view_referrers (page_url, referrer, view_count)
        VALUES ('$page_url', '$referrer', 1)
        ON DUPLICATE KEY UPDATE view_count = view_count + 1
    ");

    // Increment unique referrer count only for first-time visits
    $conn->query("
        UPDATE page_views 
        SET unique_referrer_count = unique_referrer_count + 1 
        WHERE page_url = '$page_url' 
        AND NOT EXISTS (SELECT 1 FROM page_view_referrers WHERE page_url = '$page_url' AND referrer = '$referrer')
    ");
}

// Commit transaction
$conn->commit();

// ======== Results from database ========

// Fetch latest view count
$result = $conn->query("SELECT view_count FROM page_views WHERE page_url = '$page_url'");
$row = $result->fetch_assoc();
echo $row ? $row['view_count'] : 1;

$conn->close();
?>

为了保证MySQL数据库的安全访问,可将相关信息存储在/var/www/config/.env的文件里。

DB_HOST=localhost
DB_USER=username
DB_PASSWORD=password
DB_NAME=database

网页加载浏览量

在网页.html文件的head里面通过JavaScript加载PHP页面处理文件。

<script>
      document.addEventListener("DOMContentLoaded", function() {
        fetch('/track_views.php', { credentials: 'include' })
          .then(response => response.text())
          .then(viewCount => {
            console.log("Page View Count:", viewCount);
            let viewElement = document.getElementById("page-views");
            if (viewElement) {
              viewElement.textContent = "浏览量: " + viewCount;
            }
          })
          .catch(error => console.error("Error fetching page views:", error));
      });
    </script>

同时,在HTML页面中显示浏览量:

<p id="page-views" style="text-align: center; font-size: 20px; font-weight: bold; margin-top: 20px;">浏览量:Loading...</p>

测试

为了使以上PHP页面处理可以正常工作,要确保php server是运行的。对于本地的测试,php已经安装运行,可以采用: php -S localhost:8000 比如,对于同一文件夹下的index.html文件,可在浏览器中打开: <http://localhost:8000/index.html

对于远端网页server上的测试,要确保/var/www/config/.env可以被server自身访问,但要保护其信息不被泄露。

此外,要结合数据库里的存储信息,检验是否正确存储和读取。以上网页浏览量统计系统适用于多个页面的访问统计。