【php】基于Xajax的在线聊天室、直播间

关于php的Xajax到底是什么,这里不再介绍,详情可以看我《【php】Xajax Helloworld》(点击打开链接)与《【php】注册系统和使用Xajax即时验证用户名是否被占用》(点击打开链接),这里具体说说,怎么用php来实现在线聊天室或者直播间,Xajax在php就像Dwr在javaee的地位,《【DWR】Helloworld》(点击打开链接),是一种无需用户刷新,与后台交互数据自动返回结果的ajax技术。

一、基本目标

1、首先输入用户名与密码之后,就可以登录在线聊天室,在左侧的在线用户列表自然可以显示当前在线的用户,而先前登录了的用户,在隔一段时间无需自动刷新,或者直接点刷新就能马上看到当前在线的的用户


2、在线聊天室自然能够实现在线聊天的功能,这个聊天无需刷新,对方隔一段时间能够收到信息


3、如果用户长时间没有发言,就会被系统自动踢出聊天室,这里为了说明结果只设置为15秒,并且gif中的等待时间已经被剪掉



二、基本思想

1、文件目录结构如下:


首先xajax_core,xajax_js与copyright.inc.php是xajax插件固有的文件,而login.html是登录页面,login.php完成登录判断并且作在线用户登记

退出登录则分如下两个步骤,先跳转到outline.php清除在线用户的登记,exit.php是清除session,

之所以要分开两个页面也做这样事,是让那些没有登录的输入网址直接访问用户直接跳到exit.php,避免与正常退出登录的用户一样需要走操作数据库的流程,

当然,也确实可以放在一起,只是这样,会导致多重逻辑判断


而整个在线聊天的核心在与chat.php,其实chat.php确实应该用框架页分块优化的,《【HTML】框架页、表单与JavaScript的综合应用》(点击打开链接),这样在线用户列表、聊天内容可以分块刷新,不影响到其他部分,不用一刷就刷整页

2、数据库中表的结构:


共三张表,user表记录了用户信息,没什么好说了,主键id与用户名、密码,消息表与在线用户信息表不设置主键,是因为这两个表要经常被擦写,如果你设置主键就会导致主键的顺序索引1、2、3、4……中间断开,不美观,这里也没有先后顺序,没必要用主键


三、制作过程

1、login.html

登录页面,没什么好说的,就一个表单:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>登录页面</title>
</head>

<body>
<form action="login.php" method="post">
用户名:<input type="text" name="username" /><br />
密码:<input type="password" name="password" /><br />
<input type="submit" value="登录" />
</form>
</body>
</html>

2、login.php

登录处理的页面,其实整个流程与之前的《【php】登录系统与输出浏览者信息》(点击打开链接)登录流程类似,只是多了一步把用户信息登记在在线列表的程序,这里如果想做得更加完善就把用户信息登记在在线列表之前,先查询库的在线列表里面有没有这个用户,如果没有才输入,防止一些用户上次不正常退出,比如直接关闭浏览器,而不是点右上角的“退出登录”。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>登陆中……</title>
</head>

<body>
<?php
session_start();
$username=$_REQUEST["username"];
$password=$_REQUEST["password"];
$con=mysql_connect("localhost","root","root");
if(!$con){
	die("数据库连接失败!");
	}
mysql_select_db("test",$con);
$dbusername=null;
$dbpassword=null;
$result=mysql_query("select * from user where username='".$username."';");
while($row=mysql_fetch_array($result)){
	$dbusername=$row["username"];
	$dbpassword=$row["password"];
}
if(is_null($dbusername)){
?>
<script>
alert("查无此人!");
window.location.href="login.html";
</script>
<?php	
	}
else{
	if($dbpassword!=$password){
?>
<script>
alert("密码错误!");
window.location.href="login.html";
</script>        
<?php
		}
	else{
		$_SESSION["username"]=$username;
		$_SESSION["code"]=mt_rand(0,100000);
		//如果用户的登录信息正确,就把用户的登录信息登录进在线用户信息表useronlinelist
		mysql_query("insert into useronlinelist(username,logindatetime,lastdatetime) values ('".$username."',now(),now());");
?>
<script>
window.location.href="chat.php";
</script>  
<?php
		}
	}
