php怎么实现聊天功能
php怎么实现聊天功能
1、在前端使用Ajax定时轮询访问php脚本,php再进行查询聊天数据进行返回给前端,最后前端将其进行渲染;
代码示例:
<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('请填写内容'); return false; } $("#content").val(""); $.post("ajax.php", {content:content});}); }) function getData(msg){ if(msg == undefined) { msg = ''; } $.post("get.php",{"msg":msg},function(data){ //var myjson = eval("("+data+")"); if(data){ var chatcontent = ''; var obj = eval('('+data+')'); $.each(obj,function(key,val){ chatcontent += "<div class='username'>"+val['username']+" 说:</div>"; chatcontent += "<div class='content'>"+val['content']+"</div>"; }) $("#chatshow").html(chatcontent); } getData(); }) } // function getUser(msg){ // if(msg == undefined){ // msg = ''; // } // $.post("getuser.php",{"msg":msg},function(data){ // //var myjson = eval("("+data+")"); // if(data){ // var chatcontent = ''; // var obj = eval('('+data+')'); // $.each(obj,function(key,val){ // chatcontent += "<div class='username'>"+val['username']+" 说:</div>"; // chatcontent += "<div class='content'>"+val['content']+"</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('请填写内容'); // 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'"; // $db = new PDO($dsn, 'root', 'root'); $db = new PDO('mysql:dbname=test;host=127.0.0.1;charset=utf8', 'root', 'adminroot'); $rs = $db->prepare("select * from chat where is_login = '1'"); $rs->execute(); while($row = $rs->fetch()){ echo '<p>'.$row['username'].'</p>'; } ?> </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='button' name='tj' id="post" value='发布' > </div> </body> </html>
<?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 'conn.inc'; 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和服务器进行长连接,来实现聊天功能。
客户端代码:
<!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('请输入用户名', 'user' + uuid(8, 16)); var avatar = ['bo-jackson.jpg', 'dog.png', 'drake.jpg', 'louis-ck.jpeg', 'michael-jordan.jpg', 'thomas.jpg']; 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 'handShake': console.log(data.msg); //发送用户登录 var user_info = {'type': 'login', 'msg': uname, 'headerimg': headerimg}; sendMsg(user_info); break; case 'login': userList(data.user_list); systemMessage('系统消息: ' + data.msg + ' 已上线'); break; case 'logout': userList(data.user_list); if (data.msg.length > 0) { systemMessage('系统消息: ' + data.msg + ' 已下线'); } break; case 'user': messageList(data); break; case 'system': 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('div.active-chat'); 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 = ''; 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('ul.people').innerHTML = html; document.querySelector('span#numbers').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('div.active-chat'); 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 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); 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] = '-'; uuid[14] = '4'; 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(''); } </script> </body> </html>
服务端代码:
<?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 < 126) { $frame[1] = $len < 16 ? '0' . dechex($len) : dechex($len); } else if ($len < 65025) { $s = dechex($len); $frame[1] = '7e' . str_repeat('0', 4 - strlen($s)) . $s; } else { $s = dechex($len); $frame[1] = '7f' . str_repeat('0', 16 - strlen($s)) . $s; } $data = ''; $l = strlen($msg); for ($i = 0; $i < $l; $i++) { $data .= dechex(ord($msg{$i})); } $frame[2] = $data; $data = implode('', $frame); return pack("H*", $data); } /** * 接受数据解析 * @param $buffer * @return mixed */ private function parse($buffer) { $decoded = ''; $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 . '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教程》
Atas ialah kandungan terperinci php怎么实现聊天功能. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



PHP 8.4 membawa beberapa ciri baharu, peningkatan keselamatan dan peningkatan prestasi dengan jumlah penamatan dan penyingkiran ciri yang sihat. Panduan ini menerangkan cara memasang PHP 8.4 atau naik taraf kepada PHP 8.4 pada Ubuntu, Debian, atau terbitan mereka

Untuk bekerja dengan tarikh dan masa dalam cakephp4, kami akan menggunakan kelas FrozenTime yang tersedia.

CakePHP ialah rangka kerja sumber terbuka untuk PHP. Ia bertujuan untuk menjadikan pembangunan, penggunaan dan penyelenggaraan aplikasi lebih mudah. CakePHP adalah berdasarkan seni bina seperti MVC yang berkuasa dan mudah difahami. Model, Pandangan dan Pengawal gu

Untuk mengusahakan muat naik fail, kami akan menggunakan pembantu borang. Di sini, adalah contoh untuk muat naik fail.

Kod Visual Studio, juga dikenali sebagai Kod VS, ialah editor kod sumber percuma — atau persekitaran pembangunan bersepadu (IDE) — tersedia untuk semua sistem pengendalian utama. Dengan koleksi sambungan yang besar untuk banyak bahasa pengaturcaraan, Kod VS boleh menjadi c

CakePHP ialah rangka kerja MVC sumber terbuka. Ia menjadikan pembangunan, penggunaan dan penyelenggaraan aplikasi lebih mudah. CakePHP mempunyai beberapa perpustakaan untuk mengurangkan beban tugas yang paling biasa.

Tutorial ini menunjukkan cara memproses dokumen XML dengan cekap menggunakan PHP. XML (bahasa markup extensible) adalah bahasa markup berasaskan teks yang serba boleh yang direka untuk pembacaan manusia dan parsing mesin. Ia biasanya digunakan untuk penyimpanan data

JWT adalah standard terbuka berdasarkan JSON, yang digunakan untuk menghantar maklumat secara selamat antara pihak, terutamanya untuk pengesahan identiti dan pertukaran maklumat. 1. JWT terdiri daripada tiga bahagian: header, muatan dan tandatangan. 2. Prinsip kerja JWT termasuk tiga langkah: menjana JWT, mengesahkan JWT dan muatan parsing. 3. Apabila menggunakan JWT untuk pengesahan di PHP, JWT boleh dijana dan disahkan, dan peranan pengguna dan maklumat kebenaran boleh dimasukkan dalam penggunaan lanjutan. 4. Kesilapan umum termasuk kegagalan pengesahan tandatangan, tamat tempoh, dan muatan besar. Kemahiran penyahpepijatan termasuk menggunakan alat debugging dan pembalakan. 5. Pengoptimuman prestasi dan amalan terbaik termasuk menggunakan algoritma tandatangan yang sesuai, menetapkan tempoh kesahihan dengan munasabah,
