PHP实时统计在线用户数及IP地理位置分布实例
本文详细介绍如何使用PHP结合MySQL和新浪IP查询接口,实现一个简单的网站在线访客统计功能。该功能不仅能显示当前在线总人数,还能根据IP识别访客所在省份并进行区域分布展示。
效果预览
技术架构与准备条件
该方案采用前后端分离的轻量级交互模式,整体流程如下:
- 数据标识:服务器为访客分配包含省份信息的
cookie。 - 持久化存储:每次页面刷新时,将访客的真实IP、省份及时间戳存入MySQL数据库。
- 活跃判定:当访客下次访问时,若数据库中已有记录则更新访问时间;若超过设定时间(如10分钟)未活动,则自动清理过期数据。
- 异步交互:前端通过jQuery发起AJAX请求,获取在线总数并渲染地域分布下拉列表。
第一步:数据库准备
我们需要创建一张 online 表来存储用户的在线状态。为保证高并发下的写入效率,本例使用MyISAM引擎,主要记录唯一标识IP以及最后在线时间戳。
CREATE TABLE IF NOT EXISTS `online` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ip` varchar(30) NOT NULL,
`province` varchar(64) NOT NULL,
`addtime` int(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
第二步:编写后端记录脚本 (online.php)
这是核心处理逻辑文件。它负责获取访客IP、调用外部API获取省份(如果本地无缓存),并在数据库中执行“存在即更新,不存在即插入”的操作。同时,脚本会定期清理掉长时间不活跃的访客记录。
include_once('connect.php'); // 确保已连接数据库
$ip = get_client_ip(); // 获取真实IP
$time = time();
// 检查当前IP是否在数据库中
$query = mysql_query("select id from online where ip='$ip'");
if(!mysql_num_rows($query)){
// 若不存在新记录,则需确定其省份信息
if(isset($_COOKIE['geoData']) && $_COOKIE['geoData']){
$province = $_COOKIE['geoData'];
} else {
// 调用新浪IP接口查询(仅取回JSON字符串解析)
$api = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=$ip";
$json = file_get_contents($api);
$arr = json_decode($json, true);
$province = $arr['province'] ?? '未知';
setcookie('geoData', $province, $time+600); // 设置Cookie有效期10分钟
}
// 新增记录
mysql_query("insert into online (ip,province,addtime) values ('$ip','$province','$time')");
} else {
// 已存在,则更新其最后活动时间
mysql_query("update online set addtime='$time' where ip='$ip'");
}
// 清除过期数据(超过10分钟/600秒无活动的视为离线)
$outtime = $time-600;
mysql_query("delete from online where addtime<$outtime");
// 统计当前有效在线数
list($totalOnline) = mysql_fetch_array(mysql_query("select count(*) from online"));
echo $totalOnline;
mysql_close();
获取真实客户端IP函数
在代理服务器或负载均衡环境下,直接获取IP可能不准,建议封装以下函数:
function get_client_ip() {
if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown"))
$ip = getenv("HTTP_CLIENT_IP");
else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown"))
$ip = getenv("HTTP_X_FORWARDED_FOR");
else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown"))
$ip = getenv("REMOTE_ADDR");
else if (isset ($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown"))
$ip = $_SERVER['REMOTE_ADDR'];
else $ip = "unknown";
return ($ip);
}
第三步:编写地区分布数据接口 (geo.php)
此接口供前端下拉列表读取。它从数据库中按省份分组统计人数,并以 JSON 格式返回。
include_once('connect.php');
// 查询各省份人数并排序
$sql = "select province,count(*) as total from online group by province order by total desc";
$result = mysql_query($sql);
$list = array();
while($row = mysql_fetch_array($result)){
$list[] = array(
'province' => $row['province'],
'total' => $row['total']
);
}
echo json_encode($list);
第四步:前端页面结构与样式 (HTML/CSS)
首先构建页面框架,一个显示总数的容器和一个默认隐藏的下拉列表。
<div class="demo">
<div id="total">当前在线:<span id="onlinenum"></span></div>
<ul id="onlinelist">
<li>加载中...</li>
</ul>
</div>
CSS 用于美化提示框及下划线动画:
.demo{width:150px; margin:20px auto; font-size:14px; position:relative;}
#total{padding:6px 10px; background:#090 url(arr.png) no-repeat right top; color:#fff; cursor:pointer; border-radius:5px; box-shadow:0 0 3px #ccc;}
#onlinelist{background:#f7f7f7; border:1px solid #d3d3d3; display:none; border-radius:5px; padding:0;margin:0; list-style:none; width:100%;position:absolute;top:100%;left:0;z-index:10;}
#onlinelist li{height:20px; line-height:20px;padding:4px 6px;border-bottom:1px dotted #d9d3d3}
#onlinelist li span{float:right}
第五步:jQuery 异步加载逻辑
页面加载完毕后初始化在线人数;鼠标悬停于统计栏时触发 AJAX 请求,动态生成省份分布列表。
$(function(){
// 初次加载在线总数
$("#onlinenum").load("online.php");
$(".demo").hover(function(){
$("#onlinelist").slideDown("fast");
var str = '';
$.getJSON("geo.php",function(json){
$.each(json,function(index,array){
str += "<li><span>"+array['total']+"</span>"+array['province']+"</li>";
});
$("#onlinelist").html(str);
});
},function(){
$("#onlinelist").slideUp("fast");
});
});
注意引入 jQuery 库以支持上述 AJAX 操作。以上就是PHP统计当前在线用户数的详细内容,更多关于PHP网页开发技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













