Web Development
Using PHP

Paul Vincent Craven
Computer Science Department, Simpson College
Indianola, Iowa
http://cs.simpson.edu
Document Date: April 19, 2014

Forward

These notes cover the material in Simpson College's CmSc 305 class. The style for these notes has been adapted from the book Dive Into HTML5 by Mark Pilgrim. This book is good introduction to some of HTML5's finer points.

Chapter 1: HTML

1.1 Introduction to HTML

1.2 HTML Worksheet

Most of the answers for this worksheet may be found at the w3schools.com website: http://w3schools.com/html/

HTML Basic

  1. What does HTML stand for?
  2. What is an HTML tag?
  3. Using html, body, h1, and p tags, construct an example HTML document.
  4. What extensions are commonly used for html files?
  5. Give an example of a heading tag:
  6. How many levels of heading tags are there?
  7. How is a paragraph formed in html?
  8. Give the html to link to the computer science web site at http://cs.simpson.edu
  9. Extra: Are links case sensitive? (Hint: The answer is not yes/no.)
  10. Give html code to show the logo.jpg image:
  11. Extra: Explain when to use a JPG image or a PNG image.
  12. Extra: What is the difference between GIF and PNG?
  13. Extra: If a developer has a 5000x4000 pixel image, and wants to make it smaller, it is possible to set the height and width of the image with HTML to something smaller. Give at least two reasons why this is the wrong approach.
  14. Explain what an HTML attribute is.
  15. Should tags and tag attribute names be upper or lower case?
  16. What is the HTML for creating a horizontal line?
  17. How are comments entered in HTML?
  18. How does a person see the HTML source of a page?
  19. Can a user see comments in the HTML source?
  20. How is a line break done in HTML?
  21. What HTML makes bold and italicized text? (Note, two different tags can make bold, and two different tags can make italicized. One of each is no longer recommended because the current standard is to remove style information from HTML documents.)
  22. ive an example of using a subscript:
  23. Give an example of using preformatted text:
  24. What are some examples of deprecated tags? Using <center> as an example, how should text be centered now?
  25. Give an example of HTML code to make red, 20 pixel text.
  26. Create a link to www.simpson.edu that will open in a new browser window.
  27. Create an HTML anchor.
  28. Create a link to an HTML anchor.
  29. What is the alt text in an image used for?
  30. How does a developer specify alt text for an image?
  31. If there are 10 images on a page, how many files are required to be fetched to display a page?
  32. Give an example of a 2 row, 2 column table with an extra row for headers.
  33. What is the difference between an ordered and an unordered list?
  34. Give an example of an unordered list with two items:
  35. What is an HTML form?
  36. Explain how understand where to place the beginning form tag, and the ending form tag.
  37. Write out code for a form that has the user enter a first name.
  38. How does the code for a password field differ from a regular field?
  39. Write the code for radio buttons that select between "graduate" or "undergraduate."
  40. How is a "submit" button placed on a form?
  41. What are other types of input fields available?
  42. What are html frames/framesets?
  43. How are colors defined in HTML?
  44. List at least 4 of the predefined color names available in HTML.

    HTML Advanced

  45. What is the main feature behind HTML 4.0?
  46. How can a person validate HTML with W3C's validator?
  47. What are some advantages to using the stand along HTMLValidator?
  48. How does an HTML document link to an external style sheet?
  49. How does an HTML document list styles internally?
  50. How does an HTML document list styles in-line?
  51. Give an example of specifying the title of a document (One that appears when bookmarking, and in the title bar of the web browser.)
  52. How is a < sign displayed in an HTML document?
  53. How is an ampersand displayed in an HTML document?
  54. What is the code for a non-breaking white space?
  55. Be able to explain each part of:
    scheme://host.domain:port/path/filename
  56. How is the text Hello "Paul" encoded in a URL?

Chapter 2: Directories

Only the smallest websites will put all of the files required into one folder. With files in different folders, it is important to be able to link between the folders effectively.

The simplest links are between HTML files in the same directory. Here is an example of linking between two files in the same directory:

<html>
<body>
<a href="page2.html">Page 2</a> <br />
</body>
</html>
<html>
<body>
<a href="page1.html">Page 1</a> <br />
</body>
</html>

Try it out: [link]

This next example adds a new page, named page3.html in a new subdirectory, named subdir. Note that the links in page1.html go down into the subdir, and page3.html has a link that goes up one directory. This is done by using ../ in front of the file name. The two dots tell the comptuer to go "up" one directory.

<html>
<body>
<a href="page2.html">Page 2</a> <br />
<a href="subdir/page3.html">Page 3</a> subdir/page3.html<br />
</body>
</html>
<html>
<body>
<a href="../page1.html">Page 1</a> <br />
<a href="../page2.html">Page 2</a> <br />
</body>
</html>

Try it out: [link]

The next example shows how to extend the same concept to link into nested directories:

<html>
<body>
<a href="page2.html">Page 2</a> <br />
<a href="subdir/page3.html">Page 3</a> subdir/page3.html<br />
<a href="subdir/supersub/page4.html">Page 4</a> subdir/supersub/page4.html<br />
</body>
</html>
<html>
<body>
<a href="../page1.html">Page 1</a> <br />
<a href="../page2.html">Page 2</a> <br />
<a href="supersub/page4.html">Page 4</a> <br />
</body>
</html>
<html>
<body>
<a href="../../page1.html">Page 1</a> <br />
<a href="../../page2.html">Page 2</a> <br />
<a href="../page3.html">Page 3</a> <br />
</body>
</html>

Try it out: [link]

URLs may be absolute or relative. The URLs shown so far have all been relative URLs. Relative URLs give directions from where the user is at, to where the user would like to go. If possible, it is best to use relative URLs. The main advantage of relative URLs it is possible to move the files into a different directory, or even a different website and still have the links work. Absolute URLs will not take into account where the user is at currently, and always link to the same place. This is the right thing to do when linking to other websites, or other major sections of a website. It is a bad idea when creating links between pages of a website, because any moving of directories will cause every link in the website to need updating.

The next example shows two kinds of absolute URLs. The first gives an absolute path. Any path that begins with a / is an absolute path. It is possible to take an absolute path, and change the name of the website and still have the path work. The second also specifies the website name. It is not possible to update the website name and not have to also update the link.

<a href="page2.html">Page 2</a> <br />
<a href="subdir/page3.html">Page 3</a> subdir/page3.html<br />
<a href="/directory_test/subdir/page3.html">Page 3</a> 
/directory_test/subdir/page3.html<br />
<a href="http://localhost/directory_test/subdir/page3.html">Page 3</a> 
http://localhost/directory_test/subdir/page3.html<br />
<a href="subdir/supersub/page4.html">Page 4</a> subdir/supersub/page4.html<br />

Try it out: [link]

If a web developer wants to link to a particular directory on a webside, he or she could use the following code:

<a href="http://cs.simpson.edu/mydir">Link to mydir on simpson webpage</a>
The webserver for Simpson will first check to see if there is a page or a web application called mydir. There is not, so it will then see if there is a directory called mydir. There is, so the website will forward the user to the directory link:
http://cs.simpson.edu/mydir/
Note the trailing slash on the link. This request and forward requires and extra round trip to and from the server. The user's experience, and the load on the server, can be improved if the link to the directory was done with a trailing slash in the first place.

If a website links to a directory, the web server will look for an index file, such as index.html or index.php. If an index file does not exist, the web server will look to see if it can create a directory listing of all the files in the directory. It is usually a bad idea for security reasons to allow this to happen on a production web server. In the apach.conf there is a configuration setting to turn this directory listing feature off.

Chapter 3: CSS

3.1 Introduction to CSS

Wednesday - Class 03

  • Feedback on HTML worksheets
  • What is CSS? Take a look at CSS Zen Garden
    • View the page source
    • View CSS sheets
    • What advantages could you see in separating content from style?
    • Show how to "inspect element" to see what styles are applying to an element you are interested in.
    • Show how to modify "live" the style of an element.
  • Start covering CSS
    • HTML5 will come after CSS
    • Link to worksheet: [DOCX]
    • Take a look at the more complex examples at the end of the tutorial even though there are no questions over them.

3.2 CSS Worksheet

Most of the answers for this worksheet may be found at the w3schools.com website: http://w3schools.com/css/

CSS Basic

  1. What does CSS stand for?
  2. What is the advantage of using CSS?
  3. Write an example CSS rule and label the selector, declaration, property and value.
  4. How are comments done in a CSS sheet?
  5. Conceptually, what is the difference between an id selector and a class selector?
  6. Give examples of: HTML Element selector, id selector, and a class selector.
  7. What are the three ways to use CSS in a document?
  8. If multiple styles are specified for an html element, in what order are evaluated? (Later ones being higher priority.)
  9. Write the CSS code to set the background color for an entire document to white:
  10. Give an example of setting properties for the background by using the shorthand property:
  11. Show how to set the color of text in h1 headings to red:
  12. Show how to center-align the text in a paragraph:
  13. Show how to indent the first line of a paragraph by 50 pixels:
  14. What is the difference between a serif font, and a sans-serif font?
  15. Give two examples of font families:
  16. What is different about a monospace font?
  17. Show how to set the font size for a paragraph to 12 pixels.
  18. What is the difference between setting the font size via pixels or via em?
  19. Show 1 of the 4 lines required to remove underlines from hyperlinks:
  20. Show how to set the vertical alignment of text in a table cell so that it is at the top.
  21. Sketch out the CSS box model, showing content, padding, border, and margin:
  22. Show how to put a 2 pixel solid border around a paragraph:
  23. Show how to put a 25 pixel margin below h1.
  24. Using grouping, show how to set the text color of h1, h2, and h3 to red.
  25. Show how to set the width of a paragraph to 800 pixels.
  26. What is the difference between a hidden element, and an element that is not displayed?
  27. What is the difference between a block element, and an in-line element?
  28. What is the difference between static, fixed, relative, and absolute positioning?
  29. What is does CSS float do?
  30. Give an example of a CSS pseudo-class:

3.3 Color Theory

3.4 Practice Applying CSS

  • Download and save this text file: [link]
  • Convert to an HTML file so it looks like this: [link]
  • Add style sheet so it looks like this: [link]
    • Cool new CSS3 property for rounded borders: [link]

Chapter 4: HTML5

4.1 HTML5 Worksheet

Use the following resources to answer the questions on this page:
W3Schools: http://www.w3schools.com/html5/default.asp
Niels Leenheer: http://html5test.com
Remy Sharp: http://html5demos.com/

  1. Rather than have tags like: HTML5 adds specific new tags to better define the structure of a document. List some of these new markup tags added for better structure definition:
  2. Explain why HTML5's media support is important. This might require a bit of searching or asking because the answer is not spelled out in the w3schools website.
  3. What are video codecs?
  4. Make a couple observations about HTML 5 video codec support across different browsers after reading through the following article:
    http://en.wikipedia.org/wiki/HTML5_video
  5. Explain the importance of these blog postings:
    http://blog.chromium.org/2011/01/html-video-codec-support-in-chrome.html
    http://blog.chromium.org/2011/01/more-about-chrome-html-video-codec.html
  6. What is the new canvas element used for?
  7. What is web storage used for? (localStorage and sessionStorage)
  8. What are some of the new form elements?
  9. What are some tags that HTML5 no longer supports?
  10. JavaScript is a language that can be used to help create interactive web pages. HTML5 adds new "events" that allow a developer to create code that will be run when these "events" occur. List two of the new events and describe when they are run. (In your own words, not copy/pasted.) Take a moment to look through all the new events available.
  11. What are Web Workers?
  12. Run IE, Firefox, and Chrome against http://html5test.com web site. Write their scores here. If you have a smart phone, try it out as well.
  13. Run this HTML5 calculator using Chrome or Firefox: http://graph.tk/ (Note that it uses web storage.)
  14. Take a look at the two drag/drop demos here: http://html5demos.com/. Give an example of how drag/drop might improve a user's experience:
  15. What does the History API do?
  16. What does cross-document messaging do?
  17. What do the geolocation tags do? How might they be used in a website?

