205

PHP WebSocket Chat Application 2.0

Posted (Updated ) in Javascript, PHP

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

PHP WebSocket Server

PHP WebSocket Server

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

WebSocket Client

Very basic WebSocket Client

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.