This section is about HTML forms and processing form data in PHP.

  1. Buggy HTML form
  2. Animal Gallery
  3. Login
  4. Show Twos
  5. Caption
  6. Calculations
  7. Complaint Letter Generator (long)

1. Buggy HTML form:

The following HTML form has several mistakes that causes it not to submit its data correctly, as well as some poor design choices that make it unpleasant to the user. Look at the form, find the bug(s), and correct the problems.

  1. buggy form page
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title>CSE major application form</title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   </head>
   
   <body>
      <form action="wherever.php">
         <legend>Log in</legend>
         <fieldset>
            UW NetID: <input type="text" id="uwnetid" size="8" /> <br />
            Password: <input type="text" size="10" /> <br />
         </fieldset>
         
         Year: 
         <input type="checkbox" name="frosh"> Freshman</input>
         <label>
         <input type="checkbox" name="soph" /> Sophomore
         <input type="checkbox" name="junior" /> Junior
         <input type="checkbox" name="senior" /> Senior
         </label>
         <br />
         
         Student ID number:
         <!-- don't allow the user to type more than 7 characters -->
         <input type="text" name="studentid" size="7" /> <br /><br />
         
         Personal statement: Please type a roughly 500-word essay explaining why you should be admitted to the CSE major: <br />
         <input type="text" name="essay" size="500" />
      </form>
   </body>
</html>

Solution

Following are all the problems with this form:

  • legend should be immediately inside of fieldset
  • form doesn't submit anywhere in particular (helps to point it to params.php for debugging)
  • the first input has an id attribute instead of name
  • the second input should be of type password, and has no name attribute
  • 'year' checkboxes should be radio buttons, and should also have value attributes to differentiate them
  • there is an incorrect closing </input> tag after the first checkbox's text (the input element is self-closing)
  • the label tag wraps around three checkboxes; each checkbox (radio button) should have its own label
  • student id box should have maxlength set, not just size
  • the "2 br" rule is violated after the student id number; wrap the line in a block-level element and style it with a margin/padding for desired amount of separation
  • personal statement should be a textarea
  • inline content cannot be "bare" inside of a form tag; needs to be inside an intervening block-level element (e.g., div, p, list) to validate
  • the form should us the POST method (method="post") instead of GET (default), since it has sensitive information and long content that should not go in a URL's query string
  • there is no submit button!

2. Animal Gallery:

Given a directory of animal pictures (images.zip), write a PHP webpage animals.php which displays these pictures.

If no query parameter is set, then the page should simply display all of the images in the images directory. The user can set an animal query parameter to choose whether to display only puppy pictures or only kitty pictures. For example, if the user entered the following URL:

.../animals.php?animal=puppy

Then the page should only display puppy pictures. You may assume that the animal query parameter is either kitty or puppy.

Form (optional):

Write an HTML form animals.html which submits to animals.php and allows you to select which animal to display.

Problem by Alex Miller

Solution

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
     <title>Animal Gallery</title>
  </head>
  <body>
    <div>
      <?php
      $animal = "";
      if (isset($_REQUEST["animal"])) {
          $animal = $_REQUEST["animal"];
      }
      $files = glob("images/{$animal}*.jpeg");
      foreach ($files as $image) {
         ?>
         <img src="<?= $image ?>" alt="animal picture" />
         <?php
      }
      ?>
    </div>
  </body>
</html>

3. Login:

Write a form, login.html, which asks the user for a username and password. Then write a script, login.php, that will accept the user's login information and look in a file to see if the user's password matches.

Each password will be stored in a separate file, named for the username, inside a folder called passwords. For instance, the user foo's password will be located in passwords/foo.

If the password entered matches the password stored in the file for that user, login.php should display a message with a class of granted. Otherwise, it should display a message with a class of denied.

screenshot of login.html filled out screenshot of login.php with access granted

Start from the following skeletons:

login.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <h1>Login</h1>
      
      <form action="">
         <dl>
            <dt>Username:</dt>
            <dd></dd>
            
            <dt>Password:</dt>
            <dd></dd>
         </dl>
      </form>
   </body>
</html>

login.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <!-- (your PHP code here!) -->
   </body>
</html>

