php怎么实现聊天功能

风磊吖_5458

风磊吖_5458

2020-05-11

4495人浏览

原创

php怎么实现聊天功能

1、在前端使用Ajax定时轮询访问php脚本,php再进行查询聊天数据进行返回给前端,最后前端将其进行渲染;

代码示例:


<title>聊天室</title><meta><script></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;]+" 说:";
                    chatcontent += "<div class=&#39;content&#39;>"+val[&#39;content&#39;]+"";
                })
                $("#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;]+" 说:";
    //                 chatcontent += "<div class=&#39;content&#39;>"+val[&#39;content&#39;]+"";
    //             })
    //             $("#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><div>
<div>
<div>在线用户列表</div>
<div>
<?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 = '1'");
    $rs->execute();
    while($row = $rs->fetch()){
        echo '<p>'.$row['username'].'</p><div class="aritcle_card flexRow artxards">
											<div class="artcardd flexRow">
												<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill2138" title="PHP"><img
														src="https://img.php.cn/upload/skill/000/000/081/178884013267959.jpg" alt="PHP" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
												<div class="aritcle_card_info flexColumn">
													<a rel="nofollow" href="/xiazai/skill2138" title="PHP" class="overflowclass">PHP</a>
													<p class="overflowclass">编写健壮的PHP代码,规避类型转换陷阱、数组怪癖及常见安全漏洞。</p>
												</div>
												<a rel="nofollow" href="/xiazai/skill2138" title="PHP" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
												</a>
											</div>
										</div>';    
    }
?>
</div>
</div>
<div></div>
</div>
<div></div>
<div>
<textarea></textarea><input>
</div>

<?php /*session_start();
$mem = new Memcache;
$mem->connect("localhost",11211);
if(isset($_POST['content'])){
    $con['username'] = $_SESSION["username"];
    $con['content'] = $_POST["content"];
    
    $data = $mem->get('chat');
    $data[] = $con;
    $mem->set("chat",$data,0,0);    
}
$mem->close();
*/
    if(isset($_POST['content'])){
        session_start();
        $filename = date("Ymd",time()).".txt";
        if(file_exists($filename)){
            $content = file_get_contents($filename);
            $data = json_decode($content,true);        
            $con['username'] = $_SESSION["username"];
            $con['content'] = $_POST["content"];
            $data[] = $con;
            $file = fopen($filename,"w");
            fwrite($file,json_encode($data));
            fclose($file);    
        }else{
            $file = fopen($filename,"w");
            $con['username'] = $_SESSION["username"];
            $con['content'] = $_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['data']);
        //print_r($new);
        echo '2222222222'.'<br>';
    }
    //echo '<br>11111111111111111111111111111111111111111111111111111111111111111111';
    usleep(1000);
}
*/
/*set_time_limit(0);
$mem = new Memcache;
$mem->connect("localhost",11211);

$count = count($mem->get("chat"));
$com = true;
//$mem->delete('chat');
if($_POST['msg'] == "one"){
    exit(json_encode($mem->get("chat")));    
}
if($_POST['msg'] == "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['msg'] == "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['username'] = "系统消息";
    $con['content'] = "欢迎来到EPGO聊天室";
    $data[] = $con;
    fwrite($file,json_encode($data));
    fclose($file);
    
    exit(json_encode($data));    
    
}

?>

2、使用WebSocket和服务器进行长连接,来实现聊天功能。

客户端代码:

nbsp;html>


    <meta>
    <meta>
    <title>websocket聊天室</title>
    <link>
    <link>
    <link>
    <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><div>
    <div>
        <div>
            <div>
                <div>在线人数:<span>0</span> 人
                </div>
            </div>
            <ul>
            </ul>
        </div>
        <div>
            <div><span>Tips: <span>PHP之websocket聊天室</span></span></div>
            <div>
            </div>
            <div>
                <a></a>
                <input>
                <a></a>
                <a></a>
            </div>
        </div>
    </div>
</div>

<script></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 + `
        `;
        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">
                    @@##@@
                    <span>` + user[i].username + `
                    <span>` + user[i].login_time + `
                    <span style="color: green;font-size: 7px;">在线
                `;
        }
        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>
                    @@##@@
                    <div class="bubble me">` + data.msg + `
                `;
        } else {
            var html = `<div>
                    @@##@@
                    <div class="bubble you">` + data.msg + `
                `;
        }
        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>

服务端代码:

<?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('resource' => $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, 'resource');
        $read_num = socket_select($sockets, $write, $except, NULL);
        if (false === $read_num) {
            $this->debug(array('socket_select_error', $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(['socket_accept_error', $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]['handShake'] == 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(
                    'send_success',
                    json_encode($recv_msg),
                    $address,
                    $port
                ));
                $this->broadcast($msg);
            }
        }
    }

    /**
     * 数据广播
     * @param $data
     */
    private function broadcast($data)
    {
        foreach ($this->_socketPool as $socket) {
            if ($socket['resource'] == $this->_master) {
                continue;
            }
            socket_write($socket['resource'], $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]['handShake'] = true;
        socket_getpeername ( $socket  , $address ,$port );
        $this->debug(array(
            'hand_shake_success',
            $socket,
            $address,
            $port
        ));
        //发送消息通知客户端握手成功
        $msg = array('type' => 'handShake', 'msg' => '握手成功');
        $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] = '81';
        $len = strlen($msg);
        if ($len getKey($req);
        return base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
    }

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

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

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

new socketServer();

推荐教程:《PHP教程

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php websocket

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

相关专题

更多
ajax教程
ajax教程

php中文网为大家带来ajax教程合集,Ajax是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。php中文网还为大家带来ajax的相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.14

2200

4

ajax中文乱码解决方法
ajax中文乱码解决方法

ajax中文乱码解决方法有设置请求头部的字符编码、在服务器端设置响应头部的字符编码和使用encodeURIComponent对中文进行编码。本专题为大家提供ajax中文乱码相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.31

340

5

ajax传递中文乱码怎么办
ajax传递中文乱码怎么办

ajax传递中文乱码的解决办法:1、设置统一的编码方式;2、服务器端编码;3、客户端解码;4、设置HTTP响应头;5、使用JSON格式。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.11.15

2033

5

ajax网站有哪些
ajax网站有哪些

使用ajax的网站有谷歌、维基百科、脸书、纽约时报、亚马逊、stackoverflow、twitter、hacker news、shopify和basecamp等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.09.24

1121

6

Golang WebSocket与实时通信开发
Golang WebSocket与实时通信开发

本专题系统讲解 Golang 在 WebSocket 开发中的应用,涵盖 WebSocket 协议、连接管理、消息推送、心跳机制、群聊功能与广播系统的实现。通过构建实际的聊天应用或实时数据推送系统,帮助开发者掌握 如何使用 Golang 构建高效、可靠的实时通信系统,提高并发处理与系统的可扩展性。

2025.12.22

175

11

PHP WebSocket 实时通信开发
PHP WebSocket 实时通信开发

本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

2026.01.19

376

22

Python WebSocket实时通信与异步服务开发实践
Python WebSocket实时通信与异步服务开发实践

本专题聚焦 Python 在实时通信场景中的开发实践,系统讲解 WebSocket 协议原理、长连接管理、消息推送机制以及异步服务架构设计。内容包括客户端与服务端通信实现、连接稳定性优化、消息队列集成及高并发处理策略。通过完整案例,帮助开发者构建高效稳定的实时通信系统,适用于聊天应用、实时数据推送等场景。

2026.03.18

355

14

WebSocket 前端开发与实战技巧
WebSocket 前端开发与实战技巧

聚焦 WebSocket 在前端项目中的工程化实践,涵盖原生 JavaScript WebSocket 连接的封装与状态管理、Vue 3 中 WebSocket 的 Composable 封装(useWebSocket)、React 中自定义 Hook 管理连接生命周期、心跳检测(Ping/Pong 定时器)与自动断线重连的实现策略、指数退避重连算法、消息序列化协议(JSON / Protobuf / MessagePack)的选型与性

2026.05.25

348

33

WebSocket发送和接收数据教程合集
WebSocket发送和接收数据教程合集

本专题整合了WebSocket发送与接收数据教程合集,阅读专题下面的文章了解更多详细内容。

2026.05.25

281

20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
墨刀帮助中心
墨刀帮助中心

共0课时 | 0人学习

MyEclipse学习中心
MyEclipse学习中心

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习