实现Hit Counter访客统计

 技术  php  sqlite 󰈭 1143字

找了下网络上的但是不是很满意… 所以打算自己通过前后端实现一下Hit Counter来进行访客统计. 后端总体通过nginx + php-fpm + sqlite实现.

sqlite数据库

在数据库的选择方面选择sqlite, 其功能简约, 需要处理的需要处理的数据量应该也不算大, 比较下来sqlite即可满足需求.

想了想好像单个table就基本可以了? 就设计如下:

1|---------------|-------|------|--------|---------|----------|----------|---------|
2| uuid(Primary) | Title | IPv4 | cookie | broswer | language | platform | Date    |
3|---------------|-------|------|--------|---------|----------|----------|---------|
4| Text          | NText | Text | Text   | Text    | Text     | Text     | Integer |
5|---------------|-------|------|--------|---------|----------|----------|---------|

创建数据表:

 1CREATE TABLE pv(
 2	uuid	Text 	NOT NULL PRIMARY KEY,
 3	title	NText	NOT NULL,
 4	ipv4	Text	NOT NULL,
 5	cookie	Text	NOT NULL,
 6	broswer	Text	NOT NULL,
 7	lang	Text	NOT NULL,
 8	plat	Text	NOT NULL,
 9	date	Integer NOT NULL
10);

其中:

  • uuid作为主键, 由php后台产生

  • ipv4的获取由php检测, 相关的代码为:

 1function getip() {
 2	$ip = false;
 3	if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
 4		$ip = $_SERVER["HTTP_CLIENT_IP"];
 5	}
 6	if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
 7		$ips = explode(", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
 8		if ($ip) {
 9			array_unshift($ips, $ip);
10			$ip = FALSE;
11		}
12		for ($i = 0; $i < count($ips); $i++) {
13			if (!preg_match("/^(10│172.16│192.168)./i", $ips[$i])) {
14				$ip = $ips[$i];
15				break;
16			}
17		}
18	}
19	return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
20}
  • date为php接收到post请求后的unix时间戳, 32位整数.

  • 其余的字段均为前端发送.

PHP代码与安全保护

考虑了过后, 好像对前端的认证会比较复杂, 而且暂时也不打算做身份认证登陆系统, 因而还是考虑后端简单地验证了一下post请求就拉倒…

主要采取的措施有:

  • 防止sql注入: 通过preparebindValue防止sql注入.

  • 冗余访问的去除: 首先通过这样一条sql查询语句, 检查当前post请求是否在一段时间内(目前设置为10分钟)发送过; 验证的方式只有通过查看其cookie和ipv4. cookie不用说, 用于君子检查罢了; ipv4可能会有一定的作用, 因为一个ipv4对于一个title的访问在10分钟内只有一次. 由此自然要解决的问题就是title的合法性验证, 因而添加了相关的python代码会自动生成一个包含所有合法title的文件以供比对, 这样只有当title合法的post请求才会被进一步处理. 不过, 由于title数量也很多, 不仅包含了posts还有模板文件自带的tags和categories, 这些还没customize过, 总共有靠近200个合法title… 因而这个方法也几乎无法防御基于暴力的一些攻击手段, 10分钟内一个IP可以向库中添加200条表项…

1$query="select date from pv where title = ? AND (ipv4 = ? OR cookie = ?)";
2$stmt = $db->prepare($query);
3$stmt->bindValue(1, $title, SQLITE3_TEXT);
4$stmt->bindValue(2, $ipv4, SQLITE3_TEXT);
5$stmt->bindValue(3, $cookie, SQLITE3_TEXT);
6$res = $stmt->execute();
  • post字段长度限制: 防止坏人注入超级多的文字(关键还是post感觉不太需要, 后续看看是否可以换成GET) 把我数据库的磁盘空间挤爆.

  • 无了… 不知道有没有更好的办法

Todo

希望实现statistics… 应该不是很难, 但是要搞一阵子, 就暂且搁置一下.

嗨! 这里是 rqdmap 的个人博客, 我正关注 GNU/Linux 桌面系统, Linux 内核, 后端开发, Python, Rust 以及一切有趣的计算机技术! 希望我的内容能对你有所帮助~
如果你遇到了任何问题, 包括但不限于: 博客内容说明不清楚或错误; 样式版面混乱等问题, 请通过邮箱 rqdmap@gmail.com 联系我!
修改记录:
  • 2023-05-29 23:05:14大幅重构了python脚本的目录结构,实现了若干操作博客内容、sqlite的助手函数;修改原本的文本数 据库(ok)为sqlite数据库,通过嵌入front-matter的page_id将源文件与网页文件相关联
  • 2023-05-08 21:44:36博客架构修改升级
  • 2022-12-31 00:47:48添加了访客统计, 更新了相关的博客、前端样式与todo项等
实现Hit Counter访客统计