Making a PHP Chat Room

I’ve been playing around with PHP and I thought I’d leave a few of my notes here including how I’m making a PHP chat room.

PHP is basically a programming language that can run in a browser when accessing servers that support it and most do. It’s designed to integrate regular HTML and PHP code fairly easily so you just create a HTML file but instead of naming the extension .htm or .html you name it .php and the browser will prefer it over an html file of the same name. Generally we use index.php as the filename.

Code like…

<html>

<body>

<?php

?>

</body

</html>

will allow you to write some php between the lines which have the question marks.

PHP syntax is a little different than Java or C so let’s talk language.

  • PHP uses // for comments
  • all lines use ; for a terminator
  • $variable – declare variable – all variables regardless of type start with $ and must be referred to them in that way
  • -> is used instead of a dot . between objects and their class variables
  • => is used to increment the indexes of an array
  • arrays can be indexed by a name, not just a number
  • echo – to display text like echo “hi” or echo $variable

Now let’s see some code…

<html>
<head>
<title>Title</title>
</head>
<body>

<?php
$a = 1;
$b = 2;
$c = $a + $b;
echo “The variable c is equal to ” . $c;

?>

</body>
</html>

And when you access this php file your browser will just show you the number 3. The php code is hidden from the user automatically.

Now let’s say our HTML has a form which will allow us to get user input. The form fields will have two aspects to them. The data and the name which refers to the data. HTML forms are pretty straight forward. We just need to place them outside of the question marked tags of the php so the browser doesn’t think we are writing php code.

<html>
<head>
<title>Title</title>
</head>
<body>

<form>
Enter your name
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Click Me”>
</form>

<?php
?>

</body>
</html>

The above code uses the tagset <form></form> to create a simple form that we can later interact with. The first <input> tag has the name of “name” and the type of input it accepts is text. The second is a button. The value is the text which appears on the button and the type of input is a submission button which would allow you to finally submit the form to the server. So how do we interact with this so that we can take the input from the user and do something with it?

Well we have to write some code in our php tag and then we need to reload the page or another one to display the results so the first thing we should modify is the form tag so that it looks like…

<form action=”index.php” method=”post”>

The action part instructs the browser to load index.php when the form submission is done. This could be any file, but since we started with the index.php this just makes it reload index.php which is necessary to display any change we might want to see within the same file. The method is called “post” and the other option is “get” which has a limited length and is less secure so post is what is usually used.

Now if the form tag has been modified in this way as soon as you click a submit button like the one the code showed the browser will send data to the server. All of the data in the input fields will be sent along with a lot of other information in a special variable array called _POST which the next page which is loaded can access. It’s accessed by creating a local variable and then copying the information from _POST into the local variable and then we can do whatever we want with it. The data however that is stored in _POST is indexed by names like the name which was in the input tag, which in that case was “name”. It sounds confusing, but basically it’s like this…

_POST is an array, it has data indexed by names, and so we grab it by the name and copy it to use it. For example

<html>
<head>
<title>Title</title>
</head>
<body>

<?php
$name = $_POST[‘name’];
echo $name;
?>

<form action=”index.php” method=”post”>
Enter your name
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Click Me”>
</form>

</body>
</html>

In the above example we use php to define a variable called $name. Now we had to assign a value to it of course so we said it equals the data we get from $_POST right? But what data? I mean _POST contains a lot of data. It is an array and we need to tell the server what data we want so we use the braces to refer to an element within the array and then we supply the element’s name which in this case is “name”. If the input field was not named “name”, but instead named “data” or something we’d use that word instead between the braces.

The next line is a simple echo command which displays the value of the variable $name which is the name we entered which passed through the post into the reloaded page and was grabbed from the array. I know it sounds complex, but it’s not that bad.

Now if we run that page and then enter a name in the text input field and then click the button the page will reload and show us our name at the top.

There is one other thing we can add however. Sometimes we don’t want to display our name unless one was actually entered previously so we could modify the code to look like this..

<html>
<head>
<title>Title</title>
</head>
<body>

<?php
if (isset($_POST[‘name’])){
$name = $_POST[‘name’];
echo $name;
}
?>

<form action=”index.php” method=”post”>
Enter your name
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Click Me”>
</form>

</body>
</html>

The complex code uses an if statement to test whether there is any data inside of the _POST array at the index named ‘name’ and if so the code we have between the curly braces can run. Otherwise it just ignores it. This type of code is good to include for error checking in many cases, but it’s not absolutely necessary in our application at this time.

At this point you can probably see how a chat application could work, but the problem is that each user loading this page would have a unique experience not shared by other users so the users could not communicate with one another. To change this we’ll need to store the information we enter into a file on the server in a file that every user can access so they can see what the other people have typed. We’ll also need a way to temporarily lock the file so that two people are not trying to store information inside of it simultaneously. That means we’ll have to learn about php file handling.

To read a file we must use a function called fopen. Fopen takes a few parameters and can open a file, but if the file does not exist or if you want to write data to the file you need the server to be setup to allow write access to the directory in which the file will be created. Alternatively the file could already exist and you could just setup the server to allow write access to that particular file. Either way you’ll have to use chmod on the file or directory to do that.

For extra security we won’t give the users write access to the directory. Instead we’ll just create a blank file with any text editor and call it “names.txt” and then change the permissions so that others can read and write to it.

The linux terminal command…

sudo chmod o+w names.txt

will change the permissions of the file names.txt to allow others (o) to write (w) to it. And that’s all you need to do as far as permissions go.

Now we need to write the code to open the file so that we can write data into it.

We don’t interact with the file directly; instead we create a handle which is just a variable that will store the data from the file as an array. The line is…

$handle = fopen(“names.txt”,’a’);

The name of our handle is “handle” but it could have been anything. The function we used was fopen which took parameters including the name of the file we wanted to open (which could be a complete directory structure if so needed) and then the mode in which we wanted to open the file, which in this case was append (a). The other options are write without appending (w) and read only (r).

To write information to the file we can use a line like…

fwrite($handle, “hello”);

which would use the fwrite function giving it the parameters of the file handle we want to use and then what data we want to write to the file which in this case is a string that says “hello”. Alternatively instead of supplying a string we could have used a variable like..

fwrite($handle, $variable);

for a similar effect.

After we write the data to the file we should close the file for many memory related reasons, but especially because it’ll affect the locking we’ll place on the file later so we use the line…

fclose($handle);

which closes the file handle.

Now to read the file we create another handle which in this case we’ll call “readin” and we use the file function giving it a parameter of the filename. It’s pretty simple.

$readin = file(“names.txt”);

Now if we wanted to display the whole contents of the file we can’t just use echo on the handle’s name because the data is stored in an array (probably technically a stream, but let’s not get too technical as of yet). We can use the function var_dump for this…

var_dump($readin);

and that will work fine for general debugging, but it’s not well formatted because it displays the word “array” and then how many elements are in the array and the array’s numerical index followed by the data type stored in each element and then the length of each element and then the value in each element. Basically it looks like garbage output.

The function print_r() does the same…

print_r($readin);

And…

print_array($readin)

again isn’t so great.

So how to do it in a nicely formatted way? We have to use a foreach function. It’ll look a bit strange, but what it does is perform the same operation on each and every element in the array as it parses through them. The lines will look like this…

foreach($readin as $thenames){
echo $thenames;
}

What that means is that for each element in the array $readin use the temporary variable $thenames and echo $thenames one at a time so we can see them.

That works wonderfully but the display of each name in the file is horizontal. I want a line break so…

$readin = file(“names.txt”);
foreach($readin as $thenames){
echo $thenames.'<br>’;
}

By adding a connotation dot I can append something onto the end of each element as it is echoed and in this case I’m adding some html code which is done by using a single-quote set and putting a html break tag in there. It works wonderfully doesn’t it? Check out our code to this point…

<html>
<head>
<title>Title</title>
</head>
<body>
<?php
if (isset($_POST[‘name’])){
$name = $_POST[‘name’];

//open file
$handle = fopen(“names.txt”,’a’);

//write to file
fwrite($handle, $name.”\n”);

//close file
fclose($handle);

//read file
$readin = file(“names.txt”);
foreach($readin as $thenames){
echo $thenames.'<br>’;
}

}
?>
<form action=”index.php” method=”post”>
Enter your name
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Click Me”>
</form>

