首页 >后端开发 >php教程 >php加swoole加mysql 仿webqq及时聊天

php加swoole加mysql 仿webqq及时聊天

不言
不言原创
2018-04-09 15:40:102500浏览

本篇文章的内容是php加swoole加mysql 仿webqq及时聊天 ,现在分享给大家,有需要的朋友可以参考一下

一、效果图
php加swoole加mysql 仿webqq及时聊天
php加swoole加mysql 仿webqq及时聊天

二、目录结构
php加swoole加mysql 仿webqq及时聊天

images : 存放图片
js : js文件
swoole

|----action.php     数据库操作类
|----config.php     数据库配置文件
|----websocket.php     swoole创建websocket协议文件

index.php : 聊天首页
login.html : 登录页面
webqq.sql : SQL数据库文件

三、数据库结构
php加swoole加mysql 仿webqq及时聊天

四、代码部分
4.1、config.php 数据库配置文件

<?php
$database = array(
    &#39;host&#39;=>&#39;127.0.0.1&#39;,
    &#39;user&#39;=>&#39;root&#39;,
    &#39;password&#39;=>&#39;4f54dd&#39;,
    &#39;port&#39;=>3306,
    &#39;database&#39;=>&#39;webqq&#39;,
    &#39;charset&#39;=>&#39;utf8&#39;
);

4.2、action.php数据库操作类

