You learned how to create forms, and use PHP to process form data. This lessons looks at how to email it.
By the end of this lesson, you will learn:
<textarea> tag.mail function to send an email message.In an earlier chapter, we created a template-based site with PHP. It included a contact form that looked like this:

Figure 1. Incomplete contact page
Now we can finish it. This is what we want:

Figure 2. Complete contact page
Here’s the code for the form.
<?php
//Path from this page to the site root.
$path_to_root = '.';
//Title of this page.
$page_title = 'Contact';
require $path_to_root . '/library/start_page.inc';
require $path_to_root . '/library/header.inc';
require $path_to_root . '/library/left_nav.inc';
?>
<div id="center_region">
<h1>Contact</h1>
<p>Please complete the form and click Send.</p>
<form action="send-contact-message.php" method="post">
<p>
Subject<br>
<input type="text" name="subject" size="40">
</p>
<p>
Comment<br>
<textarea name="message" rows="5" cols="40"></textarea>
</p>
<p>
<button type="submit">Send</button>
</p>
</form>
<p><a href="index.php">Home</a></p>
</div>
<?php
require $path_to_root . '/library/footer.inc';
require $path_to_root . '/library/end_page.inc';
?>
Figure 3. Code for contact form
Lines 1 to 9 and 28 to 31 are the templating system at work. The form itself is the HTML from lines 13 to 35.
There’s a new form element on line 20: <textarea>. It creates the multi-line field in Figure 2. The rows attribute specifies the number of rows the field has. The cols attribute specifies the number of columns.
If we want the field to have contents when the page loads, we could add it inside the tag. For instance:
<textarea>(Type your message here)</textarea>
would show this when the page loads:

Figure 4. <textarea> with content
send-contact-message.php (named in the action property of the form) will send the message. Here’s the code:
<h1>Contact</h1> <?php //Get message data. $subject = $_POST['subject']; $message = $_POST['message']; //Email it. mail( 'email address', //Where to send "Contact form - $subject", //Email subject $message //Message body ); ?> <p>Thank you! Your message has been sent.</p>
Figure 5. send-contact-message.php
I’ve omitted the PHP that adds the header, nav bar, etc.
Lines 4 and 5 get the subject and the message. Nothing new there.
Lines 7 to 11 sends the email using the email() function. We give the function three arguments:
You should replace the email address with your own, if you want to test the program.
A couple of things to notice. First, I split the function call over a few lines, to make it easier to read. I added comments at the end of each line, explaining the arguments.
Line 9 adds the text “Contact form – “ in front of the subject. This will help the recipient know where the message came from.
The mail() function will work only if your server is set up correctly. PHP has to know what program on the server to use to send email.
Most shared hosting servers will be set up correctly. However, your test server on your local machine (e.g., your XAMPP server) might have some trouble. That’s OK; it’s just for testing anyway.
You can try it.
I’ve had trouble sending email to Gmail using the basic mail() function. Here’s the code I used in an application that worked:
$to_address = 'email address'; $subject = 'Card order'; $message = "Stuff stuff, thing thing"; $from = 'another email address'; $headers = "MIME-Version: 1.0\n"; $headers .= "Content-type: text/plain; charset=iso-8859-2\n"; $headers .= "From: $from\n" . "Reply-To: $from\n" . "X-Mailer: PHP/" . phpversion() . "\n"; mail($to_address, $subject, $message, $headers);
Figure 6. Sending email to Gmail
You may need to use this approach for some other services as well.
In this lesson, you learned:
<textarea> tag.mail function to send an email message.Let’s see how you can store form data to a file.
You just learned how to send form data be email. But sometimes you want that data to be immediately available on your server. Let’s see one way to do that.
By the end of this lesson, you should:
Let’s say you want people to be able to add comments to a Web page. Here’s what the user sees when there are no comments:

Figure 1. No comments
There are two pieces to the comment area:

Figure 2. Comment area pieces
First, there’s the current comments. There are none in this case.
Second, there’s a form for adding new comments. This will always be the same, no matter how many comments there are.
Users add comments by typing in the text field and clicking the button:

Figure 3. Adding a comment
When they click Save, the page reloads, and shows the new comment in the comment area.

Figure 4. Comment showing
We need a place to keep comments that people enter, so we can read them back and show them on Renata’s page.
For this example, we’ll store them in a file. When there’s a new comment, we’ll append it to the file. Append means “add to the end.”
When Renata’s page – renata.php – loads, we’ll show the comments. We’ll put some PHP on the page that will read the comments in and insert them into the HTML.
This will work most easily if the comments file already contains HTML tags. But people who type comments don’t type HTML. They just type text:

Figure 3 (again). Adding a comment
So we’ll add some HTML tags around what they type.
Whenever you save data that people type, you have to worry about security. You don’t want hackers typing comments that, for example, contain JavaScript. We’ll address that later.
Let’s draw a picture of what happens behind the scenes. It will show us the flow of control, that is, what happens first, what happens next, and so on.

Figure 5. Comment control flow
The browser asks the server for renata.php (1). PHP code in renata.php reads the comments file, and inserts the comments into the HTML (2). renata.php also contains HTML to show the form (the <form> tag and friends).
Once the browser has shown the page, it waits for the user to do something. Suppose the user types a comment, and clicks the Save button (3). The browser looks at the action property of the form: action="save-renata-comment.php". So it asks the server for that page, and sends the form data along with the request (4).
The server loads save-renata-comment.php. Code in that file takes the new comment, wraps it in a <p> tag, and appends it to the comments file. Then it redirects the browser. That is, it tells the browser to load another page. Which one? renata.php (6).
So the browser loads renata.php (1). Code in renata.php reads the comments file (2), which now has the new comment on the end. So the new comment appears.
Phew! That’s a lot of work! But it’s a lot of work for the computers, not for us. We tell them what to do, and they do it.
Let’s have a look at the pieces.
Here’s what the comments file looks like after a comment has been added:
<p>You are so cute!</p><hr>
Figure 6. Comments file with one comment
We need to read that in to the right place in renata.php (2 in Figure 5). Here’s the code for the entire file. (I’ve wrapped it in the template code we saw earlier.)
<?php
//Path from this page to the site root.
$path_to_root = '..';
//Title of this page.
$page_title = 'Renata';
require $path_to_root . '/library/start_page.inc';
require $path_to_root . '/library/header.inc';
require $path_to_root . '/library/left_nav.inc';
?>
<div id="center_region">
<h1>Dog profile: Renata</h1>
<p>Here is Renata.</p>
<p><img src="renata.jpg" alt="Renata"></p>
<h2>Comments</h2>
<?php
if( file_exists('renata_comments.txt') ) {
readfile('renata_comments.txt');
}
else {
print '<p>There are no comments yet.</p>';
}
?>
<h2>Add a comment</h2>
<form action="save-renata-comment.php" method="post">
<p>
<textarea rows="3" cols="30" name="comment"></textarea>
</p>
<p>
<button type="submit">Save</button>
</p>
</form>
<p><a href="index.php">Back to the dog list</a></p>
</div>
<?php
require $path_to_root . '/library/footer.inc';
require $path_to_root . '/library/end_page.inc';
?>
Figure 7. renata.php
Everything up to line 9 is templating code. The real stuff starts on line 10.
Lines 10 to 14 are simple HTML. That’s the main content of the page. The comment section follows.
There may be comments, or there may not be. If there are comments, we want to show them. Otherwise, we want to tell the user that there are no comments yet.
We’re going to store comments in the file renata_comments.txt. The file will be created when the first comment is added. If there are no comments, the file won’t even exist.
Here’s line 16:
if( file_exists('renata_comments.txt') ) {
file_exists() is a function that returns true if the file is found. If it is, line 17 runs:
readfile('renata_comments.txt');
This reads the file, and inserts it into the HTML output stream.
If the file does not exist, then file_exists('renata_comments.txt') is false, and line 20 runs:
print '<p>There are no comments yet.</p>';
This outputs the text in the quotes. Remember that we need to include the HTML tags.
The rest of the page uses stuff we’ve seen before.
The user types a comment and clicks the same button. The browser takes the URL in the form’s action attribute – save-renata-comment.php – and goes there, sending the contents of the comment field (4 in Figure 5).
Here’s save-renata-comment.php:
<?php
//Get the user's comment.
$comment = $_POST['comment'];
//Append it to the comments file.
$f = fopen('renata_comments.txt', 'a');
fwrite($f, "<p>$comment</p><hr>");
fclose($f);
//Jump back to Renata's page.
header('location:renata.php');
?>
Figure 8. save-renata-comment.php
Here’s what happens when the user clicks the Send button.
![]() Browser |
![]() Web server |
![]() PHP interpreter |
Gimme save-renata-comment.php.And here's some form data: comment=You+are+so+cute!
|
||
(Fetches save-renata-comment.php from disk.)Oh! This is a PHP file. Hey, PHP interpreter! Run this. |
||
|
Get the form data. Save data to the file. Hey, server, here's the result. No HTML, but I have an HTTP header for you: Location: renata.php
|
||
Hey, browser. Here's the contents of
save-renata-comment.php.
Just an HTTP header:Location: renata.php
|
||
|
OK. Hey, send me renata.php.
|
||
(Fetches renata.php from disk.)Oh! This is a PHP file. Hey, PHP interpreter! Run this. |
||
|
HTML, send it through. Here's some PHP. Read the file, put it in the HTML. More HTML. Hey, server, here's the result. |
||
Hey, browser. Here's the contents of
renata.php.
|
||
|
OK. (Render for user.) |
Figure 9. After the Save button is pressed
Let’s have a look at the code again.
<?php
//Get the user's comment.
$comment = $_POST['comment'];
//Append it to the comments file.
$f = fopen('renata_comments.txt', 'a');
fwrite($f, "<p>$comment</p><hr>");
fclose($f);
//Jump back to Renata's page.
header('location:renata.php');
?>
Figure 8 (again). save-renata-comment.php
Line 3 gets the user’s comment, and puts it into the variable $comment.
Line 5 is new. We want to write to the comments file. But before we do that, we need to open it. That’s what the fopen() function does.
We give fopen() two arguments:
The 'a' means the file is opened in append mode. That means that anything we write to the file will be added to the end.
Take another look at the line:
$f = fopen('renata_comments.txt', 'a');
What is $f for? fopen() return a file handle. This is a special object that refers to the file. You don’t need to know what it is, exactly. Just use it.
The next line is:
fwrite($f, "<p>$comment</p><hr>");
This writes data to $f. Because the program opened the file in append mode, the data is written to the end of the file.
Remember that it’s easier if the file contains HTML. But the user types just plain text into the comment field. So we wrap the comment in a <p> tag. We also add a horizontal rule (<hr>) to separate comments from each other.
Finally, the program closes the file in line 9. PHP will close files for you automatically if you forget to do it.
One more thing to notice about the code.
<?php
//Get the user's comment.
$comment = $_POST['comment'];
//Append it to the comments file.
$f = fopen('renata_comments.txt', 'a');
fwrite($f, "<p>$comment</p><hr>");
fclose($f);
//Jump back to Renata's page.
header('location:renata.php');
?>
Figure 8 (again). save-renata-comment.php
This program does not send any HTML to the browser. The program adds the new comment, then tells the browser to jump to another page.
PHP files don’t have to generate an <html> tag. Most do, but this one doesn’t. In future chapters, you’ll see other programs that have the same pattern:
$_POST.Is save-renata-comment.php really a Web “page?” Well, it’s a PHP file that has a URL. But it doesn’t show anything to the user. save-renata-comment.php does its work, then generates an HTTP header that says to the browser, “Sorry, you need to go to another place. Here is the URL.”
I don’t care whether you call it a page or not. The important thing to understand is that:
Some PHP programs don’t create HTML.
There’s a problem with the code, though. Evil people could cause some problems.
Actually, what they would do is write a program that repeatedly loaded our page and shoved a lot of data into the comments field. Do that a 100,000 times, and the disk could get full.
Let’s make the following changes.
Here’s the new version of save-renata-comment.php.
<?php
//Make sure the file exists.
touch('renata_comments.txt');
//Check the length of the comments file.
if ( filesize('renata_comments.txt') < 50000 ) {
//Get the user's comment.
// Limit it to 2,000 characters.
$comment = substr($_POST['comment'], 0, 2000);
//Convert special characters to HTML entities.
$comment = htmlentities($comment);
//Append comment to the comments file.
$f = fopen('renata_comments.txt', 'a');
fwrite($f, "<p>$comment</p><hr>");
fclose($f);
}
//Jump back to Renata's page.
header('location:renata.php');
?>
Figure 10. Secure version of save-renata-comment.php
Look at line 5:
if ( filesize('renata_comments.txt') < 50000 ) {
The filesize() function returns the number of bytes in the file. If this number is less than 50,000, the statements inside the braces ({}) will run. The braces extend from lines 5 to 15, and include the code that adds data to the comments file.
You can have as many statements as you want in the braces. You can have other if statements, if you want. We’ll see that later.
There is one problem with the filesize() function. It will cause an error if the file does not exist. That’s what line 3 does. The touch() function creates the file if it doesn’t exist.
Have a look at line 8:
$comment = substr($_POST['comment'], 0, 2000);
$_POST['comment'] returns the contents of the comment form field, as before. But rather than just putting that in $comment, something is done with it first.
substr() is a function that returns part of a string. It takes three arguments. The first is the string to process. The next two are numbers. One is the start position of the string. The other is the number of characters to return.
Here are some examples.
$x = 'Lion King';
print substr($x, 0, 3);
The first character is at position 0, not 1. So this says “Start at character 0, and return three characters. The result is:
Lio
How about this one?
print substr('Renata is cute', 2, 4);
This says “Start at character 2 and return 4 characters”. Character 2 is the third character (the first one is character 0). So the result is:
nata
One more.
$r = 'Rupert Giles';
$s = substr($r, 10, 8);
print $s;
This says “Start at the 11th character, and return 8 characters.” The 11th character is the “e” in “Giles.” The result will be:
es
substr() cannot return 8 characters, because there aren’t that many. So it returns what it can.
Back to the code. The line is:
$comment = substr($_POST['comment'], 0, 2000);
This says “Start at character 0 (the first character) and return the first 2,000 characters.” If there are, say, 23 characters, then $comment will contain all 23. If there are 4,321 characters, $comment will contain 2,000 characters.
The last thing we need to do is make sure that any JavaScript that the user types into the comment field will not run when the page is shown. There are various ways to do this; we’ll use the simplest.
For JavaScript to run, it has to have a <script> tag around it, like this:
<script>
alert("Evil JavaScript");
</script>
As you know, the < and the > have special meaning to the browser. They mean “Here is some HTML.” If you want to show a less than sign in your content, you need to replace < with <. This is an HTML entity. It displays a less than sign, that isn’t interpreted as the start of a tag.
We can tell PHP to replace all the characters that have special meaning in HTML, like <, with their HTML entities. This is harmless:
<script>
alert("Evil JavaScript");
</script>
It won’t be executed, because there is no < to indicate the start of an HTML tag.
Here’s is what we do on line 10:
$comment = htmlentities($comment);
htmlentities() is a function that will go through a string, and replace all of the special characters with HTML entities.
Let’s say someone types this into the comment field:

Figure 11. Evil JavaScript
Here is what would be stored into the comments file:
<p><script>
alert(\"Evil JavaScript\");
</script></p><hr>
The only HTML tags are the <p> and <hr> we added ourselves.
This lesson shows you how to add form data to a file. PHP gets the form data, opens the file in append mode, and writes the data.
We also looked as some security measures. We limited the total size of the comments file, the size of any one comment, and made sure that JavaScript typed into a comment would not execute.
Time for some exercises.
Write a PHP program that emails a light bulb joke. Here is the form:

Figure 1. Form
When the user clicks the button, some PHP sends an email somewhere, and then shows this:

Figure 2. Output
Only use your own email address! Don’t spam.
You can try my version (it doesn’t actually send email, just shows the output). You can download the files.
Upload your solution to your server. Put the URL below.
(Log in to enter your solution to this exercise.)
Create an application to save jokes to a file. The main menu is like this:

Figure 1. Main page
Click “See joke list” and you see the jokes file:

Figure 2. Show jokes
The user can also type a new joke into the main page:

Figure 3. Adding a joke
Clicking the button will add the joke to the file, and show a confirmation page:

Figure 4. Joke added
You can try my solution, though it doesn’t actually save new jokes. You can also download the files.
Upload your solution to your server. Put the URL of the main page below.
(Log in to enter your solution to this exercise.)
Write a PHP application that lets you collect quotes you like. It should let you:
You can try the application.
The page that shows the quotes should say “No quotes yet” if there are none. Otherwise, it should show the quotes.
Separate quotes with <hr> tags.
save-quotes.php is the file that saves a new quote. It should:
stripslashes() to remove PHP’s “helpful” backslashes.<br> tags.These two lines will help:
$quote = stripslashes($_POST['quote']);
$quote = str_replace("\n", '<br>', $quote);
You can download a zip file that has everything except two PHP files: see-quotes.php and save-quotes.php.
You can also download my solution, but do the exercise yourself first!
Put the URL of your solution below.
(Log in to enter your solution to this exercise.)
A zoo has a ticket booth. Visitors come up to the booth, and order tickets for adult and children (e.g., 1 adult and two children). The booth attendant collects the entry fee, and prints out the tickets.
Write a PHP application for the attendant. It starts out like this:

Figure 1. Empty form
Notice that the focus is in the first input field.
You can download the background image. It’s from a design on OSWD, by GGGDesign.
The attendant enter the numbers of adults and children, and clicks the Total button. The page shows the total, and a Print button:

Figure 2. Form with data
When the attendant clicks the Print button, three things happen.
Clicking on the “Show log” link shows the transaction log:

Figure 3. Log
Each log entry has the date and time, as well as the number of tickets ordered. This code might be useful:
date('l, F jS Y, h:i:s A')
You can try the application (although I have disabled the logging, to keep the file size down).
Upload your solution to your server. Put the URL below.
(Log in to enter your solution to this exercise.)