Phone: 415-963-0926 | 415-963-0927
Log in Currency: £ $
Basket: 0 domains, no hosting yet
 

PHP programming tutorial

6. User Input

None of what we've learned so far is really particularly useful until you start reading user input in some way or other. The previous chapters have laid the foundation you need to understand what's going on here. Now we're ready to start doing something that's actually useful with PHP and this chapter will contain the first example programs that actually have a useful purpose.

PHP normally has user input passed to it through one of two methods; either GET or POST. With GET requests, the data is passed along as part of the URL. With POST requests, the browser sends the data as part of the headers when requesting the page. Either way PHP decodes the data for you and places it into a couple of easy-to-use superglobal arrays. Superglobal basically just means that the variables are available from anywhere within your program - they are always available in all scopes.

Reading GET data

GET data is made available via the $_GET array. If you were to use the URL http://yoursite.com/yourscript.php?foo=bar, an element would be created in the $_GET array with a key of 'foo' and a value of 'bar'. Let's start with a very simple example to illustrate how it works:

<?php
    $output 
print_r($_GETtrue);
    echo 
nl2br($output);
?>

This program uses the print_r() function to list the contents of the $_GET array - the second argument tells print_r() to return the output rather than send it straight to the browser. The reason we need to do this is because we want to add HTML line breaks for each new line in the output so that it's more easily viewable in a browser - this is done with the built-in function nl2br(). You can see this script running by clicking here. Look at the URL and change it and observe the effect it has on the output from the program. Let's see how one of the elements in the array can be used in practice:

<?php
    
echo "Hello "$_GET['name'] . "!<br />\n";
?>

In this example, we use the element in the $_GET array with the key 'name' to greet the person whose name is entered on the URL. Try out this example here. Try changing the name on the URL and see what happens - what happens if you remove the name parameter entirely?

You can obviously also use the superglobal arrays in function calls, conditionals and loops just like ordinary arrays. Here's an example of a conditional based on user input:

<?php
    
if ($_GET['name'] != 'alice' && $_GET['name'] != 'bob') {
        echo 
"Invalid name entered!<br />\n";
        exit;
    }
    print 
"Hello Alice and Bob!<br />\n";
?>

This program will complain about an invalid name until either alice or bob is entered. Test it out by clicking here. What happens if you change 'alice' in the URL to 'Alice'? Because PHP's string comparisons are case sensitive, 'Alice' and 'alice' are different strings and therefore if Alice doesn't capitalise her name, we don't recognise her. We can fix this by using the strcasecmp() function to make a case-insensitive string comparison:

<?php
    
if (strcasecmp($_GET['name'], 'alice') != && 
        
strcasecmp($_GET['name'], 'bob') != 0) {
    
        echo 
"Invalid name entered!<br />\n";
        exit;
    }
    print 
"Hello Alice and Bob!<br />\n";
?>

Now you can see that it's case insensitive - alice can capitalise her however she likes. When you're working with user-supplied data; PHP's built-in string functions are invaluable - you are strongly encouraged to familiarise yourself with them.

It can be useful to be able to do different things based on the URL of a program alone, but it's more often useful to give the user some kind of form to interract with. Here's a simple example of using a form to send user input into PHP:

<?php
    
if (strcasecmp($_GET['firstname'], 'alice') == 0) {
        echo 
"Hello Alice!<br />\n";
    }    
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="get">
Enter your name: <input type="text" name="firstname">
<input type="submit" value="Submit"></form>

To test this script out click here. You can see that we've got a very basic HTML form with only one field and a submit button. If the name entered matches 'alice' then the program greets her. You can see the value of the field being passed to the script via the URL, but the web browser is doing this for you rather than you having to manually change the URL.

We've also introduced another superglobal array - $_SERVER; this variable contains various server environment information - one piece of information stored in the $_SERVER superglobal is the location of the PHP script itself. We use this 'PHP_SELF' key to fill the form's action attribute as this allows us to call the PHP script anything and have it work. We could equally well put the form in a completely separate HTML page and set the action attribute to point at the URL of the PHP script.

It's worth reading about the different form fields that you can submit to PHP from HTML. Here's w3schools page on HTML forms.

How about POST data?

We can modify the previous program to use HTTP POST by making a couple of simple changes. Firstly we use $_POST rather than $_GET, secondly we modify the form's method attribute to say 'post' rather than 'get'. Here's the example:

<?php
    
if (strcasecmp($_POST['firstname'], 'alice') == 0) {
        echo 
"Hello Alice!<br />\n";
    }    
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Enter your name: <input type="text" name="firstname">
<input type="submit" value="Submit"></form>

You can test this script here. It behaves exactly the same as the previous example using GET, except that the data is never sent on the URL - it you keep an eye on the URL in the address bar, it never changes. This is because the data is now being sent as part of the HTTP request rather than on the URL itself. The advantage of this approach is that you can send more data as you're not limited by the maximum length of a URL (only a few thousand characters). Let's use POST for a more complex form:

<?php
    
foreach ($_POST as $key => $value) {
        echo 
ucfirst($key) . ": " $value "<br />\n";
    }
?><br />
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<table>
<tr><td>Enter your name:</td><td><input type="text" name="name"></td></tr>
<tr><td>Enter your e-mail address:</td><td><input type="text" name="email"></td></tr>
<tr><td>Subject:</td><td><input type="text" name="subject"></td></tr>
<tr><td>Message:</td><td><textarea name="message"></textarea></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit"></td></tr>
</table>
</form>

You can test this script out here. By adding a few form fields you can see that we've got all the elements we need to make a very basic form mailer. This example loops over each of the elements in the POST array and outputs them one by one with the key and value separated by a colon. The key is being passed through ucfirst() function which capitalises the first letter.

It's easy to give those values as arguments to PHP's built-in mail() function and that gives us the basis of our form mailer. Let's see that as an example:

<?php
    
if (isset($_POST['name'])) {
        
$destination 'mailtest@digital-crocus.com';

        
$message 'Form submitted at ' $_SERVER['PHP_SELF'] . "\r\n";
        foreach (
$_POST as $key => $value) { 
            
$message .= ucfirst($key) . ': ' $value "\r\n";
        }

        
$headers 'From: ' $_POST['email'] . "\r\n" 
                   
'Reply-To: ' $_POST['email'] . "\r\n";
    
        
mail($destination$_POST['subject'], $message$headers);
        echo 
'Email Sent';
        exit;
    }
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<table>
<tr><td>Enter your name:</td><td><input type="text" name="name"></td></tr>
<tr><td>Enter your e-mail address:</td><td><input type="text" name="email"></td></tr>
<tr><td>Subject:</td><td><input type="text" name="subject"></td></tr>
<tr><td>Message:</td><td><textarea name="message"></textarea></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit"></td></tr>
</table>
</form>

This will produce a very crude form mailer. I'm not going to give an example here because I don't want my inbox to be flooded by people testing it, but I'll leave it to you to test this script out yourself - just change the destination e-mail address to point to your own.

This script detects whether the form has been submitted by using the isset() function on one of the fields in the $_POST array. It then prepares all of the arguments for the mail() function, starting with the destination e-mail address. The message body is then built-up, starting with the first line which lets you know the location of the script. We then loop over the $_POST array adding each element to the message much as we did in the previous example only this time we're adding to a string rather than outputting directly to the browser.

This introduces a new operator - the concatenating assignment operator. This operator allows you to add a new string to the end of an existing string without having to repeat the name of the variable. In other words, the following two examples are exactly equivalent:

<?php
    
foreach ($_POST as $key => $value) {
        
$message $message ucfirst($key) . ': ' $value "\r\n";    
    }
?>

<?php
    
foreach ($_POST as $key => $value) {
        
$message .= ucfirst($key) . ': ' $value "\r\n";    
    }
?>

Notice how we're using "\r\n" as a newline rather than the more usual "<br />\n". This is because the strings we are constructing are not being sent to be rendered by the browser, they're going to be put into an e-mail, and e-mails have different standards on what constitues a new line.

There are a couple of problems with our basic form mailer - it doesn't do any validation on the user input, and it doesn't do any error checking on the mail() function. These two principals are absolutely key to writing robust and reliable code with PHP.

Validation is the process of checking user input data to ensure that the user has entered something which is sensible for the question being asked of them and won't break our program. Validation rules will vary depending on the type of input data being accepted, but some examples that apply to our form mailer are; check to see if the e-mail address contains an @ sign, check that at least 2 characters of text have been entered in the subject, check that at least three characters have been entered in each of the other fields.

To check whether the mail() function has been successful or not, we simply need to look at its return value. It returns TRUE if the mail was successfully sent and FALSE otherwise. Let's combine both validation and error checking into the final example:

<?php
    
function validate() { 
        
$ret TRUE;
        if (
strlen($_POST['name']) < 3) {
            echo 
"Please enter your name.<br />\n";    
            
$ret FALSE;
        }
        if (
strlen($_POST['message']) < 3) {
            echo 
"Please enter your message.<br />\n";    
            
$ret FALSE;
        }
        if (
strlen($_POST['subject']) < 2) { 
            echo 
"Please enter a subject.<br />\n";
            
$ret FALSE;
        }
        if (!
preg_match(
        
'/^([a-z0-9])(([-a-z0-9._])*([a-z0-9]))*\@([a-z0-9])' .
        
'(([a-z0-9-])*([a-z0-9]))+' 
        
'(\.([a-z0-9])([-a-z0-9_-])?([a-z0-9])+)+$/i'$_POST['email'])) {
            echo 
"Please enter a valid e-mail address.<br />\n";
            
$ret FALSE;
        }
        return 
$ret;
    }
    if (isset(
$_POST['name']) && validate()) {
        
$destination 'mailtest@digital-crocus.com';

        
$message 'Form submitted at ' $_SERVER['PHP_SELF'] . "\r\n";
        foreach (
$_POST as $key => $value) { 
            
$message .= ucfirst($key) . ': ' $value "\r\n";
        }

        
$headers 'From: ' $_POST['email'] . "\r\n" 
                   
'Reply-To: ' $_POST['email'] . "\r\n";
    
        if (
mail($destination$_POST['subject'], $message$headers)) { 
            echo 
'Email Sent';
        } else {
            echo 
'Failed to send email!';
        }
        exit;
    }
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<table>
<tr><td>Enter your name:</td><td><input type="text" name="name" value="<?php 
    
