Even though it hasn’t worked for quite some time now, my previous PHP WebSocket chat application has garnered quite a bit of attention and is still one of my most heavily trafficked posts. As a result I thought I’d provide you all with a working script as of Feb 15, 2012. Because I’m your typical lazy developer, I’ll be building on top of other peoples’ work – most notably PHPWebSocket.
You can download the final script here. According to the Wikipedia article on WebSockets, it should work in IE10+, Firefox 7+ and Chrome 14+. Personally I tested with Chrome 17.0.963.46 and Firefox 10.0.1.
I want to stress that this tutorial is designed to be extremely basic and as such does not give alot of functionality out of the box (but provides all the tools necessary to add more). It’s simply a working example of a PHP-based WebSocket server.
The Implementation – Server Side
While the PHPWebSocket class works, it puts alot of variables and constants into the global scope. This is a big no-no in my opinion so I moved the entire script into a class PHPWebSocket and added the following functions:
- bind: Binds a given function name to a given event. Valid events include:
- open: Triggers as a user connects
- close: Triggers as a user disconnects
- message: Triggers when a user sends data to the server
- unbind: Unbinds all functions from a given event, or all functions from all events if no event name is given.
- log: Logs a message to the standard output
Below is an example of your server script for a very basic chat application (Note that I’ve set the server to run on 127.0.0.1. Set this to your network IP if you want others on the network/internet to be able to connect to your server):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | <?php // prevent the server from timing out set_time_limit(0); // include the web sockets server script (the server is started at the far bottom of this file) require 'class.PHPWebSocket.php'; // when a client sends data to the server function wsOnMessage($clientID, $message, $messageLength, $binary) { global $Server; $ip = long2ip( $Server->wsClients[$clientID][6] ); // check if message length is 0 if ($messageLength == 0) { $Server->wsClose($clientID); return; } //Send the message to everyone but the person who said it foreach ( $Server->wsClients as $id => $client ) if ( $id != $clientID ) $Server->wsSend($id, "Visitor $clientID ($ip) said \"$message\""); } // when a client connects function wsOnOpen($clientID) { global $Server; $ip = long2ip( $Server->wsClients[$clientID][6] ); $Server->log( "$ip ($clientID) has connected." ); //Send a join notice to everyone but the person who joined foreach ( $Server->wsClients as $id => $client ) if ( $id != $clientID ) $Server->wsSend($id, "Visitor $clientID ($ip) has joined the room."); } // when a client closes or lost connection function wsOnClose($clientID, $status) { global $Server; $ip = long2ip( $Server->wsClients[$clientID][6] ); $Server->log( "$ip ($clientID) has disconnected." ); //Send a user left notice to everyone in the room foreach ( $Server->wsClients as $id => $client ) $Server->wsSend($id, "Visitor $clientID ($ip) has left the room."); } // start the server $Server = new PHPWebSocket(); $Server->bind('message', 'wsOnMessage'); $Server->bind('open', 'wsOnOpen'); $Server->bind('close', 'wsOnClose'); // for other computers to connect, you will probably need to change this to your LAN IP or external IP, // alternatively use: gethostbyaddr(gethostbyname($_SERVER['SERVER_NAME'])) $Server->wsStartServer('127.0.0.1', 9300); ?> |
The Implementation – Client Side
I wasn’t impressed with the JavaScript class provided with PHPWebSocket either, so instead I’m using a more flexible one called FancyWebSocket (which I’ve also made modifications to). Like the server functions I added, FancyWebSocket allows you to bind functions to open, close, and message events so your page should look something like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | <!doctype html> <html> <head> <meta charset='UTF-8' /> <style> input, textarea {border:1px solid #CCC;margin:0px;padding:0px} #body {max-width:800px;margin:auto} #log {width:100%;height:400px} #message {width:100%;line-height:20px} </style> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> <script src="fancywebsocket.js"></script> <script> var Server; function log( text ) { $log = $('#log'); //Add text to log $log.append(($log.val()?"\n":'')+text); //Autoscroll $log[0].scrollTop = $log[0].scrollHeight - $log[0].clientHeight; } function send( text ) { Server.send( 'message', text ); } $(document).ready(function() { log('Connecting...'); Server = new FancyWebSocket('ws://127.0.0.1:9300'); $('#message').keypress(function(e) { if ( e.keyCode == 13 && this.value ) { log( 'You: ' + this.value ); send( this.value ); $(this).val(''); } }); //Let the user know we're connected Server.bind('open', function() { log( "Connected." ); }); //OH NOES! Disconnection occurred. Server.bind('close', function( data ) { log( "Disconnected." ); }); //Log any messages sent from server Server.bind('message', function( payload ) { log( payload ); }); Server.connect(); }); </script> </head> <body> <div id='body'> <textarea id='log' name='log' readonly='readonly'></textarea><br/> <input type='text' id='message' name='message' /> </div> </body> </html> |
How to Run It
After downloading, simply open a terminal and type
php5 ./server.php |
Then load it up in your browser.
Further Reading
If you want to see the true awesomeness of WebSockets and what they can do for you and your site, head on over to Kaazing and check out their Lightning Fast Stock Trade demo. It’s very cool stuff.
A redditor whipped up a version 13 compatible websocket implementation here. The comments include a couple of links to other implementations.
I would also highly advise you check out Ratchet. It’s an up to date websocket implementation for PHP.