mysql_close($con);
?>

</body>
</html>

登录之后会让用户进入聊天室chat.php,这网页是整个工程的核心,放在最后讲,做的时候也应该最后做,先把用户退出登录的离线处理页面与清理session页面做好。


3、outline.php

用户退出登录的离线处理页面,操作数据库,把在线用户信息表除名

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
</head>

<body>
<?php
session_start();
if(isset($_SESSION["code"])){
	$username=$_SESSION["username"];
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
		}
	mysql_select_db("test",$con);
	//把当前退出用户从在线用户信息表useronlinelist除名
	mysql_query("DELETE FROM useronlinelist WHERE username = '".$username."';");
	mysql_close($con);
?>
<script>
window.location.href="exit.php";
</script>


<?php
}
else{
?>
<script>
alert("请正常登录!");
window.location.href="exit.php";
</script>
<?php
}
?>
</body>
</html>


4、exit.php

与《【php】登录系统与输出浏览者信息》(点击打开链接)完全相同,完全没有改动

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>登出页面</title>
</head>

<body>
<?php
session_start();
session_destroy();
?>
<script>
window.location.href="login.html";
</script>
</body>
</html>

5、chat.php

在线聊天核心页面

(1)HTML布局

这里其实更应该用框架页来做的《【HTML】框架页、表单与JavaScript的综合应用》(点击打开链接),因为可以分块刷新,不影响到其他部分,不用一刷就刷整页,这里的div布局具体怎么布置《【CSS】关于div的对齐与网页布局》(点击打开链接),左上是一个“欢迎登录”语句,右上是一个“退出登录”,左中是“在线用户列表”里面的ul设置了useronlist是为了其后xajax可以控制,右中的"聊天室"的结构与左中完全一模一样,最下方是那些表单,能够让用户填写自己要发表的内容,行列文本的tomanspan,也是为了被xajax控制,因为这个对……说,实质上也同样是一个在线用户列表。其余混杂在里面的php部分主要是判断用户是否登录这一页。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>欢迎登录聊天室</title>
</head>

<body>
<?php
session_start();
if(isset($_SESSION["code"])){
?>
<div style="float:left">欢迎登录!<?php
echo "${_SESSION["username"]}";
?></div><div style="float:right"><a href="outline.php">退出登录</a></div>
<div style="clear:both"></div>
<div style="float:left; margin-right:5%;">
在线用户列表
<ul id="useronlist">
加载中……
</ul>

</div>
<div style="float:left">
聊天室
<ul id="messagecontent">
</ul>
</div>
<div style="clear:both"></div>
<div><?php
echo "${_SESSION["username"]}";
?>对<span id="tomanspan"></span>说:<input type="text" id="message" style="width:80%"/><button οnclick="sendmessage()">发言</button><button οnclick="onlineuserlist()">刷新</button></div>
<?php
}
else{
?>
<script>
alert("请正常登录!");
window.location.href="exit.php";
</script>
<?php
}
?>
</body>
</html>
(2)XAJAX部分

也就是整个页面实现的核心,

首先是清理垃圾函数$xajax->registerFunction("cleardirty");这个函数会被其后的javascript语句每隔60秒执行一次,这个函数主要是防止一些用户上次不正常退出,比如直接关闭浏览器,而不是点右上角的“退出登录”,而造成数据库里面产生脏数据。同时也没有必要在在线聊天记录表中保存这么多聊天记录,甚至可以不自动删除1天前的聊天记录,时间可以更短,毕竟查询最近10条聊天记录,可能与刚插入的聊天记录产生读写互斥,所以还是通过时间差来比对。

function cleardirty(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	mysql_query("delete from useronlinelist where timestampdiff(second,lastdatetime,now())>60;");
	mysql_query("delete from message where timestampdiff(hour,speakdatetime,now())>1; ");
	mysql_close($con);
	return $orps;
}
删除那些最后一次发表时间离现在超过60秒的人,注意mysql中是怎么求时间差的,

然后删除那些离现在已经超过1天的消息,

之后是在线用户列表显示函数$xajax->registerFunction("userlist");与在线消息显示函数$xajax->registerFunction("message");,这个两个函数会被其后的javascript语句每隔10秒执行一次,也就是每隔10秒就刷新一下页面

function userlist(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$result=mysql_query("select * from useronlinelist;");
	$textto="<select id='toman' name='toman'><option value='大家'>大家</option>";
	$textonline="";
	while($row=mysql_fetch_array($result)){
		$textto.="<option value='${row["username"]}'>${row["username"]}</option>";
		$textonline.="<li>${row["username"]}</li>";
	}
	$textto.="</select>";
	$orps->assign("tomanspan","innerHTML",$textto);
	$orps->assign("useronlist","innerHTML",$textonline);
	mysql_close($con);
	return $orps;
	}
function message(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$result=mysql_query("select * from message order by speakdatetime desc limit 10;");
	$messagecontent="";
	while($row=mysql_fetch_array($result)){
		$messagecontent.="<li>【${row["fromman"]}】对【${row["toman"]}】说:${row["message"]}(${row["speakdatetime"]})</li>";
	}
	$orps->assign("messagecontent","innerHTML",$messagecontent);
	mysql_close($con);
	return $orps;
}
两函数的结构完全相同,把所有的查询出来的结果,通过字符串不停地连接连成有序列表的<li>节点部分,

然后通过xajax指派到相应的<ul>节点下,这样也就实现了刷新功能

同时在线用户列表显示函数$xajax->registerFunction("userlist");,对于“对……说”这部分的构造要注意,因为构造<select>的工作必须在xajax的完成,再把一个完整的下拉列表放置在行内文本中,不能在html部分,放置一个<select>再把<option>,这里理论是可以的,但是在实际上xajax不知道什么原因无法指派。

最后发表函数$xajax->registerFunction("insertmessage");这个函数仅仅是用户点击发表按钮,并取得里面的发表人、收信人、发表内容才会被执行

要插入一条用户发表的信息入数据库之前,你首先要判断,这个用户是否离上次发表超过15秒,是否已经被清理垃圾函数$xajax->registerFunction("cleardirty");清理,而且判断其离上次发表是否超过15秒,清理了则弹出,未被清理也未超过15秒才允许入库并更新库里面的最后一次发表时间,如果不判断是否已经被清理垃圾函数$xajax->registerFunction("cleardirty");清理,会由于这个函数在并行,谁先谁后的操作系统线程问题,导致整个系统出现了问题。

function insertmessage($from,$to,$message){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$dbusername=null;
	$result=mysql_query("select * from useronlinelist where username='".$from."';");
	while($row=mysql_fetch_array($result)){
		$dbusername=$row["username"];
	}
	$result=mysql_query("select timestampdiff(second,(select lastdatetime from useronlinelist where username='".$from."'),now()) as difftime;");
	$difftime=null;
	while($row=mysql_fetch_array($result)){
		$difftime=$row["difftime"];
	}
	if(!(is_null($dbusername))&&$difftime<60){
		mysql_query("update useronlinelist set lastdatetime=now() where username='".$from."';");	
		mysql_query("insert into message(fromman,toman,message,speakdatetime) values ('".$from."','".$to."','".$message."',now());");
	}
	else{
		$orps->alert("长达60秒没有发言,请重新登录!");
		$orps->script("window.location.href='outline.php';");
	}
	mysql_close($con);
	return $orps;
}

综上所述,整个xajax部分如下,其余没有说明的语句,在之前的《【php】Xajax Helloworld》(点击打开链接)与《【php】注册系统和使用Xajax即时验证用户名是否被占用》(点击打开链接)说过,这里不再赘述,你完全可以用一个include语句将其分开,我是见小工程就放在一个页面chat.php里面:

<?php
include 'xajax_core/xajax.inc.php';
$xajax=new xajax();
$xajax->registerFunction("cleardirty");
$xajax->registerFunction("userlist");
$xajax->registerFunction("message");
$xajax->registerFunction("insertmessage");
function cleardirty(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	mysql_query("delete from useronlinelist where timestampdiff(second,lastdatetime,now())>60;");
	mysql_query("delete from message where timestampdiff(hour,speakdatetime,now())>1; ");
	mysql_close($con);
	return $orps;
}
function userlist(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$result=mysql_query("select * from useronlinelist;");
	$textto="<select id='toman' name='toman'><option value='大家'>大家</option>";
	$textonline="";
	while($row=mysql_fetch_array($result)){
		$textto.="<option value='${row["username"]}'>${row["username"]}</option>";
		$textonline.="<li>${row["username"]}</li>";
	}
	$textto.="</select>";
	$orps->assign("tomanspan","innerHTML",$textto);
	$orps->assign("useronlist","innerHTML",$textonline);
	mysql_close($con);
	return $orps;
	}
function message(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$result=mysql_query("select * from message order by speakdatetime desc limit 10;");
	$messagecontent="";
	while($row=mysql_fetch_array($result)){
		$messagecontent.="<li>【${row["fromman"]}】对【${row["toman"]}】说:${row["message"]}(${row["speakdatetime"]})</li>";
	}
	$orps->assign("messagecontent","innerHTML",$messagecontent);
	mysql_close($con);
	return $orps;
}
function insertmessage($from,$to,$message){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$dbusername=null;
	$result=mysql_query("select * from useronlinelist where username='".$from."';");
	while($row=mysql_fetch_array($result)){
		$dbusername=$row["username"];
	}
	$result=mysql_query("select timestampdiff(second,(select lastdatetime from useronlinelist where username='".$from."'),now()) as difftime;");
	$difftime=null;
	while($row=mysql_fetch_array($result)){
		$difftime=$row["difftime"];
	}
	if(!(is_null($dbusername))&&$difftime<60){
		mysql_query("update useronlinelist set lastdatetime=now() where username='".$from."';");	
		mysql_query("insert into message(fromman,toman,message,speakdatetime) values ('".$from."','".$to."','".$message."',now());");
	}
	else{
		$orps->alert("长达60秒没有发言,请重新登录!");
		$orps->script("window.location.href='outline.php';");
	}
	mysql_close($con);
	return $orps;
}
$xajax->processRequest();
$xajax->printJavascript();
?>

(3)javascript部分

有了上面的xajax数字叙述,这里什么时候执行什么xajax函数顺理成章,注意对于发表函数$xajax->registerFunction("insertmessage");要在这里javascript中取到上面html部分的发信人、收信人、发送内容,才执行,而当前时间则用mysql语句的now()

<script>
onlineuserlist();
setInterval("onlineuserlist()",10000);
setInterval("cleardirty()",60000);
function cleardirty(){
	xajax_cleardirty();
	}
function onlineuserlist(){
	xajax_userlist();
	xajax_message();
	}
function sendmessage(){
	var from="<?php
echo "${_SESSION["username"]}";
?>";
	var to=document.getElementById("toman").value;
	var message=document.getElementById("message").value;	
	xajax_insertmessage(from,to,message);
	xajax_userlist();
	xajax_message();
	document.getElementById("message").value="";
	}
</script>

至此整个chat.php如下:

<?php
include 'xajax_core/xajax.inc.php';
$xajax=new xajax();
$xajax->registerFunction("cleardirty");
$xajax->registerFunction("userlist");
$xajax->registerFunction("message");
$xajax->registerFunction("insertmessage");
function cleardirty(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	mysql_query("delete from useronlinelist where timestampdiff(second,lastdatetime,now())>60;");
	mysql_query("delete from message where timestampdiff(hour,speakdatetime,now())>1; ");
	mysql_close($con);
	return $orps;
}
function userlist(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$result=mysql_query("select * from useronlinelist;");
	$textto="<select id='toman' name='toman'><option value='大家'>大家</option>";
	$textonline="";
	while($row=mysql_fetch_array($result)){
		$textto.="<option value='${row["username"]}'>${row["username"]}</option>";
		$textonline.="<li>${row["username"]}</li>";
	}
	$textto.="</select>";
	$orps->assign("tomanspan","innerHTML",$textto);
	$orps->assign("useronlist","innerHTML",$textonline);
	mysql_close($con);
	return $orps;
	}
function message(){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$result=mysql_query("select * from message order by speakdatetime desc limit 10;");
	$messagecontent="";
	while($row=mysql_fetch_array($result)){
		$messagecontent.="<li>【${row["fromman"]}】对【${row["toman"]}】说:${row["message"]}(${row["speakdatetime"]})</li>";
	}
	$orps->assign("messagecontent","innerHTML",$messagecontent);
	mysql_close($con);
	return $orps;
}
function insertmessage($from,$to,$message){
	$orps=new xajaxResponse();
	$con=mysql_connect("localhost","root","root");
	if(!$con){
		die("连接失败!");
	}
	mysql_select_db("test",$con);
	mysql_query("set names utf8");
	$dbusername=null;
	$result=mysql_query("select * from useronlinelist where username='".$from."';");
	while($row=mysql_fetch_array($result)){
		$dbusername=$row["username"];
	}
	$result=mysql_query("select timestampdiff(second,(select lastdatetime from useronlinelist where username='".$from."'),now()) as difftime;");
	$difftime=null;
	while($row=mysql_fetch_array($result)){
		$difftime=$row["difftime"];
	}
	if(!(is_null($dbusername))&&$difftime<60){
		mysql_query("update useronlinelist set lastdatetime=now() where username='".$from."';");	
		mysql_query("insert into message(fromman,toman,message,speakdatetime) values ('".$from."','".$to."','".$message."',now());");
	}
	else{
		$orps->alert("长达60秒没有发言,请重新登录!");
		$orps->script("window.location.href='outline.php';");
	}
	mysql_close($con);
	return $orps;
}
$xajax->processRequest();
$xajax->printJavascript();
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>欢迎登录聊天室</title>
</head>

<body>
<?php
session_start();
if(isset($_SESSION["code"])){
?>
<div style="float:left">欢迎登录!<?php
echo "${_SESSION["username"]}";
?></div><div style="float:right"><a href="outline.php">退出登录</a></div>
<div style="clear:both"></div>
<div style="float:left; margin-right:5%;">
在线用户列表
<ul id="useronlist">
加载中……
</ul>

</div>
<div style="float:left">
聊天室
<ul id="messagecontent">
</ul>
</div>
<div style="clear:both"></div>
<div><?php
echo "${_SESSION["username"]}";
?>对<span id="tomanspan"></span>说:<input type="text" id="message" style="width:80%"/><button οnclick="sendmessage()">发言</button><button οnclick="onlineuserlist()">刷新</button></div>
<?php
}
else{
?>
<script>
alert("请正常登录!");
window.location.href="exit.php";
</script>
<?php
}
?>
</body>
</html>
<script>
onlineuserlist();
setInterval("onlineuserlist()",10000);
setInterval("cleardirty()",60000);
function cleardirty(){
	xajax_cleardirty();
	}
function onlineuserlist(){
	xajax_userlist();
	xajax_message();
	}
function sendmessage(){
	var from="<?php
echo "${_SESSION["username"]}";
?>";
	var to=document.getElementById("toman").value;
	var message=document.getElementById("message").value;	
	xajax_insertmessage(from,to,message);
	xajax_userlist();
	xajax_message();
	document.getElementById("message").value="";
	}
</script>

到这里整个在线聊天做完。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值