echo htmlentities($_POST['name']); ?>"></td></tr>
<tr><td>Enter your e-mail address:</td><td><input type="text" name="email" value="<?php
    
echo htmlentities($_POST['email']); ?>"></td></tr>
<tr><td>Subject:</td><td><input type="text" name="subject" value="<?php 
    
echo htmlentities($_POST['subject']); ?>"></td></tr>
<tr><td>Message:</td><td><textarea name="message"><?php 
    
echo htmlentities($_POST['message']); ?></textarea></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit"></td></tr>
</table>
</form>

Here we've added a function called validate() that takes no arguments and returns either TRUE if everything checks out, or FALSE if one of the validation checks fails. We then check this function before running any of the code that sends the e-mail. We're also checking the return value of the mail function and only reporting that the e-mail was sent if the call to mail() was successful. You can play with the validation in this script by clicking here - try submitting the form without filling out any of the fields. Notice how we've also added values to each of the fields in the HTML form so that if you fail the validation, anything you've entered is not lost.

We're using the htmlentities() function to ensure the string is in the proper format to be used in the HTML form. Read the documentation for this function to learn more about what it does.

The validate() function only does a few simple checks - it is up to you to build appropriate validation checks for your code. The checks in this example use the built-in strlen() function to ensure that each string is a minimum length. We also use preg_match() to do a regular expression match on the e-mail address - Regular expressions are a huge topic too big to cover in this tutorial, but you can often drop in a snippet of regex that you've found online without having to get into writing regex yourself. That's what we've done here - we've copied in the regular expression '/^([a-z0-9])(([-a-z0-9._])*([a-z0-9]))*\@([a-z0-9])(([a-z0-9-])*([a-z0-9]))+(\.([a-z0-9])([-a-z0-9_-])?([a-z0-9])+)+$/i' which we know to be a fairly good validation of an e-mail address.

That validation is by no means complete - there are many more checks you could do. The e-mail address match regular expression itself is flawed and will allow some invalid addresses to slip through the net (as well as blocking a small number of valid addresses). For a much more comprehensive e-mail address validation function click here.

One important security consideration to be aware of when using the mail() function is that if you're allowing the user to specify the destination address - you need to do some extra verification to ensure they're not spammers. In some cases this is captchas such as reCaptcha. Other times you can hold the e-mail for manual approval. The important thing to be aware of is that if you allow the destination e-mail address to be set from user data in any way, you need to be aware of the risks of your script being used to send spam. We avoid this risk in our form mailer by hardcoding the destination address into the script itself - this way the script will only ever send e-mail to one address. It can still be used to send spam to that single destination address, but at least it can't be used to spam the rest of the internet.

The $_REQUEST superglobal

If you want to use a variable but you don't care whether it's sent via GET or POST - or you want to allow your script to support working with both types of request, there's a solution: use the $_REQUEST superglobal. This array contains everything in $_GET combined with everything in $_POST.

The $_REQUEST superglobal also contains any cookies that are passed to the script - we'll cover cookies in more detail in a later chapter.

Here's a simple example using $_REQUEST:

<?php
    
if (isset($_REQUEST['name'])) {
        echo 
"Hello " $_REQUEST['name'] . "<br />\n";
    }
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
Enter name: <input type="text" name="name">
<input type="submit" value="Submit">
</form>

You can test this out by clicking here. The program will accept a name either on the URL in a GET request, or when you submit the form in a POST request.

Previous chapter... (5. Functions)
Next chapter... (7. Scope)
 

Back to top


About Digital Crocus:

Digital Crocus offer affordable UK web hosting to get you up and running from just $32.49 per year or $3.99 per month. Our most basic account would be enough to get started learning PHP and host a few websites with a moderate amount of traffic. We offer easy upgrade options as your requirement grows and a friendly and helpful email and phone customer support service. If you're looking to buy web hosting, consider giving us a try - under our money back guarantee we'll refund you if you're not 100% satisfied.

About the author:

Kieran Simkin is an experienced software developer and co-founder of Digital Crocus. Kieran is also a keen amateur photographer and musician and has a personal portfolio which you can see online.

Questions Resellers Hosting Domains Home