Chapter 5: PHP

5.1 PHP Worksheet

Many of these items can be found on Wikipedia, but do not cut/paste your answer from the web.

    Section 1: Web and Internet server basics

  1. What is a web server?
  2. What are the top four web servers that are on the market?
  3. What is an application server?
  4. What are three major types of application servers that you can get?
  5. What are some application servers that are on the market?
  6. What is a load balancer?
  7. What are the different types of load balancing listed here?
    http://technet.microsoft.com/en-us/library/ee191506.aspx
  8. See http://en.wikipedia.org/wiki/Web_hosting_service Describe:
    1. Free hosting
    2. Shared web hosting
    3. Reseller hosting
    4. Virtual dedicated hosting
    5. Dedicated hosting
    6. Managed hosting
    7. Co-location hosting
    8. Cloud hosting
  9. See: http://en.wikipedia.org/wiki/Domain_Name_System
    With the address: www.simpson.edu, what is the TLD, SLD, and third level domain name?
  10. What is a domain name registrar?

    Section 2: PHP

    See http://w3schools.com/php/default.asp
    For now we are skipping form processing, file management, cookies, sessions, database interaction, and XML.
  11. How does PHP code get separated from HTML code?
  12. Can users see PHP code?
  13. A new developer opens up a .php file in his/her browser. It "kind of" works, but not really. Explain what is happening.
  14. Show the code required to create a variable that is assigned to the text "Simpson College".
  15. How does PHP print the contents of a variable into a PHP document?
  16. How are strings concatenated together in PHP?
  17. Take a look at the PHP String Functions link. Pick one of the commands and write a brief summary of it.
  18. From that list of string functions, look at fprintf. How would you print out a floating number to only two decimal places?
  19. Give a simple example of an if/elseif/else statement in PHP that is different than the one shown in w3schools.
  20. Show an example of a PHP "for" loop that is different than the tutorial.
  21. Show an example of creating and calling a simple function in PHP.
  22. Use the date() function (look under the PHP Advanced section) and show how to output the date in the following format: 2009-07-01
  23. Show how to use a PHP "include" statement to perform a server-side include. This is very handy when you have common headers or footers you wish to include.

Chapter 6: Creating a Menu

This is an example of two pages in a website. The user may navigate between the two. Note that there is a lot of similar code between the pages.

6.1 Version 1

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />  
  <title>My Menu Test Title</title>
</head>

<body>
  <a href='menu1.php'>Page 1</a> <a href='menu2.php'>Page 2</a>

  <p>The first page of my site.</p>

  <p>Page 1</p>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
  <title>My Menu Test Title</title>
</head>

<body>
  <a href='menu1.php'>Page 1</a> <a href='menu2.php'>Page 2</a>

  <p>This is the second page of my site.</p>

  <p>Page 2</p>
</body>
</html>

6.2 Version 2

The common HTML code has been moved to a couple separate PHP files. These files are brought in with an include function. This prevents duplication and allows multiple pages to be updated simultaneously.

It is possible that a person could directly navigate to the common include files. This is an issue that can be fixed, but that solution is beyond the scope of this chapter.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

<html>
<?php
include("common_head_section.php");
?>

<body>
  <?php
    include("common_menu.php");
    ?>

  <p>The first page of my site.</p>

  <p>Page 1</p>
</body>
</html>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<?php
include("common_head_section.php");
?>

<body>
  <?php include("common_menu.php");  ?>

  <p>This is the second page of my site.</p>

  <p>Page 2</p>
</body>
</html>
<head>
 <title>My Menu Test Title</title>
 <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
</head>
<?php
	echo "<h1>My Menu Test</h1>";
	echo "<p>";
	echo "<a href='menu1.php'>Page 1</a> ";
	echo "<a href='menu2.php'>Page 2</a>";
	echo "</p>";
?>

6.3 Version 3

In this version, the concepts of functions, and if statements have been introduced. The file menu2.php calls the date function to get the current day of the week. It then uses if statements to trigger output that will automatically change depending on what day of the week it is.

A function is created in common_menu.php and called in the menu files to write out the menu. By using if statements, this version of the menu system prevents links from being created in the menu that link back to the page the user is already on.

<html>
<?php
include("common_head_section.php");
?>
<body>
<?php
include("common_menu.php");
writeMenu('menu1.php');

?>
<p>The first page of my site.</p>
<p>Page 1</p>
</body>
</html>
<html>
<?php
include("common_head_section.php");
?>
<body>
<?php
include("common_menu.php");
writeMenu('menu2.php');

?>
<p>This is the second page of my site.</p>
<?php
$d=date("D");
echo "The current day is $d.";
if ($d=="Fri") {
	echo "Nooo! Please don't sing Katy Perry!";
}
if ($d=="Mon") {
	echo "Ugh. Monday.";
}
if ($d=="Mon" || $d=="Wed" || $d=="Fri" ) {
	echo "<p>CIS 305 day";
}
?>
<p>Page 2</p>
</body>
</html>
<head>
<title>My Menu Test Title</title>
</head>
<?php
function writeMenu($current_page) {
	echo "<h1>My Menu Test</h1>";
	echo "<p>";
	if( $current_page == "menu1.php" ) {
		echo "Page 1 ";
	} else {
		echo "<a href='menu1.php'>Page 1</a> ";
	}
	if( $current_page == "menu2.php" ) {
		echo "Page 2";
	} else {
		echo "<a href='menu2.php'>Page 2</a>";
	}
	echo "</p>";
}
?>

6.4 Version 4

This version shows how to use arrays and for statements to have several menu items without creating a long chain of if statements.

<html>
<?php
include("common_head_section.php");
?>
<body>
<?php
include("common_menu.php");
writeMenu('menu1.php');

?>
<p>The first page of my site.</p>
<p>Page 1</p>
</body>
</html>
<html>
<?php
include("common_head_section.php");
?>
<body>
<?php
include("common_menu.php");
writeMenu('menu2.php');

?>
<p>This is the second page of my site.</p>
<?php
$d=date("D");
echo "The current day is $d.";
if ($d=="Fri") {
	echo "Nooo! Please don't sing Katy Perry!";
}
if ($d=="Mon") {
	echo "Ugh. Monday.";
}
if ($d=="Mon" || $d=="Wed" || $d=="Fri" ) {
	echo "<p>CIS 305 day";
}
?>
<p>Page 2</p>
</body>
</html>
<head>
<title>My Menu Test Title</title>
</head>
<?php
function writeMenu($current_page) {
	echo "<h1>My Menu Test</h1>";
	echo "<p>";
	$links=array("menu1.php","menu2.php");
	$titles=array("Page 1","Page 2");
	
	for( $i=0; $i < count($links); $i++ ) {
		if ($links[$i] != $current_page ) {
			echo "<a href='$links[$i]'>$titles[$i]</a> ";
		} else {
			echo "$titles[$i] ";
		}
	}
	

	echo "</p>";
}
?>

Chapter 7: Forms

7.1 Creating a Basic Form

Generic form, nothing specific to PHP.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />

  <title>Sample Form</title>
</head>

<body>
  <h1>Form Test</h1><!-- All elements of the form should be contained 
      inside the form tags. -->

  <form action="form_process.php" method="get">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" /><br />
    Last name: <input type="text" name="lastname" /><br />
    <br />
    <!-- Enter male/female -->

    <fieldset>
      <input type="radio" name="sex" value="male" /> Male<br />
      <input type="radio" name="sex" value="female" /> Female
    </fieldset><br />
    <!-- Enter transportation -->

    <fieldset>
      I have a bike: <input type="checkbox" name="vehicles[]" value="Bike" /><br />
      I have a car: <input type="checkbox" name="vehicles[]" value="Car" /><br />
      I have an airplane: <input type="checkbox" name="vehicles[]" value="Airplane" />
    </fieldset><br />
    <!-- Add submit button -->
     <input type="submit" value="Submit" />
  </form>
</body>
</html>

This will 'catch' the results of the form. No processing or PHP specific things yet. Try it out. Look at the URL line and see what is in it.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1>
</body>
</html>

Try it out: [link]

7.2 Using Form Results

This will take the input values from the prior form and print.

(See what happens if you access the page directly.)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1><?php
  $firstname = $_GET['firstname'];
  $lastname = $_GET['lastname'];

  echo "Hello ".$firstname." ".$lastname." .";
  ?>
</body>
</html>

Try it out: [link]

7.3 Get vs. Post

Change the $_GET to a $_POST. Does it work? Try changing the form tag in the form page to a "post" instead of a get. Now does it work? If you use $_REQUEST it works with either.

Here is a page that shows simple validation. Note that it also demonstrates:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1>
  <?php
  // Process first and last name
  $firstname = $_GET['firstname'];
  $lastname = $_GET['lastname'];
  echo "Hello $firstname $lastname. <br />";

  // Did the user hit a one of the sex radio buttons?
  if( isset($_GET['sex'])) {
   // ...they did. Which one?
   $sex = $_GET['sex'];
   echo "You are $sex. <br />";
  }

  // Did the use check any of the vehicles?
  if( isset($_GET['vehicles'])) {
   // They did. Get an array of each one
   $vehicles = $_GET['vehicles'];
   // How many items in the array?
   $n = count($vehicles);
   // Print the array
   for($i=0; $i<$n;$i++) {
    echo "<br />$vehicles[$i]";
   }
  }
  ?>
</body>
</html>

Try it out: [link]

7.4 Encoding HTML Entities

This works. But it is not safe at all. For example, try entering these for the first name:

<h1>Paul 
<p 
<plaintext>Paul 
<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT> 
There are a lot of really evil things a person could do with this.

HTML Entities

Before displaying any variable on a web page, it should be encoded. For example, try entering the following as a first name in the form example:

"><h1>hi</h1>

To properly manage this field, try encoding the field instead:

<input type="text" name="firstname" value="<?php 
if(!empty($firstname))
	echo htmlentities($firstname);
?>"/>

This uses a new function, htmlentities. This function takes all quotes, and HTML-like characters and encodes them so that they appear properly in an HTML page. This code also uses the function empty to see if a variable exists. The first time the page is brought up, that variable will not have been created, and an error will occur if the program does not check first.

What are HTML entities? HTML entities allow special characters to be displayed in an HTML page without actually using those characters. This keeps the source file as plain ASCII text, and allows some of the characters to be set aside to be used for code.

Take a look at the table shown here:
http://www.w3schools.com/HTML/html_entities.asp

Note: This is different than URL encoding. If there is a parameter in the URL, and that URL has special characters in it, the characters need to be encoded. See:
http://www.w3schools.com/tags/ref_urlencode.asp

7.5 Validating Input Part 1

First, learn regular expressions:
http://www.phpro.org/tutorials/Introduction-to-PHP-Regex.html

Regular expressions are useful:
http://xkcd.com/208/

Next, start with a basic form:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Test</h1>

  <form action="form_process.php" method="get">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" /><br />
    <input type="submit" value="Submit" />
  </form>
</body>
</html>

Then, use the command preg_match to see if the input matches the regular expression:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1><?php
  /* Validation of first name */
  if(empty($_REQUEST['firstname'])) {
      /* First, if there is no firstname in the request, print an error. */
          echo "<p>Error, no first name entered.</p>";
          $firstname=NULL;
  } else {
          /* There is a first name. Set a variable to its value. */
          $firstname = $_REQUEST['firstname'];
          /* Use the regular expression ^[A-Za-z]{1,25}$ and see if the value matches it */
          if (!preg_match("/^[A-Za-z]{1,25}$/", $firstname)) {
                  /* No match. End the script immediately with 'die'. */
                  /* Note, using 'die' as a bad practice. */
                  die("Bad name, please re-enter."); 
          }
  }

  echo "Hello $firstname."
  ?>
</body>
</html>

Try it out: [link]

The command preg_match is new. This command takes a regular pattern (preg) and attempts to match it against a string.

Unfortunately this example will not validate names like "O'Malley" or "Van Wyk" or "Newton-John". To support this, the pattern would need to be updated to add these characters to the list of what is permissable.

This code also introduces the command die. Dying should only be done in the most desperate of circumstances. A normal user should not be able to trip a die command. Obviously, the command has been used improperly here. Look at the resulting html output from the page. What happened?

Search the web and come up with regular expressions for phone numbers, and e-mail addresses. Try them out.

7.6 Validating Input Part 2

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Test</h1><?php 
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo $message;
          }       
  }
  ?>

  <form action="form_process.php" method="get">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" /><br />
    <!-- Add submit button -->
    <input type="submit" value="Submit" />
  </form>
</body>
</html>
<?php
/* Keep track if there is an error or not */
$error=FALSE;

/* Validation of first name */
if(empty($_REQUEST['firstname'])) {
	/* There was no first name, that's odd */
	$error=TRUE;
	/* Create an array of messages to display the user */
	$messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>";
} else {
	/* Get the first name from the request */
	$firstname = $_REQUEST['firstname'];
	/* See if the first name matches our not-very-good filter */
	if (!preg_match("/^[A-Za-z]{1,25}$/", $firstname)) {
		/* No match, display an error */
		$error=TRUE;
			/* Create an array of messages to display the user */
		$messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>"; 
		
	}
}

/* If there was an error, include the form again. Otherwise continue on. */
if($error) {
	include("form.php");
} else {
	include("next.php");
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1><?php
  echo "Hello $firstname."
  ?>
</body>
</html>

Try it out: [link]

This is one way of processing the form, but it isn't perfect. If a user bookmarks the form after a failed attempt, or if the user bookmarks the following page, then the bookmark will be for the form_process.php page, rather than the form or the following link.

Even more obvious, the form value lost, and the user must re-enter the data.

7.7 Preserving form input

This version of form.php will preserve the value save in the form.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Test</h1><?php 
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo $message;
          }       
  }
  ?>

  <form action="form_process.php" method="get">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" <?php
	if( isset($firstname) ) {
		echo 'value="';
		echo htmlentities ($firstname);
		echo '"';
	}
	?>/><br />
    <!-- Add submit button -->
    <input type="submit" value="Submit" />
  </form>
</body>
</html>

Try it out: [link]

7.8 Complex form with many input types

There are many other types of input. This next example is more complex. The code below properly handles several types of input. It also places an error next to the field that is not correct.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
  <title>Sample PHP</title>
  <style type="text/css">
        .errormsg { color: red; }
  </style>
</head>

<body>
  <h1>Form Test</h1><?php 
   
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo "<p class='errormsg'>$message</p>";
          }       
  }
  ?><!-- All elements of the form should be contained 
      inside the form tags. -->

  <form action="form_process.php" method="post">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" value=
    "<?php if( isset($firstname)) { echo htmlentities($firstname); } ?>" />
     <?php if( isset($messages['firstname'])) echo "<span class='errormsg'>".$messages['firstname']."</span>"; ?><br />

    Last name: <input type="text" name="lastname" value=
    "<?php if( isset($lastname)) { echo htmlentities($lastname); } ?>" />
     <?php if( isset($messages['lastname'])) echo "<span class='errormsg'>".$messages['lastname']."</span>"; ?><br />

    <br />
    <!-- Enter male/female -->

    <fieldset>
      <input type="radio" name="sex" value=
      "male" <?php if( isset($sex) and $sex=="male" ) {echo "checked='yes'";} ?> />
      Male<br />
      <input type="radio" name="sex" value=
      "female" <?php if( isset($sex) and $sex=="female" ) {echo "checked='yes'";} ?> />
       Female
    </fieldset><br />
    <!-- Enter transportation -->
     
    <!-- The [] in the name attribute triggers special handling with
       PHP. It means nothing special in HTML -->

    <fieldset>
      I have a bike: <input type="checkbox" name="vehicles[]"
      value="Bike" <?php if( isset($vehicles_associative['Bike']) ) {echo "checked='yes'";} ?> />
      <br />
      I have a car: <input type="checkbox" name="vehicles[]" value=
      "Car" <?php if( isset($vehicles_associative['Car']) ) {echo "checked='yes'";} ?> />
      <br />
      I have an airplane: <input type="checkbox" name="vehicles[]"
      value=
      "Airplane" <?php if( isset($vehicles_associative['Airplane']) ) {echo "checked='yes'";} ?> />
      </fieldset><br />
    <!-- Add submit button -->
     <input type="submit" value="Submit" />
  </form>
</body>
</html>
<?php
$error=FALSE;

if(!empty($_REQUEST['firstname'])) {
	$firstname = $_REQUEST['firstname'];
	if (!preg_match("/^[A-Za-z]{1,25}$/", $firstname)) {
		$error=TRUE;
		$messages['firstname']="Error - Invalid First Name"; 
	}
} else {
	$firstname="";
	$error=TRUE;
	$messages['firstname']="Error - Invalid First Name";
}

if(!empty($_REQUEST['lastname'])) {
	$lastname = $_REQUEST['lastname'];
	if (!preg_match("/^[A-Za-z]{1,25}$/", $lastname)) {
		$error=TRUE;
		$messages['lastname']="Error - Invalid Last Name"; 
	}
} else {
	$error=TRUE;
	$messages['lastname']="Error - Invalid Last Name";
}

if(!empty($_REQUEST['sex'])) {
	$sex = $_REQUEST['sex'];
	if (!preg_match("/^(male|female)$/", $sex)) {
		$error=TRUE;
		$messages['sex']="Error - Invalid Sex"; 
	}
} else {
	$error=TRUE;
	$messages['sex']="Error - No sex selected";
}

// Did the use check any of the vehicles?
if( isset($_REQUEST['vehicles'])) {
 // They did. Get an array of each one
 $vehicles = $_REQUEST['vehicles'];
 // How many items in the array?
 $n = count($vehicles);
 // Print the array
 for($i=0; $i<$n;$i++) {
 	if (!preg_match("/^(Bike|Car|Airplane)$/", $vehicles[$i])) {
		$error=TRUE;
		$messages['Vehicles']="Error - Invalid Vehicle Selection"; 
	} else {
		$vehicles_associative[$vehicles[$i]] = TRUE;
	}
 }
}

if($error==TRUE) {
	include("form.php");
} else {
	include("next.php");
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1><?php
    echo "Hello $firstname."
    ?>
</body>
</html>

Try it out: [link]

To fix the issue of improper URLs, it is necessary to learn how to use sessions.

Chapter 8: Sessions

8.1 Redirects:

When a program is done processing a form it can do an include command for the next page:

if($error==FALSE) {
	include("next.php");
} else {
	include("form.php");
}

The problem with this is that if the user bookmarks the resulting URL, it will not be for index.php, but instead for the login_process.php. Then the user will arrive at a page different than expected, and the form will process with no form information data giving the user lots of angry messages.

The other way to do it is by the use of a redirect. Instead of directly including more php code, the application server sends a short message saying "Go to this page instead." The browser will get that response and make a second request from the new page.

if($error==FALSE) {
	header("Location: next.php");
} else {
	header("Location: form.php");
}

A 'redirect' will send a message back to the client web browser. The client web browser will not display anything, but will look at the message and see that it has been redirected to another web page.

The following code has a form very similar to what has been used before. But there is a problem. If the user makes a mistake, the $messages variable that is set in form_process.php will not be set after the redirect to form.php.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Test</h1><?php 
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo $message;
          }       
  }
  ?>

  <form action="form_process.php" method="get">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" <?php
	if( isset($firstname) ) {
		echo 'value="';
		echo htmlentities ($firstname);
		echo '"';
	}
	?>/><br />
    <!-- Add submit button -->
    <input type="submit" value="Submit" />
  </form>
</body>
</html>
<?php
/* Keep track if there is an error or not */
$error=FALSE;

/* Validation of first name */
if(empty($_REQUEST['firstname'])) {
	/* There was no first name, that's odd */
	$error=TRUE;
	/* Create an array of messages to display the user */
	$messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>";
} else {
	/* Get the first name from the request */
	$firstname = $_REQUEST['firstname'];
	/* See if the first name matches our not-very-good filter */
	if (!preg_match("/^[A-Za-z]{1,25}$/", $firstname)) {
		/* No match, display an error */
		$error=TRUE;
		/* Create an array of messages to display the user */
		$messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>"; 
	}
}

/* If there was an error, include the form again. Otherwise continue on. */
if($error==FALSE) {
	/* Instead of doing an 'include', do a redirect */
	header("Location: next.php");
} else {
	/* Instead of doing an 'include', do a redirect */
	header("Location: form.php");
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1><?php
  echo "Hello $firstname."
  ?>
</body>
</html>

Try it out: [link]

8.2 Cookies

By default, each web request is "stateless." Without doing some extra work, there is no way to tell that the second page that "Bob" requests is in any way related to the first request he made. This makes any interaction, even as simple as a log-in request, a problem.

One way to get around this is to use a "cookie." The concept of using a cookie may be explained by your instructor, or get even more detail by reading up on it here:
http://en.wikipedia.org/wiki/HTTP_cookie

A client may look at his or her cookies by using the web browser.

fig.firefox_cookies1
Figure 8.1: Cookies in Firefox

fig.firefox_cookies2
Figure 8.2: Cookies in Firefox

8.3 Sessions

8.4 To start a session:

session_start();

This line must be ahead of any references to session variables. It may only be called once per web request.

8.5 To set a session variable:

For example, this counts and displays the number of times a user has viewed a page within this session:
<?php
session_start();
if(isset($_SESSION['views']))
    $_SESSION['views'] = $_SESSION['views']+ 1;
else
    $_SESSION['views'] = 1;

echo "views = ". $_SESSION['views']; 
?>

Try it out: [link]

The next example uses the session to save and retrieve the values from the form. This is more complex than the handling of variables in the prior examples, but it has several advantages. The user may bookmark the form, even after a failed attempt at the form, and not worry about bookmarking form_process.php instead of form.php. If the user bookmarks after the form is successfully filled out, he or she will bookmark the desired next.php rather than form_process.php. Another advantage is that $_SESSION['firstname'] will be available for all furture page requests from the user.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Test</h1><?php 
  session_start();
  if(isset($_SESSION['messages'])) {
	$messages = $_SESSION['messages'];
	$form = $_SESSION['form'];
	unset($_SESSION['messages']);
	unset($_SESSION['form']);
  }
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo $message;
          }       
  }
  ?>

  <form action="form_process.php" method="get">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" <?php
	if( isset($form['firstname']) ) {
		echo 'value="';
		echo htmlentities ($form['firstname']);
		echo '"';
	}
	?>/><br />
    <!-- Add submit button -->
    <input type="submit" value="Submit" />
  </form>