(Note that this is not a secure system yet, so don't try this on a real site! See extra modification #3 below for a way of making this more secure.)

Extra Modifications:

If you have time, try modifying your login system to do the following:

  1. Add a checkbox on login.html with the label, "I'm a new user." This should create a new file on the server to store that user's password, and grant access with a separate new-user greeting message (again with a class of granted) containing the new user's username.

    screenshot of login.html filled out, with new user checkbox screenshot of login.php with new user greeting

    (You may assume no one checks the "new user" box if they already have an account.)

  2. Modify your code to look for all the passwords in a single file, passwords.txt, with a line for each user's name and password, separated by a colon (:) character:

    stepp:purple_dinos4ur
    mdoocy:MoGRan!!
    poetalex:isPoetical()
    ...
    

    (You may assume no one enters a password containing a colon character.)

  3. Modify your code to store passwords in digest form ("encrypted" in common parlance, though technically different) using the PHP hash function. Cryptographic hashing algorithms (such as SHA-256) produce a large number that will always be the same for a particular input, but from which it is impossible to reconstitute the original text.

    $password = 'purple_dinos4ur';
    $digest_password = hash('sha256', $password);
    print $digest_password; // 026a527cc81584d8d7283f4cca423b9f964a19fb4a919118ebaff5f8e6b586fe

    Since the hashed form is impossible to reverse, storing the hash of a password in hashed form is more secure.

    stepp:026a527cc81584d8d7283f4cca423b9f964a19fb4a919118ebaff5f8e6b586fe
    mdoocy:f597498b0c3a892c8514afb72e9c6333122904eb976aa3204788ae4dac04e43b
    poetalex:21b8cb690edd4eef1404f6609541c664ee8cd79eb957888ca5931e1a752baaad
    ...
    

    Because identical inputs will always have the same output, the submitted password can be checked against the correct one by comparing the hashes of each. If the hashes of each password match, the passwords themselves must have also been identical.

problem by Morgan Doocy

Solutions

Solution 1

login.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <h1>Login</h1>
      
      <form action="login.php" method="POST">
         <dl>
            <dt>Username:</dt>
            <dd><input type="text" name="username" /></dd>
            
            <dt>Password:</dt>
            <dd><input type="password" name="password" /></dd>
         </dl>
         
         <p><input type="submit" value="Log in" /></p>
      </form>
   </body>
</html>
login.php
<?php
   $username = $_REQUEST['username'];
   $password = $_REQUEST['password'];
   
   $passwordfile = "passwords/$username";
   
   $granted = file_exists($passwordfile) && file_get_contents($passwordfile) == $password;
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <?php
         if ($granted) {
            ?>
            <h1 class="granted">Access granted</h1>
            <?php
         } else {
            ?>
            <h1 class="denied">Access denied!</h1>
            <?php
         }
      ?>
   </body>
</html>

Solution 2

login.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <h1>Login</h1>
      
      <form action="login.php" method="POST">
         <dl>
            <dt>Username:</dt>
            <dd><input type="text" name="username" /></dd>
            
            <dt>Password:</dt>
            <dd><input type="password" name="password" /></dd>
         </dl>
         
         <p><label><input type="checkbox" name="new" /> I am a new user.</label></p>
         
         <p><input type="submit" value="Log in" /></p>
      </form>
   </body>
</html>
login.php
<?php
   $username = $_REQUEST['username'];
   $password = $_REQUEST['password'];
   $new = isset($_REQUEST['new']);
   
   $passwordfile = "passwords/$username";
   
   if ($new) {
      file_put_contents($passwordfile, $password);
   } else {
      $granted = file_exists($passwordfile) && file_get_contents($passwordfile) == $password;
   }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <?php
         if ($new) {
            ?>
            <h1 class="granted">Welcome, <?= $username ?>!</h1>
            <?php
         } else if ($granted) {
            ?>
            <h1 class="granted">Access granted</h1>
            <?php
         } else {
            ?>
            <h1 class="denied">Access denied!</h1>
            <?php
         }
      ?>
   </body>
</html>

Solution 3

login.php
<?php
   $entered_user = $_REQUEST['username'];
   $entered_pass = $_REQUEST['password'];
   $new = isset($_REQUEST['new']);
   
   $passwordfile = 'passwords.txt';
   
   if ($new) {
      file_put_contents($passwordfile, "$entered_user:$entered_pass\n", FILE_APPEND);
   } else {
      $granted = false;
      $passwords = explode("\n", file_get_contents($passwordfile));
      foreach ($passwords as $line) {
         list($stored_user, $stored_pass) = explode(':', $line);
         if ($entered_user == $stored_user && $entered_pass == $stored_pass) {
            $granted = true;
            break;
         }
      }
   }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <?php
         if ($new) {
            ?>
            <h1 class="granted">Welcome, <?= $entered_user ?>!</h1>
            <?php
         } else if ($granted) {
            ?>
            <h1 class="granted">Access granted</h1>
            <?php
         } else {
            ?>
            <h1 class="denied">Access denied!</h1>
            <?php
         }
      ?>
   </body>
</html>

4. Show Twos:

Write a PHP function show_twos that outputs factors of 2 in a passed integer with accompanying HTML. For example:

<?php
                    // output:
show_twos(7);       // <strong>7 =</strong> 7<br/>
show_twos(18);      // <strong>18 =</strong> 2 * 9<br/>
show_twos(68);      // <strong>68 =</strong> 2 * 2 * 17<br/>
show_twos(120);     // <strong>120 =</strong> 2 * 2 * 2 * 15<br/>
?>

The idea is to express the number as a product of factors of 2 and an odd number. The number 120 has 3 factors of 2 multiplied by the odd number 15. For odd numbers (e.g. 7), there are no factors of 2, so you just show the number itself. Assume that your method is passed a number greater than 0.

Your function should surround the given number and the equals sign in a <strong> tag, and end its output with a <br/> tag.

Problem by Alex Miller.

Solution

<?php
function showTwos($n) { ?>
   <strong><?= $n ?> =</strong>
   <?php
   while ($n % 2 == 0) {
      print "2 *";
      $n = $n / 2;
   }
   ?>
   <?= $n ?><br />
   <?php
}

                    // output:
showTwos(7);        // <strong>7 =</strong> 7<br/>
showTwos(18);       // <strong>18 =</strong> 2 * 9<br/>
showTwos(68);       // <strong>68 =</strong> 2 * 2 * 17<br/>
showTwos(120);      // <strong>120 =</strong> 2 * 2 * 2 * 15<br/>
?>

5. Caption:

Write a form, caption.html, which asks the user to select a photo to display, and to enter two lines of caption. Then write a script, caption.php, that will accept the submitted information and display the photo and captions on-screen:

screenshot of caption.html filled out screenshot of caption.php

Start from the following skeletons:

caption.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="form">
      <h1>Captionator</h1>
      
      <dl>
         <dt>Image:</dt>
         <dd> ... </dd>
   
         <dt class="line1">Line 1:</dt>
         <dd class="line1"> ... </dd>
   
         <dt class="line2">Line 2:</dt>
         <dd class="line2"> ... </dd>
      </dl>
      
   </body>
</html>

caption.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="viewer">
      <p><img id="image" src="" alt="" /></p>
      <h1 id="line1"><span></span></h1>
      <p id="line2"></p>
   </body>
</html>

Provide several photo URLs to select from in the form of a dropdown menu. Give the options in the dropdown user-friendly labels, but make the user's final selection result in an absolute URL being submitted to the server script. For the img's alt text, use a combination of both caption lines.

Extra modification:

Modify your form to upload an image file instead of selecting a URL to display from a dropdown. Your server script should place the uploaded file in a directory called images, and give the file whatever name it had before the user uploaded it.

screenshot of caption.html with file upload form element

(Note: On your computer, the file upload input element may look different than the one shown.)

problem by Morgan Doocy

Solutions

Solution 1

caption.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="form">
      <h1>Captionator</h1>
      
      <form action="caption.php" enctype="multipart/form-data" method="POST">
         <dl>
            <dt>Image:</dt>
            <dd>
               <select name="image">
                  <option value="https://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-snc3/16143_839416365818_10732919_47146344_2237396_n.jpg">Cupcake</option>
                  <option value="http://thechive.files.wordpress.com/2010/09/leo-struts-photoshop-funny-11.jpg">Leo Strutting</option>
               </select>
            </dd>
         
            <dt class="line1">Line 1:</dt>
            <dd class="line1"><input type="text" name="line1" /></dd>
         
            <dt class="line2">Line 2:</dt>
            <dd class="line2"><textarea name="line2" rows="2" cols="30"></textarea></dd>
         </dl>
         
         <p><input type="submit" value="Captionate!" /></p>
      </form>
   </body>
</html>
caption.php
<?php
   $image = $_REQUEST['image'];
   $line1 = $_REQUEST['line1'];
   $line2 = $_REQUEST['line2'];
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="viewer">
      <p><img id="image" src="<?= $image ?>" alt="<?= "$line1. $line2" ?>" /></p>
      <h1 id="line1"><span><?= $line1 ?></span></h1>
      <p id="line2"><?= $line2 ?></p>
   </body>
</html>

Solution 2

caption.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="form">
      <h1>Captionator</h1>
      
      <form action="caption.php" enctype="multipart/form-data" method="POST">
         <dl>
            <dt>Image:</dt>
            <dd><input type="file" name="image" /></dd>
         
            <dt class="line1">Line 1:</dt>
            <dd class="line1"><input type="text" name="line1" /></dd>
         
            <dt class="line2">Line 2:</dt>
            <dd class="line2"><textarea name="line2" rows="2" cols="30"></textarea></dd>
         </dl>
         
         <p><input type="submit" value="Captionate!" /></p>
      </form>
   </body>
</html>
caption.php
<?php
   $tmpname = $_FILES['image']['tmp_name'];
   $movedname = 'images/' . $_FILES['image']['name'];
   move_uploaded_file($tmpname, $movedname);
   
   $line1 = $_REQUEST['line1'];
   $line2 = $_REQUEST['line2'];
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="viewer">
      <p><img id="image" src="<?= $movedname ?>" alt="<?= "$line1. $line2" ?>" /></p>
      <h1 id="line1"><span><?= $line1 ?></span></h1>
      <p id="line2"><?= $line2 ?></p>
   </body>
</html>

6. Calculations:

Given an input file input.txt:

add:1 2 3 4
add:4 -1 6 3
multiply:2 4
subtract:8 4 2
divide:8 2 2

Write a PHP page calculations.php that reads in the file and calculates the result for each line in the file. For example, the result for the line

divide:8 2 2

Would be:

8 / 2 / 2 = 2

Your output should consist of a series of list items. Each list item should have the original line from the input file, followed by an equals sign, followed by the result. For example:

divide:8 2 2 = 2

Problem by Alex Miller.

Solution

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
     <title>Calculations</title>
  </head>
  <body>
    <ul>
      <?php
      $lines = file("input.txt");
      foreach ($lines as $line) {
         $split = split(":", $line);
         $numbers = split(" ", $split[1]);
         $sum = $numbers[0];
         for ($i = 1; $i < sizeof($numbers); $i++) {
             if ($split[0] == "add") {
                 $sum += $numbers[$i];
             } else if ($split[0] == "multiply") {
                 $sum *= $numbers[$i];
             } else if ($split[0] == "subtract") {
                 $sum -= $numbers[$i];
             } else if ($split[0] == "divide") {
                 $sum /= $numbers[$i];
             }
         }
	     ?>
         <li>
	        <?= $line ?> = <?= $sum ?>
        </li>
         <?php
      }
      ?>
    </ul>
  </body>
</html>

7. Complaint Letter Generator: (long)

Write an HTML form that allows the user to generate complaint letters. The user will specify the first/last name of the person to complain about, the person's gender, and how many sentences of complaints to generate. The following should be the appearance of your form:

expected form output

Start from the following skeleton:

complaint.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
      <title>Stefanie's Complaint Generator!</title>
      <link href="http://www.cs.washington.edu/education/courses/cse190m/09sp/labs/section4-complaint/complaint.css" type="text/css" rel="stylesheet" />
   </head>
   
   <body>
      <h1>Stefanie's Complaint Generator!</h1>
      <h2>Complain about a person</h2>
      
      <ul>
         <li>
            What's the full name of the person you want to complain about? <br />
            ???
         </li>

         <li>Is that person 
            female
            or 
            male?
         </li>

         <li>
            How many sentences do you want to generate?
            ???
         </li>
      </ul>

      Complain!
      
      <p>
         Inspired by <a href="http://www.pakin.org/complaint/">Scott Pakin's Complaint Letter Generator</a>.
      </p>
   </body>
</html>

Test your form by having it initially submit its data to the following URL:

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

Once your form submits properly, write a PHP page letter.php on the server to process this form data. Start from the following skeleton:

letter.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
      <title>Official Complaint Letter!</title>
      <link href="http://www.cs.washington.edu/education/courses/cse190m/09sp/labs/section4-complaint/complaint.css" type="text/css" rel="stylesheet" />
   </head>
   
   <body>
      <h1>My complaint about ???</h1>
      
      <p>
         ???
      </p>
   </body>
</html>

On the server there is a file sentence.txt containing a bunch of complaint sentences. Your PHP code should read this file, randomly pick sentences from it, and turn these into a complaint letter. The file has one sentence per line, such as:

_FNAME_ only wants to dominate or intimidate others.
It's knowledge that _HESHE_ recently claimed that truth is merely a social construct.
No matter what terms are used, _NAME_ is unconstrained by conscience.

You will need to personalize the letter by inserting the person's name and other information into it. The following are the patterns you will need to replace:

You can use the str_replace function to help you replace the above patterns in the text. If you write the code correctly, you can replace each placeholder with a single call. When you're finished with your page, it should look like the following:

expected form output

Your finished code might look like the following sample solution, written by TA Stefanie Hatcher:

Basic Validation:

If you finish all of the above work and have time left, try to add some basic server-side data validation to your form. If the user submits an empty first or last name, you should print an error message rather than creating a complaint letter.

problem by Stefanie Hatcher with contributions from Brian Le; inspired by Scott Pakin's Complaint Generator

Solutions

1. Buggy HTML form:

Following are all the problems with this form:

2. Animal Gallery:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
     <title>Animal Gallery</title>
  </head>
  <body>
    <div>
      <?php
      $animal = "";
      if (isset($_REQUEST["animal"])) {
          $animal = $_REQUEST["animal"];
      }
      $files = glob("images/{$animal}*.jpeg");
      foreach ($files as $image) {
         ?>
         <img src="<?= $image ?>" alt="animal picture" />
         <?php
      }
      ?>
    </div>
  </body>
</html>

3. Login:

Solution 1

login.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <h1>Login</h1>
      
      <form action="login.php" method="POST">
         <dl>
            <dt>Username:</dt>
            <dd><input type="text" name="username" /></dd>
            
            <dt>Password:</dt>
            <dd><input type="password" name="password" /></dd>
         </dl>
         
         <p><input type="submit" value="Log in" /></p>
      </form>
   </body>
</html>

login.php

<?php
   $username = $_REQUEST['username'];
   $password = $_REQUEST['password'];
   
   $passwordfile = "passwords/$username";
   
   $granted = file_exists($passwordfile) && file_get_contents($passwordfile) == $password;
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <?php
         if ($granted) {
            ?>
            <h1 class="granted">Access granted</h1>
            <?php
         } else {
            ?>
            <h1 class="denied">Access denied!</h1>
            <?php
         }
      ?>
   </body>
</html>

Solution 2

login.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <h1>Login</h1>
      
      <form action="login.php" method="POST">
         <dl>
            <dt>Username:</dt>
            <dd><input type="text" name="username" /></dd>
            
            <dt>Password:</dt>
            <dd><input type="password" name="password" /></dd>
         </dl>
         
         <p><label><input type="checkbox" name="new" /> I am a new user.</label></p>
         
         <p><input type="submit" value="Log in" /></p>
      </form>
   </body>
</html>

login.php

<?php
   $username = $_REQUEST['username'];
   $password = $_REQUEST['password'];
   $new = isset($_REQUEST['new']);
   
   $passwordfile = "passwords/$username";
   
   if ($new) {
      file_put_contents($passwordfile, $password);
   } else {
      $granted = file_exists($passwordfile) && file_get_contents($passwordfile) == $password;
   }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <?php
         if ($new) {
            ?>
            <h1 class="granted">Welcome, <?= $username ?>!</h1>
            <?php
         } else if ($granted) {
            ?>
            <h1 class="granted">Access granted</h1>
            <?php
         } else {
            ?>
            <h1 class="denied">Access denied!</h1>
            <?php
         }
      ?>
   </body>
</html>

Solution 3

login.php

<?php
   $entered_user = $_REQUEST['username'];
   $entered_pass = $_REQUEST['password'];
   $new = isset($_REQUEST['new']);
   
   $passwordfile = 'passwords.txt';
   
   if ($new) {
      file_put_contents($passwordfile, "$entered_user:$entered_pass\n", FILE_APPEND);
   } else {
      $granted = false;
      $passwords = explode("\n", file_get_contents($passwordfile));
      foreach ($passwords as $line) {
         list($stored_user, $stored_pass) = explode(':', $line);
         if ($entered_user == $stored_user && $entered_pass == $stored_pass) {
            $granted = true;
            break;
         }
      }
   }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Login</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/login/login.css" />
   </head>

   <body>
      <?php
         if ($new) {
            ?>
            <h1 class="granted">Welcome, <?= $entered_user ?>!</h1>
            <?php
         } else if ($granted) {
            ?>
            <h1 class="granted">Access granted</h1>
            <?php
         } else {
            ?>
            <h1 class="denied">Access denied!</h1>
            <?php
         }
      ?>
   </body>
</html>

4. Show Twos:

<?php
function showTwos($n) { ?>
   <strong><?= $n ?> =</strong>
   <?php
   while ($n % 2 == 0) {
      print "2 *";
      $n = $n / 2;
   }
   ?>
   <?= $n ?><br />
   <?php
}

                    // output:
showTwos(7);        // <strong>7 =</strong> 7<br/>
showTwos(18);       // <strong>18 =</strong> 2 * 9<br/>
showTwos(68);       // <strong>68 =</strong> 2 * 2 * 17<br/>
showTwos(120);      // <strong>120 =</strong> 2 * 2 * 2 * 15<br/>
?>

5. Caption:

Solution 1

caption.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="form">
      <h1>Captionator</h1>
      
      <form action="caption.php" enctype="multipart/form-data" method="POST">
         <dl>
            <dt>Image:</dt>
            <dd>
               <select name="image">
                  <option value="https://fbcdn-sphotos-a.akamaihd.net/hphotos-ak-snc3/16143_839416365818_10732919_47146344_2237396_n.jpg">Cupcake</option>
                  <option value="http://thechive.files.wordpress.com/2010/09/leo-struts-photoshop-funny-11.jpg">Leo Strutting</option>
               </select>
            </dd>
         
            <dt class="line1">Line 1:</dt>
            <dd class="line1"><input type="text" name="line1" /></dd>
         
            <dt class="line2">Line 2:</dt>
            <dd class="line2"><textarea name="line2" rows="2" cols="30"></textarea></dd>
         </dl>
         
         <p><input type="submit" value="Captionate!" /></p>
      </form>
   </body>
</html>

caption.php

<?php
   $image = $_REQUEST['image'];
   $line1 = $_REQUEST['line1'];
   $line2 = $_REQUEST['line2'];
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="viewer">
      <p><img id="image" src="<?= $image ?>" alt="<?= "$line1. $line2" ?>" /></p>
      <h1 id="line1"><span><?= $line1 ?></span></h1>
      <p id="line2"><?= $line2 ?></p>
   </body>
</html>

Solution 2

caption.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="form">
      <h1>Captionator</h1>
      
      <form action="caption.php" enctype="multipart/form-data" method="POST">
         <dl>
            <dt>Image:</dt>
            <dd><input type="file" name="image" /></dd>
         
            <dt class="line1">Line 1:</dt>
            <dd class="line1"><input type="text" name="line1" /></dd>
         
            <dt class="line2">Line 2:</dt>
            <dd class="line2"><textarea name="line2" rows="2" cols="30"></textarea></dd>
         </dl>
         
         <p><input type="submit" value="Captionate!" /></p>
      </form>
   </body>
</html>

caption.php

<?php
   $tmpname = $_FILES['image']['tmp_name'];
   $movedname = 'images/' . $_FILES['image']['name'];
   move_uploaded_file($tmpname, $movedname);
   
   $line1 = $_REQUEST['line1'];
   $line2 = $_REQUEST['line2'];
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
   <head>
      <title>Captionator</title>
      <link rel="stylesheet" type="text/css" href="http://webster.cs.washington.edu/cse190m/sections/4/caption/caption.css" />
   </head>

   <body id="viewer">
      <p><img id="image" src="<?= $movedname ?>" alt="<?= "$line1. $line2" ?>" /></p>
      <h1 id="line1"><span><?= $line1 ?></span></h1>
      <p id="line2"><?= $line2 ?></p>
   </body>
</html>

6. Calculations:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
     <title>Calculations</title>
  </head>
  <body>
    <ul>
      <?php
      $lines = file("input.txt");
      foreach ($lines as $line) {
         $split = split(":", $line);
         $numbers = split(" ", $split[1]);
         $sum = $numbers[0];
         for ($i = 1; $i < sizeof($numbers); $i++) {
             if ($split[0] == "add") {
                 $sum += $numbers[$i];
             } else if ($split[0] == "multiply") {
                 $sum *= $numbers[$i];
             } else if ($split[0] == "subtract") {
                 $sum -= $numbers[$i];
             } else if ($split[0] == "divide") {
                 $sum /= $numbers[$i];
             }
         }
	     ?>
         <li>
	        <?= $line ?> = <?= $sum ?>
        </li>
         <?php
      }
      ?>
    </ul>
  </body>
</html>
Valid XHTML 1.1 Valid CSS!