<?php
class Action
{
    private $conn;
    public function __construct()
    {
        require_once (__DIR__.&#39;/config.php&#39;);
        $this->conn = mysqli_connect($database[&#39;host&#39;],$database[&#39;user&#39;],$database[&#39;password&#39;],$database[&#39;database&#39;]) or die (&#39;Connect mysql failed ~~&#39;.mysqli_connect_error());
    }

    //login
    public function login($nickname,$username,$password)
    {
        session_start();
        $sql = " select `id` from `users` where `username` = &#39;{$username}&#39; ";
        if($query = $this->conn->query($sql)) {
            $row = mysqli_fetch_assoc($query);
            $now = date(&#39;Y-m-d H:i:s&#39;);
            if($row[&#39;id&#39;]) {
                $sql = " update `users` set `nickname` = &#39;{$nickname}&#39; , `username` = &#39;{$username}&#39; ,`password` = md5(&#39;{$password}&#39;) , `login_time` = &#39;{$now}&#39; , `login_num` = (`login_num` + 1) where `id` = {$row[&#39;id&#39;]} ";
            } else {
                $sql = " insert into `users` (`nickname`,`username`,`password`,`login_time`,`login_num`) values (&#39;{$nickname}&#39; , &#39;{$username}&#39; , md5(&#39;{$password}&#39;) , &#39;{$now}&#39; ,&#39;1&#39;)";
            }
            $this->conn->query($sql);
            $user_id = $this->conn->insert_id;
            $_SESSION[&#39;uid&#39;] = $row[&#39;id&#39;] ? $row[&#39;id&#39;] :  $user_id;
            $_SESSION[&#39;nickname&#39;] = $nickname;
            return 1;
        } else {
            return 0;
        }
    }

    //add friend
    public function addFriend($from_uid,$to_uid)
    {
        $sql = " select * from `friend` where `from_uid` = &#39;{$from_uid}&#39; and `to_uid` = &#39;{$to_uid}&#39; ";
        if($query = $this->conn->query($sql)) {
            $is_friend = mysqli_fetch_assoc($query);
            if(!$is_friend[&#39;to_uid&#39;]){
                if($from_uid == $to_uid) {
                    return 2;
                } else {
                    $sql = " select `nickname` from `users` where `id` = &#39;{$to_uid}&#39; ";
                    $query = $this->conn->query($sql);
                    $ret = mysqli_fetch_assoc($query);
                    $nickname = $ret[&#39;nickname&#39;];
                    if($nickname){
                        $sql = " insert into `friend` (`from_uid`,`to_uid`,`nickname`) values (&#39;{$from_uid}&#39;,&#39;{$to_uid}&#39;,&#39;{$nickname}&#39;) ";
                        $this->conn->query($sql);
                        return array(&#39;to_uid&#39;=>$to_uid,&#39;nickname&#39;=>$nickname);
                    } else {
                        return 3;
                    }
                }
            } else {
                return 4;
            }
        } else {
            return 0;
        }
    }

    //friend lists
    public function friendLists($from_uid)
    {
        $sql = " select `id`,`nickname` from `users` where `id` != &#39;{$from_uid}&#39; ";
        if($query = $this->conn->query($sql)) {
            $lists = [];
            while ($row = mysqli_fetch_assoc($query)) {
                $sql_1 = " select `fd` from `fd_tmp` where `uid` = &#39;{$row[&#39;id&#39;]}&#39; ";
                $query_1 = $this->conn->query($sql_1);
                $ret = mysqli_fetch_assoc($query_1);
                $row[&#39;status&#39;] = $ret[&#39;fd&#39;] ? &#39;online&#39; : &#39;offline&#39; ;
                $lists[] = $row;
            }
            return $lists;
        } else {
            return 0;
        }
    }


    //load history message
    public function loadHistory($from_uid,$to_uid)
    {
        $sql = " select `from_uid`,`to_uid`,`message`,`send_time` from `chat` where  ( (`from_uid` = &#39;{$from_uid}&#39; and `to_uid` = &#39;{$to_uid}&#39;) or (`to_uid` = &#39;{$from_uid}&#39; and `from_uid` = &#39;{$to_uid}&#39;) ) order by `send_time` desc";
        if($query = $this->conn->query($sql)) {
            $message = [];
            while ($row = mysqli_fetch_assoc($query)) {
                $message[] = $row;
            }
            return $message;
        } else {
            return 0;
        }
    }

    //send message
    public function sendMessage($from_uid,$to_uid,$message)
    {
        $time = date(&#39;Y-m-d H:i:s&#39;);
        $sql = " insert into `chat` (`from_uid`,`to_uid`,`message`,`send_time`) values (&#39;{$from_uid}&#39;,&#39;{$to_uid}&#39;,&#39;{$message}&#39;,&#39;{$time}&#39;) ";
        if($query = $this->conn->query($sql)) {
            $last_id = $this->conn->insert_id;
            return $last_id;
        } else {
            return 0;
        }
    }

    //get fd 
    public function getFd($uid)
    {
        $sql = " select `fd` from `fd_tmp` where `uid` = &#39;{$uid}&#39; ";
        if($query = $this->conn->query($sql)) {
            $row = mysqli_fetch_assoc($query);
            return $row[&#39;fd&#39;] ? $row[&#39;fd&#39;] : 0;
        } else {
            return 0;
        }
    }

    //bind fd 
    public function bindFd($uid,$fd)
    {
        $sql = " insert into `fd_tmp` (`fd`,`uid`) values (&#39;{$fd}&#39;,&#39;{$uid}&#39;) ";
        if($this->conn->query($sql)) {
            return $fd;
        } else {
            return 0;
        }
    }

    //unbind fd 
    public function unbindFd($fd)
    {
        $sql = " delete from `fd_tmp` where `fd` = &#39;{$fd}&#39; ";
        if($this->conn->query($sql)) {
            return 1;
        } else {
            return 0;
        }
    }

    public function __destruct()
    {
        mysqli_close($this->conn);
    }
}

//process ajax request
if($_POST && isset($_POST[&#39;typ&#39;]))
{
    $action = new Action();
    switch ($_POST[&#39;typ&#39;]) {
        case &#39;login&#39;:
            $ret = $action->login($_POST[&#39;nickname&#39;],$_POST[&#39;username&#39;],$_POST[&#39;password&#39;]);
            break;
        case &#39;addFriend&#39;:
            $ret = $action->addFriend($_POST[&#39;from_uid&#39;],$_POST[&#39;to_uid&#39;]);
            break;
        case &#39;friendLists&#39;:
            $ret = $action->friendLists($_POST[&#39;from_uid&#39;]);
            break;
        case &#39;loadHistory&#39;:
            $ret = $action->loadHistory($_POST[&#39;from_uid&#39;],$_POST[&#39;to_uid&#39;]);
            break;
        case &#39;sendMessage&#39;:
            $ret = $action->sendMessage($_POST[&#39;from_uid&#39;],$_POST[&#39;to_uid&#39;],$_POST[&#39;message&#39;]);
            break;
    }
    echo json_encode(array(&#39;data&#39;=>$ret));
}

4.3、websocket.php文件

<?php
require_once(__DIR__.&#39;/action.php&#39;);
new Websocket();
class Websocket
{
    private $serv;
    private $action;

    public function __construct()
    {
        $this->action = new action();
        $this->serv = new swoole_websocket_server(&#39;0.0.0.0&#39;,9502);
        $this->serv->on(&#39;open&#39;,array($this,&#39;onOpen&#39;));
        $this->serv->on(&#39;message&#39;,array($this,&#39;onMessage&#39;));
        $this->serv->on(&#39;close&#39;,array($this,&#39;onClose&#39;));
        $this->serv->start();
    }

    public function onOpen($server,$request)
    {
        echo "Welcome {$request->fd} \n";
    }

    public function onMessage($server,$request)
    {
        $data = json_decode($request->data);
        $from_uid = $data->from_uid;
        $to_uid = $data->to_uid;
        $message = $data->message;
        $this->action->unbindFd($from_uid);
        $from_fd = $this->action->bindFd($from_uid,$request->fd);
        if($from_fd) {
            $to_fd = $this->action->getFd($to_uid);
            if($to_fd) {
                $server->push($to_fd,$message);
            } 
        } else {
            $server->push($request->fd,&#39;bind from_fd failed ~~&#39;);
        }
    }

    public function onClose($server,$fd)
    {
        $this->action->unbindFd($fd);
        echo "Goodbye {$fd} \n";
    }
}

4.4、index.php首页聊天文件

<?php
session_start();
if(!$_SESSION[&#39;nickname&#39;] && !$_SESSION[&#39;uid&#39;]){
    echo &#39;<script>window.location.href="login.html";</script>&#39;;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-touch-fullscreen" content="yes" />
    <meta name="format-detection" content="telephone=no"/>
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <META HTTP-EQUIV="pragma" CONTENT="no-cache"> 
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate"> 
<META HTTP-EQUIV="expires" CONTENT="0">
    <meta name="format-detection" content="telephone=no" />
    <meta name="msapplication-tap-highlight" content="no" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1" />
    <title>webqq----swoole</title>
    <script type="text/javascript" src="js/jquery.js"></script>
    <style type="text/css">
    html,body{margin:0;padding: 0;background-color: #eee;background-image: url("./images/1.jpg") }
    .userlists{width:280px;height: 620px;border:1px #222 solid;box-shadow:3px 3px 10px #222;border-radius:5px;margin:100px 0px 0px 100px;background-color: #fff}
    .userlists-title{background-color: #222;color:#fff;height: 50px;padding-top:10px;text-align: center;border-radius: 5px 5px 0px 0px;position: relative;}
    .lists_left{height: 500px;overflow-y:scroll;}
    .lists_left::-webkit-scrollbar {display:none}
    .lists_left ul,li{margin:0px;padding:0px;list-style: none}
    .lists_left li{border-bottom:  1px #666 solid;height: 35px;line-height: 35px;}
    .lists_left li a{text-decoration: none;color:#000;height: 100%;display: block;padding-left: 10px}
    .tools{border-radius: 0px 0px 5px 5px;}
    .h10{height: 10px;}
    .h30{height: 500px}
    .circular{height: 30px;width: 30px;border-radius: 30px;background-color: #fff;margin:0 auto;}
    .find{height: 40px;line-height:40px;text-align:center;background-color: #ccc}
    .find input{outline: none}
    .dialogue{width: 600px;height: 600px;background-color: #fff;position: absolute;top:100px;left: 450px;border-radius: 5px;border:1px #222 solid;box-shadow:3px 5px 5px #222;border-radius:5px;display: none;}
    .close{border:1px #fff solid;border-radius:5px;display: inline-block;width: 50px;height: 25px;line-height: 25px;position: absolute;right: 15px;top:12px;}
    .send{height: 50px;line-height: 50px;background-color: #222;border-radius: 0px 0px 5px 5px;text-align: center; }
    .send input[name=&#39;content&#39;]{height: 30px;width:480px;padding:0px 5px;outline: none}
    .send input[name=&#39;sendBtn&#39;]{height: 34px;width:80px;display: inline-block;}
    .chat-line{width:360px;border-radius: 10px;margin:10px;padding: 10px;word-wrap:break-word}
    .from{border:1px red solid;float: right;}
    .to{border:1px green solid;float: left;}
    .all{position: absolute;top:0;right: 100px}
    .scroll_box{position: relative;overflow-y:scroll;height: 500px};
    .scroll_box::-webkit-scrollbar {display:none}
    .lists  {position: absolute;left: 0;top: 0;}

    </style>
</head>
<body>
    <p class="userlists">
        <p class="userlists-title"><?php echo $_SESSION[&#39;nickname&#39;];?><br>好友列表</p>
        <p class="lists_left">
            <ul id="friend_lists">
            </ul>
        </p>
        <p class="userlists-title tools"><p class="h10"></p><p class="circular"></p></p>
    </p>

    <p class="dialogue">
        <p class="userlists-title">正在与 <t id="uname">.....</t> 聊天 <span class="close">关闭</span></p>
        <p class="scroll_box">
            <p class="lists " id="chat-box">
            </p>
        </p>
        <p class="send">
            <input type="hidden" name="to_uid" >
            <input type="text" name="content" placeholder="发送内容">
            <input type="button" name="sendBtn" id="sendMessage" value="发送">
        </p>
    </p>



    <script type="text/javascript">
        $(function(){
            $.post("./swoole/action.php",{from_uid:<?php echo $_SESSION[&#39;uid&#39;];?>,typ:&#39;friendLists&#39;},function(res){
                var r = eval("(" + res + ")");
                if(r.data) {
                    var h = "";
                    for(var i = 0; i< r.data.length; i++) {
                        var status = r.data[i].status =="offline" ? "离线" : "在线" ; 
                        h += &#39;<li><a data-id="&#39; + r.data[i].id + &#39;" data-nickname="&#39; + r.data[i].nickname + &#39;" class="friend" href="javascript:;">&#39; +  r.data[i].nickname + "  ( " + status +&#39; ) </a></li>&#39;;
                    }
                    $("#friend_lists").html(h);
                }
            });


            $("#friend_lists").on("click",".friend",function(){
                var to_uid = $(this).attr("data-id");
                var nickname = $(this).attr("data-nickname");
                $("#uname").html(nickname);
                $("input[name=&#39;to_uid&#39;]").val(to_uid);
                $.post("./swoole/action.php",{from_uid:<?php echo $_SESSION[&#39;uid&#39;];?>,to_uid:to_uid,typ:"loadHistory"},function(res){
                    var r = eval("(" + res + ")");
                    if(r.data) {
                        var h = "";
                        for (var i = r.data.length - 1; i >= 0; i--) {
                            if(r.data[i].from_uid == <?php echo $_SESSION[&#39;uid&#39;];?>) {
                                h += &#39;<p class="chat-line from">&#39; + r.data[i].message + &#39;</p>&#39;;
                            } else {
                                h += &#39;<p class="chat-line to">&#39; + r.data[i].message + &#39;</p>&#39;;
                            }
                        }
                        $("#chat-box").html(h);
                        srcollBox()
                    }
                });
                $(".dialogue").show();
                

            });

            $("#sendMessage").on("click",function(){
                if($("input[name=&#39;content&#39;]").val()) {
                    srcollBox()
                    sendMessage();

                } else {
                    alert("please input your message~");
                }
                
            });
            $(document).keyup(function(evt){
                if(evt.keyCode == 13) {
                    if($("input[name=&#39;content&#39;]").val()) {
                        srcollBox()
                        sendMessage();
                    } else {
                        alert("please input your message~");
                    }
                }
            });

            $(".close").on("click",function(){
                $(".dialogue").hide();
            });
            function srcollBox(){
                var h = $(".lists").height();
                $(".scroll_box").scrollTop(h,4000)
            }
            srcollBox();

            if(window.WebSocket){
                var ws = new WebSocket("ws://192.168.0.140:9502");
                ws.onopen = function(evt){
                    console.log("Connect WebSocket succuess ~~ \n");
                }
                ws.onmessage = function(evt){
                    $("#chat-box").append(&#39;<p class="chat-line to">&#39; + evt.data + &#39;</p>&#39;);
                    srcollBox();
                    console.log("message on server : " + evt.data + "\n");
                }
                ws.onclose = function(evt){
                    console.log("WebSocket closed ~~\n");
                }
                ws.onerror = function(evt){
                    console.log("Connect WebSocket failed ~~\n");
                }
                function sendMessage(){
                    var params = {
                        from_uid : <?php echo $_SESSION[&#39;uid&#39;];?>,
                        to_uid : $("input[name=&#39;to_uid&#39;]").val(),
                        message : $("input[name=&#39;content&#39;]").val(),
                        typ : "sendMessage"
                    };
                    var msg = JSON.stringify(params);
                    $("#chat-box").append(&#39;<p class="chat-line from">&#39; + $("input[name=&#39;content&#39;]").val() + &#39;</p>&#39;);
                    srcollBox();
                    $.post("./swoole/action.php",params,function(res){
                        var r = eval("(" + res + ")");
                        if(r.data) {
                            ws.send(msg);
                        } else {
                            alert("send message failed , insert mysql failed~~\n");
                        }
                    });
                    
                }
            } else {
                alert("Your browser does not support WebSocket !");
            }
        });
    </script>
</body>
</html>

4.5、login.html 登录文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-touch-fullscreen" content="yes" />
    <meta name="format-detection" content="telephone=no"/>
    <meta name="apple-mobile-web-app-status-bar-style" content="black" />
    <meta name="format-detection" content="telephone=no" />
    <meta name="msapplication-tap-highlight" content="no" />
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1" />
    <title>webqq----swoole</title>
    <script type="text/javascript" src="./js/jquery.js"></script>
    <style type="text/css">
    html,body{margin:0;padding: 0;background-color: #eee}
    .login-form{background-color: #fff;width: 500px;height: 500px;margin:100px auto;border:1px #ccc solid;border-radius: 5px;box-shadow: 3px 3px 3px #666}
    h3{text-align: center;margin-top: 100px}
    .container{text-align: center;margin-top: 30px;}
    .container label{display: inline-block;width: 50px;}
    .container input{display: inline-block;height: 25px;line-height: 25px;padding: 0px 5px;width: 300px;outline: none}
    input[name=&#39;login&#39;]{background-color: #5aba1f;color:#fff;border:none;width: 150px;height: 30px;line-height: 30px;border-radius: 5px;margin-top: 30px;cursor: pointer;}
    .warning{border:2px #f00 solid;}
    </style>
</head>
<body>

    <form method="post" action="" class="login-form">
        <h3>WebQQ</h3>
        <p class="container"><label>昵称:</label><input type="text" name="nickname" placeholder="昵称" ></p>
        <p class="container"><label>帐号:</label><input type="text" name="username" placeholder="用户"></p>
        <p class="container"><label>密码:</label><input type="password" name="password" placeholder="密码"></p>
        <p class="container"><input type="button" name="login" value="登录"></p>
    </form>
    <script type="text/javascript">
        $(function(){
            $("input[name=&#39;login&#39;]").click(function(){
                var nickname = $("input[name=&#39;nickname&#39;]").val();
                var username = $("input[name=&#39;username&#39;]").val();
                var password = $("input[name=&#39;password&#39;]").val();
                if(nickname == ""){
                    alert("请设置昵称");
                    $("input[name=&#39;nickname&#39;]").focus();
                    $("input[name=&#39;nickname&#39;]").addClass("warning");
                    $("input[name=&#39;username&#39;]").removeClass("warning");
                    $("input[name=&#39;password&#39;]").removeClass("warning");
                } else if(username == "") {
                    alert("请输入帐号");
                    $("input[name=&#39;username&#39;]").focus();
                    $("input[name=&#39;nickname&#39;]").removeClass("warning");
                    $("input[name=&#39;username&#39;]").addClass("warning");
                    $("input[name=&#39;password&#39;]").removeClass("warning");
                } else if(password == "") {
                    alert("请输入密码");
                    $("input[name=&#39;password&#39;]").focus();
                    $("input[name=&#39;nickname&#39;]").removeClass("warning");
                    $("input[name=&#39;username&#39;]").removeClass("warning");
                    $("input[name=&#39;password&#39;]").addClass("warning");
                } else {
                    $("input[name=&#39;nickname&#39;]").removeClass("warning");
                    $("input[name=&#39;username&#39;]").removeClass("warning");
                    $("input[name=&#39;password&#39;]").removeClass("warning");
                    $.post("./swoole/action.php",{nickname:nickname,username:username,password:password,typ:&#39;login&#39;},function(res){
                        var r = eval("(" + res + ")");
                        if(r.data == "1"){
                            window.location.href="index.php";
                        } else {
                            alert("failed~~");
                        }
                    });
                }
            });
        });
    </script>
</body>
</html>

4.6、webqq.sql 数据结构文件

-- Adminer 4.1.0 MySQL dump

SET NAMES utf8;
SET time_zone = &#39;+00:00&#39;;
SET foreign_key_checks = 0;
SET sql_mode = &#39;NO_AUTO_VALUE_ON_ZERO&#39;;

DROP TABLE IF EXISTS `chat`;
CREATE TABLE `chat` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT &#39;ID&#39;,
  `from_uid` int(10) unsigned NOT NULL,
  `to_uid` int(10) unsigned NOT NULL,
  `message` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `send_time` timestamp NOT NULL DEFAULT &#39;0000-00-00 00:00:00&#39; ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


DROP TABLE IF EXISTS `fd_tmp`;
CREATE TABLE `fd_tmp` (
  `fd` int(10) unsigned NOT NULL,
  `uid` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=&#39;FD值与用户ID绑定&#39;;


DROP TABLE IF EXISTS `friend`;
CREATE TABLE `friend` (
  `from_uid` int(10) unsigned DEFAULT NULL,
  `to_uid` int(10) unsigned NOT NULL,
  `nickname` varchar(45) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=&#39;好友列表&#39;;


DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT &#39;ID&#39;,
  `nickname` varchar(45) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;昵称&#39;,
  `username` varchar(45) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;登陆名称&#39;,
  `password` char(32) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;登陆密码&#39;,
  `login_time` datetime NOT NULL COMMENT &#39;最后登陆时间&#39;,
  `login_num` int(10) unsigned DEFAULT &#39;0&#39; COMMENT &#39;登陆次数&#39;,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=&#39;用户列表&#39;;


-- 2018-03-27 10:05:35

4.7、服务器环境centos7 + mariadb + swoole + apache + php7
注意事项:须安装swoole扩展,Linux服务器,PHP7+版本以上
进行项目根目录使用: php websocket.php  执行该文件

源码下载地址:https://pan.baidu.com/s/1sWY-...


以上是php加swoole加mysql 仿webqq及时聊天 的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn