37

PHP Web Socket Chat Application

Posted May 26th, 2010 (Updated 15 Feb 2012) in Javascript, PHP

UPDATE 15 Feb 2012: This post is woefully out of date. See my new PHP WebSocket Chat Application 2.0 post for a working tutorial compatible with the latest WebSocket spec as of Feb 15, 2012.

Today I’ll be doing an in-depth tutorial on how to create a simple, real-time chat application with HTML5 web sockets.

Disclaimer: Due to the relative infancy of web socket technology, this tutorial will currently only work on Google Chrome and the spec isn’t finalized yet so it may break in the future (specifically during the handshake phase).

Rather than reinventing the wheel I’ll be using two open source scripts freely available on the internet to take care of most of the hard work for us. These are PHPWebSocket by georgenava and ServerEventsDispatcher by Ismael. This tutorial has the following prerequisites:

Let’s begin.

Firstly set up a folder for your webapp – I called mine chat. This is the file structure I used:

/chat
/chat/assets/javascript/ServerEventDispatcher.js
/chat/includes/websocket.class.php
/chat/index.php
/chat/server.php

Now for the index.php file that our visitors will see:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>HTML5 Chat</title>
<style>
	body {width:960px;margin:auto}
	#conversation {height:500px;border:1px solid #000}
	input {width:100%}
</style>
<script src='assets/javascript/ServerEventDispatcher.js'></script>
</head>
<body>
	<div id='conversation'>&nbsp;</div>
	<input type='text' name='say'>
</body>
</html>

We’ll make one relatively minor change to ServerEventDispatcher.js to get it accepting our web socket’s address in its constructor. Here’s the modification:

//change
var ServerEventsDispatcher = function(){
	var conn = new WebSocket('ws://socket.server.com');
 
//to
var ServerEventsDispatcher = function( host ) {
	var conn = new WebSocket('ws://' + host);

While we’re here, there’s a weird bug involving the FIRST message sent from the server starting with a NULL character – if anyone here knows why or how to fix this properly please let me know. In the mean time here’s the code to fix it client-side:

// dispatch to the right handlers
conn.onmessage = function(evt) {
	data = evt.data;
	if ( !data.charCodeAt(0) )
		data = data.substr(1);
 
	var data = JSON.parse( data ),
		event_name = data[0],

Now to add in the client-side events. When the visitor loads our page, we want it to connect to the web socket server, print a ‘Connected’ message and also to allow the user to send and receive messages. ServerEventDispatcher makes all these actions very quick and simple to impliment. Add the following script to your page:

<script>
	//Connect to the server
	var server = new ServerEventsDispatcher("127.0.0.1:12345/chat/server.php");
 
	//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.data );
	});
 
	//Log a message to the conversation window
	function log( msg ) {
		document.getElementById('conversation').innerHTML += msg + '<br>';
	}
 
	//Does the actual sending of a message
	function send( msg ) {
		server.trigger( 'message', { data: msg } );
	}
 
	//Sends a message when user presses the 'enter' key
	function onkey( event ) {
		if ( event.keyCode == 13 )
		send( document.getElementById('message').value );
	};
</script>

…and remember to add the ‘onkey’ event to the text input field:

<input type='text' name='say' onkeypress='onkey(event)'>

That should be just about it for the client side. So what’s going on?

ServerEventDispatcher uses a very similar syntax to JQuery – so if you’re a JQuery user you should feel right at home with this syntax. We created 3 events – one for both connection and disconnection messages and one for displaying anything sent back from the server. Also created was a trigger – for sending data entered to the server. These are all pretty self explanatory and you should get the gist of things from the comments.

OK…so can we run it? Nope. Not yet.

The client side and the easy part is over but now moving on to the server script. We’ll be using PHP in a way you probably haven’t used it before. Generally when you load a webpage, your PHP scripts execute and close in the blink of an eye and that’s it – however today we’ll be running a script as a server in itself – it won’t close until it either crashes (hopefully not) or we close it. Let’s get going. I’m calling the server script server.php.

From PHPWebSockets, copy websocket.class.php to the includes folder as per my file structure above. You’ll notice that in this file there is a function called process (Around line 47). This function is given the message the visitor entered, and returns it straight back to them – in our chat application that’s a little helpful, however we want the message to be sent back to all connected users in the conversation – not just the person who sent the message. Here’s the modified function.

function process($user,$msg) {
	//$this-&gt;send($user-&gt;socket,$msg);
 
	//Send message to all connected usersusers
	foreach ( $this-&gt;sockets as $socket )
		if ( $socket != $this-&gt;master )
			$this-&gt;send( $socket, $msg );
}

We’re done! Now to fire up this bad boy

Open a terminal window (Command line on windows) and navigate to your project directory. Execute the script with PHP and if all went to plan you should get the following message:

$ php -f server.php
Server Started : 2010-05-26 22:40:03
Listening on   : localhost port 12345
Master socket  : Resource id #5

If you did then – congratulations! You may now visit your site:

http://localhost/chat

Type into the text field and your message should be echoed back to you in the conversation window. Open a second browser and connect there too. Type something and both windows should get the message. Welcome to the future.

Download the finished web application here.

UPDATE Nov 14, 2010: Since the writing of this post, the handshake spec has changed in such a way that browsers requiring the new spec will return the error code INVALID_STATE_ERR upon connection. I checked the PHPWebSocket page for an updated version but it looks like the developer hasn’t released one yet so instead I now recommend using Bohuco’s excellent websocket script instead.

  • Download Bohuco’s script from here and place into /includes/WebSocketServer.php
  • Change server.phpto the following:
    <?php
    	require dirname(__FILE__).'/includes/WebSocketServer.php';
     
    	function process(WebsocketUser $user, $msg, WebsocketServer $server)
    	{
    		$server->send( $user->socket, $msg );
    	}
     
    	$server = new WebsocketServer('localhost', 12345, 'process');
    	$server->run();

That should be all there is to it. I made one other slight modification to index.php, adding a quick and simple local echo to illustrate when a user has sent a message to the server which I’ve provided below:

//Sends a message when user presses the 'enter' key
function onkey( event ) {
	if ( event.keyCode == 13 )
	{
		var message = document.getElementById('message').value;
		log( '&gt; ' + message );
		send( message );
	}
};

The updated download can be found here.

  • Frank

    Hello, this is a great article, just what i was looking for, nice work!! =)

    There’s a problem with the link to download the finished application working. Let me know if you can send me those files.

    Thanx!

  • Samson

    WTF! where is the finished web application???

  • Flynsarmy

    Hey guys. Sorry about, that the files are back. I believe since i posted this tutorial, the websocket handshake has been modified slightly. You might have to download a newer copy of PHPWebSocket to get it working. I’ll update my tutorial when I get some free time.

  • Samson

    Hi, I appreciate your work. But I have some problems. Please be kind enough to guide me.

    * I went to http://code.google.com/p/phpwebsocket/ and got the files.

    * Then navigated to the project directly by Command prompt (Window) and executed php -q server.php
    Then I got this.
    Server Started : 2010-11-09 16:56:32
    Master socket : Resource id #4
    Listening on : localhost port 12345

    * Then browsed the client.html
    Initially I got “WebSocket – status 0″ in the textarea.
    When I type “Hi” and send it, I got “Error: INVALID_STATE_ERR: DOM Exception 11″

    I cannot imagine the failure. Hope your help.

    Thanks.

  • Anne

    Hi,

    I’m also getting the same error.

    Initially it was “ReferenceError: WebSocket is not defined”

    When type Hi, error was “TypeError: socket is undefined”

  • ld

    Hello, very nice tutorial and thanks you for this.
    But i am have problem what have Samson and maybe you can help ? and how to fix this problem ?
    Thanks.

  • pistacchio

    thanks, just what i was looking for. tomorrow i’ll give it an actual try :)

  • Rob Quist

    Hey there,

    This is a great article! You’ve helped me a lot!

    The only thing i’ve bumped up to now, is, how do i make multiple clients be able to chat with each other?
    If i chat on my laptop the server sees the chatline and sends it back. Very nice. Only problem is, my desktop pc doesn’t see the chatline from the laptop, and the other way around.

    Did i do something wrong? Do i need to modify the script?

    Thanks in advantage!

    Rob

  • Flynsarmy

    Hey Rob,

    This error will occur if you’re using my example code. In index.php change
    var server = new ServerEventsDispatcher(“127.0.0.1:12345″);
    to
    var server = new ServerEventsDispatcher(“<your network ip>:12345″);

    and in server.php change
    $server = new WebsocketServer(‘localhost’, 12345, ‘process’);
    to
    $server = new WebsocketServer(‘<your network ip>’, 12345, ‘process’);

    Remember to restart server.php in the terminal for the changes to take affect!

    One other thing to note is that web sockets are being removed from all major browsers very shortly due to security concerns with the web socket protocol. See here for more information http://goo.gl/0ffw6

  • boobood

    can I use my domain name instead of “your network ip”?

    • Flynsarmy

      I’ve never tried but I would assume it’d work. Give it a shot

  • Preed

    Hey, nice stuff! I really hope that we could get a good PHP Websocket solution that works properly on common web hotels one day.
    Sad thing about FF4, but I think its gonna be solved quite soon, web sockets are too important to just ignore.

    I didn’t get the example running (just extracted your v2-zip) it’s missing some functions in WebSocketServer.php, will look into it tomorrow though.

  • dlm

    ye, it dont work. can u please post the solution preed, if u got it? thanks so far.

    btw – to enable websocket function in firefox 4:

    open firefox4 – goto about:config – type “websocket” into the “Filter:” – enable it.

  • Arash Manteghi

    this code doesn’t work. I did all changes that friends sayed in comment but it have again error. what shoud I do?

    • Flynsarmy

      Arash,

      What browser are you using? Web Sockets have been removed from most browsers because of gaping security holes. It’s possible the browser you’re using does not support websockets at all.

      In addition, it’s possible Firefox is still using the old websocket revision whereas chrome moved to the newer one. I know the script provided worked with chrome (until chrome removed websocket support) however I don’t believe I ever tested in Firefox.

  • kimsoy

    sir, will this code work if i’ll use two PC’s? because i’m planning to test the chat through 2 clients from different computers.. pls advice.

  • kimsoy

    oh.. i need some clarifications..

    i’ll be running my server here in my desktop.. say having 192.X.X.X
    so, my desktop running with server.php should look like this?
    $server = new WebsocketServer(‘192.X.X.X’, 12345, ‘process’);
    is this correct?

    if i’ll run a client on my laptop.. the index.php should look like this?
    var server = new ServerEventsDispatcher(“192.X.X.X:12345″);
    is this correct?

    need your advice..

    • Flynsarmy

      Yes I believe that’s correct.

      If you’re having issues connecting with those settings, it may be because your browser no longer supports websockets (or they may be turned off). The websocket spec was deemed to be a major security hole and I believe every browser has since disabled them.

  • kimsoy

    yes.. i already did it and it worked.. i believe the websocket on mozilla is turned off. i used google chrome to test the socket.. although it only showed a blank screen, the index.php notified me that it is already connected. so i think websockets in chrome still works..

    tnx sir!

  • apantev

    Do you have any idea how to extend this example to use secure websocket (wss) instead of the standard websocket (ws)?

  • Shav

    I’m trying to get the server to run on a linux machine on my local network. The linux box has a static IP of 192.168.0.180. I have checked the server and the process is running at localhost:12345. When the client attempts to connect I get “Disconnected”. I get this if I attempt to connect to localhost, 127.0.0.1 or 192.168.0.180 at 12345. Funny thing is if I run the server from my local XAMPP server it will connect to it just fine. From either the XAMPP server or the linux box. Anyone have an idea why it’s not connecting to the linux machine?

    -Shav

  • Dietger

    Hey there,

    The example with the Bohuco’s websocket works great except for one thing. The message is only visible to the person who sends it. Its not a chat anymore but just an echo of your input :(

    • AT

      Amend WebSocketServer.php instead.

      public function send($client, $msg){
      $msg = $this->wrap($msg);
      $this->say(“> “. $msg);
      //@socket_write($client, $msg, strlen($msg));

      //Send message to all connected users
      foreach ( $this->sockets as $socket ) {
      if ( $socket != $this->master ) @socket_write($socket, $msg, strlen($msg));
      }
      }

  • sam

    I try your code on linux , it does not work.
    Here is the url
    http://club.khmer.org/websocket/chat/

    The phpwebsocket is working fine.
    http://club.khmer.org/websocket/client/

  • Pingback: HTML 5 Web Sockets

  • Port Forward Podcast

    I have just forked and updated the web sockets example. This version uses the HyBi-10 standard and works correctly in chrome:

    https://github.com/esromneb/phpwebsocket

    If you like the project, you can support me by listening to my podcast:

    http://portforwardpodcast.com/

    Happy sockets to you all!

    • alam

      comand line throws error….. and the chrome also not supporting

      • Flynsarmy

        Try this.

        • alam

          when I execute the below command on command line,

          C:\wamp\www\chat>php -q chatbot.demo.php

          It shows the following error,

          PHP Fatal error: Call to undefined function socket_create() in C:\wamp\www\chat
          \websocket.class.php on line 16
          PHP Stack trace:
          PHP 1. {main}() C:\wamp\www\chat\chatbot.demo.php:0
          PHP 2. WebSocket->__construct() C:\wamp\www\chat\chatbot.demo.php:24

          Fatal error: Call to undefined function socket_create() in C:\wamp\www\chat\webs
          ocket.class.php on line 16

          Call Stack:
          0.0005 338480 1. {main}() C:\wamp\www\chat\chatbot.demo.php:0
          0.0019 459520 2. WebSocket->__construct() C:\wamp\www\chat\chatbot.dem
          o.php:24

          • Flynsarmy

            I googled your error. One of the top results was this.

            • alam

              gr8!!!! Thank u It’s working….

              Do u have any idea how to do audio and video chatting??

              • Flynsarmy

                I don’t. You’ll have to search yourself.

                • alam

                  Thank u….for ur help

  • lilzz

    http://www.flynsarmy.com/2010/05/php-web-socket-chat-application/

    I follow the instructions inside and bring up the socket server
    php -f server.php

    then bring up the client application on webbrowser.
    http://localhost/chat

    I checked the output on the command line

    php -f server.php

    Warning: date(): It is not safe to rely on the system’s timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected ‘America/Los_Angeles’ for ‘PDT/-7.0/DST’ instead in /Applications/XAMPP/xamppfiles/htdocs/chat/includes/websocket.class.php on line 21
    Server Started : 2012-03-28 14:49:41
    Listening on : localhost port 12345
    Master socket : Resource id #5

    Resource id #6 CONNECTED!

    Requesting handshake…
    GET /chat/server.php HTTP/1.1
    Upgrade: WebSocket
    Connection: Upgrade
    Host: 127.0.0.1:12345
    Origin: http://localhost
    Sec-WebSocket-Key1: KL P* 1 K *20 B 4O7< 13939h
    Sec-WebSocket-Key2: 2K68%'84 9s 6Q2 3Rl2

    ?)?j????
    Handshaking…
    HTTP/1.1 101 Web Socket Protocol Handshake
    Upgrade: WebSocket
    Connection: Upgrade
    WebSocket-Origin: http://localhost
    WebSocket-Location: ws://127.0.0.1:12345/chat/server.php

    Done handshaking…
    Resource id #6 DISCONNECTED!

    The problem I have as soon as I type in the http://localhost/chat on my browser this socket is disconnected as evidented by id#6 DISCONNECTED on the output of the command line.

    **Why the socket automatically disconnected when I fire up the client app on the browser??**

    • Flynsarmy

      This script is extremely out of date and won’t work in modern browsers. At the top of the page I linked to an updated version of this script that will. See Web Socket Chat Application 2.0 for more details.

  • asad

    hello sir,
    I am getting disconnected message
    LUSR1556 C:\xampp
    # php c:\xampp\htdocs\chat\server.php
    Resource id #6 DISCONNECTED!

    and the same message in one the client side:
    Disconnected.

    anyway you can help. thanks.