Simple Chat Using WebSocket and PHP Socket

The WebSocket is a feature of HTML5 for establishing a socket connections between a web browser and a server, once the connection has been established with the server, all WebSocket data (frames) are sent directly over a socket rather than usual HTTP response and requests, giving us much faster and persistent communication between a web browser and a server. Let’s create a simple chat system using this cool technology (HTML5 WebSocket and PHP).

WebSocket Chat

Browser Support

Old browsers do not support WebSockets, you need latest browser that supports HTML5 WebSocket features, Please see caniuse.com to find-out all WebSocket supported browsers.

Getting Started with WebSocket

Client side WebSocket implementation is very easy, the entire code consist of few methods and events. Have a look at code below for example.

1
2
3
4
5
6
7
8
//create a new WebSocket object.
websocket = new WebSocket("ws://localhost:9000/daemon.php");
websocket.onopen = function(evt) { /* do stuff */ }; //on open event
websocket.onclose = function(evt) { /* do stuff */ }; //on close event
websocket.onmessage = function(evt) { /* do stuff */ }; //on message event
websocket.onerror = function(evt) { /* do stuff */ }; //on error event
websocket.send(message); //send method
websocket.close(); //close method

To open the socket connection, we simply call new WebSocket(ws://SERVER URL), since WebSocket uses a different protocol for the connections, we use ws:// instead of http://, followed by host, port number and daemon script in your server:

url-breakdown

Right after opening the connection, we need to attach some event handlers that let us know status of connectivity, errors and incoming messages, for your references:

  • WebSocket(wsUri) — creates a new WebSocket object.
  • .onopen — Event occurs when connection is established.
  • .onclose — Event occurs when connection is closed.
  • .onmessage — Event occurs when client receives data from server.
  • .onerror — Event occurs when there is an error.
  • .send(message) — Transmits data to server using open connection.
  • .close() — Terminates existing connection.

You can implement WebSocket with jQuery support in your webpage like this.

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
$(document).ready(function(){
    //Open a WebSocket connection.
    var wsUri = "ws://localhost:9000/daemon.php";  
    websocket = new WebSocket(wsUri);
   
    //Connected to server
    websocket.onopen = function(ev) {
        alert('Connected to server ');
    }
   
    //Connection close
    websocket.onclose = function(ev) {
        alert('Disconnected');
    };
   
    //Message Receved
    websocket.onmessage = function(ev) {
        alert('Message '+ev.data);
    };
   
    //Error
    websocket.onerror = function(ev) {
        alert('Error '+ev.data);
    };
   
     //Send a Message
    $('#send').click(function(){
        var mymessage = 'This is a test message';
        websocket.send(mymessage);
    });
});

Chat Page

As explained in examples above, we start by creating a WebSocket object, attaching event handlers and then using websocket.send() method to send the data. Since we are sending a collection of chat values, such as user name, message, color etc, we’ll convert our data to JSON format before sending to 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
$(document).ready(function(){
    //create a new WebSocket object.
    var wsUri = "ws://localhost:9000/daemon.php";  
    websocket = new WebSocket(wsUri);
   
    websocket.onopen = function(ev) { // connection is open
        $('#message_box').append("<div class="system_msg">Connected!</div>"); //notify user
    }

    $('#send-btn').click(function(){ //use clicks message send button  
        var mymessage = $('#message').val(); //get message text
        var myname = $('#name').val(); //get user name
       
        if(myname == ""){ //empty name?
            alert("Enter your Name please!");
            return;
        }
        if(mymessage == ""){ //emtpy message?
            alert("Enter Some message Please!");
            return;
        }
       
        //prepare json data
        var msg = {
        message: mymessage,
        name: myname,
        color : '<?php echo $colours[$user_colour]; ?>'
        };
        //convert and send data to server
        websocket.send(JSON.stringify(msg));
    });
   
    //#### Message received from server?
    websocket.onmessage = function(ev) {
        var msg = JSON.parse(ev.data); //PHP sends Json data
        var type = msg.type; //message type
        var umsg = msg.message; //message text
        var uname = msg.name; //user name
        var ucolor = msg.color; //color

        if(type == 'usermsg')
        {
            $('#message_box').append("<div><span class="user_name" style="color:#"+ucolor+"">"+uname+"</span> : <span class="user_message">"+umsg+"</span></div>");
        }
        if(type == 'system')
        {
            $('#message_box').append("<div class="system_msg">"+umsg+"</div>");
        }
       
        $('#message').val(''); //reset text
    };
   
    websocket.onerror   = function(ev){$('#message_box').append("<div class="system_error">Error Occurred - "+ev.data+"</div>");};
    websocket.onclose   = function(ev){$('#message_box').append("<div class="system_msg">Connection Closed</div>");};
});

Below is our HTML for the chat system, it comes with some basic styling, I have not included the CSS part here, but you should find it in sample file.

1
2
3
4
5
6
7
8
<div class="chat_wrapper">
<div class="message_box" id="message_box"></div>
<div class="panel">
<input type="text" name="name" id="name" placeholder="Your Name" maxlength="10" style="width:20%"  />
<input type="text" name="message" id="message" placeholder="Message" maxlength="80" style="width:60%" />
<button id="send-btn">Send</button>
</div>
</div>

Chat Server using PHP Socket

Ok! Now we have our chat page ready to connect to server, but we also need to create a WebSocket server that runs permanently (no time-outs), performs WebSocket handshaking, send/receive data from chat page and handles multiple clients, for that we will create a daemon script in PHP. Everyone knows PHP is mostly used to create dynamic webpages, but most of us didn’t know that we can also create daemons (that run in the background) using nothing but PHP.

Install WebSocket Server
Install a local web server such as WAMP or XAMPP. I am using XAMPP server on Win-XP, it lets me use shell option to start my daemon script. I am not sure if WAMP has the same feature, but you can follow Dani’s solution here to run this server script. If you want to implement it on your website, first check whether your host allows you to run daemon scripts and shell commands.
Xampp Shell

PHP Socket Steps
We will be using PHP socket to create our WebSocket Chat server, Basically our PHP Chat server should do the following.

  1. Open a socket.
  2. Bind to a address.
  3. Listen incoming connections.
  4. Accept connections.
  5. WebSocket Handshake.
  6. Unmask/Encode data frames.

Open a socket:
First we create a socket with PHP socket_create(Domain, Type, Protocol) like this:

1
2
//Create TCP/IP sream socket and return the socket resource
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

Bind to a address:
Bind the name to the socket, this has to be done before a connection is established using socket_connect() or socket_listen().

1
2
// Bind the source address
socket_bind($socket, 'localhost');

Listen incoming connections:
Once the socket is created, we want our server to listen to incoming connection on that socket.

1
2
// Listen to incoming connection
socket_listen($socket);

Accept connections:
This function will accept incoming connections.

1
2
// Accept new connections
socket_accept($socket);

Handshake:
Client has to introduce itself by sending a WebSocket handshake request to establish a successful connection with server, a handshake request contains a Sec-WebSocket-Key a base64 encoded randomly generated 16-byte value. And the server reads the key, attaches magic string “258EAFA5-E914-47DA-95CA-C5AB0DC85B11”, hash key with SHA1, returns the key in Sec-WebSocket-Accept encoded with base64.
websocket-handshake-header
Handshake response with PHP :

1
2
3
4
5
6
7
8
9
$secKey = $headers['Sec-WebSocket-Key'];
$secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$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/deamon.php\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_conn,$upgrade,strlen($upgrade));

Unmasking/Encoding data frames.
After the handshaking, client can now send and receive messages, but the messages sent are all encrypted, so if we want to display them, each data frame needs to be unmasked as described here

Starting Chat Server

It’s time to download the sample files by clicking download button below, you should find 2 PHP files, index.php and server.php. Using your Shell command-line interface in XAMPP, start WebSocket chat server by typing :

1
php -q c:\path-to-server\server.php

Once the server starts, you can navigate to index.php page using your browser and start test chatting.

Download

245 Comments Add Comment

  • can you help me setting this up in linux server.
    I ran the server.No error came(hoping that its running)
    but what does this mean:

    1
    var wsUri = "ws://localhost:9001/demo/server.php";

    why demo? even when I am running in local..its working without any demo folder in my XAMPP.
    In my case the url should be something like this:
    ws://XXX.com:9000/development/chat/server.php

     Reply
  • Why my server.php starts running after a while? It works great, but after some time watching Netstat on XAMPP, the socket becomes OLD and disapear :c

     Reply
  • Hi
    i want to implement web socket in to my web project which is based on cakephp.
    i am new with cake php as well for web socket.
    any one can help me?
    how can install web-socket in to the server?
    how can link to the server?
    i am working on Apache server.
    i have seen some demo on internet but i can’t understton how can i implement in to my server as well in my project.
    Please help me
    Thank you

     Reply
  • Hello all,

    I understood jquery part of the tutorial.

    Anyone please elaborate or explain how server.php works? There are lots of syntax unfamiliar to me.

    Thank you

     Reply
    • PHP is great language and it is a great example of what PHP can do, but PHP is still not a viable solution to run as daemon, as you can see it relies on infinite loop which may cause memory leak and server crash overtime. I suggest you look at Node.js, C#, ASP.NET etc, they are much more reliable and faster.

    • I disagree. The code above demonstrates that php is well suited for this. C# is a dreadful language for web related work, something like Perl, php or Python are infinitely better. If code is written correctly then you won’t get memory leaks!

  • hi
    first thank you.it was very helpful.
    when i run this on localhost it works after running the server.i changed it and add a few things and i needed to try it on web so i could test it with chatting with another person.
    i made a free host on web and upload the files there but i don’t know how to run the server there,because it gives me “Error Occurred – undefined”.the host uses cpanel.
    can anyone help me?

     Reply
  • Can anybody tell me how I can send binary/file data through websocket from client to server and server to client?

     Reply
  • Thanks man it worked like charm

     Reply
  • selebriti.website

    That is so inspiring coding, thanks dude!

     Reply
  • Tashi Delek Chamling,

    After months of struggle with other library, I failed to understand websocket with PHP. Your work really helped me understand with less pain.

    I would like to bother more about websocket while I go through as I am new to it.

    Thank you once again.

     Reply
  • Thank you! This is the ONLY EXAMPLE ON THE WEB that actually works.
    I lost 3 days with frameworks, classes (things like Ratchet), tutorials, always either unfinished or untested. And none of them is correctly documented.
    If you are interested, here is the version without jquery. Just pure Javascript.

    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
    function InitWS()
    {

        //create a new WebSocket object.
        var wsUri = "ws://localhost:9000/demo/server.php";  
        websocket = new WebSocket(wsUri);
        websocket.onopen = function(ev) { // connection is open
            document.getElementById('message_box').innerHTML += "Connected!"; //notify user
        }
       

        document.getElementById('send-btn').addEventListener("click",function(){ //use clicks message send button  
            var mymessage = document.getElementById('message').value; //get message text
            var myname = document.getElementById('name').value; //get user name
            if(myname == ""){ //empty name?
                alert("Enter your Name please!");
                return;
            }
            if(mymessage == ""){ //emtpy message?
                alert("Enter Some message Please!");
                return;
            }
            //prepare json data
            var msg = {
            message: mymessage,
            name: myname,
            color : ''
            };
            //convert and send data to server
            websocket.send(JSON.stringify(msg));


        //#### Message received from server?
        websocket.onmessage = function(ev) {
            var msg = JSON.parse(ev.data); //PHP sends Json data
            var type = msg.type; //message type
            var umsg = msg.message; //message text
            var uname = msg.name; //user name
            var ucolor = msg.color; //color

            if(type == 'usermsg')
            {
                document.getElementById('message_box').innerHTML += ""+uname+" : "+umsg+"";
            }
            if(type == 'system')
            {
                document.getElementById('message_box').innerHTML += ""+umsg+"";
            }
           
            document.getElementById('message').value = ""; //reset text
        };
        websocket.onerror   = function(ev){document.getElementById('message_box').innerHTML += "Error Occurred - "+ev.data+"";};
        websocket.onclose   = function(ev){document.getElementById('message_box').innerHTML += "Connection Closed"};

        }, false);
    }
     Reply
  • Thank you very much, quite helped his article ….

     Reply
  • Hi,
    Nice tutorial.
    It is a multi user chat room but i want to make it one-to-one chat how can i do this? what modifications are required? I also need multiple one-to-one chats like facebook. How it is possible with only one server? Is there any mechanism that two clients can communicate directly?

     Reply
  • What is shout.php file where is it?
    we have to download from somewhere or it can be paced in xampp?

     Reply
  • sir i m using your websocket it’s working fine in my localhost but its not working on live server what wrong going on with me suggest me please

     Reply
  • This has been asked about 20 times in these comments but does anyone know how to make this work for p2p or private messaging? My two thoughts so far is modifying the daemon to receive multiple connections or spawn multiple daemons

     Reply
  • Hi
    can I get response from server without sending request from client….?
    like I want to send notification to other users when any order is purchased from my site..no any request if order is placed entry goes into mysql database and then server will send notification to other users.
    is it possible using websockets? if yes then please help me.
    Thanks in advance.

     Reply
  • Re detecting message boundaries: Critically important, of course, so thank you for sharing that information!
    Absent any other widely used conventions, I wonder if the usually-ignored ASCII SOM and EOM might be used for such, since it seems one could do so without a risk of ambiguity? — AS

     Reply
  • I just wanted to add a quick comment in case anyone runs into a problem where only a portion of their message appears to be transferred.

    WebSockets use TCP, which is stream-oriented, not message-oriented. If you try to send a chat message with this that is, let’s say 1 million characters long, it probably won’t work. You will end up trying to parse malformed JSON. And the reason is pretty simple. As data comes in to the host (either client or server), it is buffered up until a there is enough available to tell the application that some data has arrived. It does not know where your message starts and ends, though – it only knows that data comes in and out.

    So if I send 1 character, it will definitely arrive correctly. But if I send more, I run the risk of only receiving part of the data by the time I decide to process it. Because it’s TCP, you can be sure you will get all of the data eventually (unless the connection is broken), but you can’t be sure that if you sent “ABCDEFGH” all at once, you will receive “ABCDEFGH” all at once. You might receive “ABCD”, at which point the OS says “ok, there is data here that you can read”, so you read it, and you wonder where you “EFGH” is. The answer is, it’s still coming. If you do this with JSON data, you might send:

    “message” : {
    “username” : “Calvin”
    “text” : “Hello World”
    }

    But you could receive:

    “message” : {
    “username” : “Calvin”
    “text” : “He

    Which, of course, will give you a parsing error. Again, the remaining bits are still coming, you just haven’t read them yet. To get around this, you need to delineate your messages somehow. You could use a special character to mark the boundaries, for example, but then it would have to be something that could not otherwise end up on your message. Then, once you’ve set that out, you would need to buffer your incoming data in a string until you’re sure you’ve got the entire message – and then you can actually use it.

     Reply
  • From the while () code, I take it that the server script runs constantly, as opposed to being awoken on an incoming connection. (I hope I’m wrong on this.) Thanks for any response.

     Reply
    • You are not wrong. Notice that the script is not invoked by an HTTP request, but rather it is explicitly started as a daemon. In other words, it is a process that continues to run in the background. So yes, it does run constantly – it must.

      When a client attempts to make a connection, it sends a request which includes the (IP) address of the server as well as the application port. The port is a fairly arbitrary number that the server script passes to the operating system. When network data arrives on the server, the OS looks at the incoming port. If there is a process on the server that has bound itself to that port (in other words, told the OS that it wants to receive messages that arrive with that port number), the OS will pass the network data through to the process. If no application has bound itself to that port, the data will be ignored.

      Connection attempts are really just incoming data. So, before the connection attempt is made, the server process that is meant to handle that connection must already exist and it must already have a socket bound to the specified port.

      All that being said, the server script will not pin your processor! Right at the top of the “while” loop, notice the socket_select function call. This wraps a system call called “select”. When you call select, you call it with a set of sockets. The call then blocks which puts the process in a “pending I/O” state. The script stops at this point and no more of it is executed. Until, that is, one of the sockets in the set undergoes some change. At that point, the system call returns, and the process continues from the socket_select call.

      Some logic is now performed: If it was a connection request, create a new socket for the client by accepting the request and then add the socket to the set; If it was a client disconnecting, remove that socket from the set; If it was a client sending data, do your application logic with the data.

      Once you’ve done all that, go back up to the top, call socket_select again, and wait until something else happens.

      If you have any other questions, let me know – always happy to answer!

  • when I try to send a dataurl as json data value it fails to compute on the PHP side (code eg below)
    any suggestions, looking into the masking part of the server side code..

    1
    2
    3
    4
    5
    6
    7
    8
    var camdata = canvas.toDataURL('image/jpeg');
            //prepare json data
            var msg = {
            camimg: camdata,
            message: mymessage,
            name: myname,
            color : '<?php echo $colours[$user_colour]; ?>'
            };
     Reply
  • Is it possible to use this chat server on a shared hosting?
    If yes how to do that?

     Reply
    • Hi Ade,
      Same is in my mind. I think its possible if they allow you to create port for websocket. Because websocket need port for connection in there server file. I donot think shared hosting guys gives port creation premission to use. If you able to run websocket on shared hosting then please mail to me also.
      Thanks.

  • How can i direct my to a particular client instead of displaying it to all connected user

     Reply
  • Thank you so much

     Reply
  • great tutorial! but it seems like a group chat. how to setup a personal chat? just chatting with one person who also connected.
    sorry, i’m blind in coding things ;)

     Reply
  • how can I use this for private chat system I mean to say one end user will connect to admin and another end user will connect to same admin for sake but there message will not be displayed to another end user like ipmessanger is it possible

     Reply
  • thanks for your great tutorial. I want to create private room with two connected clients. would you please give me any idea how to do it.

    thank again,

     Reply
  • Thanks for the tutorial.
    I am getting error on client console as
    “WebSocket connection to ‘ws://localhost/sockt/server.php’ failed: Error during WebSocket handshake: Unexpected response code: 200”

    Can you please help me with this.

    Thanks,
    MG

     Reply
    • Pradeep SawantPradeeq

      Hi Monil,
      This is because of websocket server not established properly. Give your domain-ip, port to ws server properly. Before that make sure port is created in hosting for ws.Create TCP port on your hosting and then used that port in your websocket server. Also used ws for http and wss for https domains while creating websocket connection.

  • shows this in my :
    Error Occurred – undefined
    Closed Connection ,
    Help me please

     Reply
    • Please share any resolution to this issue. While it works fine on my XAMPP desktop, it fails as you describe as soon as I try it on a remote server. — AS

    • For this to work on a remote system, chage localhost to numeric ip. e.g 192.168.1.2

  • hi ,Thanks for this tutorial .when i execute server file through windows command prompt , i get warning :
    Warning: socket_bind(): unable to bind address [10013]: An attempt was made to
    access a socket in a way forbidden by its access permissions.

    in Source file , the socket bind code is socket_bind($socket, 0, $port);
    i replace 0 with $host Address ,this is right?
    thanks for your help.

     Reply
    • Hi donot change that line. First create TCP port on your hosting for websocket and then use that for websocket. Pass your domain IP and port on that websocket server. Check my other reply also.

  • next question – from wiche line you fetch the ip adress?

     Reply
  • how can i start the server.php automaticly by starting xampp whitout typing the code in the shell?

     Reply
    • Hi sadman,
      I will face this issue. Whenever you close your shell that socket close automatically from running.
      Solution is that.. execute 1 php file who start your server using shell command. Execute shell server start command using php file. And hit that php from browser Your socket never closed even if you closed shell.

  • Hi,

    How can I check if user is already connected to the web-socket?

     Reply
    • Hi vishal,
      It is too simple. Check ws onmessage method. Console ws broadcasted msg. If connection established then server broadcast connection success msg..

  • Thanks for tutorial!!
    Can anybody further elaborate how to write private chat ? I’m not sure how to specify the connection when send the response text…

     Reply
  • Hello,

    How could i modify this code to make it a P2P type of a chat that is to not use a server but to ping the user IP directly. Will I be able to achieve that functionality by modifying this code?

     Reply
  • I have integrated web Socket chat and it is working perfectly. But When we test, we execute command by writing “php -q /path/to/server.php” each time. It is not a solution to do So how can I install webSocket service on linux.

     Reply
    • If you use the screen command in you linux console you can close the terminal and the process will keep running.

    • Hi,
      Check my other reply also.. For that first create 1 TCP port by using linux hosting and used that port for websocket. If your domain is https then u need to use proxy setting in your linux.

  • HI… anyone tell me how can I implement private chat with two clients in ratchet.

     Reply
    • Add a variable to identify recipient. If the message’s recipient is the same with user SESSION(according to your management). append it to message’s div entry. Done good for me.

    • Hi Henry, could you show me the code to make privite chat

  • When we refresh the page. It will create a new resource id for example Resource id #1 and keep increasing when a page connected. It’s that no problem?

     Reply
  • Thanks for this excellent example/tutorial ! It works very well with ws://, however, wss:// leads to an unknown error. Is there anything I need to know, change or add in order to get it working ? Thanks in advance !

     Reply
  • Thank you so much ! . . .

     Reply
  • thanks for the tutorial.
    which would be the correct way to save the chat history in a database?
    is good practice to save the messages received from server.php, or should be done differently?
    greetings.

     Reply
    • Hi, check my other reply. Same question his asking.. create db connection and insert query in ws server so every socket message is store directly into db.

  • thank you…….
    thank you…….
    thank you…….

     Reply
  • So how does one encode a text data frame? Please explain, the RFC reference is very difficult to grasp.

     Reply
  • I try since 3hours but it’s doesn’t works…
    I try with EasyPHP then XAMPP and it’s the same !
    When i starting chat erver, i’ve got alwas this message :
    “Warning: socket_bind() expects parameter 3 to be long, string given in C:\xampp\
    htdocs\chat2\server.php on line 12”
    I read php doc (socket_bind()) but i don’t find solution. :(

     Reply
  • Error Occurred – undefined
    Connection Closed
    was occured

     Reply
  • How can run this non Windows 7 with WAMP

     Reply
  • Hello Saran Chamling,
    Thank you for this great tutorial which inspired me a lot. Otherwise, I want it to work on my web site instead of running it on my localhost. Do you have an idea how to change that.
    All reagards

    David Edgar

     Reply
  • Poxa, um exemplo excepcional, teve muita utilização para mim

     Reply
  • HI

    i am use xampp.its working fine on my local.

    my server is linux,how i use,server.php.

    import think is every time i post the value of port.

    when some select another online user,i need run server.php,

    how i will do in my server.

     Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.