使用PHP实现实时聊天功能的消息红包和群发功能

1. 前言

实时聊天功能已经成为了现代社交平台上必不可少的一部分,它可以为用户提供快捷、实时、直接的沟通方式。同时,在聊天功能中加入消息红包和群发功能,具有一定的创新意义和商业价值。

本文将介绍如何使用PHP实现实时聊天功能的消息红包和群发功能。

2. 功能实现

2.1 实时聊天功能实现

实时聊天功能需要使用WebSocket技术,WebSocket是一种在单个TCP连接上进行全双工通信的协议,而不像HTTP那样每次请求都需要建立一个新的连接。相比于HTTP轮询技术,WebSocket技术具有低延迟、全双工通信和高效性等优点。

以下是使用PHP和JavaScript实现实时聊天的代码:

//服务器端代码

$server = new swoole_websocket_server("0.0.0.0", 9501);

$server->on('open', function (swoole_websocket_server $server, $request) {

echo "server: handshake success with fd{$request->fd}\n";

});

$server->on('message', function (swoole_websocket_server $server, $frame) {

echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";

foreach ($server->connections as $fd) {

$server->push($fd, $frame->data);

}

});

$server->on('close', function ($ser, $fd) {

echo "client {$fd} closed\n";

});

$server->start();

//客户端代码

var wsServer = 'ws://localhost:9501';

var websocket = new WebSocket(wsServer);

websocket.onopen = function (evt) {

console.log("Connected to WebSocket server.");

};

websocket.onclose = function (evt) {

console.log("Disconnected");

};

websocket.onmessage = function (evt) {

console.log('Retrieved data from server: ' + evt.data);

};

websocket.onerror = function (evt, e) {

console.log('Error occured: ' + evt.data);

};

以上代码实现了一个简单的PHP WebSocket服务器和一个JavaScript WebSocket客户端,可以实现实时聊天的基本功能。

2.2 消息红包功能实现

消息红包是指在聊天中发送一个有价值的礼物,接收者可以领取礼物并获得里面的奖励。实现消息红包功能需要考虑以下几个方面:

2.2.1 数据库表设计

首先需要设计两张数据库表,一张是红包表,记录红包的信息;另一张是红包明细表,记录红包的领取信息。

红包表结构如下:

CREATE TABLE `red_packet` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`title` varchar(50) NOT NULL DEFAULT '' COMMENT '红包标题',

`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '红包金额',

`total` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '红包数量',

`left_num` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '红包剩余数量',

`create_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',

`expire_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '过期时间',

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

红包明细表结构如下:

CREATE TABLE `red_packet_detail` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`red_packet_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '红包ID',

`receiver_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '领取者ID',

`amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '领取金额',

`create_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',

PRIMARY KEY (`id`),

KEY `red_packet_id` (`red_packet_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='红包明细表';

2.2.2 红包生成

生成红包可以采用随机或固定金额的方式。随机金额可以让红包更具有惊喜感,而固定金额可以让发送者更加把控红包的总额。以下是红包生成的PHP代码:

/**

* 生成红包

* @param float $total 红包金额

* @param int $num 红包数量

* @return array 返回红包列表

*/

function genRedPackets($total, $num) {

$min = 0.01; //最小金额

$list = array();

for ($i = 0; $i < $num; $i++) {

if ($num == 1) {

$money = round($total, 2); //只有一个红包,直接取总金额作为红包金额

} else {

$max = $total - $min * ($num - $i); //最大金额

$money = mt_rand(1, $max * 100) / 100; //随机生成红包金额

$money = max($min, $money); //保证红包不小于最小金额

$money = min($max, $money); //保证红包不大于最大金额

$money = round($money, 2); //保留两位小数

}

$list[] = $money;

$total -= $money; //减去发出去的红包金额

}

return $list;

}

2.2.3 红包发送

发送红包需要先将红包信息插入红包表中,然后再将红包明细记录插入到红包明细表中。以下是发送红包的PHP代码:

/**

* 发送红包

* @param int $sender_id 发送者ID

* @param string $title 红包标题

* @param float $total 红包金额

* @param int $num 红包数量

* @return bool 发送成功返回true,否则返回false

*/

function sendRedPacket($sender_id, $title, $total, $num) {

$time = time();

$expire_time = $time + 24 * 3600; //红包过期时间为24小时

$list = genRedPackets($total, $num);

$redPacketModel = new RedPacketModel();

$redPacketDetailModel = new RedPacketDetailModel();

$redPacketModel->begin(); //开启事务

//插入红包记录

$red_packet_data = array(

'title' => $title,

'amount' => $total,

'total' => $num,

'left_num' => $num,

'create_time' => $time,

'expire_time' => $expire_time,

);

$red_packet_id = $redPacketModel->insert($red_packet_data);

if(!$red_packet_id) {

$redPacketModel->rollback(); //失败回滚事务

return false;

}

//插入红包明细记录

foreach ($list as $money) {

$red_packet_detail_data = array(

'red_packet_id' => $red_packet_id,

'receiver_id' => 0,

'amount' => $money,

'create_time' => $time,

);

$red_packet_detail_id = $redPacketDetailModel->insert($red_packet_detail_data);

if(!$red_packet_detail_id) {

$redPacketModel->rollback(); //失败回滚事务

return false;

}

}

$redPacketModel->commit(); //提交事务

return true;

}

2.2.4 红包领取

领取红包需要判断红包是否过期或已领取完毕,然后再将领取信息记录到红包明细表中。以下是领取红包的PHP代码:

/**

* 领取红包

* @param int $receiver_id 领取者ID

* @param int $red_packet_id 红包ID

* @return bool 领取成功返回true,否则返回false

*/

function receiveRedPacket($receiver_id, $red_packet_id) {

$time = time();

$redPacketModel = new RedPacketModel();

$redPacketDetailModel = new RedPacketDetailModel();

$red_packet = $redPacketModel->getById($red_packet_id);

if(!$red_packet || $red_packet['expire_time'] < $time || $red_packet['left_num'] <= 0) {

return false; //红包已过期或已领完

}

$redPacketModel->begin(); //开启事务

//查询一个未领取的红包

$red_packet_detail = $redPacketDetailModel->findOneBy('red_packet_id', $red_packet_id, 'receiver_id, amount');

if(!$red_packet_detail) {

$redPacketModel->rollback(); //失败回滚事务

return false;

}

//领取红包

$update_data = array(

'receiver_id' => $receiver_id,

'create_time' => $time,

);

$redPacketDetailModel->updateById($red_packet_detail['id'], $update_data);

$left_num = $red_packet['left_num'] - 1;

$update_data = array(

'left_num' => $left_num,

);

if($left_num == 0) {

$update_data['expire_time'] = $time; //红包领完了,设为过期

}

$redPacketModel->updateById($red_packet_id, $update_data);

$redPacketModel->commit(); //提交事务

//异步通知发送者和领取者

$sender_id = 0; //根据红包信息获取发送者ID

notifyRedPacket($sender_id, $receiver_id, $red_packet_id, $red_packet['title'], $red_packet_detail['amount']);

return true;

}

2.3 群发功能实现

群发功能是指在聊天中一次性发送多条消息给多个用户。实现群发功能需要考虑以下几个方面:

2.3.1 数据库表设计

群发功能需要新增一张数据库表来记录每个用户接收到的消息。以下是群发记录表的结构:

CREATE TABLE `multicast_record` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`sender_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '发送者ID',

`receiver_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '接收者ID',

`content` text COMMENT '消息内容',

`create_time` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='群发记录表';

2.3.2 群发消息发送

在聊天界面中,增加一个群发按钮,在点击群发按钮后弹出一个选择框供用户选择要发送的用户。选择完毕后,将选中的用户ID列表和消息内容提交给服务器端,并由服务器端完成消息的群发。以下是群发消息发送的PHP代码:

/**

* 群发消息

* @param int $sender_id 发送者ID

* @param array $receiver_ids 接收者ID列表

* @param string $content 消息内容

* @return bool 发送成功返回true,否则返回false

*/

function multicast($sender_id, $receiver_ids, $content) {

$time = time();

$multicastRecordModel = new MulticastRecordModel();

//插入群发记录

foreach ($receiver_ids as $receiver_id) {

$multicast_record_data = array(

'sender_id' => $sender_id,

'receiver_id' => $receiver_id,

'content' => $content,

'create_time' => $time,

);

$multicast_record_id = $multicastRecordModel->insert($multicast_record_data);

if(!$multicast_record_id) {

return false;

}

}

//异步通知接收者

notifyMulticast($sender_id, $receiver_ids, $content);

return true;

}

2.3.3 群发消息接收

在客户端界面中,需要使用WebSocket技术监听服务器端发送过来的群发消息,并在聊天界面中展示。以下是群发消息接收的JavaScript代码:

websocket.onmessage = function (evt) {

var data = JSON.parse(evt.data);

console.log('Retrieved data from server: ' + evt.data);

if(data.type == 'multicast') { //群发消息

console.log('Received multicast message: ' + data.content);

} else { //单点消息

console.log('Received message: ' + data.content);

}

};

3. 总结

本文介绍了如何使用PHP实现实时聊天功能的消息红包和群发功能。其中,实时聊天功能使用了WebSocket技术;消息红包功能实现了红包生成、红包发送、红包领取等基本功能;群发功能实现了群发消息发送和群发消息接收等基本功能。这些功能的实现可以为现代社交平台的开发提供一定的借鉴和参考价值。

后端开发标签