Grow your CSS skills. Land your dream job.

Building a jQuery/PHP Powered Chat Room

Published by Chris Coyier

The Plan

In this tutorial we are going to build a little chat program that is really easy to get up and running on any server running PHP. No database is required - as the chat will store itself in a simple text file. The technologies used:

  • PHP - Will handle all the server side stuff
    • Writing new messages to the text file
    • Reading out new messages from the text file
    • Retrieving the "state" of the text file
    • Basic security
  • jQuery/JavaScript - Will handle the client side stuff. This is an AJAX-y application, meaning that messages pop onto the screen (both yours and others) without needing any page refresh.

    • Periodically asking the server if there are new messages that have been posted
    • Appending new messages to the chat
    • Scrolling the chat down to the most recent messages
    • Asking and setting the user name
    • Limiting the text input to prevent gigantic ridiculous messages
    • Basic security
  • Text File - Stores the chat

NOT The Plan

This tutorial covers all kinds of interesting things and interesting technology and the end result is definitely a chat room. What it isn't is the World's Most Full-Featured Chat Room. You can't kick people out or ban people. People can potentially have the same name. You can't see all the current members of the chat. In other words, this ain't IRC. It's just a fun demo and totally workable in a number of situations. If you want to take this and run with it and make it more full featured, be our guest!

Basic HTML Structure

<div id="page-wrap">

    <h2>jQuery/PHP Chat</h2>
    
    <p id="name-area"></p>
    
    <div id="chat-wrap"><div id="chat-area"></div></div>
    
    <form id="send-message-area">
        <p>Your message: </p>
        <textarea id="sendie" maxlength = '100'></textarea>
    </form>

</div>

Precious little markup here folks. Even what you are looking at above is 50% unrelated to the specific functionality of this tutorial. The page-wrap is to center things. The double-divs thing going on with the chat-wrap and chat-area is just to pull off the totally unnecessary (but cool) double border effect in the chat area.

The two most important areas are the textarea with the id of "sendie" and the chat-area div. JavaScript will be targeting these.

The JavaScript Half of the Engine

We're going to get a little Object Oriented with our JavaScript. We'll create a "Chat" function that is parent to a bunch of other functions for dealing with Chat-related stuff.

function Chat () {
    this.update = updateChat;
    this.send = sendChat;
    this.getState = getStateOfChat;
}

updateChat will ask the server if there are new lines in the text file. If there are, it will return them as JSON and then this function will append those new lines to the chat. sendChat will be called when a message is entered into the text area and return is pressed. The function will pass that data to the server to do what it will with it. getStateOfChat asks the server basically how many lines the current text file is, so it has something to compare against and know when lines are "new" or not. This information is returned as JSON as well. And those functions look like:

//gets the state of the chat
function getStateOfChat() {
	if(!instanse){
		instanse = true;
		$.ajax({
			type: "POST",
			url: "process.php",
			data: {'function': 'getState', 'file': file},
			dataType: "json",	
			success: function(data) {state = data.state;instanse = false;}
		});
	}	
}

//Updates the chat
function updateChat() {
	if(!instanse){
		instanse = true;
		$.ajax({
			type: "POST",
			url: "process.php",
			data: {'function': 'update','state': state,'file': file},
			dataType: "json",
			success: function(data) {
				if(data.text){
					for (var i = 0; i < data.text.length; i++) {
						$('#chat-area').append($("

						"+ data.text[i] +"

						"));
					}	
				}
				document.getElementById('chat-area').scrollTop = document.getElementById('chat-area').scrollHeight;
				instanse = false;
				state = data.state;
			}
		});
	}
	else {
		setTimeout(updateChat, 1500);
	}
}

//send the message
function sendChat(message, nickname) { 
	updateChat();
	$.ajax({
		type: "POST",
		url: "process.php",
		data: {'function': 'send','message': message,'nickname': nickname,'file': file},
		dataType: "json",
		success: function(data){
			updateChat();
		}
	});
}

All three of these functions make use of jQuery's AJAX abilities, and do their communicating with a PHP file called process.php, which of course we'll need to build!

The PHP Half of the Engine

Part of the data that gets passed with the AJAX calls is an (arbitrary) value named "function". This is just to let the PHP file know what kind of thing we need done. As such, the first thing we'll do is snag that value and set up a switch statement that covers each possible function. We also set up a blank array to store values in that will ultimately be encoded into JSON at the end and passed back.

When we are trying to getState, the text file is read and the number of lines in returned. When we update, the file is read and any new lines are retuned. When we send, the message is processed and then written into the text file as a new line.

<?php

    $function = $_POST['function'];
    
    $log = array();
    
    switch($function) {
    
       case('getState'):
           if (file_exists('chat.txt')) {
               $lines = file('chat.txt');
           }
           $log['state'] = count($lines); 
           break;  
      
       case('update'):
          $state = $_POST['state'];
          if (file_exists('chat.txt')) {
             $lines = file('chat.txt');
          }
          $count =  count($lines);
          if ($state == $count){
             $log['state'] = $state;
             $log['text'] = false;
          } else {
             $text= array();
             $log['state'] = $state + count($lines) - $state;
             foreach ($lines as $line_num => $line) {
                 if ($line_num >= $state){
                       $text[] =  $line = str_replace("\n", "", $line);
                 }
             }
             $log['text'] = $text; 
          }
            
          break;
       
       case('send'):
       	 $nickname = htmlentities(strip_tags($_POST['nickname']));
	     $reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
	     $message = htmlentities(strip_tags($_POST['message']));
	     if (($message) != "\n") {
	       if (preg_match($reg_exUrl, $message, $url)) {
	          $message = preg_replace($reg_exUrl, '<a href="'.$url[0].'" target="_blank">'.$url[0].'</a>', $message);
	       } 
	          fwrite(fopen('chat.txt', 'a'), "<span>". $nickname . "</span>" . $message = str_replace("\n", " ", $message) . "\n"); 
	     }
         break;
    }
    echo json_encode($log);
?>

Kicking it all off

We're going to need to do some JavaScript stuff to get this party started. We'll need to load jQuery, load the "engine", then do some quick functions to gather the chat participants name for joining the chat.

While we are at it, let's put the stuff in for limiting the length of the entered text and sending the text with a return-key press.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script src="chat.js"></script>
<script>

  // ask user for name with popup prompt    
  var name = prompt("Enter your chat name:", "Guest");
 
  // default name is 'Guest'
  if (!name || name === ' ') {
    name = "Guest";  
  }
  
  // strip tags
  name = name.replace(/(<([^>]+)>)/ig,"");
  
  // display name on page
  $("#name-area").html("You are: <span>" + name + "</span>");
  
  // kick off chat
  var chat =  new Chat();

  $(function() {
  
     chat.getState(); 
     
     // watch textarea for key presses
     $("#sendie").keydown(function(event) {  
     
         var key = event.which;  
   
         //all keys including return.  
         if (key >= 33) {
           
             var maxLength = $(this).attr("maxlength");  
             var length = this.value.length;  
             
             // don't allow new content if length is maxed out
             if (length >= maxLength) {  
                 event.preventDefault();  
             }  
         }  
                                                                                                     });
     // watch textarea for release of key press
     $('#sendie').keyup(function(e) {  
                
        if (e.keyCode == 13) { 
        
              var text = $(this).val();
              var maxLength = $(this).attr("maxlength");  
              var length = text.length; 
               
              // send 
              if (length <= maxLength + 1) { 
                chat.send(text, name);  
                $(this).val("");
              } else {
                $(this).val(text.substring(0, maxLength));
              }  
        }
     });
  });
</script>

Periodically Checking for New Messages

We need to use the "update" function of our chat to poll the text file for new messages and append them if necessary. So we'll need to call that update function on a regular basis, and we'll use JavaScript's setInterval() function for that:

<body onload="setInterval('chat.update()', 1000)">

The Goods

Download Files

Note: Remember this is PHP powered, so you can't just download the files and open them on your local machine and have it work, unless you are running a local PHP server. Also remember to change the file permissions of the chat.txt file to be writable by the server when uploading to your own test location.

Comments

  1. Permalink to comment#

    Nice article/script.

    Just a quick typo though, Chris. On the ‘Note’

    “Remember this is PHP powered, so you can”

    I think you mean . . .

    “Remember this is PHP powered, so you can’t

  2. Permalink to comment#

    I’ve been working on something quite similar to this. However, I utilize long polling (make a connection to the server, and wait for a response) instead of pinging the server every second for an update.

    I made a simple screencast showing the basics of long polling: http://screenr.com/SNH

    • Hey Stephen love the idea gmail me and we can work together about the log polling

    • Cerium
      Permalink to comment#

      I should take a look at this, I’ve been searching information on long polling for some time.

      @Chris : nice & original article ;)

      Just one thing :

      Would be better & faster (in my opinion) if it was in the $(function() {});, isn’it ?

      $(function() {
      //other stuff

      setInterval(function() { //use a function not a string
      chat.update();
      }, 1000);
      });

      Fire the setInterval before the onload event, and doesn’t starts JS compiler/compilator (I’m not sure what is the right word in english).

  3. Permalink to comment#

    Love the idea. Of course it’s just more of a functional concept for now, so going into minor annoying details makes no sense, as any real implementation would require some TLC anyway.

    But good on principle.

  4. Juan Pina
    Permalink to comment#

    I tested in IE and it seems to fail. Cant send message and didnt seem to refresh.

  5. Permalink to comment#

    Sweet example. This might overload your database though, so remember to use this script on a separate database than the one used for others.

    Reminds me a lot of “phpFreeChat” (which has way more functionality), but this one just looks sleeker and uses jQuery.

    Great work folks!

    • Permalink to comment#

      Whoops – nevermind! I saw later on that it doesn’t make database calls, but writes to a file. Sweet!

  6. The demo is already being trolled.

    • TeMc
      Permalink to comment#

      Indeed it is… Sad sad situation.

    • Yeah I figured. This is one of those situations where a small handful of idiots can ruin a perfectly good demo.

      Oh well. I’ll publish their IP’s.

      It’s not really meant to be a hangout right now anyway, just a demo of the functionality.

    • Rahul
      Permalink to comment#

      Nicely said… :)

  7. Alex
    Permalink to comment#

    This is really well done! I am glad that it will also be updated to add new things.
    And I have to agree, some people are spamming a lot in there….
    Anyway, thanks for teaching this.

  8. Thanks Chris and Kenrick!

  9. Permalink to comment#

    If you plan on having this scale beyond the basic AJAX experience, you should look into a technology called Comet. It’s great at handling “live” applications like chat being handled with AJAX by making low-latency requests and server-side push.

    http://www.cometd.org/

  10. It’s a really cool demo, but UTF-8 characters seem to get screwed up a little bit. Perhaps encoding needs to be done before outputting.

  11. Permalink to comment#

    Love the site, this is my first time posting and you probably recognize some of the code on my site. I find this to be very intruiging and useful but what happens to great finds like these once you can embed Google waves in your blog? I hope everyone isn’t sick of hearing about them before they hit mainstream.

  12. Permalink to comment#

    Nice one :D

  13. Permalink to comment#

    good job, thanks Chris & Kenrick :)

  14. Permalink to comment#

    Use COMET instead of periodically checking for new messages. It’s faster and more smooth (like normal chat). It’s more complicated though, but not much :) The idea is in creating infinite loop in php on server resulting in persistent browser-server connection. Don’t worry, then client disconnects php will break the loop.

  15. Permalink to comment#

    amazing tutorial…
    i’ll share on my facebook..
    thanks CSS Trick.

  16. Permalink to comment#

    If you scroll up it will jump down to the bottom when it refresh…

  17. Hitesh Chavda
    Permalink to comment#

    I have one small Question…

    Chat is refreshed every 1000 mili second, right..

    but can I know that chat is refreshed every 1 sec OR after the response of the last request?

    I think you know what i want to say!!

  18. silvers
    Permalink to comment#

    HI! i haven’t read through this yet, but as soon as i saw the header i was immediately exctied and wanted to say what an amazing idea it was to add a tutorial on this subject.

    it’s such a sweet idea. you have such great ideas for topics. you must be so busy!

    i really like the way that you use so many different languages and techniques as it gives us all a more complete web design/development understanding.

  19. Permalink to comment#

    Hey Chris,

    Long time reader, first time commenter (had to say it!).. I was wondering if you had any advice on expandability. I would like to convert this concept from the simple, single room chat into something more complex that could write to distinct text files for both future reference and privacy. Is this a possibility?

    Thanks,
    Elliot

    • Yea elliot, simply chancing the name of the file in the process.php file u can write to a differnt file hence chat rooms. and ill be doing that for 2.0

  20. silvers
    Permalink to comment#

    hey chris,

    very nice chat room thing! i was wondering, are you gonna implement it in to your site for a hangout? cos if you do it would be sweet to have a few rooms, like a css room/ php room etc… so we could talk about stuff on the fly?

    i don’t know, i just think you’ve done really well and it would be nice to make it a full feature. i have no idea how much more work that would cause you so i’d understand if it was a mission.

  21. Permalink to comment#

    Wow. That’s very awesome, and I could definitely do this.

    I would also like to see an advanced tutorial on how to advance this, such as not allowing multiple instances of the same username and banning. Plus moderators.

  22. gorkem
    Permalink to comment#

    Does not support Turkish characters?

  23. Euan
    Permalink to comment#

    how would you insert time not ip

  24. Kyle Cotter
    Permalink to comment#

    awesome!!! @kenrick i’ve been waiting for this ever since i saw the demo!!! Thanks chris and kenrick!!!! I jumped up and literally hurt myself when i saw this article finally posted!!!

  25. Mike
    Permalink to comment#

    Hi Chris,

    i have great fun and learn very much with all the screencasts on your site and this is a very nice concept of a web based chat application.

    Just one idea. I think, you should implement some locking logic, especially for the file handling, to make the application thread safe.

  26. Hi Chris!

    This is a pretty nice demo. Nice tutorial for a basic and functional chat.

  27. Cesar
    Permalink to comment#

    Nice demo!

    What is the live help chat used on http://www.psd2xhtml.com/chat.html it looks like mootools, ajax and html is used and it’s pretty nice but I can’t find the name of it.

    Thank you.

  28. Mike
    Permalink to comment#

    Nice tut, but doesn’t work in IE!

  29. Permalink to comment#

    The double-divs thing going on with the chat-wrap and chat-area is just to pull off the totally unnecessary (but cool) double border effect in the chat area.

    Is that even needed? For a double border, couldn’t you just use border: 3px double black; or whatever?

    • To be honest, I kind of forgot/didn’t know there even was a “double” property to borders. I’ll have to experiment more with that. It seems like that is very rarely used, so I wonder if there are some problems with it.

  30. Thomas
    Permalink to comment#

    Awesome little script here! Too bad it’ll only eat utf-8 characters… even with another charset, something screws up foreign characters like æ,ø and å :(

  31. Permalink to comment#

    ya
    i learnt it and got it well
    its simple

  32. have a sample page dude…. better show it before someone else try it self . n thks… keep posting
    n greetings from indonesia

  33. sory bro… i dont see “vew demo” he… I have try that… n it simple to use… but how about the database? its growing big hm…. n how we can prune an older message… before it be bulk on server?

  34. Big Georgian
    Permalink to comment#

    Hi Criss.

    Nice chat, but this script not works correctly with utf-8. I’ll trying to write on Georgian and this is my result:

    გამარჯობა -> transformed to -> á

  35. Permalink to comment#

    I’m currenly working on an implementation of a GMail chat clone that utilizes push through a forever-frame. I made a version that uses short pulls with simply Javascript, but was not quite as impressed as the responsiveness of the GMail push chat method.

    I’ll post it when / if I ever get done (should be soon enough though, one hopes).

    My problem was making this forever-frame (constantly loading iframe) that doesn’t block outgoing XMLHttpRequests from sending (i.e. your messages responding back to the user). If anybody knows a sure fire way to do this, let me know, else I’ll keep hacking away at it, :D.

    – Dan


  36. $message = htmlentities(strip_tags($_POST['message']));

    htmlentities – make UTF string unreadable…

  37. nadya
    Permalink to comment#

    I really liked your example on the top of the page with the two bots talking to each other :D :D :D cool :P

  38. Permalink to comment#

    hey. the demo isn’t working. :(

  39. hikma
    Permalink to comment#

    This very interesting as am planing to build a site for my self and i would need a very interesting live chat room and i will try and not the code and see how you got in there …………………..thanks

  40. J.
    Permalink to comment#

    It’s a great system. One Question!! How can I make the sent messages permanently stay on the page? Right now when you refresh the page it’ll clear out the message for the next new guest, I’d like to make them stay for the next guest entering the page, and manually clear them from the .txt

    Looking forward to your reply!!!!!!!!! – I great appreciate your help!!!!! Thank you!

  41. Mohamed
    Permalink to comment#

    This is fantastic job, I uploaded in my site but no action,
    Show me how to change chat.txt to be writable!

  42. Rick
    Permalink to comment#

    I have downloaded the files and it works great!!! I am using this web chat application to demonstrate Cross Site Scripting to my fellow colleagues. I see that index.php the command: name:=name.replace strips out tags and also in the process.php in the case(‘send’) section a lot of code is used to strip tags out. But if I remove (comment out) many of these I discover that an statement can be written to the chat.txt file but it does not display in the chat window. How can I make the statement display in the chat window so a user can click on the link and redirect the user to another site. Please remember I am using this to show Cross Site Scripting. Thanks, rick1235

    • Rick
      Permalink to comment#

      Im trying to make an HREF statement appear in the chat window so I may demonstrate Cross Site Scripting. I am able to write the HREF statment to the chat.txt file but it does not appear in the chat window.

  43. Erica
    Permalink to comment#

    In case this isn’t obvious, I want to save someone somewhere a little time: If you’re trying to use this at https , change the script tag’s src reference to https as well.

    (That being said, if you are really serious about security, in general, you should be looking at the Chat version 2 anyway…)

    Thank you very much for this post!

  44. Sv9t
    Permalink to comment#

    Hi! wonderful chat. But I have a problem with the Russian Cyrillic Linux system. Words displayed “Вл Ð ° Ð ¾ “or” null “, that I do? system on Windows – time will be displayed words correctly.

    PS sorry for my english, I translate with Google translator

  45. Nanthakumar
    Permalink to comment#

    HI…. Can Anyone Help With This I Am Doing Chat Concept in that “Is Typing” Concept I Cant Make it…..I tried setInterval But thats Not Working…..

  46. Sreenivas
    Permalink to comment#

    We have deployed on linux server it is not working on it and it is working locally well

    dreamin.in/jchat

    I am unable to find what went wrong

  47. Permalink to comment#

    To fix charset:

    $message = htmlentities(strip_tags($_POST['message']), ENT_COMPAT, 'UTF-8');
    
  48. Takashi

    How to make a button to send message?

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".