</body>
</html>

Now we have a program that opens a file, writes to it, and returns the data for as many names as we want to enter into it, but if another user is using it we can’t see what they’ve typed until we enter something of our own, so really we need to refresh the page automatically every so often.

If we set the refresh rate too low there will be lag. If we set too high it will be difficult to type in some browsers that clear the forms on refresh so maybe every five seconds for testing? That sounds good.

There are ways within html through the header part of the file to set the file to periodically refresh at a particular rate. Just below the head tag we place…

<meta http-equiv=”refresh” content=”5″>

And there you go. The page will refresh every five seconds. You can slow this down if you want, but every five seconds works well.

The problem however is that previous text disappears because upon refresh our name field within the _POST becomes empty.

We can’t remove the if isset thing altogether however or we’ll keep adding blank data to the end of our file every time the page refreshes. So what can we do?

Well we only want to write data to our file if the name element in the _POST array isn’t empty right? So we can use the != test operator which means “is not” in a line like this…

if (!empty($name)){}

to test whether $name is empty or not. If it is not we can execute code within the braces which is where we will move our file writing code to but we want to be able to write to the file regardless so we’ll keep that just outside of that code block. The modified code will look like…

<html>
<head>
<meta http-equiv=”refresh” content=”5″>
<title>Title</title>
</head>
<body>
<?php

$name = $_POST[‘name’];

if (!empty($name)){
//open file
$handle = fopen(“names.txt”,’a’);

//write to file
fwrite($handle, $name.”\n”);

//close file
fclose($handle);
}
//read file
$readin = file(“names.txt”);
foreach($readin as $thenames){
echo $thenames.'<br>’;
}

?>
<form action=”index.php” method=”post”>
Enter your name
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Click Me”>
</form>

</body>
</html>

Now we have a program that actually works something like a chat program would. It still looks like it should be used just for names however so let’s modify it’s appearance a bit to make it look more like a chatroom.

<html>
<head>
<meta http-equiv=”refresh” content=”5″>
<title>PHP CHAT ROOM</title>
</head>
<body>
### WELCOME TO PHP CHAT ROOM ### <br>

<?php

$name = $_POST[‘name’];

if (!empty($name)){
//open file
$handle = fopen(“names.txt”,’a’);

//write to file
fwrite($handle, $name.”\n”);

//close file
fclose($handle);
}
//read file
$readin = file(“names.txt”);
foreach($readin as $thenames){
echo $thenames.'<br>’;
}

?>
<form action=”index.php” method=”post”>
### Enter Your Message ###
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Talk”>
</form>

</body>
</html>

Pretty cool eh? Now the problem we’ll have is that the file will keep getting longer and longer and will have to be edited manually at some point or deleted or something to reset it right? We really should do this from within the php code right? We can use the function count() to count how many elements are in the array and execute some code to erase the first line of the file based on whether the file has gotten too long. Sounds good. There is a clunky way this can be done that I’ll put here for reference. The problem is that using this method it’s easy for another person to miss a large portion of what has been chatted about…

<html>
<head>
<meta http-equiv=”refresh” content=”5″>
<title>PHP CHAT ROOM</title>
</head>
<body>
### WELCOME TO PHP CHAT ROOM ### <br>

<?php

$name = $_POST[‘name’];

if (!empty($name)){
//open file
$handle = fopen(“names.txt”,’a’);

//count number of lines
$filetocount = “names.txt”;
$lines = count(file($filetocount));

//if the lines are too many erase the file
if ($lines> 10){
fclose($handle);
$handle = fopen(“names.txt”,’w’);
fwrite($handle, $name.”\n”);
fclose($handle);
$handle = fopen(“names.txt”,’a’);
}

//write to file
fwrite($handle, $name.”\n”);

//close file
fclose($handle);
}
//read file
$readin = file(“names.txt”);

 

