137

PHP WebSocket Chat Application 2.0

Posted February 15th, 2012 in Javascript, PHP and tagged , by Flynsarmy

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 Implimentation – 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 Implimentation – 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 implimentation here. The comments include a couple of links to other implementations.

  • Pat

    How would you make it so they could change their username?

    • Joe

      You be a programmer and you write that functionality.

  • luntegg

    Thanks! It’s all work!

  • Daniel

    Thanks. I want to create a chat application. Could I use the server side in php, and customice my own client side in java with sockets?
    My application is java, and I want the php server because I dont have a VPS.
    Thanks.

  • Sebastian

    Hi everyone,

    everythink work’s fine. Thank you so much for this example running out-of-the-box.

    Actually I’m trying to write a message to the socket from another PHP-Script.
    I started with normal PHP-Sockets:

    $string = "Hello World";
    $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    $conn = socket_connect($socket, $host, $port);
    $send = socket_write($socket, $string, strlen($string));
    socket_close($socket);

    But here’s the problem: The server does not recognize the new client and can’t send the message to other clients.
    After round about 15 seconds the server get’s the closing information from the client an print this to the console.

    Has anyone an advice, how to write correct at the socket, so all other clients would receive the message from the server?

    Thanks,
    Sebastian

  • Masoud

    Hi,
    How can I run server.php on an online server. I mean, I uploaded the files into my host , but I cant run server.php :(
    Any help

    • Stefan

      Run “php server.php” using ssh

  • Stefan

    Thank you! That’s the only working version of a php websocket server I found :)

  • Fab

    Hi.
    Thank you for offering this great example – helped me a lot !
    I want to add some Authentication (and later authorization). Any idea how to handle authentication by create the connection?

Page generated in
0.01213 sec