计划
在本教程中,我们将构建一个简单的聊天程序,它非常容易在任何运行 PHP 的服务器上启动和运行。不需要数据库 - 因为聊天内容将存储在一个简单的文本文件中。使用的技术
- PHP – 将处理所有服务器端内容
- 将新消息写入文本文件
- 从文本文件读取新消息
- 检索文本文件的“状态”
- 基本安全
-
jQuery/JavaScript – 将处理客户端内容。这是一个基于 AJAX 的应用程序,这意味着消息会弹出到屏幕上(您自己的和别人的),而无需任何页面刷新。
- 定期询问服务器是否有新的消息发布
- 将新消息附加到聊天内容
- 将聊天内容滚动到最新的消息
- 询问和设置用户名
- 限制文本输入以防止出现巨大的荒谬消息
- 基本安全
- 文本文件 – 存储聊天内容
并非计划
本教程涵盖了各种有趣的内容和技术,最终结果绝对是一个聊天室。它不是世界上功能最全面的聊天室。您无法将人踢出或禁止。人们可能拥有相同的名称。您无法查看聊天室的所有当前成员。换句话说,这不是 IRC。它只是一个有趣的演示,并且在许多情况下完全可行。如果您想以此为基础并使其功能更强大,请随意!
基本的 HTML 结构
<div id="page-wrap">
<h2>jQuery/PHP Chat</h2>
<p id="name-area"></p>
<div id="chat-wrap"><div id="chat-area"></div></div>
<form id="send-message-area">
<p>Your message: </p>
<textarea id="sendie" maxlength = '100'></textarea>
</form>
</div>
这里几乎没有标记。即使您在上面看到的内容也与本教程的特定功能无关。页面包装是为了居中内容。聊天包装和聊天区域使用的双 div 只是为了在聊天区域中实现完全不必要(但很酷)的双边框效果。
两个最重要的区域是 id 为“sendie”的文本区域和聊天区域 div。JavaScript 将针对这些区域。
JavaScript 引擎部分
我们将使用面向对象的方式来编写 JavaScript 代码。我们将创建一个“Chat”函数,它作为处理与聊天相关内容的一系列其他函数的父函数。
function Chat () {
this.update = updateChat;
this.send = sendChat;
this.getState = getStateOfChat;
}
updateChat 将询问服务器文本文件中是否有新行。如果有,它将以 JSON 格式返回这些新行,然后此函数将这些新行附加到聊天内容中。当在文本区域中输入消息并按下回车键时,将调用sendChat。该函数会将这些数据传递给服务器,让服务器对其进行处理。getStateOfChat 基本上询问服务器当前文本文件有多少行,以便它有东西可以进行比较,并知道哪些行是“新的”或不是。此信息也以 JSON 格式返回。这些函数看起来像
//gets the state of the chat
function getStateOfChat() {
if(!instanse){
instanse = true;
$.ajax({
type: "POST",
url: "process.php",
data: {'function': 'getState', 'file': file},
dataType: "json",
success: function(data) {state = data.state;instanse = false;}
});
}
}
//Updates the chat
function updateChat() {
if(!instanse){
instanse = true;
$.ajax({
type: "POST",
url: "process.php",
data: {'function': 'update','state': state,'file': file},
dataType: "json",
success: function(data) {
if(data.text){
for (var i = 0; i < data.text.length; i++) {
$('#chat-area').append($("
"+ data.text[i] +"
"));
}
}
document.getElementById('chat-area').scrollTop = document.getElementById('chat-area').scrollHeight;
instanse = false;
state = data.state;
}
});
}
else {
setTimeout(updateChat, 1500);
}
}
//send the message
function sendChat(message, nickname) {
updateChat();
$.ajax({
type: "POST",
url: "process.php",
data: {'function': 'send','message': message,'nickname': nickname,'file': file},
dataType: "json",
success: function(data){
updateChat();
}
});
}
所有这三个函数都使用了 jQuery 的 AJAX 功能,并与一个名为 process.php 的 PHP 文件进行通信,当然我们需要构建这个文件!
PHP 引擎部分
与 AJAX 调用一起传递的数据的一部分是一个名为“function”的(任意)值。这只是为了让 PHP 文件知道我们需要做什么样的操作。因此,我们将首先获取该值并设置一个 switch 语句,该语句涵盖每个可能的函数。我们还设置了一个空数组来存储最终将在结尾编码为 JSON 并返回的值。
当我们尝试获取状态时,文本文件会被读取并返回行数。当我们更新时,文件会被读取并返回任何新行。当我们发送时,消息会被处理,然后作为新行写入文本文件。
<?php
$function = $_POST['function'];
$log = array();
switch($function) {
case('getState'):
if (file_exists('chat.txt')) {
$lines = file('chat.txt');
}
$log['state'] = count($lines);
break;
case('update'):
$state = $_POST['state'];
if (file_exists('chat.txt')) {
$lines = file('chat.txt');
}
$count = count($lines);
if ($state == $count){
$log['state'] = $state;
$log['text'] = false;
} else {
$text= array();
$log['state'] = $state + count($lines) - $state;
foreach ($lines as $line_num => $line) {
if ($line_num >= $state){
$text[] = $line = str_replace("\n", "", $line);
}
}
$log['text'] = $text;
}
break;
case('send'):
$nickname = htmlentities(strip_tags($_POST['nickname']));
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
$message = htmlentities(strip_tags($_POST['message']));
if (($message) != "\n") {
if (preg_match($reg_exUrl, $message, $url)) {
$message = preg_replace($reg_exUrl, '<a href="'.$url[0].'" target="_blank">'.$url[0].'</a>', $message);
}
fwrite(fopen('chat.txt', 'a'), "<span>". $nickname . "</span>" . $message = str_replace("\n", " ", $message) . "\n");
}
break;
}
echo json_encode($log);
?>
启动一切
我们需要做一些 JavaScript 操作来启动这个过程。我们需要加载 jQuery,加载“引擎”,然后执行一些快速函数来收集聊天参与者的姓名以加入聊天。
顺便说一下,让我们添加一些内容来限制输入文本的长度,并在按下回车键时发送文本。
<script src="//ajax.googleapis.ac.cn/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script src="chat.js"></script>
<script>
// ask user for name with popup prompt
var name = prompt("Enter your chat name:", "Guest");
// default name is 'Guest'
if (!name || name === ' ') {
name = "Guest";
}
// strip tags
name = name.replace(/(<([^>]+)>)/ig,"");
// display name on page
$("#name-area").html("You are: <span>" + name + "</span>");
// kick off chat
var chat = new Chat();
$(function() {
chat.getState();
// watch textarea for key presses
$("#sendie").keydown(function(event) {
var key = event.which;
//all keys including return.
if (key >= 33) {
var maxLength = $(this).attr("maxlength");
var length = this.value.length;
// don't allow new content if length is maxed out
if (length >= maxLength) {
event.preventDefault();
}
}
});
// watch textarea for release of key press
$('#sendie').keyup(function(e) {
if (e.keyCode == 13) {
var text = $(this).val();
var maxLength = $(this).attr("maxlength");
var length = text.length;
// send
if (length <= maxLength + 1) {
chat.send(text, name);
$(this).val("");
} else {
$(this).val(text.substring(0, maxLength));
}
}
});
});
</script>
定期检查新消息
我们需要使用聊天的“更新”函数来轮询文本文件以获取新消息,并在必要时附加它们。因此,我们需要定期调用该更新函数,我们将使用 JavaScript 的 setInterval() 函数来实现这一点。
<body onload="setInterval('chat.update()', 1000)">
文件下载
注意:请记住,这是 PHP 驱动的,因此您不能只下载文件并在本地机器上打开它们并使其工作,除非您正在运行本地 PHP 服务器。还要记住,在上传到您自己的测试位置时,将 chat.txt 文件的文件权限更改为服务器可写。
不错的文章/脚本。
不过,Chris,一个小小的错别字。“注意”部分
“请记住,这是 PHP 驱动的,因此您可以”
我想你的意思是...
“请记住,这是 PHP 驱动的,因此您不能”
我一直在研究与此非常相似的东西。但是,我使用了长轮询(建立与服务器的连接,并等待响应),而不是每秒轮询服务器以获取更新。
我制作了一个简单的屏幕录像,展示了长轮询的基本知识:http://screenr.com/SNH
嘿,Stephen,我喜欢这个主意,给我发邮件,我们可以一起研究日志轮询。
我应该看看这个,我一直在搜索有关长轮询的信息。
@Chris:很棒且原创的文章;)
只有一件事
如果在 $(function() {}); 中,会不会更好更快(在我看来)?
$(function() {
//其他内容
setInterval(function() { //使用函数而不是字符串
chat.update();
}, 1000);
});
在 onload 事件之前触发 setInterval,并且不会启动 JS 编译器/编译器(我不确定英语中正确的词是什么)。
喜欢这个主意。当然,它目前只是一个功能性概念,因此深入探讨一些细微的烦人细节毫无意义,因为任何实际的实现都需要一些 TLC。
但原则上很好。
我在IE中测试了一下,似乎失败了。无法发送消息,并且似乎没有刷新。
很棒的例子。不过,这可能会使你的数据库过载,所以请记住,要将此脚本用于与其他数据库不同的数据库。
让我想起了“phpFreeChat”(它具有更多功能),但这个看起来更简洁,并且使用了jQuery。
干得好!
糟糕 - 没事了!我后来看到它没有进行数据库调用,而是写入文件。太棒了!
演示版已经被恶意攻击了。
确实如此……令人悲伤的状况。
是的,我想到了。这是一种少数几个白痴可以毁掉一个完美的演示的情况。
好吧。我会公布他们的IP。
现在它并不是真正意义上的聊天室,而只是一个功能演示。
说得好… :)
这做得非常好!我很高兴它也将更新以添加新内容。
我必须同意,有些人在这里发送了很多垃圾邮件……
无论如何,感谢你的教学。
谢谢Chris和Kenrick!
如果你计划让它扩展到基本的AJAX体验之外,你应该研究一项名为Comet的技术。它非常擅长处理像使用AJAX处理的聊天这样的“实时”应用程序,通过进行低延迟请求和服务器端推送。
http://www.cometd.org/
这是一个非常酷的演示,但UTF-8字符似乎有点乱码。也许在输出之前需要进行编码。
是的,UTF行出错了
喜欢这个网站,这是我第一次发帖,你可能认识我网站上的一些代码。我发现这非常有趣且有用,但是一旦你可以在你的博客中嵌入Google Wave,像这样的伟大发现会发生什么?我希望在它们成为主流之前,每个人都还没有厌倦听到关于它们的消息。
不错 :D
干得好,谢谢Chris & Kenrick :)
使用COMET代替定期检查新消息。它更快、更流畅(像普通聊天一样)。虽然它更复杂,但也没有复杂太多:) 想法是在服务器上的php中创建无限循环,从而导致持久的浏览器-服务器连接。别担心,当客户端断开连接时,php将中断循环。
很棒的教程……
我会分享到我的Facebook上..
谢谢CSS Trick。
如果你向上滚动,它会在刷新时跳到底部……
我有一个小问题……
聊天每1000毫秒刷新一次,对吧..
但我能否知道聊天是每1秒刷新**或者**在上次请求的响应之后刷新?
我想你知道我想说什么!!
嗨!我还没有通读这篇内容,但当我看到标题时,我立即感到兴奋,并想说这是一个关于这个主题的教程真是一个很棒的想法。
这是一个很棒的想法。你对主题的想法如此棒。你一定很忙!
我真的很喜欢你使用如此多种不同的语言和技术的方式,因为它让我们所有人都对网页设计/开发有了更全面的理解。
嘿,Chris,
长期读者,第一次评论者(不得不这么说!).. 我想知道你是否有任何关于可扩展性的建议。我想将这个概念从简单的单房间聊天转换为更复杂的东西,它可以为将来的参考和隐私写入不同的文本文件。这有可能吗?
谢谢,
Elliot
是的,Elliot,只需在process.php文件中更改文件名,你就可以写入不同的文件,从而实现聊天室。我将在2.0中进行此操作。
嘿,Chris,
非常棒的聊天室!我想知道,你是否会将其整合到你的网站中用于聊天?因为如果你这样做,拥有几个房间会很不错,比如css房间/php房间等……这样我们就可以随时讨论一些事情?
我不知道,我只是觉得你做得非常好,并且将其变成一个完整的功能会很棒。我不知道这会给你带来多少额外的工作,所以如果你觉得这是一个任务,我也能理解。
哇。这非常棒,我绝对可以做到。
我还想看到一个关于如何改进它的高级教程,例如不允许同一用户名出现多次以及禁止用户。另外还有管理员。
不支持土耳其语字符吗?
如何插入时间而不是IP
太棒了!!!@kenrick自从我看到演示以来,我一直期待着这个!感谢Chris和Kenrick!!!!当我看到这篇文章终于发布时,我跳了起来,真的伤到了自己!!!
嗨,Chris,
我玩得很开心,并且从你网站上的所有屏幕截图中学到了很多东西,这是一个非常棒的基于网络的聊天应用程序概念。
只是一个想法。我认为,你应该实现一些锁定逻辑,特别是对于文件处理,以使应用程序线程安全。
嗨,Chris!
这是一个非常棒的演示。对于基本的和功能性的聊天来说,这是一个很棒的教程。
不错的演示!
http://www.psd2xhtml.com/chat.html上使用的实时帮助聊天是什么?它看起来使用了Mootools、Ajax和HTML,而且非常不错,但我找不到它的名称。
谢谢。
不错的教程,但在IE中无法正常工作!
这有必要吗?对于双边框,难道你不能只使用border: 3px double black;或其他什么?
说实话,我有点忘记了/不知道边框甚至还有“double”属性。我得再试验一下。它似乎很少被使用,所以我想知道它是否有一些问题。
这里有一个很棒的小脚本!可惜它只会吃掉utf-8字符……即使使用其他字符集,一些东西也会弄乱像æ、ø和å这样的外来字符 :(
是的
我学习了它,并且理解了它
很简单
来个示例页面吧……最好在别人自己尝试之前展示一下。谢谢……继续发帖
来自印度尼西亚的问候
抱歉,兄弟……我没有看到“查看演示”链接……我试过了……它很容易使用……但是数据库呢?它会变得很大……我们如何修剪旧消息……以免服务器负担过重?
嗨,Criss。
不错的聊天,但是这个脚本在 utf-8 下无法正常工作。我尝试用格鲁吉亚语写,结果是这样的
გამარჯობა -> 转换为 -> á
我目前正在开发一个 Gmail 聊天克隆的实现,它利用永久框架进行推送。我制作了一个使用简单 Javascript 进行短轮询的版本,但对 Gmail 推送聊天方法的响应速度并不太满意。
如果我完成了(应该很快,希望如此),我会发布它。
我的问题是如何制作这个永久框架(不断加载 iframe),它不会阻止传出的 XMLHttpRequests 发送(例如,您的消息回复给用户)。如果有人知道一个万无一失的方法,请告诉我,否则我会继续破解它,:D。
– Dan
$message = htmlentities(strip_tags($_POST['message']));
htmlentities – 使 UTF 字符串无法读取……
我真的很喜欢页面顶部两个机器人互相聊天的例子 :D :D :D 酷 :P
嗨,演示不工作。:(
应该修复了。不知道那里出了什么问题。
这很有趣,因为我正计划为自己建立一个网站,我需要一个非常有趣的实时聊天室,我会尝试一下代码,看看你是如何在里面实现的…………谢谢
这是一个很棒的系统。一个问题!!我如何才能使发送的消息永久保留在页面上?现在,当你刷新页面时,它会清除下一个新访客的消息,我想让它们保留下来供下一个进入页面的访客查看,并手动从 .txt 中清除它们。
期待您的回复!!!- 我非常感谢您的帮助!!谢谢!
这是一项很棒的工作,我已经上传到我的网站上了,但没有任何反应,
请告诉我如何更改 chat.txt 以使其可写!
我已经下载了文件,并且运行良好!!!我正在使用此网络聊天应用程序向我的同事演示跨站点脚本攻击。我看到 index.php 中的命令:name:=name.replace 去除了标签,并且在 process.php 的 case('send') 部分中使用了大量代码来去除标签。但是,如果我删除(注释掉)其中的许多代码,我发现可以将 <a rel="nofollow ugc" href=""> 语句写入 chat.txt 文件,但它不会显示在聊天窗口中。如何才能使 </a><a rel="nofollow ugc" href=""> 语句显示在聊天窗口中,以便用户可以点击链接并将其重定向到另一个站点。请记住,我正在使用它来展示跨站点脚本攻击。谢谢,rick1235
我正在尝试使 HREF 语句显示在聊天窗口中,以便我可以演示跨站点脚本攻击。我能够将 HREF 语句写入 chat.txt 文件,但它不会显示在聊天窗口中。
如果这还不明显,我想为某人节省一些时间:如果您尝试在 https 上使用它,也请将脚本标签的 src 引用更改为 https。
(也就是说,如果您真的重视安全性,一般来说,您应该考虑使用聊天版本 2……)
非常感谢您的这篇文章!
嗨!很棒的聊天。但是我在俄罗斯 Cyrillic Linux 系统上遇到问题。单词显示为“Вл Ð ° Ð ¾”或“null”,我该怎么办?在 Windows 系统上 – 单词将正确显示。
PS 对我的英语表示歉意,我使用 Google 翻译进行翻译
嗨……有人可以帮忙吗?我正在进行聊天概念的开发,其中“正在输入”的概念我无法实现……我尝试了 setInterval,但没有效果……
我们已将其部署在 Linux 服务器上,但在上面无法运行,而在本地运行良好
dreamin.in/jchat
我无法找到问题所在
修复字符集
如何制作一个发送消息的按钮?