</body>
</html>
<?php
session_start();

/* Keep track if there is an error or not */
$error=FALSE;

/* Validation of first name */
if(empty($_REQUEST['firstname'])) {
	/* There was no first name, that's odd */
	$error=TRUE;
	/* Create an array of messages to display the user */
	$messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>";
} else {
	/* Get the first name from the request */
	$firstname = $_REQUEST['firstname'];
	/* See if the first name matches our not-very-good filter */
	if (!preg_match("/^[A-Za-z]{1,25}$/", $firstname)) {
		/* No match, display an error */
		$error=TRUE;
		/* Create an array of messages to display the user */
		$messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>"; 
		$form['firstname']=$firstname;
	} else {
		/* First name is good! Save to the session. */
		$_SESSION['firstname'] = $firstname;
	}
}

/* If there was an error, include the form again. Otherwise continue on. */
if($error==FALSE) {
	header("Location: next.php");
} else {
	$_SESSION['messages'] = $messages;
	$_SESSION['form'] = $form;
	header("Location: form.php");
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>

<body>
  <h1>Form Submitted</h1><?php

  session_start();
  $firstname = $_SESSION['firstname'];
  echo "Hello $firstname."
  ?>
</body>
</html>

Try it out: [link]

Chapter 9: Introduction to Databases

9.1 Introduction to the terminology

A database table is similar to a spreadsheet table that lists data items in rows.

fig.table
Figure 9.3: Table

fig.fields
Figure 9.4: Field

fig.rows
Figure 9.5: Row

fig.database
Figure 9.6: Database

9.2 Set up the database

Start up EasyPHP and MySQL.

Click 'e' button, and then select "Administration."

fig.select_administration
Figure 9.7: Selecting the administration menu

Click Manage MySQL

fig.manage_mysql
Figure 9.8: Manage Databases

Select "Databases" tab.

Create a new database. Use the name "cis305example". This is not case sensitive, and whatever you type will just be taken as lower case.

fig.create_new_database
Figure 9.9: Create a new database

Create a new table called "People" with 3 fields.

fig.create_people_table
Figure 9.10: Create a database table

Fill out the information as follows:

fig.people_table
Figure 9.11: Create fields for database table

Afterwards, you should have a table:

fig.list_tables
Figure 9.12: List of tables

The table detail should look like this:

fig.table_detail
Figure 9.13: Detail of people table

Click the insert tab then add the record data:

fig.add_people_record
Figure 9.14: Add record to people table

After inserting the record, the system should display a message like this:

fig.record_inserted
Figure 9.15: Record inserted

Hit the browse tab and make sure the record was added:

fig.browse_people
Figure 9.16: Browse people

9.3 Sample code to display database records

The code to list the fields looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />

  <title>List People</title>
</head>

<body>
  <h1>List of people:</h1>
  <?php
  /* Info to hook up to a database.
   * Normally, we'd import this from a common file. You would
   * not want to update this in each file when the password
   * changes.
   */
  $username = "root";
  $password = "";
  $database = "cis305example";
  $server   = "localhost";

  // This connects to the database server. It is necessary before
  // doing any database commands.
  mysql_connect($server,$username,$password);

  // This selects which database on the server will be used.
  mysql_select_db($database);

  // Pull all users from the database
  $query="SELECT * FROM people";
  $result=mysql_query($query);

  // Get the number of rows in the result
  $num=mysql_numrows($result);

  // Loop through each record. This could also
  // be done with a 'for' loop.
  $i=0;
  while ($i < $num) {
          $firstname=mysql_result($result,$i,"first");
          $lastname=mysql_result($result,$i,"last");
          echo "$firstname $lastname<br />";
          $i++;
  }
  echo "<p>Total number: $num</p>";
  ?>
</body>
</html>

Try it out: [link]

The example in the section above has a problem. It is not secure against HTML code that is contained in the database fields. To properly display the first name and last name, use the htmlentities function again. Change the following code:

echo "$firstname $lastname
";

To this:

echo htmlentities($firstname);
echo " ";
echo htmlentities($lastname);
echo "
";

9.4 Sample code to insert records

The SQL database statement to insert a record into the database is simple. It looks like this:

insert into people (first, last)
values ('Jane','Smith')

For more information on this statement, read W3School's coverage on the INSERT INTO statement.

These four files will list people in the table, and allow a user to insert a person into the table.

The first file is a common include file that sets up the database connection. The code in this file is not different than prior code examples, it has just been put into a separate file.

<?php
	/* Info to hook up to a database.
	* This is imported by other pages to set up the database. This
	* page should never be called directly.
	*/
	$username = "root";
	$password = "";
	$database = "cis305example";
	$server   = "localhost";

	// This connects to the database server. It is necessary before
	// doing any database commands.
	mysql_connect($server,$username,$password);

	// This selects which database on the server will be used.
	mysql_select_db($database);
  ?>

This file is very similar to the prior version of list_people.php. The main differences:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />

  <title>Manage People</title>
</head>

<body>
  <h1>Manage people</h1>
  <p><a href="form.php">Add new person</a></p>
  <h2>List of people:</h2>
  <?php
  // Include common db setup code
  include ("db_setup.php");

  // Pull all users from the database
  $query="SELECT * FROM people";
  $result=mysql_query($query);

  // Get the number of rows in the result
  $num=mysql_numrows($result);

  // Loop through each record. This could also
  // be done with a 'for' loop.
  $i=0;
  while ($i < $num) {
		$firstname=mysql_result($result,$i,"first");
		$lastname=mysql_result($result,$i,"last");
		echo htmlentities($firstname);
		echo " ";
		echo htmlentities($lastname);
		echo "<br />";
		$i++;
  }
  echo "<p>Total number: $num</p>";
  ?>
</body>
</html>

This is a simple form to take a first and last name. It is very similar to prior examples. It expects that form information will be stored in the session in an array called form.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>
 
<body>
  <h1>Form Test</h1><?php 
  session_start();
  if(isset($_SESSION['messages'])) {
    $messages = $_SESSION['messages'];
    $form = $_SESSION['form'];
    unset($_SESSION['messages']);
    unset($_SESSION['form']);
  }
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo $message;
          }       
  }
  ?>
 
  <form action="form_process.php" method="get">
    <!-- Enter name -->
    First name: <input type="text" name="firstname" <?php
    if( isset($form['firstname']) ) {
        echo 'value="';
        echo htmlentities ($form['firstname']);
        echo '"';
    }
    ?>/><br />
    Last name: <input type="text" name="lastname" <?php
    if( isset($form['lastname']) ) {
        echo 'value="';
        echo htmlentities ($form['lastname']);
        echo '"';
    }
    ?>/><br />	
    <!-- Add submit button -->
    <input type="submit" value="Submit" />
  </form>
</body>
</html>

This code processes the form. It includes the code required to insert the record into the database. The important part of the code for the SQL insert statement is:

/* Set up the database connection */
include ("db_setup.php");

/* Escape the string to prevent SQL injection */
$firstname_safe = mysql_real_escape_string($form['firstname']);
$lastname_safe = mysql_real_escape_string($form['lastname']);

/* Construct the SQL statement */
$query="insert into people (first, last) values ('$firstname_safe', '$lastname_safe')";

/* Run the SQL statement */
mysql_query($query);

Note lines 5 and 6. Just like HTML, input from the user could be in the form of a database query. Terrible things could happen, including the deletion of all the data in the database table. See the following comic for an example: [link] The function mysql_real_escape_string will keep this from happening.

Remember, before entering data it is necessary to "sanatize" any input data.

<?php
session_start();
 
/* Keep track if there is an error or not */
$error=FALSE;
 
/* Validation of first name */
if(empty($_REQUEST['firstname'])) {
    /* There was no first name, that's odd */
    $error=TRUE;
    /* Create an array of messages to display the user */
    $messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>";
} else {
    /* Get the first name from the request */
    $form['firstname'] = $_REQUEST['firstname'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[A-Za-z]{1,25}$/", $form['firstname'])) {
        /* No match, display an error */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>"; 
    } 
}
/* Validation of last name */
if(empty($_REQUEST['lastname'])) {
    /* There was no last name, that's odd */
    $error=TRUE;
    /* Create an array of messages to display the user */
    $messages['lastname']="<p class='errormsg'>Error - Invalid Last Name</p>";
} else {	
    /* Get the last name from the request */
    $form['lastname'] = $_REQUEST['lastname'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[A-Za-z]{1,25}$/", $form['lastname'])) {
        /* No match, display an error */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['lastname']="<p class='errormsg'>Error - Invalid Last Name</p>"; 
    }	
}
 
/* If there was an error, include the form again. Otherwise continue on. */
if($error==FALSE) {
	/* Set up the database connection */
	include ("db_setup.php");
	
	/* Escape the string to prevent SQL injection */
	$firstname_safe = mysql_real_escape_string($form['firstname']);
	$lastname_safe = mysql_real_escape_string($form['lastname']);
	
	/* Construct the SQL statement */
	$query="insert into people (first, last) values ('$firstname_safe', '$lastname_safe')";
	
	/* Run the SQL statement */
	mysql_query($query);

    header("Location: list_people.php");
} else {
    $_SESSION['messages'] = $messages;
    $_SESSION['form'] = $form;
    header("Location: form.php");
}

?>

Try it out: [link]

9.5 Sample code to delete records

Deleting records requires a minimum of two files. One to list the items, and one to process the delete request.

To list the items, take the prior example list_people.php and modify it in the following way:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />

  <title>Manage People</title>
</head>

<body>
  <h1>Manage people</h1>
  <p><a href="form.php">Add new person</a></p>
  <h2>List of people:</h2>
  <?php
  // Include common db setup code
  include ("db_setup.php");

  // Pull all users from the database
  $query="SELECT * FROM people";
  $result=mysql_query($query);

  // Get the number of rows in the result
  $num=mysql_numrows($result);

  // Loop through each record. This could also
  // be done with a 'for' loop.
  $i=0;
  while ($i < $num) {
		$id=mysql_result($result,$i,"id");
		$firstname=mysql_result($result,$i,"first");
		$lastname=mysql_result($result,$i,"last");
		echo "[<a href='delete_process.php?id=$id'>delete</a>] ";
		echo htmlentities($firstname);
		echo " ";
		echo htmlentities($lastname);
		echo "<br />";
		$i++;
  }
  echo "<p>Total number: $num</p>";
  ?>
</body>
</html>

This code will process the delete request, removing it from the database. It uses the delete SQL statement.

