首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

5.2  实现Ajax聊天

我们将保持应用是简单的、模块化的和可扩展的。为了做到这一点,我们不实现登录模块、聊天室、在线用户表等功能。为了保持它的简单风格,我们试图将精力集中在本章的目标——Ajax聊天上。我们将实现基本的聊天功能:在不引起任何网页重新加载的情况下发送和接收消息。我们也允许用户挑选消息的颜色,这又是一个学习Ajax机制的好机会。

从本章下面要讲的应用程序出发,通过实现前面方案中的其他模块或这里尚未提及的模块,我们可以很容易地扩展这个应用。如果感兴趣的话,可以将这部分作为自己的课后作业。

注意

要想使这些示例运行起来,需要GD库。附录A的安装介绍中包含如何支持GD库。

这个聊天应用可以在线测试:http://ajaxphp.packtpub.com,如图5.2所示。

图5.2  Ajax聊天

本章的新奇之处是会有两个XMLHttpRequest对象。第一个处理更新聊天窗口,第二个处理颜色取色(当点到图片上时,坐标被发送到服务器上,服务器用颜色代码响应)。

Ajax聊天的消息被保存到一个队列中(FIFO结构的),就像在第4章了解到的,即使服务器很慢,也不会丢失消息,而且它们会以发送时的顺序到达服务器。与现在因特网上的其他方式不同,我们保证在一次请求还未结束之前,不向服务器重复发送多个请求。

* 实现步骤——Ajax聊天

(1)连接Ajax数据库,并用下面的代码创建表chat:

CREATE TABLE chat

(

  chat_id int(11) NOT NULL auto_increment,

  posted_on datetime NOT NULL,

  user_name varchar(255) NOT NULL,

  message text NOT NULL,

  color char(7) default '#000000',

  PRIMARY KEY (chat_id)

);

(2)在Ajax文件夹下,创建新文件夹chat。

(3)从下载代码中将palette.png文件复制到chat文件夹下。

(4)我们将创建一个由服务器功能开始的应用。在chat文件夹下,创建文件config.php,并把数据库配置代码加到此文件里(改变这些变量值来匹配配置)。

<?php

//定义数据库连接数据

define('DB_HOST', 'localhost');

define('DB_USER', 'ajaxuser');

define('DB_PASSWORD', 'practical');

define('DB_DATABASE', 'ajax');

?>

(5)现在加入标准错误处理文件error_handler.php:

<?php

//设置用户错误处理方法为error_handler

set_error_handler('error_handler', E_ALL);

//错误处理函数

function error_handler($errNo, $errStr, $errFile, $errLine)

{

  //清除所有已经生成的输出

  if(ob_get_length()) ob_clean();

  //输出错误消息

  $error_message = 'ERRNO: ' . $errNo . chr(10) .

                       'TEXT: ' . $errStr . chr(10) .

                       'LOCATION: ' . $errFile .

                       ', line ' . $errLine;

  echo $error_message;

  //阻止处理任何其他PHP脚本

  exit;

}

?>

(6)创建文件chat.php并加入下面代码:

<?php

//参考包含Chat类的文件

require_once("chat.class.php");

//取回执行的操作

$mode = $_POST['mode'];

//默认情况下最后的id是0

$id = 0;

//创建一个新的聊天实例

$chat = new Chat();

//如果操作是 SendAndRetrieve

if($mode == 'SendAndRetrieveNew')

{

  //取回用来添加一个新消息的作用参数

  $name = $_POST['name'];

  $message = $_POST['message'];

  $color = $_POST['color'];

  $id = $_POST['id'];

 

  //检查是否我们有合法的值

  if ($name != '' && $message != '' && $color != '')

  {

    //把消息传递到数据库    

    $chat->postMessage($name, $message, $color);

  }

}

//如果操作是 DeleteAndRetrieve

elseif($mode == 'DeleteAndRetrieveNew')

{

  //删除所有已存在的消息

  $chat->deleteMessages();        

}

//如果操作是Retrieve

elseif($mode == 'RetrieveNew')

{

  //获取客户取回的最后消息的id

  $id = $_POST['id'];   

}

//清除输出

if(ob_get_length()) ob_clean();

//发送Headers阻止浏览器缓存

header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');

header('Cache-Control: no-cache, must-revalidate');

header('Pragma: no-cache');

header('Content-Type: text/xml');

//从服务器取回新消息

echo $chat->retrieveNewMessages($id);

?>

(7)创建文件chat.class并加入下面代码:

<?php

//加载配置文件

require_once('config.php');

//加载错误处理模块

require_once('error_handler.php');

   

//包含服务端聊天功能的类

class Chat

{

  //数据库处理

  private $mMysqli; 

 

  //构造函数打开数据库连接

  function __construct()

  {  

    //连接到数据库

    $this->mMysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD,

                                                                 DB_DATABASE);

  }

//析构函数关闭数据库连接 

  public function __destruct()

  {

    $this->mMysqli->close();

  }

  //截去包含消息的表

  public function deleteMessages()

  {

    //建立增加一个新消息到服务器的SQL查询

    $query = 'TRUNCATE TABLE chat';

    //执行SQL查询

    $result = $this->mMysqli->query($query);     

  }

 

  /*

   postMessages方法向数据库中插入消息

   - $name代表post消息的用户的名称

   - $messsage是post的消息

   - $color包含用户选取的颜色

  */

  public function postMessage($name, $message, $color)

  { 

    //转换变量数据,以便安全地将它们添加到数据库

    $name = $this->mMysqli->real_escape_string($name);

    $message = $this->mMysqli->real_escape_string($message);

    $color = $this->mMysqli->real_escape_string($color);

    //建立增加一个新消息到服务器的SQL查询

    $query = 'INSERT INTO chat(posted_on, user_name, message, color) ' .

                'VALUES (NOW(), "' . $name . '" , "' . $message .

                '","' . $color . '")';

    //执行SQL查询

    $result = $this->mMysqli->query($query);      

  }

  /*

   retrieveNewMessages方法提取已经发送给服务器的新消息

   -$id参数由客户端发送,而且它是客户端接收到的最后一个消息的id

   通过$id从数据库获取最近的消息,并利用XML格式返回给客户端。

  */

  public function retrieveNewMessages($id=0)

  {

    //转换变量数据

    $id = $this->mMysqli->real_escape_string($id);

    //组成取回新消息的SQL查询

    if($id>0)

    {

      //取回比$id新的消息

      $query =

      'SELECT chat_id, user_name, message, color, ' .

      '       DATE_FORMAT(posted_on, "%Y-%m-%d %H:%i:%s") ' .

      '       AS posted_on ' .

      ' FROM chat WHERE chat_id > ' . $id .

      ' ORDER BY chat_id ASC';

    }

    else

    {

      //第一次加载仅仅从服务器取回最后50个消息

      $query =

      ' SELECT chat_id, user_name, message, color, posted_on FROM ' .

      '    (SELECT chat_id, user_name, message, color, ' .

      '    DATE_FORMAT(posted_on, "%Y-%m-%d %H:%i:%s") AS posted_on ' .

      '     FROM chat ' .

      '     ORDER BY chat_id DESC ' .

      '      LIMIT 50) AS Last50' .

      ' ORDER BY chat_id ASC';

    }

    //执行查询

    $result = $this->mMysqli->query($query); 

    //建立XML响应

    $response = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';

    $response .= '<response>'; 

    //输出清除标志

    $response .= $this->isDatabaseCleared($id);

    //检查看我们是否有任何结果

    if($result->num_rows)

    {     

      //在所有取来的消息间循环来建立结果消息

      while ($row = $result->fetch_array(MYSQLI_ASSOC))

      {

        $id = $row['chat_id'];

        $color = $row['color'];

        $userName = $row['user_name'];

        $time = $row['posted_on'];

        $message = $row['message'];

        $response .= '<id>' . $id . '</id>' .

                        '<color>' . $color . '</color>' .

                        '<time>' . $time . '</time>' .

                        '<name>' . $userName . '</name>' .

                        '<message>' . $message . '</message>';

      }

      //尽快关闭数据库连接

      $result->close();

    }

   

    //完成XML响应并返回它

    $response = $response . '</response>';

    return $response;   

  }

  /*

    isDatabaseCleared方法查看自从上次访问服务器后数据库是否被清空。

      参数包含最后从客户端接收的消息的id。

  */

  private function isDatabaseCleared($id)

  {

    if($id>0)

    {

      //通过检查其id号比客户的最后id号小的行数,我们检查看是否一个截去操作同时//被执行

      $check_clear = 'SELECT count(*) old FROM chat where chat_id<=' . $id;

      $result = $this->mMysqli->query($check_clear);

      $row = $result->fetch_array(MYSQLI_ASSOC);     

           

      //如果一个截去操作发生了,白色书写板需要被重新设置

      if($row['old']==0)

        return '<clear>true</clear>';    

    }

    return '<clear>false</clear>';

  }

}

?>

(8)创建文件get_color.php并加入下面代码:

<?php

//图片文件的名字

$imgfile='palette.png';

//加载图片文件

$img=imagecreatefrompng($imgfile);

//获得用户单击点的坐标

$offsetx=$_GET['offsetx'];

$offsety=$_GET['offsety'];

//获取单击的颜色

$rgb = ImageColorAt($img, $offsetx, $offsety);

$r = ($rgb >> 16) & 0xFF;

$g = ($rgb >> 8) & 0xFF;

$b = $rgb & 0xFF;

//返回颜色代码

printf('#%02s%02s%02s', dechex($r), dechex($g), dechex($b));

?>

(9)现在开始处理客户端了。先创建文件chat.css并加入下面代码:

body

{

  font-family: Tahoma, Helvetica, sans-serif;

  margin: 1px;

  font-size: 12px;

  text-align: left

}

#content

{

  border: DarkGreen 1px solid;

  margin-bottom: 10px

}

input

{

  border: #999 1px solid;

  font-size: 10px

}

#scroll

{

  position: relative;

  width: 340px;

  height: 270px;

  overflow: auto

}

.item

{

  margin-bottom: 6px

}

#colorpicker

{

  text-align:center 

}

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论