Article

Build Your Own Database Driven Web Site using PHP & MySQL, Part 3: Introducing PHP

Page: 1 2 3 4 Next

User Interaction and Forms

For most database driven web sites these days, you need to do more that just dynamically generate pages based on database data; you must also provide some degree of interactivity, even if it’s just a search box.

Veterans of JavaScript tend to think of interactivity in terms of event handlers, which let you react directly to the actions of the user—for example, the movement of the cursor over a link on the page. Server-side scripting languages such as PHP have a more limited scope when it comes to support for user interaction. As PHP code is only activated when a request is made to the server, user interaction can occur only in a back-and-forth fashion: the user sends requests to the server, and the server replies with dynamically generated pages.

The Rise of Ajax
To some extent, the rise of Ajax techniques in the JavaScript world over the past few years has changed this. It’s now possible for JavaScript code, responding to a user action such as mouse movement, to send a request to the web server, invoking a PHP script. For the purposes of this book, however, we’ll stick to non-Ajax applications. If you’d like to learn how to use PHP with Ajax, check out Build Your Own AJAX Web Applications by Matthew Eernisse (Melbourne: SitePoint, 2006).

The key to creating interactivity with PHP is to understand the techniques we can use to send information about a user’s interaction along with a request for a new web page. As it turns out, PHP makes this fairly easy.

The simplest method we can use to send information along with a page request is to use the URL query string. If you’ve ever seen a URL in which a question mark followed the file name, you’ve witnessed this technique in use. For example, if you search for “SitePoint” on Google, it will take you to the following URL to see the search results:

http://www.google.com/search?hl=en&q=SitePoint&btnG=Google+Search&meta=

See the question mark in the URL? See how the text that follows the question mark contains things like your search query (SitePoint) and the name of the button you clicked (Google+Search)? That information is being sent along with the request for http://www.google.com/search.

Let’s code up an easy example of our own. Create a regular HTML file called welcome1.html (no .php file name extension is required, since there will be no PHP code in this file) and insert this link:

<a href="welcome1.php?name=Kevin">Hi, I&rsquo;m Kevin!</a>

This is a link to a file called welcome1.php, but as well as linking to the file, you’re also passing a variable along with the page request. The variable is passed as part of the query string, which is the portion of the URL that follows the question mark. The variable is called name and its value is Kevin. To restate, you have created a link that loads welcome1.php, and informs the PHP code contained in that file that name equals Kevin.

To really understand the effect of this link, we need to look at welcome1.php. Create it as a new HTML file, but, this time, note the .php file name extension—this tells the web server that it can expect to interpret some PHP code in the file. In the <body> of this new web page, type the following:

<?php  
$name = $_GET['name'];  
echo 'Welcome to our web site, ' . $name . '!';  
?>

Now, put these two files (welcome1.html and welcome1.php) onto your web server, and load the first file in your browser (the URL should be similar to http://localhost/welcome1.html, or http://localhost:8080/welcome1.html if your web server is running on a port other than 80). Click the link in that first page to request the PHP script. You should see that the resulting page says “Welcome to our web site, Kevin!”, as shown below.

Greet users with a personalized welcome message

Let’s take a closer look at the code that made this possible. The most important line is this one:

$name = $_GET['name'];

If you were paying close attention in the section called “Arrays”, you’ll recognize what this line does. It assigns to a new variable called $name the value stored in the 'name' element of the array called $_GET. But where does the $_GET array come from?

It turns out that $_GET is one of a number of variables that PHP automatically creates when it receives a request from a browser. PHP creates $_GET as an array variable that contains any values passed in the query string. $_GET is an associative array, so the value of the name variable passed in the query string can be accessed as $_GET['name']. Your welcome1.php script assigns this value to an ordinary PHP variable ($name), then displays it as part of a text string using an echo statement:

echo 'Welcome to our web site, ' . $name . '!';

The value of the $name variable is inserted into the output string using the string concatenation operator (.) that we looked at in the section called “Variables, Operators, and Comments”.

But look out! There is a security hole lurking in this code! Although PHP is an easy programming language to learn, it turns out it’s also especially easy to introduce security issues into web sites using PHP if you’re unaware of what precautions to take. Before we go any further with the language, I want to make sure you’re able to spot and fix this particular security issue, since it’s probably the most common kind of security issue on the Web today.

The security issue here stems from the fact that the welcome1.php script is generating a page containing content that is under the control of the user—in this case, the $name variable. Although the $name variable will normally receive its value from the URL query string in the link on the welcome1.html page, a malicious user could edit the URL to send a different value for the name variable.

To see how this would work, click the link in welcome1.html again. When you see the resulting page (with the welcome message containing the name “Kevin”), take a look at the URL in the address bar of your browser. It should look similar to this:

http://localhost/welcome1.php?name=Kevin

Edit the URL to insert a <b> tag before the name, and a </b> tag following the name, like this:

http://localhost/welcome1.php?name=<b>Kevin</b>

Hit Enter to load this new URL, and notice that the name in the page is now bold, as shown below.

Greet users with a personalized welcome message

See what’s happening here? The user can type any HTML code into the URL, and your PHP script includes it in the code of the generated page without question. If the code is as innocuous as a <b> tag there’s no problem, but a malicious user could include sophisticated JavaScript code that performed malicious actions like steal the user’s password. All the attacker would have to do, then, would be to publish the modified link on some other site under the attacker’s control, and then entice one of your users to click it. The attacker could even embed the link in an email and send it to your users. If one of your users clicked the link, the attacker’s code would be included in your page and the trap would be sprung!

I hate to scare you with this talk of malicious hackers attacking your users by turning your own PHP code against you, particularly when you’e only just learning the language. The fact is, however, that PHP’s biggest weakness as a language is how easy it is to introduce security issues like this. Some might say that most of the energy you spend learning to write PHP to a professional standard is spent on avoiding security issues. The sooner you’re exposed to these issues, however, the sooner you become accustomed to avoiding them, and the less of a stumbling block they’ll be for you going forward.

So, how can we generate a page containing the user’s name without opening it up to abuse by attackers? The solution is to treat the value supplied for the $name variable as plain text to be displayed on your page, rather than as HTML to be included in the page’s code. This is a subtle distinction, so let me show you what I mean.

Copy your welcome1.html file and rename it to welcome2.html. Edit the link it contains so that it points to welcome2.php instead of welcome1.php:

<a href="welcome2.php?name=Kevin">Hi, I&rsquo;m Kevin!</a>

Copy your welcome1.php file and rename it to welcome2.php. Edit the PHP code it contains so that it looks like this:

<?php  
$name = $_GET['name'];  
echo 'Welcome to our web site, ' .  
   htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '!';  
?>

There’s a lot going on in this code, so let me break it down for you. The first line is the same as it was previously, assigning to $name the value of the 'name' element from the $_GET array. The echo statement that follows it is drastically different, though. Whereas previously, we simply dumped the $name variable, naked, into the echo statement, this version of the code uses the built-in PHP function htmlspecialchars to perform a critical conversion.

Remember, the security hole comes from the fact that, in welcome1.php, HTML code in the $name variable is dumped directly into the code of the generated page, and can therefore do anything that HTML code can do. What htmlspecialchars does is convert “special HTML characters” like “<” and “>” into HTML character entities like &lt; and &gt;, which prevents them from being interpreted as HTML code by the browser. I’ll demonstrate this for you in a moment.

First, let’s take a closer look at this new code. The call to the htmlspecialchars function is the first example in this book of a PHP function that takes more than one parameter. Here’s the function call all by itself:

htmlspecialchars($name, ENT_QUOTES, 'UTF-8')

The first parameter is the $name variable (the text to be converted). The second parameter is the PHP constant ENT_QUOTES, which tells htmlspecialchars to convert single and double quotes in addition to other special characters. A PHP constant is like a variable whose value you’re unable to change. Unlike variables, constants don’t start with a dollar sign. PHP comes with a number of built-in constants like ENT_QUOTES that are used to control built-in functions like htmlspecialchars. The third parameter is the string 'UTF-8', which tells PHP what character encoding to use to interpret the text you give it.

The Perks and Pitfalls of UTF-8 with PHP

You may have noticed that all of the example HTML pages in this book contain the following <meta> tag near the top:

<meta http-equiv="content-type" content="text/html; charset=utf-8"/>

This tag tells the browser that receives this page that the HTML code of the page is encoded as UTF-8 text. UTF-8 is one of many standards for representing text as a series of ones and zeros in computer memory, called character encodings. If you’re curious to learn all about character encodings, check out The Definitive Guide to Web Character Encoding.

In a few pages, we’ll reach the section on building HTML forms. By encoding your pages as UTF-8, your users can submit text containing thousands of foreign characters that your site would otherwise be unable to handle.

Unfortunately, many of PHP’s built-in functions, such as htmlspecialchars, assume you’re using the much simpler ISO-8859-1 character encoding by default. Therefore, you need to let them know you’re using UTF-8 when you use these functions.

If you can, you should also tell your text editor to save your HTML and PHP files as UTF-8 encoded text, but this is only required if you want to type advanced characters (like curly quotes or dashes) or foreign characters (like “é”) into your HTML or PHP code. The code in this book plays it safe and uses HTML character entities (for example, &rsquo; for a curly right quote), which will work regardless.

Open up welcome2.html in your browser and click the link that now points to welcome2.php. Once again, you’ll see the welcome message “Welcome to our web site, Kevin!”. As you did before, modify the URL to include <b> and </b> tags surrounding the name:

http://localhost/welcome2.php?name=<b>Kevin</b>

This time, when you hit Enter, instead of the name turning bold in the page, you should see the actual text that you typed, as shown below.

It sure is ugly, but it’s secure!

If you view the source of the page, you can confirm that the htmlspecialchars function did its job and converted the “<” and “>” characters present in the provided name into the &lt; and &gt; HTML character entities, respectively. This prevents malicious users from injecting unwanted code into your site. If they try anything like that, the code is harmlessly displayed as plain text on the page.

We’ll make extensive use of the htmlspecialchars function throughout this book to guard against this sort of security hole. No need to worry too much if you’re having trouble grasping the details of how to use it for now. Before long, you’ll find its use becomes second nature. For now, let’s look at some more advanced ways of passing values to PHP scripts when we request them.

Passing a single variable in the query string was nice, but it turns out you can pass more than one value if you want to! Let’s look at a slightly more complex version of the previous example. Save a copy of your welcome2.html file as welcome3.html, and change the link to point to welcome3.php with a query string as follows:

<a href="welcome3.php?firstname=Kevin&amp;lastname=Yank">Hi, I&rsquo;m Kevin Yank!</a>

This time, our link passes two variables: firstname and lastname. The variables are separated in the query string by an ampersand (&, which must be written as &amp; in HTML). You can pass even more variables by separating each name=value pair from the next with an ampersand.

As before, we can use the two variable values in our welcome3.php file:

<?php  
$firstname = $_GET['firstname'];  
$lastname = $_GET['lastname'];  
echo 'Welcome to our web site, ' .  
   htmlspecialchars($firstname, ENT_QUOTES, 'UTF-8') . ' ' .  
   htmlspecialchars($lastname, ENT_QUOTES, 'UTF-8') . '!';  
?>

The echo statement is becoming quite sizable now, but it should still make sense to you. Using a series of string concatenations (.), it outputs “Welcome to our web site, ” followed by the value of $firstname (made safe for display using htmlspecialchars), a space, the value of $lastname (again, treated with htmlspecialchars), and finally an exclamation mark.

The result is shown below.

Create an even more personalized welcome message

This is all well and good, but we still have yet to achieve our goal of true user interaction, where the user can enter arbitrary information and have it processed by PHP. To continue with our example of a personalized welcome message, we’d like to invite the user to type his or her name and have it appear in the resulting page. To enable the user to type in a value, we’ll need to use a HTML form.

Create a new HTML file named welcome4.html and type in this HTML code to create the form:

<form action="welcome4.php" method="get">  
 <div><label for="firstname">First name:  
   <input type="text" name="firstname" id="firstname"/></label>  
 </div>  
 <div><label for="lastname">Last name:  
   <input type="text" name="lastname" id="lastname"/></label></div>  
 <div><input type="submit" value="GO"/></div>  
</form>

Self-closing Tags

The slashes that appear in some of these tags (such as <input .../>) are no cause for alarm. The XHTML standard for coding web pages calls for slashes to be used in any tag without a closing tag, which includes <input/> and <meta/> tags, among others.

Many developers prefer to code to the HTML standard instead of adopting XHTML and, in fact, this is a matter of some debate within web development circles. The upcoming HTML 5 standard leaves the choice up to the developer, so neither approach is strictly “more correct” than the other.

If you’re curious about the factors to consider when making this decision for yourself, check out the relevant page of the SitePoint HTML Reference.

The form this code produces is shown below.

Make your own welcome message

This form is quite plain-looking, I’ll grant you. Some judicious application of CSS would make this—and all the other pages in this book—look more attractive. Since this is a book about PHP and MySQL, however, I’ve stuck with the plain look. Check out SitePoint books like The Art & Science of CSS (Melbourne: SitePoint, 2007) for advice on styling your forms with CSS.

Also make a copy of welcome3.php named welcome4.php. There’s nothing that needs changing in this file.

This form has the exact same effect as the second link we looked at (with firstname=Kevin&amp;lastname=Yank in the query string), except that you can now enter whatever names you like. When you click the submit button (which is labeled GO), the browser will load welcome4.php and add the variables and their values to the query string for you automatically. It retrieves the names of the variables from the name attributes of the <input type="text"/> tags, and obtains the values from the text the user types into the text fields.

Apostrophes in Form Fields

If you are burdened with the swollen ego of most programmers (myself included), you probably took this opportunity to type your own name into this form. Who can blame you?

If your last name happens to include an apostrophe (for example, Molly O’Reilly), the welcome message you saw may have included a stray backslash before the apostrophe (that is, “Welcome to our web site, Molly O\'Reilly!”).

This bothersome backslash is due to a PHP security feature called magic quotes, which we’ll learn about in Chapter 4: Publishing MySQL Data on the Web. Until then, please bear with me.

The method attribute of the <form> tag is used to tell the browser how to send the variables and their values along with the request. A value of get (as used in welcome4.html above) causes them to be passed in the query string (and appear in PHP’s $_GET array), but there is an alternative. It can be undesirable—or even technically unfeasible—to have the values appear in the query string. What if we included a <textarea> tag in the form, to let the user enter a large amount of text? A URL whose query string contained several paragraphs of text would be ridiculously long, and would possibly exceed the maximum length for a URL in today’s browsers. The alternative is for the browser to pass the information invisibly, behind the scenes.

Make a copy of welcome4.html and name it welcome5.html. The code for the form in this new page is exactly the same, but where we set the form method to get in the last example, here we set it to post. Of course, we’ve also set the action attribute to point at welcome5.php:

<form action="welcome5.php" method="post">  
 <div><label for="firstname">First name:  
   <input type="text" name="firstname" id="firstname"/></label>  
 </div>  
 <div><label for="lastname">Last name:  
   <input type="text" name="lastname" id="lastname"/></label></div>  
 <div><input type="submit" value="GO"/></div>  
</form>

This new value for the method attribute instructs the browser to send the form variables invisibly, as part of the page request, rather than embedding them in the query string of the URL.

Again, make a copy of welcome4.php and name it welcome5.php.

As we’re no longer sending the variables as part of the query string, they stop appearing in PHP’s $_GET array. Instead, they’re placed in another array reserved especially for “posted” form variables: $_POST. We must therefore modify welcome5.php to retrieve the values from this new array:

<?php  
$firstname = $_POST['firstname'];  
$lastname = $_POST['lastname'];  
echo 'Welcome to our web site, ' .  
   htmlspecialchars($firstname, ENT_QUOTES, 'UTF-8') . ' ' .  
   htmlspecialchars($lastname, ENT_QUOTES, 'UTF-8') . '!';  
?>

The figure below shows what the resulting page looks like once this new form is submitted.

This personalized welcome is achieved without a query string

The form is functionally identical to the previous one; the only difference is that the URL of the page that’s loaded when the user clicks the GO button will be without a query string. On the one hand, this lets you include large values, or sensitive values (like passwords), in the data that’s submitted by the form, without their appearing in the query string. On the other hand, if the user bookmarks the page that results from the form’s submission, that bookmark will be useless, as it lacks the submitted values. This, incidentally, is the main reason why search engines use the query string to submit search terms. If you bookmark a search results page on Google, you can use that bookmark to perform the same search again later, because the search terms are contained in the URL.

Sometimes, you want access to a variable without having to worry about whether it was sent as part of the query string or a form post. In cases like these, the special $_REQUEST array comes in handy. It contains all the variables that appear in both $_GET and $_POST. With this variable, we can modify our form processing script one more time so that it can receive the first and last names of the user from either source:

<?php  
$firstname = $_REQUEST['firstname'];  
$lastname = $_REQUEST['lastname'];  
echo 'Welcome to our web site, ' .  
   htmlspecialchars($firstname, ENT_QUOTES, 'UTF-8') . ' ' .  
   htmlspecialchars($lastname, ENT_QUOTES, 'UTF-8') . '!';  
?>

That covers the basics of using forms to produce rudimentary user interaction with PHP. We’ll look at more advanced issues and techniques in later examples.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article