Grow your CSS skills. Land your dream job.

Chat2: Group Chat Room with PHP, jQuery, and a Text File

Published by Chris Coyier

This is an update to original Chat Room we published here on CSS-Tricks. In some ways, the technology is the same. We are going to employ PHP to talk to the server, jQuery to keep the chat rolling, and the chats themselves will be stored in .txt files just like the first version.

What is changed is the addition of some new features:

  • Usernames are unique to users currently chatting
  • You can see a "currently chatting" user list
  • There are multiple rooms for chatting

A Little MySQL

While the first version of this used no database at all, we are going to employ a little MySQL for this version. There is a file in the download called Setup.sql for use in building the initial database. MySQL isn't for the chats themselves, but for two other things:

  • Keeping track of active users
  • The rooms

When someone comes in to chat, they choose a username. Using some jQuery, it makes an AJAX request to see if that username is currently in use in the database. If it is in use, you get a warning:

Otherwise, it says it's cool:

If it is cool, and you click to join the chats, that username will be put into the database and thus further checks for it's name will tell others that name is unavailable. Idle users are removed from the database.

Adding/Editing/Removing Rooms

The names of the chatrooms are kept in the database. To add a new chatroom, just add a new row to the database with the name of the chatroom and the filename of the text file you intend to store the chat:

Then it's just a matter of making sure the text file is on the server in the right place with proper server-writeable file permissions (see the download for properly location).


I'm sure you've noticed by now we haven't been looking at any actual code. This is on purpose. All the code is available in the download (see below). It is not so incredibly much that it's overwhelming, but I think it's too much for a standard written tutorial/overview. Instead, let's overview what it's responsible for:

Username checking: On the homepage of the chat, when you choose your username, jQuery is there watching that text input. When you type a character (on keyup) it asks a certain PHP file (via AJAX) if that username is in use. The PHP file responds with a yes or no, and a message is appended to the screen accordingly.

Message box: When a user types into the textarea for sending a message, the jQuery watches that box and ensures the text is under a certain number of characters (set via maxlength attribute on the textarea)

Sending message: When the return/enter key is pressed in the chat box the value of it is sent for processing. PHP writes the text to the text file.

Updating the chat: Every few seconds, jQuery asks a PHP file to poll the text file to see if there are any new lines, if there are, they are displayed.

Features it doesn't have

  • You can't kick people out
  • It doesn't do special characters

You wanna add that stuff in? I'd love it and I'll update this.

Demo and Download

Download Files

UPDATE: It turns out there was a SECURITY PROBLEM with one particular aspect of it, which can get grant access to any file on the server. A reader was able to show me how they could publicly access my wp-config.php WordPress file, which is of course super sensitive. The vulnerability is in the update.php file, which accepts a "state" and "file" parameter. Accessed directly, and with a relative file path, you can get access to protected files that way. When it gets fixed I'll update the downloadable code.

UPDATE: Jason Gradwell suggested some protection on the PHP side, which would require the filed to be called via Ajax only and only from a specific source.

<?php if (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_REFERER']!="") { 
} ?>


Special thanks to Kenrick Beckett who created the original code that powered this and Jason Lengstorf for looking it over and tidying some things up security-wise.

For the Future

