avatar

目录
写个网站流量统计插件

插件效果

  • 闲来无事写个简易网站流量统计插件:
  • 开发用到: php mysql js html
  • 效果如下

  • 简易的流量统计插件,数据大致参考即可,没有高级算法,仅统计下IP和PV
  • 不防刷,用软件数据分分钟刷上去
  • 插件非常轻,对网站加载速度影响大概在5ms左右

统计数据分析

  1. 今日IP
  2. 今日PV
  3. 昨日IP
  4. 昨日PV
  5. 当前在线

计算方法

如何准确获取到客户端IP

统计IP需要获取到客户端真实的IP地址,仅js实现效果并不好。在这里我采用了[搜狐]的接口

Javascript
1
<script src="https://pv.sohu.com/cityjson?ie=utf-8"></script>

将搜狐提供的js嵌入到网页,访问结果如下:

  • 直接返回了一个 returnCitySN 对象,我们可以获得准确的IP地址、cid(cid是什么给我留言)、地区
Javascript
1
var returnCitySN = {"cip": "223.241.141.73", "cid": "340000", "cname": "安徽省"};

通过returnCitySN获取ip、cname

Javascript
1
2
var ip = returnCitySN.cip;
var cname = returnCitySN.cname;

至此,IP已经拿到

后端存储方法

  • 前端将IP、cname、访问的url传输到后端

wnzz_visit表(直接存储访问记录)

键名 说明 类型
id 自动编号 int11
ip ip地址 varchar128
cname 地区 varchar255
url 访问地址 varchar255
time 访问时间戳 int11
siteid 统计站点编号 int11
  • 字段 siteid,用来标记和区分不同的站点,这样可以实现多站点统计,只需要确保siteid不重复即可

wnzz_cal表(聚合一天的数据,存储计算结果)

  • 该表的作用是,当某一天已经过去时,自动计算某一天IP和PV总值,记录在这个表中

为什么需要这个表?因为当日统计的IP和PV都是动态计算的,php从数据库读出所有访问的数据,然后再对数据进行统计,如此方法加大了服务器的开销,所以对于一些不必要的重复计算,我们计算一次,存储其即可,下次需要直接读取。

键名 说明 类型
id 自动编号 int11
timestamp 某一天0点的时间戳 int11
timestr 某一天用字符表示,例如2019-05-05 varchar255
ips IP总数 int11
pvs PV总数 int11
siteid 统计站点编号 int11

计算IP、PV

  • 首先需要确认 siteid 和统计事件的区间

    php
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <?php
    //设置北京时间为默认时区
    date_default_timezone_set('PRC');
    // 现在的时间戳
    $now = time();
    // 现在对应今日0点的时间戳
    $today = strtotime(date("Y-m-d"), $now);
    // 现在对应昨日0点的时间戳
    $yesterday = $today - 86400;
    // 现在对应明日0点的时间戳
    $tomorrow = $today + 86400;
  • 动态统计一下今天的数据,即 today<=time<tomorrow,执行如下sql语句

    sql
    1
    2
    - 原生SQL写法
    SELECT * FROM `wnzz_visit` WHERE `time`>{$today} AND `time`<{$tomorrow} AND `siteid`={$siteid};
  • 持久层框架写法(下面提供)

    php
    1
    $res_t = $bean->findByX(['ip'], "wnzz_visit", ["time>{$today}", "time<{$tomorrow}", "siteid={$siteid}"]);
  • 从数据库读出的数据形如如下:

    coq
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    datas=>[

    ["ip"=>"127.0.0.1"],

    ["ip"=>"127.0.0.1"],

    ["ip"=>"127.0.0.1"],

    ["ip"=>"127.0.0.2"],

    ["ip"=>"127.0.0.2"],

    ["ip"=>"127.0.0.2"],

    ["ip"=>"127.0.0.3"]

    ]

  • 用PHP实现
    php
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <?php
    /**
    * @return array(ips, pvs)
    */
    function cal_ipandpv($datas){
    // echo "emmm<br/>";
    // print_r($datas);
    // $ip['192.168.1.1'] = 10;
    $ip = array();
    foreach($datas as $index => $item){
    if(array_key_exists($item['ip'], $ip)){
    // 统计过
    $ip[$item['ip']] += 1;
    }else{
    // 没统计过
    $ip[$item['ip']] = 1;
    }
    }
    // 累加IP和PV
    $ips = 0;
    $pvs = 0;
    foreach($ip as $keyip => $count){
    $ips++;
    $pvs += $count;
    }
    return [$ips, $pvs];
    }

