php 防止多次刷新以依赖统计脚本

qyzbxkaa  于 2023-01-24  发布在  PHP
关注(0)|答案(2)|浏览(97)

我正在做一个项目,其中一个Web应用程序将以某种方式JavaScript代码收集有关访问者的统计信息,但据我所知,在服务器端PHP应用程序,我应该以某种方式处理代码,多刷新不计数和计数的IP为基础是不是一个好主意,因为许多用户可能有相同的IP,cookie或会话也容易受到此问题的攻击,因为cookie管理器可以清除与站点相关的所有cookie,这样PHP就无法识别用户并将其视为新用户,时间框架作业和所有其它解决该问题方法也是据我所知基于cookie或会话或IP或IP/引用者和来自报头的所有其它可用数据的混合,我怎么能处理它,从用户那里得到更可靠的数据,不允许他们创建虚假的统计数据。因为我相信一定有办法(我希望如此)...!

w46czmvw

w46czmvw1#

我认为cookie是解决这类问题的理想选择,但如果你不想使用它,那么你就有了一个很坚韧的cookie。不幸的是,由于HTTP是无状态的,你没有太多其他的选择。
在这种情况下,我会使用session vars,因为用户不能干预保存在那里的数据,但是存在会话劫持的风险。但是如果你的网站有这个漏洞,你需要考虑在一个更全球化的层面上保护网站,而不仅仅是点击计数器。会话变量被绑定到你的网站,因为其中的数据被保存在服务器上,而不是用户的浏览器中。并且绑定到您的用户,因为它在用户的浏览器中保存了一个带有密钥的cookie,以便从服务器请求数据。
下面是一个示例,说明如何实现这一点,而不必担心删除站点上的其他会话。

<?php
function hit_counter() {
    if(isset($_SESSION['hit_counter'])) { // Check if the user has the hit_counter session
        if(isset($_SESSION['hit_counter']['time']) && isset($_SESSION['hit_counter']['page'])) { // Check if the user has the time and the page set from the last visit
            $last_time = $_SESSION['hit_counter']['time'];
            $last_page = $_SESSION['hit_counter']['page'];

            $now = time(); // The current UNIX time stamp in seconds
            $current_page = $_SERVER['REQUEST_URI']; // The page name

            /*
                If the users hasn't requested this page
                in the last 10 seconds or if the user 
                comes from another page increment the 
                hit counter
            */
            if(($now - $last_time) > 10 || $last_page != $current_page) {
                /* INCREMENT YOUR HIT COUNTER HERE */
            }
        }

        unset($_SESSION['hit_counter']); // Delete this hit counter session
    }

    // And create a new hit counter session
    $_SESSION['hit_counter'] = array();
    $_SESSION['hit_counter']['time'] = time();
    $_SESSION['hit_counter']['page'] = $_SERVER['REQUEST_URI'];
}
?>

因为你只是在使用unset()这个计数器变量,所以你永远不会触及任何其他的会话变量。你不需要处理session_destroy(),但是你需要确保在你想使用函数的每一个页面的开头都有一个session_start()
如果您只想计算用户来自站点上其他页面的点击数,则可以编辑脚本,使其不考虑时间因素。
就我所知,这是一个对大多数网站来说安全级别合理的点击计数器,或者至少是一个好的开始。
关于PHP sessions的更多信息。

ubby3x7f

ubby3x7f2#

我创造了这个

<?php

namespace Codelaby\EventDateGenerator;

class CounterVisitors
{
    private $filename = "counter.txt";
    private $sessionId;
    private $sessionStart;

    public function __construct()
    {
        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }
        if (!isset($_SESSION['sessionId'])) {
            $this->sessionId = md5(uniqid(rand(), true));
            $_SESSION['sessionId'] = $this->sessionId;
            $this->sessionStart = time();
            $this->hitCounter();
        } else {
            $this->sessionId = $_SESSION['sessionId'];
            if (!isset($_SESSION['sessionStart'])) {
                $this->sessionStart = time();
            } else {
                $this->sessionStart = $_SESSION['sessionStart'];
            }
            if (time() - $this->sessionStart > 60) {
                $this->sessionStart = time();
                $this->hitCounter();
            }
        }
        $_SESSION['sessionStart'] = $this->sessionStart;
    }

    private function saveCounter($counter = 0)
    {
        if (!file_exists($this->filename)) {
            touch($this->filename);
        }
        $fp = fopen($this->filename, "w");
        if (!flock($fp, LOCK_EX)) {
            return;
        }
        fwrite($fp, $counter);
        flock($fp, LOCK_UN);
        fclose($fp);
    }

    public function readCounter()
    {
        if (!file_exists($this->filename)) {
            touch($this->filename);
        }
        $fp = fopen($this->filename, "r");
        if (!flock($fp, LOCK_EX)) {
            return;
        }
        $file_size = filesize($this->filename);
        if ($file_size <= 0) {
            $counter = 0;
        } else {
            $counter = intval(fread($fp, $file_size));
        }
        flock($fp, LOCK_UN);
        fclose($fp);
        return $counter;
    }

    public function hitCounter()
    {
        $counter = $this->readCounter();
        $counter++;
        $this->saveCounter($counter);
        return $counter;
    }

    public function resetCounter($counter = 0)
    {
        $this->saveCounter(0);
    }
}

如何使用

session_start() //before send headers

$counterVisitors = new CounterVisitors();
$visitors = $counterVisitors->readCounter();

echo 'visitors: ' . $visitors;

脚本生成counter.txt(如果不存在),仅在用户启动新会话或等待60秒刷新时递增访问

相关问题