foreach($readin as $thenames){
echo $thenames.'<br>’;

}
?>
<form action=”index.php” method=”post”>
### Enter Your Message ###
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Talk”>
</form>

</body>
</html>

In the above code when the amount of lines in the file exceed 10 the file is closed from append mode and reopened in write mode and wiped clean and then closed and reopened in append mode as it was before. Effective in solo applications, but it won’t work for a chat. What we need is something that will remove line or two lines only so that the last few lines are always seen.

I’ll add an explanation next time I work on this tutorial, but this will be the finished code…

<html>
<head>
<meta http-equiv=”refresh” content=”5″>
<title>PHP CHAT ROOM</title>
</head>
<body>
### WELCOME TO PHP CHAT ROOM ### <br>

<?php

$name = $_POST[‘name’];

if (!empty($name)){
//open file
$handle = fopen(“names.txt”,’a’);

//write to file
fwrite($handle, $name.”\n”);

//close file
fclose($handle);
}

///trim

$readin = file(“names.txt”);//read file

$newarray = file(“names.txt”,FILE_IGNORE_NEW_LINES);//converts file into an array
$linecount = count($newarray);//counts the lines

if($linecount >20) {//if the line count exceeds 20

array_splice($newarray, 0, 1);//remove 1 lines

fclose($readin);//close the file
$handle = fopen(“names.txt”,’w’);//reopen in write only to erase the file
fclose($readin);//close the file
$handle = fopen(“names.txt”,’a’);//reopen in append mode

foreach($newarray as $addthis){//each element of the array will be called addthis
fwrite($handle, $addthis.”\n”);//write each element of the array to the file
}

$readin = file(“names.txt”);
}
foreach($readin as $thenames){

echo $thenames.'<br>’;

}

?>
<form action=”index.php” method=”post”>
### Enter Your Message ###
<br>
<input name=”name” type=”text”>
<br>
<input type=”submit” value=”Talk”>
</form>

</body>
</html>

Now that will work fine on most browsers. I noticed on midori browser however the field is cleared everytime the page refreshes, so either you could make an alternative php file for users of midori type browsers to use which has a longer delay so the user has more time to type before the refresh (that kind of detection and redirection is fairly easy to implement usually or a simple link can be provided to the user when logging in) or you could just lengthen the time for everyone. I think the first option is best. But ultimately the solution is to simply separate the php file into two separate pages one containing the output that needs to be refreshed and the other the input controls and then joining them together by the use of frames on a homepage. So that’s what we’ll do.

Also we want to include a way to login with a username so that the messages can be labeled as originating from a particular user. And so we’ll do that as well and luckily that will be easier by the use of that homepage also. So we are going to entirely rework our code to make this happen.

We’ll need to create three files. They will be called:

  1. login.htm
  2. user.php
  3. chatroom.php

The login will be a simple html page with a form for logging into the chatroom. It will take the logged in user to the user page which will have the buttons and text fields to allow the user to chat and it will have a frame which shows the chatroom. This will give us a nice clean interface where the chatroom can regularly refresh without affecting our text input area.

The html for login.htm is very straight forward.

<html>
<title>Login to PHP CHAT</title>
<body>
### LOGIN TO PHP CHAT ###

<form action=”user.php” method=”post”>
Enter a screen name to login: <br>
<input name=”name” type=”text” required>
<br>
<input type=”submit” value=”ENTER”>

</form>
### LOGIN TO PHP CHAT ###

</body>
</html>

Now obviously we could have some type of security here that would test a login password against a hardcoded password or a stored password stored on the server. That stored file could even be encrypted and another php file could encrypt the password entered before making the comparison which could offer even more security, but honestly this is a chatroom, so who cares? This simple form will do, but some kind of validation checking is good so that they are forced to enter something so we included the keyword “required” in the tag for the user to input his name. That’s pretty cool.

Now we could code something that checks the username against a file that lists all the people currently logged in so that we don’t get duplicates, but let’s ignore that possibility for now.

Now as we know once the submit button is clicked the _POST variable picks up all the output as stores it. The element named “name” will carry our name forward to the next page loaded, so we