純PHP 簡易(Server/Client)線上聊天室[websocket chat] 範例
純PHP 簡易(Server/Client)線上聊天室[websocket chat] 範例
資料來源: https://github.com/sanwebe/Chat-Using-WebSocket-and-PHP-Socket
https://github.com/zhenbianshu/websocket
GITHUB:
https://github.com/jash-git/PHP-websocket-chat [函數版]
https://github.com/jash-git/Linux_Windows_PHP_WebSocket_Server [類別版]
01.使用WINDOWS的USBWebserver_v8.6環境下測試可用
02.SERVER(server.php)
<?php $host = 'localhost'; //host $port = '9000'; //port $null = NULL; //null var //Create TCP/IP sream socket $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); //reuseable port socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); //bind socket to specified host socket_bind($socket, 0, $port); //listen to port socket_listen($socket); //create & add listning socket to the list $clients = array($socket); //start endless loop, so that our script doesn't stop while (true) { //manage multipal connections $changed = $clients; //returns the socket resources in $changed array socket_select($changed, $null, $null, 0, 10); //check for new socket if (in_array($socket, $changed)) { $socket_new = socket_accept($socket); //accpet new socket $clients[] = $socket_new; //add socket to client array $header = socket_read($socket_new, 1024); //read data sent by the socket perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake socket_getpeername($socket_new, $ip); //get ip address of connected socket $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected'))); //prepare json data send_message($response); //notify all users about new connection //make room for new socket $found_socket = array_search($socket, $changed); unset($changed[$found_socket]); } //loop through all connected sockets foreach ($changed as $changed_socket) { //check for any incomming data while(socket_recv($changed_socket, $buf, 1024, 0) >= 1) { $received_text = unmask($buf); //unmask data $tst_msg = json_decode($received_text, true); //json decode $user_name = $tst_msg['name']; //sender name $user_message = $tst_msg['message']; //message text $user_color = $tst_msg['color']; //color //prepare data to be sent to client $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message, 'color'=>$user_color))); send_message($response_text); //send data break 2; //exist this loop } $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ); if ($buf === false) { // check disconnected client // remove client for $clients array $found_socket = array_search($changed_socket, $clients); socket_getpeername($changed_socket, $ip); unset($clients[$found_socket]); //notify all users about disconnected connection $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected'))); send_message($response); } } } // close the listening socket socket_close($socket); function send_message($msg) { global $clients; foreach($clients as $changed_socket) { @socket_write($changed_socket,$msg,strlen($msg)); } return true; } //Unmask incoming framed message function unmask($text) { $length = ord($text[1]) & 127; if($length == 126) { $masks = substr($text, 4, 4); $data = substr($text, 8); } elseif($length == 127) { $masks = substr($text, 10, 4); $data = substr($text, 14); } else { $masks = substr($text, 2, 4); $data = substr($text, 6); } $text = ""; for ($i = 0; $i < strlen($data); ++$i) { $text .= $data[$i] ^ $masks[$i%4]; } return $text; } //Encode message for transfer to client. function mask($text) { $b1 = 0x80 | (0x1 & 0x0f); $length = strlen($text); if($length <= 125) $header = pack('CC', $b1, $length); elseif($length > 125 && $length < 65536) $header = pack('CCn', $b1, 126, $length); elseif($length >= 65536) $header = pack('CCNN', $b1, 127, $length); return $header.$text; } //handshake new client. function perform_handshaking($receved_header,$client_conn, $host, $port) { $headers = array(); $lines = preg_split("/\r\n/", $receved_header); foreach($lines as $line) { $line = chop($line); if(preg_match('/\A(\S+): (.*)\z/', $line, $matches)) { $headers[$matches[1]] = $matches[2]; } } $secKey = $headers['Sec-WebSocket-Key']; $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); //hand shaking header $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "WebSocket-Origin: $host\r\n" . "WebSocket-Location: ws://$host:$port/demo/shout.php\r\n". "Sec-WebSocket-Accept:$secAccept\r\n\r\n"; socket_write($client_conn,$upgrade,strlen($upgrade)); }
03.CLIENT(index.php)
<?php $colors = array('#007AFF','#FF7000','#FF7000','#15E25F','#CFC700','#CFC700','#CF1100','#CF00BE','#F00'); $color_pick = array_rand($colors); ?> <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <style type="text/css"> .chat-wrapper { font: bold 11px/normal 'lucida grande', tahoma, verdana, arial, sans-serif; background: #00a6bb; padding: 20px; margin: 20px auto; box-shadow: 2px 2px 2px 0px #00000017; max-width:700px; min-width:500px; } #message-box { width: 97%; display: inline-block; height: 300px; background: #fff; box-shadow: inset 0px 0px 2px #00000017; overflow: auto; padding: 10px; } .user-panel{ margin-top: 10px; } input[type=text]{ border: none; padding: 5px 5px; box-shadow: 2px 2px 2px #0000001c; } input[type=text]#name{ width:20%; } input[type=text]#message{ width:60%; } button#send-message { border: none; padding: 5px 15px; background: #11e0fb; box-shadow: 2px 2px 2px #0000001c; } </style> </head> <body> <div class="chat-wrapper"> <div id="message-box"></div> <div class="user-panel"> <input type="text" name="name" id="name" placeholder="Your Name" maxlength="15" /> <input type="text" name="message" id="message" placeholder="Type your message here..." maxlength="100" /> <button id="send-message">Send</button> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script language="javascript" type="text/javascript"> //create a new WebSocket object. var msgBox = $('#message-box'); var wsUri = "ws://localhost:9000/demo/server.php"; websocket = new WebSocket(wsUri); websocket.onopen = function(ev) { // connection is open msgBox.append('<div class="system_msg" style="color:#bbbbbb">Welcome to my "Demo WebSocket Chat box"!</div>'); //notify user } // Message received from server websocket.onmessage = function(ev) { var response = JSON.parse(ev.data); //PHP sends Json data var res_type = response.type; //message type var user_message = response.message; //message text var user_name = response.name; //user name var user_color = response.color; //color switch(res_type){ case 'usermsg': msgBox.append('<div><span class="user_name" style="color:' + user_color + '">' + user_name + '</span> : <span class="user_message">' + user_message + '</span></div>'); break; case 'system': msgBox.append('<div style="color:#bbbbbb">' + user_message + '</div>'); break; } msgBox[0].scrollTop = msgBox[0].scrollHeight; //scroll message }; websocket.onerror = function(ev){ msgBox.append('<div class="system_error">Error Occurred - ' + ev.data + '</div>'); }; websocket.onclose = function(ev){ msgBox.append('<div class="system_msg">Connection Closed</div>'); }; //Message send button $('#send-message').click(function(){ send_message(); }); //User hits enter key $( "#message" ).on( "keydown", function( event ) { if(event.which==13){ send_message(); } }); //Send message function send_message(){ var message_input = $('#message'); //user message text var name_input = $('#name'); //user name if(message_input.val() == ""){ //empty name? alert("Enter your Name please!"); return; } if(message_input.val() == ""){ //emtpy message? alert("Enter Some message Please!"); return; } //prepare json data var msg = { message: message_input.val(), name: name_input.val(), color : '<?php echo $colors[$color_pick]; ?>' }; //convert and send data to server websocket.send(JSON.stringify(msg)); message_input.val(''); //reset message input } </script> </body> </html>
04.Winondows_USBWebserver啟動SERVER.bat
..\..\php\php.exe server.php
05.執行步驟:
01.Winondows_USBWebserver啟動SERVER.bat
02.開啟瀏覽器執行index.php * N次