Home  >  Article  >  Backend Development  >  How to implement chat function in php

How to implement chat function in php

Guanhui
GuanhuiOriginal
2020-05-11 11:40:204103browse

How to implement chat function in php

How to implement the chat function in php

1. Use Ajax on the front end to poll the php script regularly, and php will query the chat data and return it. to the front end, and finally the front end renders it;

Code example:

<html>
<head>
<title>聊天室</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="../jquery.min.js"></script>
<script>
$(function(){
    $("#post").click(function(){
        
    var content=$("#content").val();
    if(!$.trim(content)){
       alert(&#39;请填写内容&#39;);
       return false;
    }
    $("#content").val("");

    $.post("ajax.php", {content:content});});
})
    
    function getData(msg){
        if(msg == undefined)
        {
            msg = &#39;&#39;;    
        }
        $.post("get.php",{"msg":msg},function(data){
            //var myjson = eval("("+data+")");
            if(data){
                var chatcontent = &#39;&#39;;
                var obj = eval(&#39;(&#39;+data+&#39;)&#39;);
                $.each(obj,function(key,val){
                    chatcontent += "<div class=&#39;username&#39;>"+val[&#39;username&#39;]+" 说:</div>";
                    chatcontent += "<div class=&#39;content&#39;>"+val[&#39;content&#39;]+"</div>";
                })
                $("#chatshow").html(chatcontent);
            }
            
            getData();    
        })    
    }
    
    // function getUser(msg){
    //     if(msg == undefined){
    //         msg = &#39;&#39;;    
    //     }
    //     $.post("getuser.php",{"msg":msg},function(data){
    //         //var myjson = eval("("+data+")");
    //         if(data){
    //             var chatcontent = &#39;&#39;;
    //             var obj = eval(&#39;(&#39;+data+&#39;)&#39;);
    //             $.each(obj,function(key,val){
    //                 chatcontent += "<div class=&#39;username&#39;>"+val[&#39;username&#39;]+" 说:</div>";
    //                 chatcontent += "<div class=&#39;content&#39;>"+val[&#39;content&#39;]+"</div>";
    //             })
    //             $("#chatshow").html(chatcontent);
    //         }
    //         getData();    
    //     })    
    // }
    
    getData("one");
    
    

    // $(function(){
    //     $("#userlist p").click(function(){
    //         $("#content").val("@"+$(this).text()+" ");    
    //     })    
    // })
    
    // $(function(){
    //     $(document).keypress(function(e){
    //         if(e.ctrlKey && e.which == 13 || e.which == 10) { 
                   
    //             var content=$("#content").val();
    //             if(!$.trim(content)){
    //                alert(&#39;请填写内容&#39;);
    //                return false;
    //             }
    //             $("#content").val("");    
    //             $.post("ajax.php", {content:content});
    //         }      
    //     })
    //     //alert(event.clientX+document.body.clientWidth);
    // })
    
    /*window.onbeforeunload=function (){ 
        //return("===onbeforeunload==="); 
        if(event.clientX>document.body.clientWidth && event.clientY < 0 || event.altKey){ 
            return("你关闭了浏览器"); 
        }else{ 
            return(document.body.clientWidth); 
        } 
    } */
    
</script>
<style>
#chat{margin:0 auto;}
#chatshow{width:500px;height:400px;overflow:auto;border:1px solid #ccc;float:left;}
#userlist{width:100px;height:400px;overflow:auto;border:1px solid #ccc;float:left;margin-right:2px;}
#userlist p{color:#0F0; cursor:pointer;}
.clearboth{clear:both;}
.username{font-weight:bold;color:#00F;font-size:12px;margin-bottom:3px;margin-top:8px;}
</style>
</head>
<body>
<div id="chat">
<div id="userlist">
<div style="font-size:12px;font-weight:bold;">在线用户列表</div>
<div class="userlist">
<?php 
    // $dsn = "mysql:host=localhost;dbname=test;charset=utf8&#39;";
 //    $db = new PDO($dsn, &#39;root&#39;, &#39;root&#39;);
    $db = new PDO(&#39;mysql:dbname=test;host=127.0.0.1;charset=utf8&#39;, &#39;root&#39;, &#39;adminroot&#39;);
    $rs = $db->prepare("select * from chat where is_login = &#39;1&#39;");
    $rs->execute();
    while($row = $rs->fetch()){
        echo &#39;<p>&#39;.$row[&#39;username&#39;].&#39;</p>&#39;;    
    }
?>
</div>
</div>
<div id="chatshow"></div>
</div>
<div class="clearboth"></div>
<div>
<textarea name="content" id="content" style="width:600px;height:100px"></textarea>
<input type=&#39;button&#39; name=&#39;tj&#39; id="post" value=&#39;发布&#39; >
</div>
</body>
</html>
<?php
/*session_start();
$mem = new Memcache;
$mem->connect("localhost",11211);
if(isset($_POST[&#39;content&#39;])){
    $con[&#39;username&#39;] = $_SESSION["username"];
    $con[&#39;content&#39;] = $_POST["content"];
    
    $data = $mem->get(&#39;chat&#39;);
    $data[] = $con;
    $mem->set("chat",$data,0,0);    
}
$mem->close();
*/
    if(isset($_POST[&#39;content&#39;])){
        session_start();
        $filename = date("Ymd",time()).".txt";
        if(file_exists($filename)){
            $content = file_get_contents($filename);
            $data = json_decode($content,true);        
            $con[&#39;username&#39;] = $_SESSION["username"];
            $con[&#39;content&#39;] = $_POST["content"];
            $data[] = $con;
            $file = fopen($filename,"w");
            fwrite($file,json_encode($data));
            fclose($file);    
        }else{
            $file = fopen($filename,"w");
            $con[&#39;username&#39;] = $_SESSION["username"];
            $con[&#39;content&#39;] = $_POST["content"];
            $data[] = $con;
            fwrite($file,json_encode($data));
            fclose($file);    
        }
            
    }



?>
<?php 
/*require &#39;conn.inc&#39;;
function getData(){
    $sql="SELECT count(*) FROM  `talkroom`";
    $res=mysql_query($sql);
    $count = mysql_fetch_row($res);
    
    return $count;    
}
$old = getData();

while(true){
    $new = getData();
    if($new[0]>$old[0]){
        //echo json_encode($new[&#39;data&#39;]);
        //print_r($new);
        echo &#39;2222222222&#39;.&#39;<br/>&#39;;
    }
    //echo &#39;<br />11111111111111111111111111111111111111111111111111111111111111111111&#39;;
    usleep(1000);
}
*/
/*set_time_limit(0);
$mem = new Memcache;
$mem->connect("localhost",11211);

$count = count($mem->get("chat"));
$com = true;
//$mem->delete(&#39;chat&#39;);
if($_POST[&#39;msg&#39;] == "one"){
    exit(json_encode($mem->get("chat")));    
}
if($_POST[&#39;msg&#39;] == "break"){
    $com = false;    
}
$time1 = time();
while(true){
    if($com){
        $data = $mem->get("chat");
        if(count($data)>$count){
            echo json_encode($data);
            break;
        }
        usleep(300);
    }else{
        break;    
    }
}
$mem->close();*/


set_time_limit(0);
$filename = date("Ymd",time()).".txt";
if(file_exists($filename)){
    $content = file_get_contents($filename);
    $data = json_decode($content,true);        
    $count = count($data);
    // echo $count;die;
    if($_POST[&#39;msg&#39;] == "one"){
        exit(json_encode($data));    
    }
    
    while(true){
        
        $contents = file_get_contents($filename);
        $datas = json_decode($contents,true);
        $counts = count($datas);    
        if($counts>$count){
            echo json_encode($datas);
            break;
        }
        usleep(300);
    }
}else{
    $file = fopen($filename,"w");
    $con[&#39;username&#39;] = "系统消息";
    $con[&#39;content&#39;] = "欢迎来到EPGO聊天室";
    $data[] = $con;
    fwrite($file,json_encode($data));
    fclose($file);
    
    exit(json_encode($data));    
    
}

?>

2. Use WebSocket to make a long connection with the server to implement the chat function.

Client code:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>websocket聊天室</title>
    <link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600" rel="stylesheet">
    <link rel="stylesheet" href="css/reset.min.css">
    <link rel="stylesheet" href="css/style.css">
    <style>
        .message img {
            float: left;
            width: 40px;
            height: 40px;
            margin-right: 12px;
            border-radius: 50%;
        }

        .you {
            margin-left: 60px;
            margin-top: -39px;
        }

        .me-header {
            float: right !important;
            margin-right: 0 !important;
        }

        .me {
            margin-right: 60px;
            margin-top: -39px;
        }

        .active-chat::-webkit-scrollbar, .left::-webkit-scrollbar {
            width: 2px;
        }
    </style>
</head>
<body>

<div>
    <div>
        <div>
            <div style="padding: 20px 29px;height: auto;">
                <div class="" style="font: 400 13.3333px Arial;font-weight: 400;">在线人数:<span id="numbers">0</span> 人
                </div>
            </div>
            <ul>
            </ul>
        </div>
        <div>
            <div><span>Tips: <span>PHP之websocket聊天室</span></span></div>
            <div class="chat active-chat" data-chat="person1"
                 style="height: auto;border-width: 0px;padding: 10px;height: 483px; padding: 10px;overflow-y: auto;scrollTop: 100px">
            </div>
            <div>
                <a href="javascript:;" class="write-link attach"></a>
                <input type="text" id="input-value" onkeydown="confirm(event)"/>
                <a href="javascript:;" class="write-link smiley"></a>
                <a href="javascript:;" class="write-link send" onclick="send()"></a>
            </div>
        </div>
    </div>
</div>

<script src="js/index.js"></script>
<script>
    var uname = prompt(&#39;请输入用户名&#39;, &#39;user&#39; + uuid(8, 16));
    var avatar = [&#39;bo-jackson.jpg&#39;, &#39;dog.png&#39;, &#39;drake.jpg&#39;, &#39;louis-ck.jpeg&#39;, &#39;michael-jordan.jpg&#39;, &#39;thomas.jpg&#39;];
    if (avatar[Math.round(Math.random() * 10)]) {
        var headerimg = "img/" + avatar[Math.round(Math.random() * 10)];
    } else {
        var headerimg = "img/" + avatar[0];
    }

    // 创建一个 websocket 连接
    var ws = new WebSocket("ws://127.0.0.1:1238");

    // websocket 创建成功事件
    ws.onopen = function () {
        var data = "系统消息:建立连接成功";
        console.log(data);

    };

    // websocket 接收到消息事件
    ws.onmessage = function (e) {
        var data = JSON.parse(e.data);
        switch (data.type) {
            case &#39;handShake&#39;:
                console.log(data.msg);
                //发送用户登录
                var user_info = {&#39;type&#39;: &#39;login&#39;, &#39;msg&#39;: uname, &#39;headerimg&#39;: headerimg};
                sendMsg(user_info);
                break;
            case &#39;login&#39;:
                userList(data.user_list);
                systemMessage(&#39;系统消息: &#39; + data.msg + &#39; 已上线&#39;);
                break;
            case &#39;logout&#39;:
                userList(data.user_list);
                if (data.msg.length > 0) {
                    systemMessage(&#39;系统消息: &#39; + data.msg + &#39; 已下线&#39;);
                }
                break;
            case &#39;user&#39;:
                messageList(data);
                break;
            case &#39;system&#39;:
                systemMessage();
                break;
        }
    }

    // websocket 错误事件
    ws.onerror = function () {
        var data = "系统消息 : 出错了,请退出重试.";
        alert(data);
    };

    function confirm(event) {
        var key_num = event.keyCode;
        if (13 == key_num) {
            send();
        } else {
            return false;
        }
    }

    function systemMessage(msg) {
        var html = `<div>
            <span>` + msg + `</span>
        </div>`;
        var active_chat = document.querySelector(&#39;div.active-chat&#39;);
        var oldHtml = active_chat.innerHTML;
        active_chat.innerHTML = oldHtml + html;
        active_chat.scrollTop = active_chat.scrollHeight;
    }

    function send() {
        var msg = document.querySelector("input#input-value").value;
        var reg = new RegExp("\r\n", "g");
        msg = msg.replace(reg, "");
        sendMsg({type: "user", msg: msg});
        document.querySelector("input#input-value").value = "";
    }

    function sendMsg(msg) {
        var data = JSON.stringify(msg);
        ws.send(data);
    }

    function userList(user) {
        var html = &#39;&#39;;
        for (var i = 0; i < user.length; i++) {
            html += `<li data-chat="person1">
                    <img src="` + user[i].headerimg + `" alt=""/>
                    <span>` + user[i].username + `</span>
                    <span>` + user[i].login_time + `</span>
                    <span style="color: green;font-size: 7px;">在线</span>
                </li>`;
        }
        document.querySelector(&#39;ul.people&#39;).innerHTML = html;
        document.querySelector(&#39;span#numbers&#39;).innerHTML = user.length;
    }

    function messageList(data) {
        if (data.from == uname) {
            var html = `<div>
                    <img src="` + data.headerimg + `" alt=""/>
                    <div class="bubble me">` + data.msg + `</div>
                </div>`;
        } else {
            var html = `<div>
                    <img src="` + data.headerimg + `" alt=""/>
                    <div class="bubble you">` + data.msg + `</div>
                </div>`;
        }
        var active_chat = document.querySelector(&#39;div.active-chat&#39;);
        var oldHtml = active_chat.innerHTML;
        active_chat.innerHTML = oldHtml + html;
        active_chat.scrollTop = active_chat.scrollHeight;
    }

    /**
     * 生产一个全局唯一ID作为用户名的默认值;
     *
     * @param len
     * @param radix
     * @returns {string}
     */
    function uuid(len, radix) {
        var chars = &#39;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz&#39;.split(&#39;&#39;);
        var uuid = [], i;
        radix = radix || chars.length;

        if (len) {
            for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
        } else {
            var r;

            uuid[8] = uuid[13] = uuid[18] = uuid[23] = &#39;-&#39;;
            uuid[14] = &#39;4&#39;;

            for (i = 0; i < 36; i++) {
                if (!uuid[i]) {
                    r = 0 | Math.random() * 16;
                    uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
                }
            }
        }

        return uuid.join(&#39;&#39;);
    }
</script>
</body>
</html>

Server code:

<?php
/**
 * Created by PhpStorm.
 * User: 25754
 * Date: 2019/4/23
 * Time: 14:13
 */

class socketServer
{

    const LISTEN_SOCKET_NUM = 9;
    const LOG_PATH = "./log/";
    private $_ip = "127.0.0.1";
    private $_port = 1238;
    private $_socketPool = array();
    private $_master = null;

    public function __construct()
    {
        $this->initSocket();
    }

    private function initSocket()
    {
        try {
            //创建socket套接字
            $this->_master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
            // 设置IP和端口重用,在重启服务器后能重新使用此端口;
            socket_set_option($this->_master, SOL_SOCKET, SO_REUSEADDR, 1);
            //绑定地址与端口
            socket_bind($this->_master, $this->_ip, $this->_port);
            //listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接,其中的能存储的请求不明的socket数目。
            socket_listen($this->_master, self::LISTEN_SOCKET_NUM);
        } catch (Exception $e) {
            $this->debug(array("code: " . $e->getCode() . ", message: " . $e->getMessage()));
        }
        //将socket保存到socket池中
        $this->_socketPool[0] = array(&#39;resource&#39; => $this->_master);
        $pid = getmypid();
        $this->debug(array("server: {$this->_master} started,pid: {$pid}"));
        while (true) {
            try {
                $this->run();
            } catch (Exception $e) {
                $this->debug(array("code: " . $e->getCode() . ", message: " . $e->getMessage()));
            }
        }
    }

    private function run()
    {
        $write = $except = NULL;
        $sockets = array_column($this->_socketPool, &#39;resource&#39;);
        $read_num = socket_select($sockets, $write, $except, NULL);
        if (false === $read_num) {
            $this->debug(array(&#39;socket_select_error&#39;, $err_code = socket_last_error(), socket_strerror($err_code)));
            return;
        }
        foreach ($sockets as $socket) {
            if ($socket == $this->_master) {
                $client = socket_accept($this->_master);
                if ($client === false) {
                    $this->debug([&#39;socket_accept_error&#39;, $err_code = socket_last_error(), socket_strerror($err_code)]);
                    continue;
                }
                //连接
                $this->connection($client);
            } else {
                //接受数据
                $bytes = @socket_recv($socket, $buffer, 2048, 0);
                if ($bytes == 0) {
                    $recv_msg = $this->disconnection($socket);
                } else {
                    if ($this->_socketPool[(int)$socket][&#39;handShake&#39;] == false) {
                        $this->handShake($socket, $buffer);
                        continue;
                    } else {
                        $recv_msg = $this->parse($buffer);
                    }
                }
                $msg = $this->doEvents($socket, $recv_msg);
                echo($msg);
                socket_getpeername ( $socket  , $address ,$port );
                $this->debug(array(
                    &#39;send_success&#39;,
                    json_encode($recv_msg),
                    $address,
                    $port
                ));
                $this->broadcast($msg);
            }
        }
    }

    /**
     * 数据广播
     * @param $data
     */
    private function broadcast($data)
    {
        foreach ($this->_socketPool as $socket) {
            if ($socket[&#39;resource&#39;] == $this->_master) {
                continue;
            }
            socket_write($socket[&#39;resource&#39;], $data, strlen($data));
        }
    }

    /**
     * 业务处理
     * @param $socket
     * @param $recv_msg
     * @return string
     */
    private function doEvents($socket, $recv_msg)
    {
        //联系我
    }

    /**
     * socket握手
     * @param $socket
     * @param $buffer
     * @return bool
     */
    public function handShake($socket, $buffer)
    {
        $acceptKey = $this->encry($buffer);
        $upgrade = "HTTP/1.1 101 Switching Protocols\r\n" .
            "Upgrade: websocket\r\n" .
            "Connection: Upgrade\r\n" .
            "Sec-WebSocket-Accept: " . $acceptKey . "\r\n\r\n";

        // 写入socket
        socket_write($socket, $upgrade, strlen($upgrade));
        // 标记握手已经成功,下次接受数据采用数据帧格式
        $this->_socketPool[(int)$socket][&#39;handShake&#39;] = true;
        socket_getpeername ( $socket  , $address ,$port );
        $this->debug(array(
            &#39;hand_shake_success&#39;,
            $socket,
            $address,
            $port
        ));
        //发送消息通知客户端握手成功
        $msg = array(&#39;type&#39; => &#39;handShake&#39;, &#39;msg&#39; => &#39;握手成功&#39;);
        $msg = $this->frame(json_encode($msg));
        socket_write($socket, $msg, strlen($msg));
        return true;
    }

    /**
     * 帧数据封装
     * @param $msg
     * @return string
     */
    private function frame($msg)
    {
        $frame = [];
        $frame[0] = &#39;81&#39;;
        $len = strlen($msg);
        if ($len < 126) {
            $frame[1] = $len < 16 ? &#39;0&#39; . dechex($len) : dechex($len);
        } else if ($len < 65025) {
            $s = dechex($len);
            $frame[1] = &#39;7e&#39; . str_repeat(&#39;0&#39;, 4 - strlen($s)) . $s;
        } else {
            $s = dechex($len);
            $frame[1] = &#39;7f&#39; . str_repeat(&#39;0&#39;, 16 - strlen($s)) . $s;
        }
        $data = &#39;&#39;;
        $l = strlen($msg);
        for ($i = 0; $i < $l; $i++) {
            $data .= dechex(ord($msg{$i}));
        }
        $frame[2] = $data;
        $data = implode(&#39;&#39;, $frame);
        return pack("H*", $data);
    }

    /**
     * 接受数据解析
     * @param $buffer
     * @return mixed
     */
    private function parse($buffer)
    {
        $decoded = &#39;&#39;;
        $len = ord($buffer[1]) & 127;
        if ($len === 126) {
            $masks = substr($buffer, 4, 4);
            $data = substr($buffer, 8);
        } else if ($len === 127) {
            $masks = substr($buffer, 10, 4);
            $data = substr($buffer, 14);
        } else {
            $masks = substr($buffer, 2, 4);
            $data = substr($buffer, 6);
        }
        for ($index = 0; $index < strlen($data); $index++) {
            $decoded .= $data[$index] ^ $masks[$index % 4];
        }
        return json_decode($decoded, true);
    }

    // 提取 Sec-WebSocket-Key 信息
    private function getKey($req)
    {
        $key = null;
        if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $req, $match)) {
            $key = $match[1];
        }
        return $key;
    }

    //加密 Sec-WebSocket-Key
    private function encry($req)
    {
        $key = $this->getKey($req);
        return base64_encode(sha1($key . &#39;258EAFA5-E914-47DA-95CA-C5AB0DC85B11&#39;, true));
    }

    /**
     * 连接socket
     * @param $client
     */
    public function connection($client)
    {
        socket_getpeername ( $client  , $address ,$port );
        $info = array(
            &#39;resource&#39; => $client,
            &#39;userInfo&#39; => &#39;&#39;,
            &#39;handShake&#39; => false,
            &#39;ip&#39; => $address,
            &#39;port&#39; => $port,
        );
        $this->_socketPool[(int)$client] = $info;
        $this->debug(array_merge([&#39;socket_connect&#39;], $info));
    }

    /**
     * 断开连接
     * @param $socket
     * @return array
     */
    public function disconnection($socket)
    {
        $recv_msg = array(
            &#39;type&#39; => &#39;logout&#39;,
            &#39;msg&#39; => @$this->_socketPool[(int)$socket][&#39;username&#39;],
        );
        unset($this->_socketPool[(int)$socket]);
        return $recv_msg;
    }

    /**
     * 日志
     * @param array $info
     */
    private function debug(array $info)
    {
        $time = date(&#39;Y-m-d H:i:s&#39;);
        array_unshift($info, $time);
        $info = array_map(&#39;json_encode&#39;, $info);
        file_put_contents(self::LOG_PATH . &#39;websocket_debug.log&#39;, implode(&#39; | &#39;, $info) . "\r\n", FILE_APPEND);
    }
}

new socketServer();

Recommended tutorial: "PHP Tutorial"

The above is the detailed content of How to implement chat function in php. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn