26

我正在寻找使用具有群聊和私人聊天功能的 PHP/Javascript (Jquery) 来实现聊天室。

问题是如何以自然的方式不断更新界面,以及如何在私人聊天中显示“X 正在输入..”消息。

显而易见的方法似乎是每 X 秒/毫秒 javascript ping 服务器并获取上次 ping 和现在之间的新消息列表。但是,如果聊天室突然充斥着 5 条消息,这会使界面看起来有点不自然。我宁愿每条消息都在输入时显示。

javascript有没有办法保持与服务器的持续连接,服务器将任何新消息推送到此连接,然后javascript将它们添加到界面中,以便它们同时出现,几乎在服务器接收到它们的同时出现?

我知道有一些轮询选项需要您安装一些 apache 模块等,但我对系统管理员很不满意,因此我希望在共享主机帐户或 php 上有一个非常容易安装的解决方案/mysql 唯一的解决方案。

4

10 回答 10

46

使用 PHP/AJAX/JSON 聊天

我使用这本书/教程来编写我的聊天应用程序:

AJAX 和 PHP:构建响应式 Web 应用程序:第 5 章:AJAX 聊天和 JSON

它展示了如何从头开始编写完整的聊天脚本。


基于彗星的聊天

您还可以将CometPHP一起使用。

来自:zeitoun

Comet 使 Web 服务器无需客户端请求就可以向客户端发送数据。因此,这种技术将产生比经典 AJAX 更具响应性的应用程序。在经典的 AJAX 应用程序中,无法实时通知 Web 浏览器(客户端)服务器数据模型已更改。用户必须创建一个请求(例如通过单击一个链接)或一个周期性的 AJAX 请求必须发生,以便从服务器获取新数据。

我将向您展示两种使用 PHP 实现 Comet 的方法。例如:

  1. 基于隐藏<iframe>使用服务器时间戳
  2. 基于经典的 AJAX 不返回请求

第一个在客户端上实时显示服务器日期,显示一个迷你聊天。

方法一:iframe + 服务器时间戳

你需要:

  • 用于处理持久 http 请求的后端 PHP 脚本backend.php
  • 一个前端的 HTML 脚本加载 Javascript 代码index.html
  • 原型 JS 库,但你也可以使用 jQuery

后端脚本 ( backend.php) 将执行无限循环,并在客户端连接时返回服务器时间。

<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sun, 5 Mar 2012 05:00:00 GMT");
flush();
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <title>Comet php backend</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

<body>
<script type="text/javascript">
// KHTML browser don't share javascripts between iframes
var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML");
if (is_khtml)
{
  var prototypejs = document.createElement('script');
  prototypejs.setAttribute('type','text/javascript');
  prototypejs.setAttribute('src','prototype.js');
  var head = document.getElementsByTagName('head');
  head[0].appendChild(prototypejs);
}
// load the comet object
var comet = window.parent.comet;
</script>

<?php
while(1) {
    echo '<script type="text/javascript">';
    echo 'comet.printServerTime('.time().');';
    echo '</script>';
    flush(); // used to send the echoed data to the client
    sleep(1); // a little break to unload the server CPU
}
?>
</body>
</html>

前端脚本 ( index.html) 创建一个“comet”javascript 对象,它将后端脚本连接到时间容器标签。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Comet demo</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script type="text/javascript" src="prototype.js"></script>

</head>
<body>
  <div id="content">The server time will be shown here</div>

<script type="text/javascript">
var comet = {
connection   : false,
iframediv    : false,

initialize: function() {
  if (navigator.appVersion.indexOf("MSIE") != -1) {

    // For IE browsers
    comet.connection = new ActiveXObject("htmlfile");
    comet.connection.open();
    comet.connection.write("<html>");
    comet.connection.write("<script>document.domain = '"+document.domain+"'");
    comet.connection.write("</html>");
    comet.connection.close();
    comet.iframediv = comet.connection.createElement("div");
    comet.connection.appendChild(comet.iframediv);
    comet.connection.parentWindow.comet = comet;
    comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='./backend.php'></iframe>";

  } else if (navigator.appVersion.indexOf("KHTML") != -1) {

    // for KHTML browsers
    comet.connection = document.createElement('iframe');
    comet.connection.setAttribute('id',     'comet_iframe');
    comet.connection.setAttribute('src',    './backend.php');
    with (comet.connection.style) {
      position   = "absolute";
      left       = top   = "-100px";
      height     = width = "1px";
      visibility = "hidden";
    }
    document.body.appendChild(comet.connection);

  } else {

    // For other browser (Firefox...)
    comet.connection = document.createElement('iframe');
    comet.connection.setAttribute('id',     'comet_iframe');
    with (comet.connection.style) {
      left       = top   = "-100px";
      height     = width = "1px";
      visibility = "hidden";
      display    = 'none';
    }
    comet.iframediv = document.createElement('iframe');
    comet.iframediv.setAttribute('src', './backend.php');
    comet.connection.appendChild(comet.iframediv);
    document.body.appendChild(comet.connection);

  }
},

// this function will be called from backend.php  
printServerTime: function (time) {
  $('content').innerHTML = time;
},

onUnload: function() {
  if (comet.connection) {
    comet.connection = false; // release the iframe to prevent problems with IE when reloading the page
  }
}
}
Event.observe(window, "load",   comet.initialize);
Event.observe(window, "unload", comet.onUnload);

</script>

</body>
</html>

方法二:AJAX不返回请求

您需要与方法 1 中的相同 + 用于数据交换的文件 ( data.txt)

现在,backend.php 将做两件事:

  1. 发送新消息时写入“data.txt”
  2. 只要“data.txt”文件不变就无限循环
<?php
$filename  = dirname(__FILE__).'/data.txt';

// store new message in the file
$msg = isset($_GET['msg']) ? $_GET['msg'] : '';
if ($msg != '')
{
    file_put_contents($filename,$msg);
    die();
}

// infinite loop until the data file is not modified
$lastmodif    = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$currentmodif = filemtime($filename);
while ($currentmodif <= $lastmodif) // check if the data file has been modified
{
    usleep(10000); // sleep 10ms to unload the CPU
    clearstatcache();
    $currentmodif = filemtime($filename);
}

// return a json array
$response = array();
$response['msg']       = file_get_contents($filename);
$response['timestamp'] = $currentmodif;
echo json_encode($response);
flush();
?>

前端脚本 ( index.html) 创建<div id="content"></div>包含来自“data.txt”文件的聊天消息的标签,最后它创建一个“comet”javascript 对象,该对象将调用后端脚本以监视新的聊天消息。

每次收到新消息和发布新消息时,comet 对象都会发送 AJAX 请求。持久连接仅用于监视新消息。时间戳 url 参数用于标识最后请求的消息,以便服务器仅在“data.txt”时间戳比客户端时间戳更新时返回。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Comet demo</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script type="text/javascript" src="prototype.js"></script>
</head>
<body>

<div id="content">
</div>

<p>
<form action="" method="get" onsubmit="comet.doRequest($('word').value);$('word').value='';return false;">
  <input type="text" name="word" id="word" value="" />
  <input type="submit" name="submit" value="Send" />
</form>
</p>

