University of Washington, CSE 190 M, Spring 2009
Lab 4: Forms and PHP (Thursday, April 23, 2009)

original lab idea by Kevin Wallace; revised by Brian Le and Marty Stepp

This lab's purpose is to give you some practice writing a PHP script that processes an HTML form. You will also practice server-side form validation using PHP. You very likely won't finish all of the exercises. Just finish as much as you can within the allotted time. You do not need to work on this lab any more after you leave your lab session, though you may if you like.

expected output

In this week's lab, we'll write code to complete a web service that allows students to submit their credit card numbers in exchange for good grades in the class. (Note: This is just a joke! We do not suggest that you actually try to bribe us for grades...) The HTML page buyagrade.html will contain a form that submits to sucker.php. After submission, sucker.php will do some checks to validate the information submitted, and it will output a web page that either confirms the submission or informs the user to try submitting again.

Lab 4 Resources

Exercises for Today:

  1. Create a Form
  2. Display Input Data
  3. Save Form Data
  4. Basic Validation
  5. Luhn Credit Card Validation

Exercise 1: Creating a Form (roughly 15 minutes)

This exercise involves creating an HTML form that POSTs its submitted data to a PHP program on a server. Download buyagrade.html to your disk (right-click the link and choose Save Link As...). You need to modify this HTML file by turning it into an HTML form. You will need to give name attributes to the form controls so they will be sent to the server as query parameters; the names are up to you. Also, some form controls (such as radio buttons) need value attributes. Fill the Section drop-down list with choices MA through MH.

When you're done with this exercise, your form should look roughly like the screenshot at the top of this handout.

Test your form to see that it is submitting the proper parameters by temporarily setting its action attribute to:

http://webster.cs.washington.edu/params.php

You can try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the source code yet, please!)

Exercise 2: Displaying Input Data (roughly 10 minutes)

In this exercise, you will write the PHP page that will handle the submitted form data. Tell you buyagrade.html to POST to sucker.php. The sucker.php page will receive the parameters from buyagrade.html and will output an HTML confirmation page. Here is a skeleton version of this page that does not actually display the data submitted by the user. Modify it to display the submitted data.

Your page should at least display the submitter's name, credit card number, and credit card type (Visa or MasterCard) in the confirmation page. For now, your page doesn't actually need to save this information in any way on the server.

expected output

To keep your code clean, as much as possible you should embed variables' values in HTML using PHP expression blocks such as <?= expression ?>.

You can try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the source code yet, please!)

Exercise 3: Save the Form Data (roughly 10 minutes)

Modify your sucker.php page to save the submitted data to the file suckers.txt. This file should have a format similar to the following:

Ryan;MA;1234123412341234;visa
Kevin W;MF;5963109385987345;mastercard
Kimberly Todd;MC;7328904328904902;mastercard
Marty Stepp;MC;4444100020003000;visa

Also change your page's output to show the complete contents of this file to the user. Place the file contents into an HTML <pre> element to preserve the whitespace.

expected output

Recall that you can read and write the contents of a file using the PHP file_get_contents and file_put_contents functions.

Exercise 4: Basic Data Validation (roughly 10 minutes)

Update your sucker.php file to verify that the user did not leave any fields blank when submitting the form. You can check whether a particular parameter has been passed using the PHP function isset.

However, isset($_REQUEST["name"]) will only check if the $_REQUEST associative array has "name" as one of its keys; it does not check to see if the value of $_REQUEST["name"] is a non-empty value. Remember that $_REQUEST["name"] = "" would give a falsey value and $_REQUEST["name"] = "abc" would give a truthy value.

If the user has not filled in every field, show an error message like the one below instead of displaying their submitted data:

expected output

Give them the chance to try again by linking back to your HTML page.

You can try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the source code yet, please!)

Exercise 5 (l33t h4x0rZ only): Verify Credit Card Numbers (roughly 15-30 minutes)

Update your sucker.php file to further check the validity of the credit card number.

If the user has not supplied a card number with the correct number of digits, show an error message like the one below:

expected output

If you finish the above checks and are really l33t, update your sucker.php file to check that the supplied card number passes the Luhn Algorithm (wiki). It is a checksum algorithm developed by Hans Peter Luhn often used to protect against accidental errors in typing credit card numbers: any valid credit card number will pass the algorithm, though not every invalid credit card number will fail it. If the submitted credit card number does not pass the Luhn Algorithm, you can display the same error as you did when the card number had the incorrect number of digits.

The Wikipedia page previously linked gives a PHP implementation of the algorithm, but it is poorly coded and hard to understand. If you are running out of time, you may use the code from that page in your php code; otherwise, the text below describes how to code this algorithm and you should use it to try to code it yourself (especially if you're a CSE major!).

From Building Java Programs:

You may not know that credit card numbers contain several pieces of information for performing validity tests. For example, a valid credit card number passes a digit-sum test known as the Luhn checksum algorithm. Luhn's algorithm states that if you sum the digits of the number in a certain way, the total sum must be a multiple of 10 for a valid Visa number. Systems that accept credit cards perform a Luhn test before contacting the credit card company for final verification. This lets the company block fake or mistyped credit card numbers.

The algorithm for summing the digits is the following. Consider each digit of the credit card to have a zero-based index: the first is at index 0, and the last is at index 15. Start from the rightmost digit and process each digit one at a time. For digits at odd-numbered indexes (the 15th digit, 13th digit, etc.), simply add that digit to the cumulative sum. For digits at even-numbered indexes (the 14th, 12th, etc), double the digit's value, then if that doubled value is less than 10, add it to the sum. If the doubled number is 10 or greater, add each of its digits separately into the sum.

The following pseudocode describes the Luhn algorithm to sum the digits:

sum = 0.
for (each digit of credit card number, starting from the last index) {
    if (digit's index is odd) {
        add digit to sum.
    } else {
        double the digit's value.
        if (doubled value < 10) {
            add doubled value to sum.
        } else {
            split doubled value into its two digits.
            add first digit to sum.
            add second digit to sum.
        }
    }
}

4111111111111111 and 4408041254369873 are example credit card numbers that pass the Luhn algorithm. The following figure shows the algorithm summing the latter number in detail. Notice how digits at even indexes are doubled and potentially split into two digits if they exceed 10 when doubled. For example, the number 7 at index 8 which is doubled to 14 which split to make 1+4.

CC #    4408 0412 5436 9873

        4   4   0   8   0   4   1   2    7    4   3   6    9    8    5    3
Scale  *2      *2      *2      *2       *2       *2       *2        *2
       --------------------------------------------------------------------
        8   4   0   8   0   4   2   2   14    4   6   6   18    8   10    3

Sum   = 8 + 4 + 0 + 8 + 0 + 4 + 2 + 2 + 1+4 + 4 + 6 + 6 + 1+8 + 8 + 1+0 + 3
      = 70

70 is divisible by 10, therefore this card number is valid.

You can try our runnable solution to this exercise (so you can see how your page is supposed to look and work. Don't look at the source code yet, please!)

Valid XHTML 1.1 Valid CSS!