Here is a roundup of things people have suggested in the comments or that I otherwise think would be cool:

  • Security problem from above fixed
  • Flood control (something like you can only submit 1 message every 5 seconds)
  • Link to logout (delete PHP session)
  • Allow some HTML, but not other (whitelist of tags). Like allow <a href="">, but still strip out javascript. Possibly a few buttons for HTML (WYSIWYG?). Code highlighting for stuff in <code> tags.
  • Allow registration, for being able to have a certain username permanently (and all the stuff that goes with that, like "lost password")
  • Protection against non-existent chat room names e.g. /Chat2/room/?name=LOL
  • Support for all special characters (UTF-8)
  • Private messages (@) (only the person who matches that username will see it)
  • Kick people out / ban people by IP (only as an admin user, or perhaps just a blacklist of IPs)
  • More emoticons
  • Have an actual submit button (for mobile devices that support JavaScript but don't have regular key events)
  • Automatic filtering of bad words
  • Utilize an outside login system, like Twitter oAuth, Google Login, or Facebook Connect
  • Usernames as emails, then use Gravatars
  • Links with 4-letter extensions don't work (e.g. .info)
  • Long polling, instead of requesting every few seconds


  1. Amjad
    Permalink to comment#

    Amazing! Simply superb.

    However here are some suggestions for a future version:

    1. Logout link
    2. Unlimited characters in a message
    3. A WYSIWYG toolbar (HTML formatting)
    4. Code highlighting (PHP, Java… )
    5. Registration option
    6. Possibly an admin panel

    Apart from that its simply the best chat app ever!

  2. The bee’s knees!

  3. Permalink to comment#


    you should use flock() for txt files.

  4. Permalink to comment#

    Just a few suggestions to improve the current chat app without really enhancing functionality.

    Add a “Log Out” button
    Add validation to the username field (Currently if you submit the form with a blank value you just get redirected to the blank jumpin.php)

    Quite a cool little app though. How long do you keep the text file? Is it limited to a certain number of lines?


  5. Permalink to comment#

    other features:
    encoding utf-8
    ‘@’ to send a private message

    nice job chris!

  6. Argeaux
    Permalink to comment#

    Well if you edit some stuff in the js code with fiebug you can mess up the whole place …

  7. AWESOME! I’ve only been waiting for this for like 2 months. Ask Kenrick, he’ll tell you I bothered him about it all the time :D. Nice to see it finally out, look forward to implementing it on my site.

  8. Permalink to comment#

    Nice one, it looks great. Although having anonymous chats isn’t always a good idea..

  9. Permalink to comment#

    I think you should check against a
    non-existent chat-name

    Btw, Good work!

  10. It seems a little odd that if you’re using MySQL for part of the application, why not use it for the actual conversations aswell?

    Having a MySQL database just to link through to flat-files is a bit clunky don’t ya think?

    • Maybe maybe not. I like the idea of the text files. You can just grab the file and you have an instant transcript of the conversation for re-purposing wherever. Clearing it out is as simple as selecting all the text and deleting it. Dealing with databases is a lot more cumbersome. Although I will say there is probably a lot more you could do having the data in a real database.

    • Jason
      Permalink to comment#

      How big can these files get? If they get too big, would it hurt response time?

    • I get having a complete flat-file chat script for the ease of management that you describe.

      Equally, I get using MySQL for everything, as it gives you a lot of extra control and manipulative power of the data.

      I don’t get relying on BOTH systems. Personally, using both systems is clunky and wildly inefficient.

      Having everything in SQL would allow you to return your chats in one query, whereas in the current setup you require two; one also needing I/O access to the filesystem.

    • I’m just not feeling how it’s “wildly inefficient”. It’s not like we are loading two different frameworks… You write to a text file, you write to a database, pretty much the same “weight” of an event.

    • Opening a MySQL connection (or accessing a file) is inefficient. You wanna reduce usage of it as much as possible.

      TBH, for the amount of data you have in your SQL, you might aswell just store it as a straight PHP array in the file itself.

      Cut out the SQL database, lovely flatfile.

      BTW, if you are really gonna expand on this (as in your current improvements listed for the future), and you’re staying flatfile, use SQLite. Much more manageable than using your own home-grown system.

    • Permalink to comment#

      I have to agree with Chris on this one. It’s really nice to be able to grab right out of that text file. Also, it seems like it would be more efficient to write and rewrite to that file than to create a new row in a database for every line of the chat. Also, the stuff he’s storing in the database should obviously be stored in a database. I disagree with the SQLite recommendation. Stick with MySQL for everything except the actual chat and text files for the chat. I think it’s a nice system. I’m not exactly a SQL expert though.

    • Why are you so against SQLite. It’s a brilliant system, almost as fast as just purely adding lines.

      It is basically the power of MySQL in a flatfile. There are only a few (uncommon) commands it can’t do well.

    • I think Benjamin Mayo has made a very good suggestion here!

    • Torrance
      Permalink to comment#

      My thought exactly.

      It seems to me either go wholly with the db, or wholly with the text files. Normally, I would have gone with the db, but here it could be very nice to be able to do away with any need for a db connection, and store configuration in a file of its own.

      Seems much cleaner that way.

    • Permalink to comment#

      Running a chat room on sql will ruin your sql server and it will get very bad. Trust me if you have a lot of visitors then it’s the worst idea ever.

    • Tholithemba
      Permalink to comment#

      What is actually the best way? can you give cons and pros for each.

  11. You have to check some things out in your PHP ;). It is possible to write directly to the text-file with the PHP-Script.

  12. Permalink to comment#

    amazing work bro…..

    keep it up

  13. Permalink to comment#

    What I would like to see integrated:

    * UTF8 / Special characters (this is really essential)
    * Private messages (@)
    * Kick/Ban people/IP out
    * “Log Out” button
    * Option to registrate your nick/name (password and email needed – account verification)
    ( * Admin panel would be awesome)

    What about making a plugin for WP from this? (and integrate it with user database and admin panel…)

    Thank you for the great web app ;)

  14. Permalink to comment#

    Really neat.

    It would be useful to have a logout button, and be able to kick people off.

  15. Permalink to comment#

    One more thing to think about is that you may want to check for new messages more because it seems a bit slow.

  16. Permalink to comment#

    thanks chris… awesome script..! :)

  17. TeMc
    Permalink to comment#

    I think minimalism is very important (ie. not accesslists of moderators, admins, colors, fonts etc.)

    However a few things I think should be in the app:
    * Indication of username that joined or left (blink red, then fade out for leaving) – Joined nickname in yellow, and after a few seconds setTimeout fade to white as the rest)
    * Timestamp of messages recieved (I like the funtionality to see the past few lines that were said when joining a room, however it could be over 3 hours old for all I know)

    Things I liked:
    * Seeing the userlist
    * Having multiple rooms
    * Live type-check for usable nickname
    * Seeing the last few lines from the log when joining a room

    Thigns I didn’t like:
    * Emoticons with grey backgrounds on white
    * Horintally scrolling
    * When pressing enter I see it going to the nextline and then it submit’s. It should return false on that key press (Only a short second visible of the mouse cursor | -symbol)
    * HTML-tags stripped (convert to htmlentities?)

  18. This is great!
    So you don’t mind if people wanted to try adding stuff to it then right?

  19. Jason
    Permalink to comment#

    The abuse is definitely hard to control. Maybe add some functionality to look for certain words and log them out if they use them…

  20. There is some douche with your name on there spamming it with cum and other stuff.

    I would personally add an IP address field in the MySQL Table.

    Find the guy. And ban him from he obviously don’t appreciate your hard work or demos.

  21. Permalink to comment#

    Great start and has good potential. I’d like to see the next version of this.

  22. wtf
    Permalink to comment#

    Freddy Gonzalez says that there is some douche with your name on there spamming it with cum and other stuff.

  23. Permalink to comment#

    One thing that was bugging me was how the chat box would only show 5 lines when you first load the page. It made it difficult to jump into the middle of a conversation.

    I changed it to show the most recent 50 lines by updating this code in the chat.js file:

    success: function(data){
    state = data.state-50;

  24. TeMc
    Permalink to comment#

    A few more bugs:

    * When posting links with an extension of 4 characters (such as *.info or *.name) it’s cut off after the 3rd character. In proces.php the reg ex only checks for {2,3}, should allow 4 aswell.
    * Non existand chatrooms. Although chatting is not possible, the user-list does work. I’d say don’t waste the resources. Either block it or fully allow non-official rooms.
    * Once again, I’m not sure why you do htmlentities(strip_tags()), I think htmlentities() is enough, Especially in a HTML/CSS chatroom ;) – maybe even good asfar as using backticks to make it pre-whitespace (a simple [span]-wrap around the backtick’ed text with whitespace-pre should do it)


  25. Permalink to comment#

    Nice Applications it’s really simple and full of features.

  26. Permalink to comment#

    This is great example thanks

  27. Permalink to comment#

    Hey Chris, this is a great web app. How would you create a private room so weird peeps don’t access the chat if you wanted to host this on your site for example. So only invited users can join in on the conversation.

  28. Permalink to comment#

    I was amazed about the chat and the fact that in the test chat rooms we did not have no swearing at all in fact it was very international and all were very nice ;-)

    I might try that chat out on a private page …

  29. Wow great chat… is that possible to create user his own group….

  30. Permalink to comment#

    Very cool chat room app. The ajax feature works well. Thank you for creating this.

  31. Madhav
    Permalink to comment#

    thats really good chat app.. :) loved it..
    as everyone suggested logout would be good option along with it…

    and it would also be good if you can provide app like one to one chat app means private chat between two people

  32. Permalink to comment#

    I had made a modification of Kenrick Beckett’s original script some time ago, with features like a current userlist and a ‘time ago’ thing on messages like facebook’s, smiley support with a smiley selector, and colored nicknames based on the first 6 chars of nick’s hash (and darkened a bit) so that it can be consistent for the same nick, I uploaded it here check it out:

  33. Permalink to comment#

    wow that’s cool You should make this a video cast so us beginner types can understand better

  34. this is a chatroom script i did a couple of years ago (when the ajax-hype first started) (last worked on it in early 2007):

    here’s how it works:

    once the user submits a message, it is saved in a mysql db (for keeping a transcript) and at the same time, a new text file is created containing JUST that one message with the username and other parameters (like if it’s a personal message to a specific user) – the filename is a number (the last post id)

    so when you enter the chat, it basically requests the last-message-id from the server (which for example is 1000 ), then it tries to pull the textfile named 1001.txt from the server – if the file exists, show the contents (the message) and ask for 1002.txt – if it does not exist, that just means, there is no new post, so it tries to pull 1001.txt from the server again in half a second (or a second)

    there are about 20 such files in the chat-folder, and everytime a new message is created, the 21st file is deleted (so it automatically cleans up)

    so unless a user actually enters a message, neither the PHP-parser or mysql are called

    i tried a single txt-file in an earlier version, but flock() is a pain in the ass – creating a single file for every message solved that problem for me

    with that technique, i’ve handled about 100 simultanious users during the NFL-draft (which, i think, is pretty good for a http-based application – and it could be more, if you increaced the timeouts a little bit (making it a little slower to respond))

    it has a userlist, private messaging, admin-features, ignore functionality, multiple rooms, and a really neat feature: if you chatted for quite some time, and you want to find something that’s been written earlier in the transcript, just scroll up and look for it – if a new message arrives, the script won’t scroll automatically (enabling you to find what you were looking for in the transcript) – if you then scroll back to the bottom of the transcript, the script will then continue to scroll automatically

    PS: sorry for my bad english

  35. ryan
    Permalink to comment#

    Has the security problem been fixed?

    Seems great though!!

  36. Permalink to comment#

    I really like the new features. Maybe ChatV3 will spark a new project?

    My Interview With Chris Coyier

    • Jason
      Permalink to comment#

      I wanted to let you know that I looked at your interview in Google Chrome (running Windows XP) and the text is so light that I can barely read it. I opened it up in Firefox and it looked normal.

      I’m not sure if something is rendering different in Chrome or what.

    • Permalink to comment#

      Thanks a lot Jason.

  37. Permalink to comment#

    How can we insert a utf-8 nick name?

  38. Permalink to comment#

    A very good tutorial as always. A very interesting idea that I have given a go at, limited testing done on it so far, but it has some promise!

    Well done again

  39. Permalink to comment#

    You can allow users to log out with this: .

  40. George Truman
    Permalink to comment#

    Haha! Taken down for security reasons.

  41. Permalink to comment#

    When I first started reading this post I thought there might be a security risk. Does sanitizing the data for this help at all, or is that not possible?

  42. Muchas gracias….

  43. hecooo
    Permalink to comment#

    hoho!It is cool~I love it!

  44. Chris Bogaards
    Permalink to comment#

    Is it possible to keep the complete chat in the chatroom? Right now, only the last 5 or so, lines remain there after you’ve been away for a couple of minutes. How can I do this? Can’t seem to find any option…

  45. Permalink to comment#

    [2] Has the security problem been fixed?

  46. Permalink to comment#

    Hey Chris, this is awesome. Thanks for making this and putting it out here — I’d love to know if the security problem has been fixed too.

  47. Permalink to comment#

    Can you go into more detail about the security problem. I don’t see how knowing the file path lets you open the file. I just want to know as this will help with making sure future projects are more secure.

  48. nice think i will turn it into a wordpress plugin

  49. dyata
    Permalink to comment#

    this is working in localhost,,
    but if i upload to web server, chat&list user chat can’t show…but that success record to txt file…

    what can i do??

  50. yes it is ok. but having some problem with IE. if i am not wrong.

    please clear it.

  51. alex
    Permalink to comment#

    great! are we allowed to customise the looks of the chat, remove the “chat v2″, use our own smilies etc?

  52. traktor
    Permalink to comment#

    Chris nice work, i was wondering if someone can help me install it and create a room.


  53. jack
    Permalink to comment#

    It’s strange that it works in IE but not FireFox. I wonder if it is incompatible with centain explorer

  54. Permalink to comment#

    how can i use chinese character in the user name and the chat?

  55. Josh
    Permalink to comment#

    First of all thanks for an amazing Product!

    I am running the 2nd Version Chat2, but when I type a message and Press Enter nothing happens! I can keep typing and the Text area gets larger and large for each time I click enter… What could be possibly wrong?

    An answer would be appereciated.. Thanks a lot

    • Josh
      Permalink to comment#

      Updates: I got it working! I think it was because I messed up some of the functions when I was trying to add the Whispering method!

      I have one simple sugggestion!

      It would be very helpfull for users like myself if there was as Short Tutorial inside the Package as well!

      Thanks a lot! It works great!

  56. Josh
    Permalink to comment#

    About the “README for Whispering.txt” File:

    I have had so many problems later trying to add the Whispering option! I later found out that there are many errors and Texts that are completely out of their correct formations and lines. Please Check the Whispering text, because I have had so many issues and couldnt work it out! A better explanation for the Whispering and a new code is what is needed, The rest works perfectly!

    Sad that I couldnt fix the Whispering Code.

    Good luck

  57. Avi Lu
    Permalink to comment#


    The algorithms you have used to remove JS and other dangerous code will not suffice. You should use the pre written solution called HTMLPurifier. Personally, I won’t install this as is.. If I had more time I would contribute to the solution myself.

    On a positive note, the fix wouldn’t take long if you look in to it.
    Further, though I understand for the purposes of the configuration file it would be best if that file could be kept out of the public domain altogether.

    Other than that, the interface is nice but some CSS for the buttons would really finish it off.
    Great job overall

  58. Oghenez
    Permalink to comment#

    @Christoph Dum
    Can i test your code?

  59. PankajRaj
    Permalink to comment#

    awesome code…

  60. Eric

    Just an FYI – You should check your included files.. some people used some colorful words in the testing chats that should be removed before someone gets a little peeved.

    Otherwise nice script – to bad its in an old ver of jQuery, scroll wont work with iPhone Safari.

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".