<script type="text/javascript">
var Comet = Class.create();
Comet.prototype = {

timestamp: 0,
url: './backend.php',
noerror: true,

initialize: function() { },

connect: function()
{
  this.ajax = new Ajax.Request(this.url, {
    method: 'get',
    parameters: { 'timestamp' : this.timestamp },
    onSuccess: function(transport) {
      // handle the server response
      var response = transport.responseText.evalJSON();
      this.comet.timestamp = response['timestamp'];
      this.comet.handleResponse(response);
      this.comet.noerror = true;
    },
    onComplete: function(transport) {
      // send a new ajax request when this request is finished
      if (!this.comet.noerror)
        // if a connection problem occurs, try to reconnect each 5 seconds
        setTimeout(function(){ comet.connect() }, 5000); 
      else
        this.comet.connect();
      this.comet.noerror = false;
    }
  });
  this.ajax.comet = this;
},

disconnect: function()
{
},

handleResponse: function(response)
{
  $('content').innerHTML += '<div>' + response['msg'] + '</div>';
},

doRequest: function(request)
{
  new Ajax.Request(this.url, {
    method: 'get',
    parameters: { 'msg' : request 
  });
}
}
var comet = new Comet();
comet.connect();
</script>

</body>
</html>

或者

您还可以查看其他聊天应用程序,了解他们是如何做到的:

于 2010-11-16T19:55:46.113 回答
5

轮询不是一个好主意。您需要一个使用长轮询或 Web 套接字的解决方案。

http://hookbox.org可能是您可以使用的最佳工具。

它是一个存在于服务器和浏览器之间的盒子,它管理称为通道的抽象(想想 IRC 通道)。它在 github 上是开源的:https ://github.com/hookbox/hookbox这个盒子是用 Python 编写的,但它可以很容易地与用任何语言编写的服务器一起使用。它还附带一个基于 jsio 构建的 Javascript 库(使用 websockets、长轮询或任何浏览器上可用的最佳技术),以保证它使用浏览器中可用的最佳技术。在演示中,我看到了用几行代码实现的实时聊天。

Hookbox 的目的是简化实时 Web 应用程序的开发,重点是与现有 Web 技术的紧密集成。简单地说,Hookbox 是一个支持 Web 的消息队列。浏览器可以直接连接到 Hookbox,订阅指定频道,并在这些频道上实时发布和接收消息。外部应用程序(通常是 Web 应用程序本身)也可以通过 Hookbox REST 接口将消息发布到通道。所有身份验证和授权都由外部 Web 应用程序通过指定的“webhook”回调执行。

替代文字

每当用户连接或操作通道时,(订阅、发布、取消订阅)Hookbox 都会向 Web 应用程序发出 http 请求以授权操作。订阅频道后,用户的浏览器将通过 javascript api 接收来自另一个浏览器的实时事件,或通过 REST api 来自 Web 应用程序的实时事件。

他们的关键见解是,所有使用 hookbox 的应用程序开发要么使用 javascript,要么使用 Web 应用程序本身的本地语言(例如 PHP)。

您需要一个可以运行 Python 但您不必了解 Python 的服务器。

如果您只想使用 websockets 和 PHP,这是一个很好的起点:http ://blancer.com/tutorials/69066/start-using-html5-websockets-today/

于 2010-11-17T18:37:58.257 回答
2

我建议使用 HTML5 WebSockets 来实现它,使用长轮询或彗星作为旧浏览器的后备。WebSockets 打开一个到浏览器的持久连接。有一个 websocket 服务器的开源php 实现

于 2010-11-17T16:08:32.257 回答
2

这可能是一个很好的起点

http://css-tricks.com/jquery-php-chat/

于 2010-11-16T16:23:26.743 回答
2

你看过PHPDaemon 吗,它是通过积极使用 libevent 和 pnctl 编写的?有很多功能,甚至是简单的聊天演示应用程序。甚至它也有一些生产实现。

于 2010-11-14T00:18:05.947 回答
1

我知道这已经很晚了,但是在这里

编辑:更新链接

于 2012-08-22T15:29:23.567 回答
1

这看起来很有希望!甚至可能超级容易重新设计:)

http://www.php-development.ru/javascripts/ajax-chat.php

Javascript/PHP 中的 Ajax 聊天脚本

描述

Ajax Chat 是用 JavaScript 和 PHP 实现的轻量级可定制网络聊天软件。该脚本不需要 Java、Flash 或任何其他插件。

特征

  • 公共和私人聊天。
  • 以注册用户或访客身份登录。
  • 离开状态、自定义颜色、笑脸、用户性别/状态图标。
  • 通过实现用户身份验证例程,Ajax Chat 可以与第三方会员系统集成。高级集成选项:如果用户登录网站,他可以自动登录聊天。

Ajax 轻量级聊天脚本

*请注意,这是从原始网站复制/粘贴的。

于 2015-01-02T22:34:05.257 回答
1

我相信您正在查看的问题需要使用彗星网络编程。您可以通过搜索 Comet 编程和 Ajaxian 找到更多关于 wikipedia 的详细信息(我还是这个网站的新手,我不能在回复中发布超过 1 个链接)。

问题是这在服务器端使用 php 无法轻松实现。更多细节: 将彗星与 php 结合使用

此外,如果您在 google 上搜索“php comet”,您会找到达到预期效果的教程。

稍后编辑

猿项目

使用这个引擎实现了一个项目。是很棒的。

彗星与php

希望这会有所帮助,加布里埃尔

于 2010-11-16T15:18:11.263 回答
0

我以前没有用 PHP 做过,但你最好打赌可能是某种套接字连接。这是套接字的PHP手册

我不记得是谁的教程了,但我制作了一个聊天室,就像你想要的那样,客户端使用 Flash,服务器使用 Java。我认为这个链接可能是教程所在的位置,它可能会帮助你。

于 2010-11-13T20:39:22.170 回答
0

我建议您将Socket.IO与NodeJS一起尝试。Socket.IO 为您提供了一个很好且非常简单的客户端 API,适用于大多数现代浏览器并尽可能使用适当的传输(Websocket、长轮询等)。NodeJS 是一个服务器端守护进程,它拥有 HTTP 连接。Socket.IO 的官方网站包含有关如何一起使用它们的信息。希望它会帮助你。

于 2010-11-16T05:17:59.763 回答