如何统计我网站的独立访客数量?

32

我正在为用户发布的文章制作一个访客计数系统,以显示首页上最受欢迎的文章。我现在有一个访客计数系统,但是它只会在每次页面刷新时注册一次视图。我不能使用Google Analytics。

我需要的是一个只计算独立访客的访客计数器。在我的情况下,独立访客指的是一个人在一天内只能查看一篇文章。即使一周也可以,我想。你能在这里写出那个PHP代码吗?如果你想的话,你还可以给我一些好的教程链接。

这是代码需要执行的操作(或等效操作):

  1. 页面加载后,检查访问者是新的还是旧的(我不知道如何做...)
  2. 如果他是旧的,忽略他
  3. 如果他是新的,在mysql中,views = views + 1

可能基于IP地址,您可以进行检查! - Deepanshu Goyal
1
@mihai 我觉得如果我阅读代码,理解起来会更容易。如果你不这么认为,我告诉你,你可以链接一些教程给我。如果你有耐心,请教我如何做我需要做的事情。 - Nirav
5个回答

25

这是一个很好的教程,它就是你需要的。 (来源:coursesweb.net/php-mysql

注册并显示在线用户和访客

使用MySQL表计算在线用户和访客数量

在本教程中,您可以学习如何注册、计数和在网页中显示在线用户和访客数量。 原理是这样的:每个用户/访客都在文本文件或数据库中注册。每次访问网站的页面时,php脚本会删除所有早于某个时间(例如2分钟)的记录,添加当前用户/访客,并获取剩余记录数以显示。

您可以将在线用户和访客存储在服务器上的文件中,也可以存储在MySQL表中。 在这种情况下,我认为使用文本文件来添加和读取记录比将它们存储到需要更多请求的MySQL表中更快。

首先介绍在服务器上记录文本文件的方法,然后介绍使用MySQL表的方法。

要下载本教程中提供的脚本文件,请单击 -> 计算在线用户和访客

• 这两个脚本都可以包含在“ .php”文件中(使用include())或“ .html”文件中(使用<script>),正如您可以在本页底部的示例中看到的; 但是服务器必须运行PHP。

将在线用户和访客存储在文本文件中

要使用PHP在服务器上的文件中添加记录,必须将CHMOD 0766(或CHMOD 0777)权限设置为该文件,以便PHP可以在其中写入数据。

  1. 在服务器上创建一个文本文件(例如,命名为userson.txt),并给它CHMOD 0777权限(在FTP应用程序中,右键单击该文件,选择属性,然后选择读取写入执行选项)。
  2. 创建一个PHP文件(命名为usersontxt.php),具有以下代码,然后将此php文件复制到与userson.txt相同的目录中。

usersontxt.php的代码:

<?php
// Script Online Users and Visitors - http://coursesweb.net/php-mysql/
if(!isset($_SESSION)) session_start();        // start Session, if not already started

$filetxt = 'userson.txt';  // the file in which the online users /visitors are stored
$timeon = 120;             // number of secconds to keep a user online
$sep = '^^';               // characters used to separate the user name and date-time
$vst_id = '-vst-';        // an identifier to know that it is a visitor, not logged user

/*
 If you have an user registration script,
 replace $_SESSION['nume'] with the variable in which the user name is stored.
 You can get a free registration script from:  http://coursesweb.net/php-mysql/register-login-script-users-online_s2
*/

// get the user name if it is logged, or the visitors IP (and add the identifier)

    $uvon = isset($_SESSION['nume']) ? $_SESSION['nume'] : $_SERVER['SERVER_ADDR']. $vst_id;

$rgxvst = '/^([0-9\.]*)'. $vst_id. '/i';         // regexp to recognize the line with visitors
$nrvst = 0;                                       // to store the number of visitors

// sets the row with the current user /visitor that must be added in $filetxt (and current timestamp)

    $addrow[] = $uvon. $sep. time();

// check if the file from $filetxt exists and is writable

    if(is_writable($filetxt)) {
      // get into an array the lines added in $filetxt
      $ar_rows = file($filetxt, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
      $nrrows = count($ar_rows);

            // number of rows

  // if there is at least one line, parse the $ar_rows array

      if($nrrows>0) {
        for($i=0; $i<$nrrows; $i++) {
          // get each line and separate the user /visitor and the timestamp
          $ar_line = explode($sep, $ar_rows[$i]);
      // add in $addrow array the records in last $timeon seconds
          if($ar_line[0]!=$uvon && (intval($ar_line[1])+$timeon)>=time()) {
            $addrow[] = $ar_rows[$i];
          }
        }
      }
    }

$nruvon = count($addrow);                   // total online
$usron = '';                                    // to store the name of logged users
// traverse $addrow to get the number of visitors and users
for($i=0; $i<$nruvon; $i++) {
 if(preg_match($rgxvst, $addrow[$i])) $nrvst++;       // increment the visitors
 else {
   // gets and stores the user's name
   $ar_usron = explode($sep, $addrow[$i]);
   $usron .= '<br/> - <i>'. $ar_usron[0]. '</i>';
 }
}
$nrusr = $nruvon - $nrvst;              // gets the users (total - visitors)

// the HTML code with data to be displayed
$reout = '<div id="uvon"><h4>Online: '. $nruvon. '</h4>Visitors: '. $nrvst. '<br/>Users: '. $nrusr. $usron. '</div>';

// write data in $filetxt
if(!file_put_contents($filetxt, implode("\n", $addrow))) $reout = 'Error: Recording file not exists, or is not writable';

// if access from <script>, with GET 'uvon=showon', adds the string to return into a JS statement
// in this way the script can also be included in .html files
if(isset($_GET['uvon']) && $_GET['uvon']=='showon') $reout = "document.write('$reout');";

echo $reout;             // output /display the result
?>
  1. 如果您想在“.php”文件中包含上述脚本,请在要显示在线用户和访问者数量的位置添加以下代码:

4. 要在“.html”文件中显示在线访问者/用户数量,请使用此代码:

<script type="text/javascript" src="usersontxt.php?uvon=showon"></script>

这个脚本(和下面呈现的其他脚本)使用 $_SESSION。在使用它的 PHP 文件开头,您必须添加: session_start();。 计算在线用户和访客数量并将其存储到 MySQL 表中

要注册、计算和显示 MySQL 表中在线访问者和用户的数量,需要执行三个 SQL 查询: 1. 删除早于某个时间的记录。 2. 插入具有新用户/访问者或更新其列中的时间戳的行(如果已插入)。 3. 选择其余行。

以下是使用 MySQL 表(名为“userson”)存储和显示在线用户和访客的脚本的代码:

  1. 首先,我们创建“userson”表,其中包含 2 个列(uvon、dt)。在“uvon”列中,存储用户的名称(如果已登录)或访问者的 IP。在“dt”列中,存储页面访问时的时间戳(Unix 时间)。
  • 在 PHP 文件中添加以下代码(例如,命名为“create_userson.php”):

create_userson.php 的代码:

<?php
header('Content-type: text/html; charset=utf-8');

// HERE add your data for connecting to MySQ database
$host = 'localhost';           // MySQL server address
$user = 'root';                // User name
$pass = 'password';            // User`s password
$dbname = 'database';          // Database name

// connect to the MySQL server
$conn = new mysqli($host, $user, $pass, $dbname);

// check connection
if (mysqli_connect_errno()) exit('Connect failed: '. mysqli_connect_error());

// sql query for CREATE "userson" TABLE
$sql = "CREATE TABLE `userson` (
 `uvon` VARCHAR(32) PRIMARY KEY,
 `dt` INT(10) UNSIGNED NOT NULL
 ) CHARACTER SET utf8 COLLATE utf8_general_ci"; 

// Performs the $sql query on the server to create the table
if ($conn->query($sql) === TRUE) echo 'Table "userson" successfully created';
else echo 'Error: '. $conn->error;

$conn->close();
?>
  1. 现在我们创建一个脚本,可以在userson表中插入、删除和选择数据(有关代码的解释,请参见脚本中的注释)。
  • 将以下代码添加到另一个名为usersmysql.php的php文件中: 在两个文件中,您必须添加用于连接到MySQL数据库的个人数据,在变量$host$user$pass$dbname中。

usersmysql.php的代码:

<?php
// Script Online Users and Visitors - coursesweb.net/php-mysql/
if(!isset($_SESSION)) session_start();         // start Session, if not already started

// HERE add your data for connecting to MySQ database
$host = 'localhost';           // MySQL server address
$user = 'root';                // User name
$pass = 'password';            // User`s password
$dbname = 'database';          // Database name

/*
 If you have an user registration script,
 replace $_SESSION['nume'] with the variable in which the user name is stored.
 You can get a free registration script from:  http://coursesweb.net/php-mysql/register-login-script-users-online_s2
*/

// get the user name if it is logged, or the visitors IP (and add the identifier)
$vst_id = '-vst-';         // an identifier to know that it is a visitor, not logged user
$uvon = isset($_SESSION['nume']) ? $_SESSION['nume'] : $_SERVER['SERVER_ADDR']. $vst_id;

$rgxvst = '/^([0-9\.]*)'. $vst_id. '/i';         // regexp to recognize the rows with visitors
$dt = time();                                    // current timestamp
$timeon = 120;             // number of secconds to keep a user online
$nrvst = 0;                                     // to store the number of visitors
$nrusr = 0;                                     // to store the number of usersrs
$usron = '';                                    // to store the name of logged users

// connect to the MySQL server
$conn = new mysqli($host, $user, $pass, $dbname);

// Define and execute the Delete, Insert/Update, and Select queries
$sqldel = "DELETE FROM `userson` WHERE `dt`<". ($dt - $timeon);
$sqliu = "INSERT INTO `userson` (`uvon`, `dt`) VALUES ('$uvon', $dt) ON DUPLICATE KEY UPDATE `dt`=$dt";
$sqlsel = "SELECT * FROM `userson`";

// Execute each query
if(!$conn->query($sqldel)) echo 'Error: '. $conn->error;
if(!$conn->query($sqliu)) echo 'Error: '. $conn->error;
$result = $conn->query($sqlsel);

// if the $result contains at least one row
if ($result->num_rows > 0) {
  // traverse the sets of results and set the number of online visitors and users ($nrvst, $nrusr)
  while($row = $result->fetch_assoc()) {
    if(preg_match($rgxvst, $row['uvon'])) $nrvst++;       // increment the visitors
    else {
      $nrusr++;                   // increment the users
      $usron .= '<br/> - <i>'.$row['uvon']. '</i>';          // stores the user's name
    }
  }
}

$conn->close();                  // close the MySQL connection

// the HTML code with data to be displayed
$reout = '<div id="uvon"><h4>Online: '. ($nrusr+$nrvst). '</h4>Visitors: '. $nrvst. '<br/>Users: '. $nrusr. $usron. '</div>';

// if access from <script>, with GET 'uvon=showon', adds the string to return into a JS statement
// in this way the script can also be included in .html files
if(isset($_GET['uvon']) && $_GET['uvon']=='showon') $reout = "document.write('$reout');";

echo $reout;             // output /display the result
?>
  1. 在您的服务器上创建这两个php文件后,在浏览器上运行"create_userson.php"以创建"userson"表格。

  2. usersmysql.php文件包含在要显示在线用户和访问者数量的php文件中。

  3. 或者,如果您想要在".html"文件中插入它,请添加此代码:

使用这些脚本的示例

• 在php文件中包含"usersontxt.php":

<!doctype html>


计算在线用户和访问者数量

• 在html文件中包含"usersmysql.php":

<!doctype html>
<html>
<head>
 <meta charset="utf-8" />
 <title>Counter Online Users and Visitors</title>
 <meta name="description" content="PHP script to count and show the number of online users and visitors" />
 <meta name="keywords" content="online users, online visitors" />
</head>
<body>

<!-- Includes the script ("usersontxt.php", or "usersmysql.php") -->
<script type="text/javascript" src="usersmysql.php?uvon=showon"></script>

</body>
</html>

无论是将数据存储到服务器的文本文件中还是存储到MySQL表中,两个脚本都会显示如下结果:

在线人数:5

访客数量:3
用户数量:2

  • MarPlo
  • Marius

有一部分,我不太清楚的是,为什么我们需要删除访问时间少于某个特定时间的访客? - Cloud
1
@Cloud 如果您需要从特定时间开始计算访问者数量。 - Mihai
我使用了PHP部分,没有MySQL表格,它只显示始终为1的访客。 - Empire of E
在这一行代码中 "$uvon = isset($_SESSION['nume']) ? $_SESSION['nume'] : $_SERVER['SERVER_ADDR']. $vst_id; " 为什么要记录自己的服务器地址来追踪访问者? - MaXi32
@Mihai - 如果您在格式化方面付出了一些努力,而不是只从其他地方复制/粘贴,那么这个答案的得分会有多高,想象一下。 - ashleedawg

20

独立访客数量始终是个难题。 检查IP地址可能有效,但是一个IP地址可能被多个用户共享。Cookie可以是可行的选择,但是Cookie可能会过期或被客户端修改。

在您的情况下,如果Cookie被修改似乎并不是什么大问题,所以我建议在这种情况下使用Cookie。 当页面加载时,检查是否存在Cookie,如果不存在,则创建一个Cookie并将访问量增加1。如果已经设置了Cookie,则不进行+1操作。

将Cookie的过期日期设置为您想要的时间,比如一周或一天,并在此后过期。到达过期日期后,它将再次成为独立的用户!


编辑:
认为在这里添加此通知可能是个好主意...
自2016年底以来,欧盟将IP地址(静态或动态)视为个人数据。
这意味着你只能有很好的理由存储IP地址(我不确定跟踪访问量是否是一个好的理由)。因此,如果您打算存储访问者的IP地址,我建议对其进行哈希或加密,使用无法反向的算法,以确保您不会违反任何法律(特别是在实施GDPR法规之后)。


1
YouTube也使用cookies吗? - Nirav
我不知道他们是否使用它们来跟踪页面浏览量。 - Jite
如果同一张表正在被多个用户用于另一个select查询,递增计数器会导致死锁吗?视图计数器应该存储在同一张表中还是单独的表中? - Rami Zebian
老实说,我不确定是否存在死锁的风险,但我猜可能有一点风险。 更新查询应该只需要很少的时间,如果使用事务,那么死锁就不会发生(至少在我记得的InnoDB中如此!)。 - Jite

7
我已经编辑了“最佳答案”的代码,但我发现有一些有用的东西缺失了。这也可以追踪用户的IP地址,如果他们使用代理或者服务器安装了nginx作为反向代理。我在函数顶部添加了以下代码:
function getRealIpAddr()
{
    if (!empty($_SERVER['HTTP_CLIENT_IP']))   //check ip from share internet
    {
      $ip=$_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //to check ip is pass from proxy
    {
      $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else
    {
      $ip=$_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}
$adresseip = getRealIpAddr();

在那之后,我修改了他的代码。
找到以下这行代码:
// get the user name if it is logged, or the visitors IP (and add the identifier)

    $uvon = isset($_SESSION['nume']) ? $_SESSION['nume'] : $_SERVER['SERVER_ADDR']. $vst_id;

将其替换为以下内容:

$uvon = isset($_SESSION['nume']) ? $_SESSION['nume'] : $adresseip. $vst_id;

这将起作用。

如果发生任何事情,以下是完整的代码:

<?php

function getRealIpAddr()
{
    if (!empty($_SERVER['HTTP_CLIENT_IP']))   //check ip from share internet
    {
      $ip=$_SERVER['HTTP_CLIENT_IP'];
    }
    elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))   //to check ip is pass from proxy
    {
      $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
    }
    else
    {
      $ip=$_SERVER['REMOTE_ADDR'];
    }
    return $ip;
}
$adresseip = getRealIpAddr();

// Script Online Users and Visitors - http://coursesweb.net/php-mysql/
if(!isset($_SESSION)) session_start();        // start Session, if not already started

$filetxt = 'userson.txt';  // the file in which the online users /visitors are stored
$timeon = 120;             // number of secconds to keep a user online
$sep = '^^';               // characters used to separate the user name and date-time
$vst_id = '-vst-';        // an identifier to know that it is a visitor, not logged user

/*
 If you have an user registration script,
 replace $_SESSION['nume'] with the variable in which the user name is stored.
 You can get a free registration script from:  http://coursesweb.net/php-mysql/register-login-script-users-online_s2
*/

// get the user name if it is logged, or the visitors IP (and add the identifier)

    $uvon = isset($_SESSION['nume']) ? $_SESSION['nume'] : $_SERVER['SERVER_ADDR']. $vst_id;

$rgxvst = '/^([0-9\.]*)'. $vst_id. '/i';         // regexp to recognize the line with visitors
$nrvst = 0;                                       // to store the number of visitors

// sets the row with the current user /visitor that must be added in $filetxt (and current timestamp)

    $addrow[] = $uvon. $sep. time();

// check if the file from $filetxt exists and is writable

    if(is_writable($filetxt)) {
      // get into an array the lines added in $filetxt
      $ar_rows = file($filetxt, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
      $nrrows = count($ar_rows);

            // number of rows

  // if there is at least one line, parse the $ar_rows array

      if($nrrows>0) {
        for($i=0; $i<$nrrows; $i++) {
          // get each line and separate the user /visitor and the timestamp
          $ar_line = explode($sep, $ar_rows[$i]);
      // add in $addrow array the records in last $timeon seconds
          if($ar_line[0]!=$uvon && (intval($ar_line[1])+$timeon)>=time()) {
            $addrow[] = $ar_rows[$i];
          }
        }
      }
    }

$nruvon = count($addrow);                   // total online
$usron = '';                                    // to store the name of logged users
// traverse $addrow to get the number of visitors and users
for($i=0; $i<$nruvon; $i++) {
 if(preg_match($rgxvst, $addrow[$i])) $nrvst++;       // increment the visitors
 else {
   // gets and stores the user's name
   $ar_usron = explode($sep, $addrow[$i]);
   $usron .= '<br/> - <i>'. $ar_usron[0]. '</i>';
 }
}
$nrusr = $nruvon - $nrvst;              // gets the users (total - visitors)

// the HTML code with data to be displayed
$reout = '<div id="uvon"><h4>Online: '. $nruvon. '</h4>Visitors: '. $nrvst. '<br/>Users: '. $nrusr. $usron. '</div>';

// write data in $filetxt
if(!file_put_contents($filetxt, implode("\n", $addrow))) $reout = 'Error: Recording file not exists, or is not writable';

// if access from <script>, with GET 'uvon=showon', adds the string to return into a JS statement
// in this way the script can also be included in .html files
if(isset($_GET['uvon']) && $_GET['uvon']=='showon') $reout = "document.write('$reout');";

echo $reout;             // output /display the result

我还没有在Sql脚本上进行测试。


7

为了判断用户是新用户还是老用户,请获取用户IP。

创建一个IP和访问时间戳的表格。

检查IP不存在time()-saved_timestamp > 60*60*24(1天)时,编辑IP的时间戳为time()(当前时间),并增加浏览量。

否则,不做任何操作。

提示:用户IP存储在$_SERVER['REMOTE_ADDR']变量中。


2
当多个用户共享一个IP地址时,例如那些在公司防火墙后面的用户,此方法将无法工作。 - demisx
当多个用户共享一个IP时,请问有什么解决方法? - John Max

3
$user_ip=$_SERVER['REMOTE_ADDR'];

$check_ip = mysql_query("select userip from pageview where page='yourpage'  and userip='$user_ip'");
if(mysql_num_rows($check_ip)>=1)
{

}
else
{
  $insertview = mysql_query("insert into pageview values('','yourpage','$user_ip')");

  $updateview = mysql_query("update totalview set totalvisit = totalvisit+1 where page='yourpage' ");
}

这是来自TalkersCode官方教程的代码,如果您有任何问题,请访问http://talkerscode.com/webtricks/create-a-simple-pageviews-counter-using-php-and-mysql.php


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接