如有疑问,欢迎打扰~~~~~

php + websocket 实现即时通讯。

右键菜单功能。

 群聊功能以及右键菜单功能

<?php
namespace app\server\controller;
use think\worker\Server;
use think\Session;
use Workerman\Lib\Timer;
// 心跳间隔55秒
define('HEARTBEAT_TIME', 55);
define('CHECK_HEARTBEAT_TIME', 10); // 检查连接的间隔时间

class Worker extends Server
{
    protected $socket = 'websocket://www.tp5.com:2346';
    protected $processes = 1;
    protected $uidConnections = array();
    static $count  = 0;

    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
    {
        // 判断当前客户端是否已经验证,既是否设置了uid,设置了直接发送消息,未设置第一次为设置uid
        dump('开始');
        $connection->lastMessageTime = time();
        if(!isset($connection->uid))
        {
            $uid = json_decode($data,true);
            if ($uid['message_type'] == 'event'){
                dump($uid);
                switch ($uid['type']){
                    case 'sendOrder':
                        $arr = [
                            'message_type'  => 'event',
                            'type'          => 'sendOrder',
                            'username'      => $uid['username'],
                            'imgUrl'        => $uid['imgUrl'],
                            'info'          => $uid['info'],
                        ];
                        $receipt = json_encode($arr,JSON_UNESCAPED_UNICODE );
                        break;
                    case 'online':
                        $arr = [
                            'message_type'  => 'event',
                            'type'          => 'online',
                            'username'      => $uid['username'],
                        ];
                        $receipt = json_encode($arr,JSON_UNESCAPED_UNICODE );
                        break;
                }

                $this->sendUser($receipt);
            }else {
                $managerInfo = $this->getManagerInfo($uid['id'], $uid);
                dump($managerInfo);
                if (!empty($managerInfo) && !empty($uid['userType'])){
                    db('wx_wechat_info')->where("openId = '{$uid['id']}'")->update(array('onlineTime'=>time(),'onlineStatus'=>'online'));
                }
                if (!empty($managerInfo) && empty($uid['userType'])){
                    db('sw_manager')->where("mg_id = {$uid['id']}")->update(array('online_time'=>time(),'online_status'=>'online'));
                }
                // 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证)
                $connection->uid = $uid['id'];
                /* 保存uid到connection的映射,这样可以方便的通过uid查找connection,
                 * 实现针对特定uid推送数据
                 */
                $this->uidConnections[$connection->uid] = $connection;
                //---------------连接时候更新状态-----------------
                $receipt = '';
                switch ($uid['message_type']){
                    case 'init':
                        $arr = [
                            'message_type'  => 'init',
                            'id'            => $uid['id'],
                            'username'      => $uid['username'],
                            'online_status' => 'online',
                            'remark'        => !empty($managerInfo['remark']) ? $managerInfo['remark'] : '',
                        ];
                        $receipt = json_encode($arr,JSON_UNESCAPED_UNICODE );
                        break;
                }
                $this->sendUser($receipt);
                return;
            }

        }else{
            $data = json_decode($data,true);
            dump($data);
            if (!empty($data['type'])){
                switch ($data['type']){
                    case 'chatMessage':
                        $chatType = $data['data']['to']['type'];

                        $arr = [
                            'message_type'=> 'chatMessage',
                            'data'=>[
                                'username'    => $data['data']['mine']['username'],
                                'avatar'      => $data['data']['mine']['avatar'],
                                'id'          => $chatType === 'friend' ? $data['data']['mine']['id'] : $data['data']['to']['id'],
                                'type'        => $chatType,
                                'content'     => $data['data']['mine']['content'],
                                'formid'      => $data['data']['mine']['id'],
                                'timestamp'   => time()*1000,
                            ]
                        ];

                        if ($chatType === 'friend'){
                            $name = $data['data']['to']['username'];
                            $form = 'msg_message';
                            $receipt = json_encode($arr,JSON_UNESCAPED_UNICODE );
                            $this->sendMessageByUid($data['data']['to']['id'],$receipt);
                        } else {
                            $name = $data['data']['to']['name'];
                            $form = 'msg_group_message';
                            $groupId = $data['data']['to']['id'];
                            $groupArr = db('msg_group_relation')->where("msGId IN ('{$groupId}') AND mgId <> {$data['data']['mine']['id']}")->field('msGId,mgId')->select();
                            $receipt = json_encode($arr,JSON_UNESCAPED_UNICODE );
                            foreach ($groupArr as $value){
                                $this->sendMessageByUid($value['mgId'],$receipt);
                            }
                        }

                        $keyword = $data['data']['mine']['content'];
                        $content = $this->getNeedBetween($keyword, '[' , ']' );
                        $type = substr($keyword,0,strpos($keyword, '['));


                        //发送方数据
                        $sendMessage = [
                            'status'        => $data['status'] === 'online' ? 2 : 1,
                            'content'       => is_string($content) ? $content : $data['data']['mine']['content'],
                            'type'          => $type,
                            'fromUserName'  => $data['data']['mine']['username'],
                            'fromUserId'    => $data['data']['mine']['id'],
                            'toUserName'    => $name,
                            'toUserId'      => $data['data']['to']['id'],
                            'addTime'       => date('Y-m-d H:i:s', time())
                        ];
                        db($form)->insert($sendMessage);
                        break;
                    case 'onClose':
                        $arr = [
                            'message_type'=> 'chatMessage',
                            'data'=>[
                                'system'    => 'true',
                                'id'        => $data['data']['mine']['id'],
                                'type'      => 'friend',
                                'content'   => '对方已离线',
                            ]
                        ];
                        $receipt = json_encode($arr,JSON_UNESCAPED_UNICODE );
                        $this->sendMessageByUid($data['data']['to']['id'],$receipt);
                        break;
                    default:
                        $this->sendUser('1111111');
                }
            }
        }
    }

    function getNeedBetween($kw1,$mark1,$mark2){
        $kw=$kw1;
        $kw='123'.$kw.'123';
        $st =stripos($kw,$mark1);
        $ed =stripos($kw,$mark2);
        if(($st==false||$ed==false)||$st>=$ed)
            return 0;
        $kw=substr($kw,($st+1),($ed-$st-1));
        return $kw;
    }

    //查找当前客户信息
    public function getManagerInfo($id, $info)
    {
        if (!empty($info['userType'])){
            $managerInfo = db('wx_wechat_info')->alias('a')->join('wx_group_customer b', 'a.id = b.wxId')->where("openId = '{$id}'")->field('a.*,b.remark')->find();
        }else {
            $managerInfo = db('sw_manager')->where("mg_id = {$id}")->find();
        }
        return $managerInfo;
    }

    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
    {
        self::$count++;

    }

    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
    {
        dump('关闭连接时触发的');
        self::$count--;
        if(isset($connection->uid))
        {
            //---------连接断开时删除映射并传给客户端----
            $data = $connection->uid;
            $arr = [
                'message_type'  => 'updateInit',
                'id'            => $data,
                'online_status' => 'offline',
            ];
            $updateArr = [
                'message_type'=> 'chatMessage',
                'data'=>[
                    'system'    => 'true',
                    'id'        => $data,
                    'type'      => 'friend',
                    'content'   => '对方已离线',
                ]
            ];
            $receipt = json_encode($arr,JSON_UNESCAPED_UNICODE );
            $receiptArr = json_encode($updateArr,JSON_UNESCAPED_UNICODE );
            $this->sendUser($receipt);
            $this->sendUser($receiptArr);
            unset($this->uidConnections[$connection->uid]);
            //---------修改数据库状态----
            if (!empty($data) && is_numeric($data)){
                db('sw_manager')->where("mg_id = {$data}")->update(array('offline_time'=>time(),'online_status'=>'offline'));
            }
            if (!empty($data) && !is_numeric($data)){
                db('wx_wechat_info')->where("openId = '{$data}'")->update(array('onlineTime'=>time(),'onlineStatus'=>'offline'));
            }
        }
    }

    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo "error $code $msg\n";
    }

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
        dump('--------------启动进程------------------');
        Timer::add(CHECK_HEARTBEAT_TIME, function()use($worker){
            $time_now = time();
            foreach($worker->connections as $connection) {
                // 有可能该connection还没收到过消息,则lastMessageTime设置为当前时间
                if (empty($connection->lastMessageTime)) {
                    $connection->lastMessageTime = $time_now;
                    continue;
                }

                // 上次通讯时间间隔大于心跳间隔,则认为客户端已经下线,关闭连接
                if ($time_now - $connection->lastMessageTime > HEARTBEAT_TIME) {

                    $connection->close();
                }
            }
        });
    }

// 向所有验证的用户推送数据
    function sendUser($message)
    {
        foreach($this->uidConnections as $connection)
        {
            $connection->send($message);
        }
    }

// 针对uid推送数据
    function sendMessageByUid($uid, $message)
    {
        if(isset($this->uidConnections[$uid]))
        {
            $connection = $this->uidConnections[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }
}
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