计算当前在线人数

  • 访问记录在十分钟以内的即算作在线

  • SQL语句

    sql
    1
    SELECT * FROM `wnzz_visit` WHERE `time`>{$onlineMin } AND `siteid`={$siteid};

插件总体代码实现

前端(js)

  • domain变量是后端接口地址,这里我开发用的本地IP

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // https://pv.sohu.com/cityjson?ie=utf-8
    var domain = "http://127.0.0.1/vsCode/wnzz/";
    var url = window.location.href;
    var siteid = 1000;

    $.get(domain + "?ip=" + returnCitySN["cip"] + "&cname=" + returnCitySN["cname"] + "&url=" + url + "&siteid=" + siteid, function(result){
    console.log(result);
    });

    $.get(domain + "?act=get&siteid=" + siteid, function(result){
    $("#wnzz").text(result);
    });
  • 在引入上面的脚本之前要先引入jQuery库和下面的搜狐库

    html
    1
    <script src="https://pv.sohu.com/cityjson?ie=utf-8"></script>
  • 访问结果会显示在ID为wnzz的标签中

后端

php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<?php
// ============================ //
// //
// 数据库参数配置 //
// //
// ============================ //
define("DB_HOST", "127.0.0.1");
// 数据库地址
define("DB_USER", "root");
// 数据库用户名
define("DB_PASSWD", "root");
// 数据库密码
define("DB_NAME", "wnzz");
// 数据库名
//设置北京时间为默认时区
date_default_timezone_set('PRC');
//输出当前时间
// echo date("Y-m-d H:i:s",time()); //2016-08-11 10:30:32
//获得当日凌晨的时间戳
// $today = strtotime(date("Y-m-d"),time());
require_once "./Tools.class.php";
require_once "./Bean.class.php";
/**
* ip
* cname
* url
* siteid
*/
/**
siteid
1000-1999 我的字段
*/
// 存储访客数据
if(isset($_GET['ip']) && isset($_GET['cname']) && $_GET['url'] && $_GET['siteid']) {
$ip = anti_sqlin($_GET['ip']);
$cname = anti_sqlin($_GET['cname']);
$url = anti_sqlin($_GET['url']);
$siteid = (int)$_GET['siteid'];
$bean = new Bean();
// 现在的时间戳
$now = time();
// 存储
$bean->save("wnzz_visit", ["ip={$ip}", "cname={$cname}", "url={$url}", "time={$now}", "siteid={$siteid}"]);
// 获取访问记录
} elseif(isset($_GET['act']) && $_GET['act'] == 'get' && isset($_GET['siteid'])) {
$siteid = (int)$_GET['siteid'];
// init
$y_ips = 0;
$y_pvs = 0;
$t_ips = 0;
$t_pvs = 0;
$online = 0;
$bean = new Bean();
// 现在的时间戳
$now = time();
// 现在对应今日0点的时间戳
$today = strtotime(date("Y-m-d"), $now);
// 现在对应昨日0点的时间戳
$yesterday = $today - 86400;
// 现在对应明日0点的时间戳
$tomorrow = $today + 86400;
// 查找昨天的记录
$res = $bean->findByX(['timestr', 'ips', 'pvs'], "wnzz_cal", ["timestamp={$yesterday}", "siteid={$siteid}"]);
if($res['status'] == 'data') {
// 有数据直接读
$y_ips = $res['data'][0]['ips'];
$y_pvs = $res['data'][0]['pvs'];
} else {
// 计算并存储
$res_m = $bean->findByX(['ip'], "wnzz_visit", ["time>={$yesterday}", "time<{$today}", "siteid={$siteid}"]);
$datas = $res_m['data'];
$ipsandpvs = cal_ipandpv($datas);
// 存储
// $ips
// $pvs
// $yesterday
// $yesterday_timestamp
$ips = $ipsandpvs[0];
$pvs = $ipsandpvs[1];
$yesterday_timestamp = date("Y-m-d", $yesterday);
$y_ips = $ips;
$y_pvs = $pvs;
$res1 = $bean->save("wnzz_cal", ["ips={$ips}", "pvs={$pvs}", "timestamp={$yesterday}", "timestr={$yesterday_timestamp}", "siteid={$siteid}"]);
// print_r($res1);
}
// 查找今天的记录
$res_t = $bean->findByX(['ip'], "wnzz_visit", ["time>{$today}", "time<{$tomorrow}", "siteid={$siteid}"]);
$datas_t = $res_t['data'];
$ipsandpvs_t = cal_ipandpv($datas_t);
$ips_t = $ipsandpvs_t[0];
$pvs_t = $ipsandpvs_t[1];
$t_ips = $ips_t;
$t_pvs = $pvs_t;
// 获取当前在线,10min内为在线
// 用PV计算当前在线数
$onlineMin = $now - 600;
$res_o = $bean->findByX(['ip'], "wnzz_visit", ["time>{$onlineMin}", "siteid={$siteid}"]);
$datas_o = $res_o['data'];
$ipsandpvs_o = cal_ipandpv($datas_o);
$ips_o = $ipsandpvs_o[0];
$pvs_o = $ipsandpvs_o[1];
// $t_ips = $ips_o;
$online = $pvs_o;
// $y_ips = 0;
// $y_pvs = 0;
// $t_ips = 0;
// $t_pvs = 0;
// $online = 0;
echo "webpro统计|今日IP[{$t_ips}]|今日PV[{$t_pvs}]|昨日IP[{$y_ips}]|昨日PV[{$y_pvs}]|当前在线[{$online}]";
}
/**
* @return array(ips, pvs)
*/
function cal_ipandpv($datas) {
// echo "emmm<br/>";
// print_r($datas);
// $ip['192.168.1.1'] = 10;
$ip = array();
foreach($datas as $index => $item) {
if(array_key_exists($item['ip'], $ip)) {
// 统计过
$ip[$item['ip']] += 1;
} else {
// 没统计过
$ip[$item['ip']] = 1;
}
}
// 累加IP和PV
$ips = 0;
$pvs = 0;
foreach($ip as $keyip => $count) {
$ips++;
$pvs += $count;
}
return [$ips, $pvs];
}
function anti_sqlin($data) {
$data = str_replace("'", "", $data);
return $data;
}

在要统计的页面中安装

在合适位置添加统计代码

  • 在head代码处添加、或者有的网站后台管理中留有网站统计填写等合适位置,添加如下代码(xxx/xxx.js改成自己的服务器上的JS地址)
html
1
2
<script src="https://pv.sohu.com/cityjson?ie=utf-8"></script>
<script src="https://xxx/xxx.js"></script>

  • 然后在你需要显示统计数据的地方添加如下div标签
html
1
<div id="wnzz"></div>

插件测试

  • 安装好后,刷新网站进行测试

安装成功!

  • 如果要实现多网站统计,设置不同的siteid,避免siteid重复即可!
文章作者: Bill
文章链接: http://blog.webpro.ltd/2019/05/29/get-my-site-pageview/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Bill's blog

评论