This example code is VERY DANGEROUS because it is missing two items:

1) In this example, the user does not need to be logged in to get to this point. Anyone may delete the people in the database. If a search engine explores the web site, it will explore all the delete links and delete all the records in the database.

2) Even if there was a log-in, this code does not check to see if the person logged in has permission to delete this particular record. Remember that the id value can be changed and anyone could swap it for a different number.

<?php
session_start();
 
/* Keep track if there is an error or not */
$error=FALSE;
 
/* Validation of first name */
if(empty($_REQUEST['id'])) {
    /* There was no first name, that's odd */
    $error=TRUE;
} else {
    /* Get the first name from the request */
    $form['id'] = $_REQUEST['id'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[0-9]{1,25}$/", $form['id'])) {
        /* No match, display an error */
        $error=TRUE;
    } 
}
 
/* If there was no error, delete the record.  */
if($error==FALSE) {
	/* Set up the database connection */
	include ("db_setup.php");
	
	/* DANGER DANGER DANGER 
	 * This example code is VERY DANGEROUS 
	 * because it is missing two items.
	 *
	 * 1) In this example, the user does not need to be logged in
	 * to get to this point. Anyone may delete the people in the
	 * database. If a search engine explores the web site, it will
	 * explore all the delete links and delete all the records in
	 * the database.
	 *
	 * 2) Even if there was a log-in, this code does not
	 * check to see if the person logged in has permission to delete
	 * this particular record. Remember that the id value can be
	 * changed and anyone could swap it for a different number.
	 */
	/* Escape the string to prevent SQL injection */
	$id_safe = mysql_real_escape_string($form['id']);
	/* Construct the SQL statement */
	$query="delete from people where id = $id_safe";
	
	/* Run the SQL statement */
	mysql_query($query);
}
/* Go back to the list people page. */
header("Location: list_people.php");

?>

Try it out: [link]

9.6 Sample code to update records

Updating is the most complex portion of Creating, Reading, Updating, and Deleting (CRUD) database records. First, the record needs to be read into the session. Next, the form needs to be displayed to the user with all the record information pre-filled in. Finally, the record data needs to be updated.

The files for listing records, displaying the form, and processing the form can be adapted to support both insertion of a new record and updating an existing record. A new file needs to be created that will load the existing record and get it ready to be put in the form.

The list_people.php file is updated with a link to edit the record.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />

  <title>Manage People</title>
</head>

<body>
  <h1>Manage people</h1>
  <p><a href="form.php">Add new person</a></p>
  <h2>List of people:</h2>
  <?php
  // Include common db setup code
  include ("db_setup.php");

  // Pull all users from the database
  $query="SELECT * FROM people";
  $result=mysql_query($query);

  // Get the number of rows in the result
  $num=mysql_numrows($result);

  // Loop through each record. This could also
  // be done with a 'for' loop.
  $i=0;
  while ($i < $num) {
		$id=mysql_result($result,$i,"id");
		$firstname=mysql_result($result,$i,"first");
		$lastname=mysql_result($result,$i,"last");
		echo "[<a href='delete_process.php?id=$id'>delete</a>] ";
		echo "[<a href='edit_process.php?id=$id'>edit</a>] ";		
		echo htmlentities($firstname);
		echo " ";
		echo htmlentities($lastname);
		echo "<br />";
		$i++;
  }
  echo "<p>Total number: $num</p>";
  ?>
</body>
</html>

This new file loads the database record into session and forwards the user to the form.

<?php
session_start();
 
/* Keep track if there is an error or not */
$error=FALSE;
 
/* Validation of first name */
if(empty($_REQUEST['id'])) {
    /* There was no first name, that's odd */
    $error=TRUE;
} else {
    /* Get the first name from the request */
    $form['id'] = $_REQUEST['id'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[0-9]{1,25}$/", $form['id'])) {
        /* No match, display an error */
        $error=TRUE;
    } 
}
 
/* If there was no error, load the record.  */
if($error==FALSE) {
	/* Set up the database connection */
	include ("db_setup.php");
	
	/* DANGER DANGER DANGER 
	 * This example code is VERY DANGEROUS 
	 * because it is missing an important items.
	 *
	 * 1) If there was a log-in, this code does not
	 * check to see if the person logged in has permission to edit
	 * this particular record. Remember that the id value can be
	 * changed and anyone could swap it for a different number.
	 */
	/* Escape the string to prevent SQL injection */
	$id_safe = mysql_real_escape_string($form['id']);
	/* Construct the SQL statement */
	$query="select * from people where id = $id_safe";
	
	/* Run the SQL statement */
	$result=mysql_query($query);
	
	/* Grab the data and put in the form array */
	$form['id']=mysql_result($result,$i,"id");
	$form['firstname']=mysql_result($result,$i,"first");
	$form['lastname']=mysql_result($result,$i,"last");
	
	/* Save form to session */
    $_SESSION['form'] = $form;
	
	/* Send message to user */
	$messages['message']="Editing the record for " . $form['firstname'] . " " . $form['lastname'];
	
	/* Save messages to session */
    $_SESSION['messages'] = $messages;
	
	/* Go to the form */
	header("Location: form.php");
} else {
	/* Error, just go back */
	header("Location: list_people.php");
}
?>

This update to the form adds a hidden html field to hold the id. Remember that any slightly sophisticated user can view and modify hidden form fields!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>
 
<body>
  <h1>Form Test</h1><?php 
  session_start();
  if(isset($_SESSION['messages'])) {
    $messages = $_SESSION['messages'];
    $form = $_SESSION['form'];
    unset($_SESSION['messages']);
    unset($_SESSION['form']);
  }
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo $message;
          }       
  }
  ?>
 
  <form action="form_process.php" method="get">
    <!-- Enter name -->
<?php
	if (isset($form['id'])) {
		echo "<input type='hidden' name='id' value='";
		echo htmlentities($form['id']);
		echo "'>";
	}
?>	
    First name: <input type="text" name="firstname" <?php
    if( isset($form['firstname']) ) {
        echo 'value="';
        echo htmlentities ($form['firstname']);
        echo '"';
    }
    ?>/><br />
    Last name: <input type="text" name="lastname" <?php
    if( isset($form['lastname']) ) {
        echo 'value="';
        echo htmlentities ($form['lastname']);
        echo '"';
    }
    ?>/><br />	
    <!-- Add submit button -->
    <input type="submit" value="Submit" />
  </form>
</body>
</html>

Updating records requires the use the update SQL statement. An if statement checks for the existance of id. If it exists, the code assumes that an update is needed rather than an insertion of an new record.

<?php
session_start();
 
/* Keep track if there is an error or not */
$error=FALSE;
 
/* Validation of first name */
if(empty($_REQUEST['id'])) {
    $form['id']="";
} else {
    /* Get the first name from the request */
    $form['id'] = $_REQUEST['id'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[0-9]{1,25}$/", $form['id'])) {
        /* No match, what is happening? */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['id']="<p class='errormsg'>System error, unable to edit record.</p>"; 
    } 
} 
/* Validation of first name */
if(empty($_REQUEST['firstname'])) {
    /* There was no first name, that's odd */
    $error=TRUE;
    /* Create an array of messages to display the user */
    $messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>";
} else {
    /* Get the first name from the request */
    $form['firstname'] = $_REQUEST['firstname'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[A-Za-z]{1,25}$/", $form['firstname'])) {
        /* No match, display an error */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>"; 
    } 
}
/* Validation of last name */
if(empty($_REQUEST['lastname'])) {
    /* There was no last name, that's odd */
    $error=TRUE;
    /* Create an array of messages to display the user */
    $messages['lastname']="<p class='errormsg'>Error - Invalid Last Name</p>";
} else {	
    /* Get the last name from the request */
    $form['lastname'] = $_REQUEST['lastname'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[A-Za-z]{1,25}$/", $form['lastname'])) {
        /* No match, display an error */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['lastname']="<p class='errormsg'>Error - Invalid Last Name</p>"; 
    }	
}
 
/* If there was an error, include the form again. Otherwise continue on. */
if($error==FALSE) {
	/* Set up the database connection */
	include ("db_setup.php");
	
	/* Escape the string to prevent SQL injection */
	$id_safe = mysql_real_escape_string($form['id']);
	$firstname_safe = mysql_real_escape_string($form['firstname']);
	$lastname_safe = mysql_real_escape_string($form['lastname']);
	
	if( $id_safe == "" ) {
		/* Construct the SQL statement */
		$query="insert into people (first, last) values ('$firstname_safe', '$lastname_safe')";
	} else {
		$query="update people set first='$firstname_safe', last='$lastname_safe' where id='$id_safe'";
	
	}
	
	/* Run the SQL statement */
	mysql_query($query);

    header("Location: list_people.php");
} else {
    $_SESSION['messages'] = $messages;
    $_SESSION['form'] = $form;
    header("Location: form.php");
}

?>

Try it out: [link]

Chapter 10: Introduction to the MVC pattern

Read up on the Model View Controller (MVC) pattern. See also the Data Access Layer (DAL) and Data Access Object (DAO).

10.1 Model

This file is used by other files to include all the model and DAO components. Right now it is simple, but if there were a lot of different types of data objects, it would allow us to easily modify what files are used in the model and DAL, while only requiring the code that uses it to include this one file.

<?php
// This file includes all the model files,
// and all the DAO files.
include 'person.php';

include 'dbsetup.php';
include 'person_dao.php';
?>

Standard database setup file, nothing new here.

<?php
	$dbusername="root";
	$dbpassword="";
	$database="cis305example";
	$server="localhost";
	
	// This connects to the database. It is necessary before
	// doing any database commands.
	mysql_connect($server,$dbusername,$dbpassword) or die ("Unable to connect to database");
	
	// This is a bad way to show an error!
	mysql_select_db($database) or die( "Unable to select database");
	
	?>

This uses a PHP class to represent a person object. Read up on PHP classes.

<?php
// This is a simple class that represents a user.
Class Person {
	
	// Public attributes
	public $first;
	public $last;
	public $id;
}
?>

10.2 Data Access Layer

All SQL code to access the person table goes here. Create additional files for accessing other tables.

This line of code uses code in a way that may be new to the reader:

while ($row = mysql_fetch_assoc($result)) {

Note this portion of the line:

$row = mysql_fetch_assoc($result)

Each time this code is run it fetches the next available row out of the result set from the SQL statement. If no result is available at all, it returns nothing.

The while statement will take any value other than zero and nothing and consider it true. So if there is a value returned, the while statement is considered true, and it loops again. If no row is returned, the statement in the while loop is considered false, and the loop ends.

Another new item is contained this code:

$person->id = $row['id'];

When working with an instance of an object, a PHP program accesses the fields and functions by using the -> symbol. This is the same as C and C++. Many other languages use the period instead.

There are cases where the -> symbol is not used. If the class has not been instantiated, and the member method or attribute is static, then it is accessed using two colons. For example:

$people = PersonDAO::get();
<?php

// This is a Data Access Object. All SQL to save/create/edit user objects
// goes in this class.

Class PersonDAO {

	public static function get() {
		// Pull all users from the database
		$query="SELECT * FROM people";
		$result=mysql_query($query) or die ("Error: $query");
		$people_array = array();
		while ($row = mysql_fetch_assoc($result)) {
			$person = new Person();
			$person->id = $row['id'];
			$person->first = $row['first'];
			$person->last = $row['last'];
			array_push($people_array,$person);
		}
		return $people_array;
	}

	// Get a user based on username and password. Returns a User object if successful,
	// otherwise returns nothing.
	public static function get_by_id($id) {
		
		// To protect MySQL injection (more detail about MySQL injection)
		$id = mysql_real_escape_string($id);
		
		$sql="select * from people where id='$id'";
		$result=mysql_query($sql);
		
		// Mysql_num_row is counting table row
		$count=mysql_num_rows($result);
		
		// If result matched $myusername and $mypassword, table must be 1 row
		if($count==1){
			$person = new Person();
			$row = mysql_fetch_assoc($result);
			$person->first=$row['first'];
			$person->last=$row['last'];
			$person->id=$id;
			return $person;
		}
		else {
			return;
		}
	}

	public static function add($person) {
		// To protect MySQL injection
		$first = mysql_real_escape_string($person->first);
		$last = mysql_real_escape_string($person->last);

		$sql="insert into people (first,last) values ('$first','$last')";
		mysql_query($sql) or die ("Error: $sql");
	}
	
	public static function delete($id) {
		// To protect MySQL injection
		$id = mysql_real_escape_string($id);
		
		$sql="delete from people where id=$id";
		$result=mysql_query($sql) or die( "Query failed");	
	}
	
	public static function update($person) {
		// To protect MySQL injection
		$id = mysql_real_escape_string($person->id);
		$first = mysql_real_escape_string($person->first);
		$last = mysql_real_escape_string($person->last);
		
		$sql="update people set first='$first', last='$last' where id='$id'";
		mysql_query($sql) or die ("Error: $sql");
	}	
	
}
?>

10.3 View

The view should not have any SQL code in it. It should call the model data access objects to get data.

This code uses the foreach loop to iterate through the array of person objects returned by the PersonDAO::get() function.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />

  <title>Manage People</title>
</head>

<body>
  <h1>Manage people</h1>
  <p><a href="form.php">Add new person</a></p>
  <h2>List of people:</h2>
  <?php
	// Include common db setup code
	include ("model/model.php");

	$people = PersonDAO::get();
	foreach ($people as $person) {
		$id_safe=htmlentities($person->id);
		$first_safe=htmlentities($person->first);
		$last_safe=htmlentities($person->last);
		echo "[<a href='controller/delete_process.php?id=$id_safe'>delete</a>] ";
		echo "[<a href='controller/edit_process.php?id=$id_safe'>edit</a>] ";		
		echo "$first_safe $last_safe <br /> \r\n";
	}
	$num = count($people);
	echo "<p>Total number: $num</p>";

  ?>
</body>
</html>

Not much is new with the form except that it goes to controller/form_process.php instead of form_process.php.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Sample PHP</title>
</head>
 
<body>
  <h1>Form Test</h1><?php 
  session_start();
  if(isset($_SESSION['messages'])) {
    $messages = $_SESSION['messages'];
    $form = $_SESSION['form'];
    unset($_SESSION['messages']);
    unset($_SESSION['form']);
  }
  if(!empty($messages)) {
          foreach ($messages as $message) {
              echo $message;
          }       
  }
  ?>
 
  <form action="controller/form_process.php" method="get">
    <!-- Enter name -->
<?php
	if (isset($form['id'])) {
		echo "<input type='hidden' name='id' value='";
		echo htmlentities($form['id']);
		echo "'>";
	}
?>	
    First name: <input type="text" name="firstname" <?php
    if( isset($form['firstname']) ) {
        echo 'value="';
        echo htmlentities ($form['firstname']);
        echo '"';
    }
    ?>/><br />
    Last name: <input type="text" name="lastname" <?php
    if( isset($form['lastname']) ) {
        echo 'value="';
        echo htmlentities ($form['lastname']);
        echo '"';
    }
    ?>/><br />	
    <!-- Add submit button -->
    <input type="submit" value="Submit" />
  </form>
</body>
</html>

10.4 Controller

Nothing in the contoller layer should display anything. It should only contain PHP code that processes a request. After the request is processed, forward to a view php file.

<?php
include ("../model/model.php");
session_start();
 
/* Keep track if there is an error or not */
$error=FALSE;
 
/* Validation of first name */
if(empty($_REQUEST['id'])) {
    $form['id']="";
} else {
    /* Get the first name from the request */
    $form['id'] = $_REQUEST['id'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[0-9]{1,25}$/", $form['id'])) {
        /* No match, what is happening? */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['id']="<p class='errormsg'>System error, unable to edit record.</p>"; 
    } 
} 
/* Validation of first name */
if(empty($_REQUEST['firstname'])) {
    /* There was no first name, that's odd */
    $error=TRUE;
    /* Create an array of messages to display the user */
    $messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>";
} else {
    /* Get the first name from the request */
    $form['firstname'] = $_REQUEST['firstname'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[A-Za-z]{1,25}$/", $form['firstname'])) {
        /* No match, display an error */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['firstname']="<p class='errormsg'>Error - Invalid First Name</p>"; 
    } 
}
/* Validation of last name */
if(empty($_REQUEST['lastname'])) {
    /* There was no last name, that's odd */
    $error=TRUE;
    /* Create an array of messages to display the user */
    $messages['lastname']="<p class='errormsg'>Error - Invalid Last Name</p>";
} else {	
    /* Get the last name from the request */
    $form['lastname'] = $_REQUEST['lastname'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[A-Za-z]{1,25}$/", $form['lastname'])) {
        /* No match, display an error */
        $error=TRUE;
        /* Create an array of messages to display the user */
        $messages['lastname']="<p class='errormsg'>Error - Invalid Last Name</p>"; 
    }	
}
 
/* If there was an error, include the form again. Otherwise continue on. */
if($error==FALSE) {

	// Create a person object and have the DAO put it in the database
	$person = new Person();
	$person->id = $form['id'];
	$person->first = $form['firstname'];
	$person->last = $form['lastname'];
	
	if( $person->id == "" ) {
		PersonDAO::add($person);
	} else {
		PersonDAO::update($person);
	}

    header("Location: ../list_people.php");
} else {
    $_SESSION['messages'] = $messages;
    $_SESSION['form'] = $form;
    header("Location: ../form.php");
}

?>
<?php
include ("../model/model.php");
session_start();

/* Keep track if there is an error or not */
$error=FALSE;
 
/* Validation of first name */
if(empty($_REQUEST['id'])) {
    /* There was no first name, that's odd */
    $error=TRUE;
} else {
    /* Get the first name from the request */
    $form['id'] = $_REQUEST['id'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[0-9]{1,25}$/", $form['id'])) {
        /* No match, display an error */
        $error=TRUE;
    } 
}
 
/* If there was no error, delete the record.  */
if($error==FALSE) {
	
	/* DANGER DANGER DANGER 
	 * This example code is VERY DANGEROUS 
	 * because it is missing two items.
	 *
	 * 1) In this example, the user does not need to be logged in
	 * to get to this point. Anyone may delete the people in the
	 * database. If a search engine explores the web site, it will
	 * explore all the delete links and delete all the records in
	 * the database.
	 *
	 * 2) Even if there was a log-in, this code does not
	 * check to see if the person logged in has permission to delete
	 * this particular record. Remember that the id value can be
	 * changed and anyone could swap it for a different number.
	 */
	PersonDAO::delete($form['id']);
}
/* Go back to the list people page. */
header("Location: ../list_people.php");

?>
<?php
include ("../model/model.php");
session_start();
 
/* Keep track if there is an error or not */
$error=FALSE;
 
/* Validation of first name */
if(empty($_REQUEST['id'])) {
    /* There was no first name, that's odd */
    $error=TRUE;
} else {
    /* Get the first name from the request */
    $form['id'] = $_REQUEST['id'];
    /* See if the first name matches our not-very-good filter */
    if (!preg_match("/^[0-9]{1,25}$/", $form['id'])) {
        /* No match, display an error */
        $error=TRUE;
    } 
}
 
/* If there was no error, load the record.  */
if($error==FALSE) {
	/* Set up the database connection */
	include ("db_setup.php");
	
	/* DANGER DANGER DANGER 
	 * This example code is VERY DANGEROUS 
	 * because it is missing an important items.
	 *
	 * 1) If there was a log-in, this code does not
	 * check to see if the person logged in has permission to edit
	 * this particular record. Remember that the id value can be
	 * changed and anyone could swap it for a different number.
	 */
	
	/* Run the SQL statement */
	$person=PersonDAO::get_by_id($form['id']);
	
	/* Grab the data and put in the form array */
	$form['id']=$person->id;
	$form['firstname']=$person->first;
	$form['lastname']=$person->last;
	
	/* Save form to session */
    $_SESSION['form'] = $form;
	
	/* Send message to user */
	$messages['message']="Editing the record for " . $form['firstname'] . " " . $form['lastname'];
	
	/* Save messages to session */
    $_SESSION['messages'] = $messages;
	
	/* Go to the form */
	header("Location: ../form.php");
} else {
	/* Error, just go back */
	header("Location: ../list_people.php");
}
?>

Try it out: [link]

Chapter 11: Login Management

11.1 Simple login check

Man websites have protected areas that only users who are logged in may see. This next example shows how to do that. This example tries to keep unauthorized users away from the content in secret_page.php.

The PHP code will store the user's id in the session variable $_SESSION['user_id']. If no id exists in that variable, the code assumes the user is not logged in.

In the code example below, the main page of the site checks this variable to see if the user is logged in or not. It includes a link to secret_page.php. The main page also offers a small form that will take in a password if the user is not logged in. If the user is logged in, the page will display an option to log out.

Note that the how the page contains HTML code inside of the else statement.

<?php
// Start the session
session_start();
// Check for user_id in the session
if( isset( $_SESSION['user_id'] )) {
	// User is logged in.
	echo "<p>You are logged in</p>";
	echo "<p><a href='controller/logout_process.php'>Logout</a></p>";
} else {
// Only display this HTML if user is not logged in.
?>
<p>You NOT are logged in</p>
<form action="controller/login_process.php" method="post">
<input type="password" name="password" />
<input type="submit" value="Login" />
</form>
<?php
}
?>
<p><a href="secret_page.php">Try to go to the secret page.</a></p>

<p>

The code to process the login is straight-forward. It should be noted that hard-coding a password in the PHP code is bad. If the PHP code is able to be seen through a bug, the password is compromised. Furthermore it prevents the password from being changed. However a hard-coded password keeps this example simple.

<?php
// Start session
session_start();
// Check password
if( $_REQUEST['password'] == "mysecret" ) {
	// Password is good, set user id
	$_SESSION['user_id'] = "JaneSmith";
}
// Redirect back to the main page
header("Location: ../main.php");
?>

The secret page only needs to include one file, and that file will check the user login status:

<?php include "controller/check_login.php"; ?>
<p>This is a secret page.</p>
<p><a href="main.php">Back to main page</p>

The code to check the login only needs to look at the user_id session variable and see if it is set. If it isn't, an error is shown. The user could instead be redirected to a login page if desired.

<?php
session_start();
// See if the user id has been set
if( !isset( $_SESSION['user_id'] )) {
	// User id not set. Stop right here with an error.
	die ("Access denied. <a href='main.php'>Login</a> first!");
}
?>

Logout can be done by unsetting the user id.

<?php
session_start();
// Unset the user id
unset($_SESSION['user_id']);
// Redirect back to the main page
header("Location: ../main.php");
?>

Try it out: [link]

11.2 SHA1 Hash

The prior example had a password in plain text. This is rarely a good idea. A common way to check passwords is to use the SHA1 hash algorithm. SHA-1 is a cryptographic hash function. Read up on hash functions and how they work.

The hash of any string can be genereated in PHP by using the sha1 function. In the example below, the SHA-1 hash will be printed to the string for "mysecret". This code will display "e9fe51f94eadabf54dbf2fbbd57188b9abee436e".

echo sha1("mysecret");

A hash function is one-way. The output number can not be put back into the hash algorithm and get the original result. What can be done to reverse the password hashing is to guess. With fast computers today, it is possible to hash an entire dictionary of words, common passwords, and short passwords. A person may then do a "reverse lookup" and get the original password. To help prevent this, programmers often salt the input.

Using sha1, the former example would look like this:

<?php
// Start session
session_start();
// Check password
if( sha1($_REQUEST['password']) == "e9fe51f94eadabf54dbf2fbbd57188b9abee436e" ) {
	// Password is good, set user id
	$_SESSION['user_id'] = "JaneSmith";
}
// Redirect back to the main page
header("Location: ../main.php");
?>

Try it out: [link]

11.3 More extensive example

This example takes the prior MVC code and expands it to allow user login and management. Click here to download the example in a zip format.

Chapter 12: JavaScript

12.1 JavaScript Worksheet

Most of the answers for this worksheet may be found at the w3schools.com website: http://www.w3schools.com/js/

  1. Is JavaScript the same thing as Java?
  2. Show code that will take an element with the id of "college" and insert Simpson College into it. (Only 1 line needed, supporting code is not required.)
  3. Explain the difference between putting JavaScript in the <head> or in the <body>.
  4. How can JavaScript be loaded from external files?
  5. Give an example of a single-line comment in JavaScript, and a multi-line comment in JavaScript.
  6. Give an example of declaring a local JavaScript variable.
  7. Give an example of declaring a global JavaScript variable.
  8. Explain the difference between global/local variables.
  9. Give an example of the increment operator, and briefly explain what it does.
  10. Explain the difference between the == and the === operators.
  11. Give your own example (not out of w3schools) of an if...else statement in JavaScript.
  12. Show the code required to display an alert (popup) box.
  13. Write a function that will add two numbers and return the result.
  14. Write an example for loop that will write to the document the numbers 50 down to 1.
  15. What does the "break" statement do?
  16. What does the "continue" statement do?
  17. What does the For...In statement do?
  18. Show an example of calling a JavaScript function when an HTML element is clicked on.
  19. What are try / catch statements used for?
  20. Show code that will store the length of a string into a different variable.

12.2 jQuery Worksheet

Most of the answers for this worksheet may be found at the w3schools.com website: http://www.w3schools.com/jquery/

  1. Give example code that will load the jQuery script library.
  2. There are multiple variations of the jQuery. Explain the difference between "Minified" and "Uncompressed."
  3. Give example jQuery code that will hide all h1 headings in a document.
  4. One of the problems with JavaScript is that a script can start running before the entire HTML document has loaded. JavaScript will throw an error if code attempts to select part of a document that has not loaded yet. Show how jQuery allows a programmer to write code that will only load when the document is ready and fully loaded.
  5. Give an example line of code that will take all paragraphs with the class of make_red and change the CSS so that the background color will be red.
  6. Explain what an "event handler" is.
  7. Give an example of an "event handler."
  8. What is an "anonymous function?" (This might require asking the instructor for a good definition.)
  9. Explain what each line of code does below. See the full example, along with the code in action here.
    $(document).ready(function(){
      $("button").click(function(){
        $("p").hide(1000);
      });
    });
    
  10. Explain how to adjust this example so that rather than clicking on "Show Panel" a user only needs to move the mouse over "Show Panel."
  11. Create your own animation using jQuery effects, similar to those examples shown here.
  12. Give a brief explanation on how to change the content of an HTML element using jQuery.
  13. What is AJAX?
  14. What does the following selector select? $("div")
  15. What does the following selector select? $("div.intro")
  16. What does the following selector select? $("div#intro.head")
  17. Is jQuery for server-side scripting or client-side scripting?
  18. What scripting language is jQuery written in?
  19. Which jQuery function is used to prevent code from running, before the document is finished loading?

Chapter 13: AJAX

AJAX is a way to dynamically update a web page with content from the web server without having to reload the entire page. For more information on AJAX and its history, read the Wikipedia article on AJAX.

The example below replaces everything in the paragraph with the id "result" with the contents of the ajax/load.php file.

This is done using AJAX implemented via jQuery's load command.

<p>This is a small file</p>
<p id="foo">This is the foo paragraph</p>
<?php 
if( isset($_REQUEST['name'])) {
	echo "<p>Hi ".$_REQUEST['name']."!</p>";
}
?>
<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		$(document).ready(function(){
			var loadUrl = "ajax/load.php";
			$("#load_basic").click(function(){
				$("#result").load(loadUrl);
			});
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>
</html> 
			

Try it out: [link]

This next example simulates a page load that takes a long time, and shows the user a graphic while the page loads.

Note that the load_long.php file has a sleep command in it. This command causes the computer to pause for the number of specified seconds.

<?php 
echo "<p>This takes a while</p>";
sleep(10);
echo "<p id='foo'>This is the foo paragraph</p>"

?>
<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		// From http://www.freeiconsdownload.com/Free_Downloads.asp?id=585
		$(document).ready(function(){
			$.ajaxSetup ({
				cache: false
			});
			var ajax_load = "<img src='img/loading2.gif' alt='loading...' />";

//			load() functions
			var loadUrl = "ajax/load_long.php";
			$("#load_basic").click(function(){
				$("#result").html(ajax_load).load(loadUrl);
			});
			
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>

</html> 
			

Try it out: [link]

Sometimes only part of a page is desired. This next example pulls the entire ajax/load.php across the network, but only uses the paragraph with the id of foo.

<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		$(document).ready(function(){
			var loadUrl = "ajax/load.php";
			$("#load_basic").click(function(){
				$("#result").load(loadUrl+" #foo");
			});
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>

</html> 
			

Try it out: [link]

It is possible to send parameters to the page that is being pulled via AJAX. This example sets the parameter name to the value fred.

<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		$(document).ready(function(){
			var loadUrl = "ajax/load.php";
			$("#load_basic").click(function(){
				$("#result").load(loadUrl,"name=fred");
			});
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>

</html> 
			

Try it out: [link]

A callback may also be used. Once the AJAX call has finished, additional JavaScript code may be run. This next example replaces the "Click me" with "Done" once the call has finished.

<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		$(document).ready(function(){
			var loadUrl = "ajax/load.php";
			$("#load_basic").click(function(){
				$("#result").load(loadUrl,null,function() {
					$("#load_basic").html("Done!");
				});
			});
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>

</html> 
			

Try it out: [link]

Sometimes the data returned from an AJAX call is not going to replace HTML elements on a page. This next example shows how to get the results on an AJAX call and use the results in other JavaScript code.

Rather than use jQuery's load command, this example uses the more complex and more flexible ajax command.

This also shows use of JavaScript's alert command for making alert boxes.

<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		$(document).ready(function(){
			var loadUrl = "ajax/load.php";
			$("#load_basic").click(function(){
				$.ajax({
					  url: loadUrl,
					  dataType: 'html',
					  data: '',
					  success: function(data) {
						  alert(data);
					  }
					});
			});
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>

</html> 
			

Try it out: [link]

This next example is similar to the prior example, however only part of the returned data is used.

<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		$(document).ready(function(){
			var loadUrl = "ajax/load.php";
			$("#load_basic").click(function(){
				$.ajax({
					  url: loadUrl,
					  dataType: 'html',
					  data: '',
					  success: function(data) {
						  var data2 = $(data);
						  var data3 = $(data2)[2];
						  alert(data3.textContent);
					  }
					});
			});
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>

</html> 
			

Try it out: [link]

This shows getting the resulting data in XML format, and using a loop to iterate through the data.

<?xml version="1.0"?>
<nutrition>

<daily-values>
	<total-fat units="g">65</total-fat>
	<saturated-fat units="g">20</saturated-fat>
	<cholesterol units="mg">300</cholesterol>
	<sodium units="mg">2400</sodium>
	<carb units="g">300</carb>
	<fiber units="g">25</fiber>
	<protein units="g">50</protein>
</daily-values>

<food>
	<name>Avocado Dip</name>
	<mfr>Sunnydale</mfr>
	<serving units="g">29</serving>
	<calories total="110" fat="100"/>
	<total-fat>11</total-fat>
	<saturated-fat>3</saturated-fat>
	<cholesterol>5</cholesterol>
	<sodium>210</sodium>
	<carb>2</carb>
	<fiber>0</fiber>
	<protein>1</protein>
	<vitamins>
		<a>0</a>
		<c>0</c>
	</vitamins>
	<minerals>
		<ca>0</ca>
		<fe>0</fe>
	</minerals>
</food>

<food>
	<name>Bagels, New York Style </name>
	<mfr>Thompson</mfr>
	<serving units="g">104</serving>
	<calories total="300" fat="35"/>
	<total-fat>4</total-fat>
	<saturated-fat>1</saturated-fat>
	<cholesterol>0</cholesterol>
	<sodium>510</sodium>
	<carb>54</carb>
	<fiber>3</fiber>
	<protein>11</protein>
	<vitamins>
		<a>0</a>
		<c>0</c>
	</vitamins>
	<minerals>
		<ca>8</ca>
		<fe>20</fe>
	</minerals>
</food>

<food>
	<name>Beef Frankfurter, Quarter Pound </name>
	<mfr>Armitage</mfr>
	<serving units="g">115</serving>
	<calories total="370" fat="290"/>
	<total-fat>32</total-fat>
	<saturated-fat>15</saturated-fat>
	<cholesterol>65</cholesterol>
	<sodium>1100</sodium>
	<carb>8</carb>
	<fiber>0</fiber>
	<protein>13</protein>
	<vitamins>
		<a>0</a>
		<c>2</c>
	</vitamins>
	<minerals>
		<ca>1</ca>
		<fe>6</fe>
	</minerals>
</food>

<food>
	<name>Chicken Pot Pie</name>
	<mfr>Lakeson</mfr>
	<serving units="g">198</serving>
	<calories total="410" fat="200"/>
	<total-fat>22</total-fat>
	<saturated-fat>9</saturated-fat>
	<cholesterol>25</cholesterol>
	<sodium>810</sodium>
	<carb>42</carb>
	<fiber>2</fiber>
	<protein>10</protein>
	<vitamins>
		<a>20</a>
		<c>2</c>
	</vitamins>
	<minerals>
		<ca>2</ca>
		<fe>10</fe>
	</minerals>
</food>

<food>
	<name>Cole Slaw</name>
	<mfr>Fresh Quick</mfr>
	<serving units=" cup">1.5</serving>
	<calories total="20" fat="0"/>
	<total-fat>0</total-fat>
	<saturated-fat>0</saturated-fat>
	<cholesterol>0</cholesterol>
	<sodium>15</sodium>
	<carb>5</carb>
	<fiber>2</fiber>
	<protein>1</protein>
	<vitamins>
		<a>30</a>
		<c>45</c>
	</vitamins>
	<minerals>
		<ca>4</ca>
		<fe>2</fe>
	</minerals>
</food>

<food>
	<name>Eggs</name>
	<mfr>Goodpath</mfr>
	<serving units="g">50</serving>
	<calories total="70" fat="40"/>
	<total-fat>4.5</total-fat>
	<saturated-fat>1.5</saturated-fat>
	<cholesterol>215</cholesterol>
	<sodium>65</sodium>
	<carb>1</carb>
	<fiber>0</fiber>
	<protein>6</protein>
	<vitamins>
		<a>6</a>
		<c>0</c>
	</vitamins>
	<minerals>
		<ca>2</ca>
		<fe>4</fe>
	</minerals>
</food>

<food>
	<name>Hazelnut Spread</name>
	<mfr>Ferreira</mfr>
	<serving units="tbsp">2</serving>
	<calories total="200" fat="90"/>
	<total-fat>10</total-fat>
	<saturated-fat>2</saturated-fat>
	<cholesterol>0</cholesterol>
	<sodium>20</sodium>
	<carb>23</carb>
	<fiber>2</fiber>
	<protein>3</protein>
	<vitamins>
		<a>0</a>
		<c>0</c>
	</vitamins>
	<minerals>
		<ca>6</ca>
		<fe>4</fe>
	</minerals>
</food>

<food>
	<name>Potato Chips</name>
	<mfr>Lees</mfr>
	<serving units="g">28</serving>
	<calories total="150" fat="90"/>
	<total-fat>10</total-fat>
	<saturated-fat>3</saturated-fat>
	<cholesterol>0</cholesterol>
	<sodium>180</sodium>
	<carb>15</carb>
	<fiber>1</fiber>
	<protein>2</protein>
	<vitamins>
		<a>0</a>
		<c>10</c>
	</vitamins>
	<minerals>
		<ca>0</ca>
		<fe>0</fe>
	</minerals>
</food>

<food>
	<name>Soy Patties, Grilled</name>
	<mfr>Gardenproducts</mfr>
	<serving units="g">96</serving>
	<calories total="160" fat="45"/>
	<total-fat>5</total-fat>
	<saturated-fat>0</saturated-fat>
	<cholesterol>0</cholesterol>
	<sodium>420</sodium>
	<carb>10</carb>
	<fiber>4</fiber>
	<protein>9</protein>
	<vitamins>
		<a>0</a>
		<c>0</c>
	</vitamins>
	<minerals>
		<ca>0</ca>
		<fe>0</fe>
	</minerals>
</food>

<food>
	<name>Truffles, Dark Chocolate</name>
	<mfr>Lyndon's</mfr>
	<serving units="g">39</serving>
	<calories total="220" fat="170"/>
	<total-fat>19</total-fat>
	<saturated-fat>14</saturated-fat>
	<cholesterol>25</cholesterol>
	<sodium>10</sodium>
	<carb>16</carb>
	<fiber>1</fiber>
	<protein>1</protein>
	<vitamins>
		<a>0</a>
		<c>0</c>
	</vitamins>
	<minerals>
		<ca>0</ca>
		<fe>0</fe>
	</minerals>
</food>

</nutrition>
<html>
	<head>
		<script type="text/javascript" src="js/jquery.js"></script>
		<script type="text/javascript">
		$(document).ready(function(){
			var loadUrl = "ajax/loadxml.php";
			$("#load_basic").click(function(){
				$.ajax({
					  url: loadUrl,
					  dataType: 'xml',
					  data: '',
					  success: function(xml) {
						  $(xml).find('food').each(function(){
							  var name = $(this).find('name').text();
							  $("#result").append("<br />"+name);
						  });
					  }
					});
			});
		});
		</script>

		<title>Javascript sample</title>
	</head>
	<body>
		<p id="load_basic">Click me!</p>
		<p id="result">Stuff goes here</p>
	</body>

</html> 
			

Try it out: [link]

XML has started to fall out of favor in many website API's in favor of JSON. The jQuery web site shows how to do JSON queries.

Chapter 14: Uploading Files

See:
The 'file' type of form input field.
The MAX_FILE_SIZE hidden input field for PHP uploads.
Multi-part and other PHP file upload considerations.

<!DOCTYPE html>

<html>
<head>
  <title>Upload Document Example</title>
</head>

<body>
  <!-- Multi-part form. Part of the form will be the form data
  part will be the file. -->
  <form enctype="multipart/form-data" action="upload_process.php" method="post">
    <!-- Note: Users can easily over-ride the value for max file size. 
    Don't depend on this. 
    For PHP this must proceed a 'file' upload type.
    -->
    <input type="hidden" name="MAX_FILE_SIZE" value="100000"> Select file to upload:
    <input type="file" name="uploadedfile" ><br>
    <input type="submit" value="Upload File">
  </form>
</body>
</html>
<html><body><pre>
<?php
/*
PHP automatically uploads the files into a temporary
directory. If you want to keep the file you need to
move it to a new home.

This is the directory where the file will be moved.
It needs to already exist. In this case, inside the php
folder. The web server process also needs permission to
write to the folder.

The folder should have a limit separate from the entire
computer. If someone uploads many large files, you want
the directory to fill, but not the entire drive on the
computer which would cause the entire website to fail.
*/

$target_path = "uploads/";

/* Add the original filename to our target path.
Result is "uploads/filename.extension"

$_FILES is a built-in array that holds info about files.
'uploadedfile' comes from the name of the field in our form.
'name' is a built-in key for the file that contains
the original file name path.

In my experience, it does not usually have the whole path,
but it could. So we strip the path into off and just
get the name with the built in php function 'basename'
*/
$target_path = $target_path.basename( $_FILES['uploadedfile']['name']);

if ($_FILES["uploadedfile"]["error"] > 0)
{
  if ($_FILES["uploadedfile"]["error"] == 2)
	echo "Uploaded file was too large.<br />";
  else
    echo "Error: " . $_FILES["uploadedfile"]["error"] . "<br />";
}
else
{
  echo "Upload:    " . $_FILES["uploadedfile"]["name"] . "<br />";
  echo "Type:      " . $_FILES["uploadedfile"]["type"] . "<br />";
  echo "Size:      " . ($_FILES["uploadedfile"]["size"] / 1024) . " Kb<br />";
  echo "Stored in: " . $_FILES["uploadedfile"]["tmp_name"] . "<br />";
}
  

/* move_uploaded_file is a built-in php function. */
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
  echo "The file ".basename( $_FILES['uploadedfile']['name'])." has been uploaded";
} else{
  echo "There was an error uploading the file, please try again!";
}
?>
</pre></body></html>

Try it out: [link]

Chapter 15: PHP Command Line

15.1 Setup PHP for the command line

By default, you can run PHP from the command line in most UNIX setups. Unfortunately, by default, windows installs of php don't usually get set up for the command prompt. It is necessary to add the php.exe to the command line. Here is a lot of information on running PHP via the command line:
http://php.net/manual/en/install.windows.commandline.php

Note that our PHP install is in a different directory than the above page assumes.

Many of these commands require proper permission to execute, and there may be a problem on lab computers getting them to work.

A very useful function to use in PHP scripts: file_get_contents. This command can put the contents of a file, or even a document fetched over HTTP into a variable.

However, having everything in one variable is a bit inconvenient. It will be easier to process if the file contents are split into an array, with each array location being a different line in the file. This can be done with the explode command.

15.2 Example, fetching weather data:

<?php
# This is a PHP script. It is designed to be run from the command line.
# It is possible to include this in a web page script. Remember though, the user
# will wait for your web page, which will wait for kcci's web page. It
# is a slow process. Plus, it decreases reliability because you now have
# more things that could go wrong.

# Print that we are fetching a page
print "Fetching page\n";

# Fetch the page
$contents = file_get_contents('http://www.schoolnet8.com/cc.phtml');

# Rather than 1 chunk of text, split the text apart into an array based on line feeds
$contents_array = explode("\n",$contents);

# For each line in the file:
foreach($contents_array as $line) {

	# Run this regular exression.
	if (preg_match("/([A-Za-z ]*)<\/a><\/th><td >([0-9: APM]*)<\/td><td>([0-9]*)/", $line, $matches)) {
		# Ok, the regular expression matched.
		# Array 0 of $matches will have the whole match
		# Array 1 the first parenthesized match, Array 2 the second, etc.
		echo "$matches[1]\n";
		echo " Time: $matches[2]\n";
		echo " Temp: $matches[3]\n";
	}
}
# We are done.
echo "\nDone fetching page.";
?>

Wait, should we even be using regex here? Read this article and then this article.

The proper way to do this is actually parse the HTML. HTML parsers are build into PHP so this is easy. Use the domDocument class to parse and access the HTML document.

<?php
# This is a PHP script. It is designed to be run from the command line.
# It is possible to include this in a web page script. Remember though, the user
# will wait for your web page, which will wait for kcci's web page. It
# is a slow process. Plus, it decreases reliability because you now have
# more things that could go wrong.

# Print that we are fetcing a page
print "Fetching page\n";

# Fetch the page
$contents = file_get_contents('http://www.schoolnet8.com/cc.phtml');

# Create a new Document Object Model DOM
$dom = new domDocument;

# Load HTML into the DOM
$dom->loadHTML($contents);

# Get rid of excess whitespace
$dom->preserveWhiteSpace = false;

# Get the table object
$tables = $dom->getElementsByTagName('table');

# Get all rows from the table
$rows = $tables->item(0)->getElementsByTagName('tr');

# Loop each row
foreach ($rows as $row)
{
	# Get each column marked by <td>
	$cols = $row->getElementsByTagName('td');

	# The city is marked by a table header <td> tag. Get that.
	$headers = $row->getElementsByTagName('th');

	# Print out what we got
	echo $headers->item(0)->nodeValue;
	echo ' '.$cols->item(0)->nodeValue;
	echo "\n";
	echo ' '.$cols->item(1)->nodeValue;
	echo "\n";
	echo ' '.$cols->item(2)->nodeValue;
	echo "\n";
}
echo "\nDone fetching page";
?>

15.3 Setting up scheduled tasks

Setting up scheduled tasks

There are many ways to set up scheduled tasks. Two popular ways:

UNIX: Use a cron job.

Windows: Use a scheduled task.

Chapter 16: Version Control

Placeholder for a discussion on version control systems and how to use SVN with the campus network.

Chapter 17: Usability

Placeholder for lecture over material contained in the book Don't Make Me Think by Steve Krug.

Chapter 18: Final Project

For your final project -- create your own website. Your website will be graded on the following categories:

HTML/CSS - Demonstrate an ability to use HTML/CSS to present web pages. Consider the style and aesthetics of the web page. Make sure there is separation of style information and content.

PHP/Database interaction - Create PHP code that interacts with the database. This could be in the form of a full CRUD application that can display, insert, and delete data. An MVC pattern is recommended. It is ok to use a framework like Yii to generate the code.

JavaScript - Utilize some kind of JavaScript in the website. It is ok to use libraries like jQuery and UI components.

Use a New Library - Use something already created that has not yet been covered in class. JavaScript UI objects, or phpBB, Wordpress, or some other library/application.

Final Presentation - Present your final project during the time scheduled for the class final.