Practical PHP and MySQL Web Site Databases: A Simplified Approach (2013)

Chapter 8. Creating a Product Catalog

You have learned the basics of PHP and MySQL, so now we will create a full database-driven web site, using a product catalog as an example. Most e-commerce web sites incorporate a catalog to display products and services. Some web sites use catalogs to display items that cannot be purchased over the Internet, such as tourist attractions or houses. The tutorial in this chapter uses a real estate agency offering various types of houses in a limited region. Real estate is an excellent example of a web site that has a catalog but buying the product over the Internet is impractical. Sensible buyers will view a property and its location before even considering the purchase.

Because so many people are involved in the purchase and sale of a house, their actions must all be carefully coordinated. The parties involved are the seller, the buyer, the real estate agent, separate lawyers for the buyer and seller, the buyer’s and seller’s banks or mortgage companies, and the buyer’s surveyor. In addition, there will probably be a chain of events involved—for example, the sellers cannot proceed with the transaction until they have found and agreed to buy another house. Similarly, buyers cannot proceed until they have a firm offer on their current house. Therefore, a catalog for a real estate web site is purely a catalog and does not include provisions for financial transactions or personal details.

The sections in this chapter are as follows:

·     Prepare the database and administration plan.

·     Create a new database and table for a real estate agent.

·     Create a home page where users can search for a suitable house.

·     Create a page so that the administrator can view the entire stock of houses or search for and view a specific house.

·     Create pages to give the full specification of each property. To save space, only one page will be provided for this tutorial.

·     Create a page so that the administrator can add new houses.

·     Create an inquiry form for users interested in viewing a house.

Prepare the Database and Administration Plan

After discussing the requirements with the real estate agent’s owner, the follow priorities were agreed upon:

·     The most important page is the search page. This must enable users to quickly find what they are looking for.

·     The top priorities when searching for a house are the following:

·        Location

·        Price

·        Number of bedrooms

·        Type of house

Therefore, the search page would contain fields for those four items.

·     The approximate location of a house will be disclosed, but the street name and house number must not be disclosed. This prevents users from bypassing the real estate agent and going directly to the house owner. It also means that, because no personal details will be recorded in the database, it might not be subject to the territory’s data protection laws.

·     The term “Vacant Possession” will not be used. A house that is empty is a magnet for miscreants.

·     The real estate agent’s photographer will provide each house’s thumbnail image as a .jpg, .gif, or .png file 150 pixels wide with a maximum height of, say, 120 pixels. The photographer also will provide enlarged versions of the photographs for the full specification pages; these will be standardized at, say, 350 pixels wide.

image Caution  A catalog always contains images, but the real estate’s administrator might not be capable of handling them. Also, the administrator might not be capable of placing new images or full specification pages inside the appropriate folder at the remote host using an FTP client. An administrator with no knowledge of HTML, PHP, and CSS would not be capable of producing the pages containing the full specifications of the properties. The solution I adopted is to ask the webmaster to be the administrator. If the webmaster is a member of the real estate agent’s staff, he would be the ideal administrator.

First we need to create the new database.

Create a New Database

In the htdocs folder within the xammp folder, create a new folder called estate.

Download the files for Chapter 8 from the book’s page at www.apress.com, and load them into the new folder estate. To create a new database, follow these steps:

1.    Use a browser to access phpMyAdmin. Type http://localhost/phpmyadmin/ into the address field of the browser. In phpMyAdmin, click the Databases tab and create a new database called estatedb.

2.    In the right pane, scroll down to find the newly created database and select the box alongside it.

3.    Click Check Privileges. Then click Add User, and add a new user and password as follows:

1.    User name: smeeton

2.    Password: Lighthouse

4.    Scroll down to the item named Global Privileges, and click Check All. Scroll to the bottom, and click Add User (or Go in some versions)to save the user’s details.

Create the File for Connecting to the Database

Name the file mysqli_connect.php. If you are using the download files, this file is already created for you and can be found in the folder named estate.

<?php
// Create a connection to the estatedb database and set the encoding to utf-8
DEFINE ('DB_USER', 'smeeton');
DEFINE ('DB_PASSWORD', 'Lighthouse');
DEFINE ('DB_HOST', 'localhost');
DEFINE ('DB_NAME', 'estatedb');
// Make the connection
$dbcon = @mysqli_connect (DB_HOST, DB_USER, DB_PASSWORD, DB_NAME) OR die image
('Could not connect to MySQL: ' . mysqli_connect_error() );
// Set the encoding
mysqli_set_charset($dbcon, 'utf8');
?>

We will assume two types of user: (i) persons viewing the web site, and (ii) the webmaster, who will maintain and update the catalog table and also use FTP to upload the images and full specification pages to the host.

I already compiled the catalog table for you and exported it into a populated file called houses.sql. You will find this among the downloaded files you just installed in the folder estate. You can import it using phpMyAdmin or compile the table manually as follows:

·     In phpMyAdmin, open the database estatedb.

·     In the home page of phpMyAdmin, click the database estatedb, and then create a table called houses with nine columns as follows:

Table 8-1. The attributes for the houses database table

image

The house reference number will be used by viewers when they inquire about a property. The column type MEDIUMINT (when unsigned) allows integers from 0 to 65,535.

TINYTEXT allows up to 255 characters.

DECIMAL allows prices up to the limit set by the first figure shown in the table. The second figure indicates the number of decimal places. The size 9,2 means that when entering nine figures, such as 123456789, the recorded result will be 1234567.89.

The thumbnail thumb holds the URL of an image—for example, images/house_01.jpg. I allowed 45 characters in the thumbnail image column because the file names for thumbnails are often long—for instance, images/bungalow_South_Devon_150px.png.

The full_spec column will contain the URL link for each house’s HTML page, which contains a full description and an enlarged image of the property.

The status column indicates whether the house is available, under offer, withdrawn from the market, or sold.

Security

As previously described, an unskilled administrator would not be able to cope with the preparation of images and might not be capable of using an FTP program to place new images or full-specification pages inside the appropriate folder at the remote host. An administrator with no knowledge of HTML, PHP, and CSS would not be capable of producing the pages containing the full specifications of the properties. Because these tasks must be performed by the webmaster, the webmaster will be the administrator. This approach eliminates a real security risk and reduces the number of special pages for administering the site. For instance, pages for editing and deleting houses would have been a security risk; instead, the webmaster can use phpMyAdmin. He is the approved user for the houses database, and no other person can access phpMyAdmin.

Based on his decisions, the required pages will be as follows:

·     The home page that doubles as a search page for the user (index.php).

·     The search results page for displaying the houses selected by the user’s search criteria.

·     Full-specification pages, one for each house. The user accesses these by clicking a link on the page for displaying the selected category of house.

·     The Contact Us page for user inquiries.

·     An administration page so that the webmaster can conveniently view the whole stock of houses.

·     An administration page so that the webmaster can search for and view a specific house.

·     An administration page so that the webmaster can add new houses. Only the webmaster knows the URL for this page, and it is not accessible from the web site.

None of the preceding pages allow the list of houses to be edited or deleted, the administrator uses phpMyAdmin to edit and delete houses. We now need to create a home page for the real estate web site.

Creating a Home Page with Search Capability

The home page is shown in Figure 8-1.

image

Figure 8-1. The home page for a real estate web site

In this tutorial, the background of the home page (and all the other pages) is a vertical gradient and the main content panel is transparent so that the gradient is visible within the panel. A gradient can be created using CSS3, but this will not work with Internet Explorer 8 (IE8). Because that browser will be around for a few years yet, I chose to use a 3-pixel-wide gradient that is repeated horizontally across the page. All the previous chapters used HTML5, but for the sake of simplicity I did not use semantic tags in those chapters, (semantic tags will not work with IE8). In this chapter, I will use semantic HTML5 tags with a JavaScript workaround for IE8. When IE8 is eventually replaced by newer versions, the JavaScript workaround can be dispensed with.

image Tip  If you would like to learn more about enhancing the appearance, accessibility, and usefulness of a web site, try my book Practical HTML5 Projects (Apress, 2012).

The home page has four pull-down menus to eliminate user-input errors and ensure that only acceptable data is entered into the database table. To save space, the database in this tutorial is simplified by restricting the choices in these pull-down menus. British prices and terminology are used in the menus. In the USA, you use some different terminology—for instance, the term semi-detached might be replaced by side-by-side-duplex. In the UK, a bungalow is a single-story building, whereas a house has two or more stories.

Although I limited the drop-down choices severely to save both space and code, a real-world house catalog would adopt the same principle but use a more extensive choice of location, price, and type of house.

In the body of the home page, the code for the main menu (menu.inc) is given in the following snippet:

<ul>
   <li><a href="about.php" title="About Us">About Us</a></li>
   <li><a href="faqs.php" title="Frequently Asked Questions">FAQs</a></li>
   <li><a href="contact.php" title="Contact Us">Contact Us</a></li>
   <li><a href="index.php" title="Return to Home Page">Home Page</a></li>
</ul>

In the downloadable menu file, the About Us and FAQs links are dead because no target pages have been made available for those two links in this tutorial.

We will now examine the header for the home page and the majority of the web pages.

The Header for the Majority of the Pages

The general header in this tutorial is not a separate included file; it is part of the HTML of the pages. The following extract from the HTML in the home page (index.php) shows in bold type how it fits between the container div and the content div. The background, border, and positioning of the text and rosette are set by the transparent.css style sheet.

<div id="container">
<header>
<h1>Devon Real Estate</h1>
<h2>Try our award-winning service</h2>
<img id="rosette" alt="Rosette" title="Rosette" height="127"
src="images/rosette-128.png" width="128">
</header>

<div id="content">

The main style sheet formats the header and provides the background image.

image Note  In the two previous chapters, we used sticky pull-down lists but the pages did not validate. In the code shown in Listing 8-1a, a sticky form is not used for the pull-down lists. However, with most modern browsers, the user’s entries will remain in the fields if the browser’s back button is clicked, thus creating the equivalent of a sticky form.

The Home Page Code

We must now examine the home page, which also doubles as a search page.

Listing 8-1a.  Creating the Home Page (index.php)

I used an internal style in addition to the main style sheet because some features are unique to the home page.

<!doctype html>
<html lang=en>
<head>
<title>Real estate home page.</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="transparent.css">
<!--[if lte IE 8]>
<link rel="stylesheet" type="text/css" href="ie8.css">
<![endif]-->
<style type="text/css">
#leftcol h3 { margin-bottom:-10px; }
#midcol h3 { margin-top:-10px; }
.black { color:black; }
form { margin-left:15px; font-weight:bold; color:black; }
select { margin-bottom:5px; }
h3 { font-size:130%; }
</style>
<!--Add conditional JavaScript for IE8-->
<!--[if lte IE 8]>
<script src="html5.js">
</script>
<![endif]-->
</head>
<body>
<div id="container">
<header>
<h1>Devon Real Estate</h1>
<h2>Try our award-winning service</h2>
<img id="rosette" alt="Rosette" title="Rosette" height="127"
src="images/rosette-128.png" width="128">
</header>
<div id="content">
<div id="leftcol">
<h3>Search for your dream house</h3><br><span class="black"><strong>IMPORTANT: You must image
select an item in<br>ALL the fields, otherwise the search will fail.</strong></span><br>
<form action="found_houses.php" method="post">
Location<br>
<select name="loctn">
   <option value="">- Select -</option>
   <option value="South_Devon">South Devon</option>
   <option value="Mid_Devon">Mid Devon</option>
   <option value="North_Devon">North Devon</option>
   </select><br>
Maximum Price<br>
   <select name="price">
   <option value="">- Select -</option>
   <option value="200000">£200,000</option>
   <option value="300000">£300,000</option>
   <option value="400000">£400,000</option>
   </select><br>
Type<br>
   <select name="type">
   <option value="">- Select -</option>
   <option value="Det-bung">Detached Bungalow</option>
   <option value="Semi-det-bung">Semi-detached Bungalow</option>
   <option value="Det-house">Detached House</option>
   <option value="Semi-det-house">Semi-detached House</option>
   </select><br>
Number of Bedrooms<br>
<select name="b_rooms">
   <option value="">- Select -</option>
   <option value="2">2</option>
   <option value="3">3</option>
   <option value="4">4</option>
</select>
<p><input id="submit" type="submit" name="submit" value="Search"></p>
</form></div>
<div id="rightcol">
<nav>
<?php include('includes/menu.inc'); ?>
</nav>
</div><!--end of side menu column-->
<div id="midcol">
<h3>All houses are situated in the beautiful green<br>rolling countryside of Devon, image
England, UK</h3>
<img alt="SW England" height="238" src="images/devon-map-crop.jpg" width="345">
</div>
<br class="clear">
</div><!--End of page content-->
<footer>footer goes here
</footer>
</div>
</body>
</html>

The main style sheet is shown next in Listing 8-1b.

Listing 8-1b.  Creating the Main Style Sheet for the Web Site Pages (transparent.css)

/*equalize all the margins, paddings and borders built into various browsers*/
div body #header #content { margin:0; padding:0; border:0; }
body { background:#FFF url(images/green-grad-800.jpg) repeat-x;}
/*add the display attribute for the semantic tags*/
header, footer, section, article, nav { display:block; }
header {width:920px; height:180px; padding:0; border:10px white solid; image
position:relative; background: url(images/header3.jpg); background-repeat:no-repeat; image
margin:10px auto; }
#header-button ul { position:absolute; top:30px; right:-80px; font-size:medium; width:160px; }
h1 { font-size:300%; color :white; position: relative; left:90px; top: 25px; width:480px; }
h2 { position:relative; left:425px; }
#rosette { position:relative; left:750px; top:-75px; }
#container { width:984px; margin:auto; }
#content { background-color:transparent; border-left:10px white solid; image
border-right:10px white solid; border-bottom:10px white solid; width: 904px; image
margin-top:-10px; margin-left:auto; margin-right:auto; padding:8px; font-size:medium; }
h2 { font-size:x-large; color:white; margin:0 0 10px 0; }
h3 { font-size:large; color:white; margin:0 0 6px 0; }
#leftcol { float:left; width: 310px; vertical-align:top; }
#rightcol { width: 135px; float:right; height: 252px; margin-right:10px; }
#midcol { margin-left:15px; margin-right:145px; margin-top:10px; vertical-align:top; }
/* set side menu block position and width*/
nav, #header-button { margin:10px 30px 0 10px; width:135px; float:right; }
/*Set list style within the menu block only. This removes bullets*/
nav li, #header-button li { list-style-type:none; }
/* set general side button styles */
nav li, #header-button li {  margin-bottom: 3px; text-align: center; width:130px; }
/* Set general anchor styles */
nav li a, #header-button li a {  display: block; color: white; font-weight: bold; image
text-decoration: none; }
/* Specify mouse state styles */
/* mouseout (default) */
nav li a, #header-button li a {  background:#559a55; color: white; image
border: 5px outset #559a55; padding-bottom:3px; }
/* mouseover */
nav li a:hover, #header-button li a:hover { background: red; color:white; image
border: 5px outset red; }
/*mouse active*/
nav li a:active { background:maroon;  border: 5px inset maroon; }
#header-button { position:absolute; top:-35px; left:710px; }
#midcol img { margin-left:10px;  }
footer { clear:both; color:black; text-align:center; margin:auto; }
#loginfields { display:block; margin-left:50px; }
#ftr { margin:auto; text-align:center; }
br.clear { clear:both;  }
#midcol img { margin-left:10px; }
footer { clear:both; color:black; margin:auto; text-align:center; }
table tr td { background-color:#FFFFFF; text-align:center; border: 1px black solid; image
border-collapse:collapse;}

The Conditional Style Sheet for Internet Explorer 8

A conditional style sheet is necessary to display the page correctly in IE8. The code for the conditional style sheet is given in Listing 8-1c.

Listing 8-1c.  Creating the Conditional Style Sheet for the IE8 Web Site Pages (ie8.css)

/*add display attributes for the semantic tags*/
header, footer, section, article, nav { display:block; }
header {width:920px; height:160px; padding:0; border:10px white solid;
background: url(images/header3.jpg); background-repeat:no-repeat; margin:10px auto; }
h1 { font-size:300%; color :white; position: relative; left:90px; top: 60px; width:480px; }
h2 { position:relative; left:425px; top:50px; }
#rosette { position:relative; left:750px; top:-25px; }
/* set menu block position and width*/
nav { margin:20px 30px 0 -30px; width:135px; float:right; }
#header-button { position:absolute; top:-25px; left:710px; }

Displaying the Catalog

After the user enters the search criteria into the home page fields (index.php as shown in Figure 8-1), clicking the Search button will reveal the selected houses as shown in Figure 8-2.

image

Figure 8-2. The houses selected by the search criteria are displayed

The search criteria resulting in the display shown in Figure 8-2 were as follows:

Location: South Devon

Max Price: £400,000

Type: Detached house

Bedrooms: 4

image Caution  To save space and avoid having to compile dozens of PHP pages for this book, all the Details links in the downloadable files are deliberately disabled except for the first one shown in Figure 8-2. When a Details link is clicked, the user will be directed to a page showing an enlarged image and a full specification of the house. The Details page is described and shown later in this chapter. (See Figure 8-10.)

The code for displaying the found houses is given in Listing 8-2.

Listing 8-2.  Creating the Results Page (found_houses.php)

The main menu is removed so that the table can span the width of the page. To enable the user to return to the home page, a Home Page button has been added to the header.

<!doctype html>
<html lang=en>
<head>
<title>The found_houses page</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="transparent.css">
<!--Add conditional JavaScript for IE8-->                                                #1
<!--[if lte IE 8]><script src="html5.js">
</script>
<![endif]-->
<!--[if lte IE 8]>
<link rel="stylesheet" type="text/css" href="ie8_admin.css">
<![endif]-->
<style type="text/css">
p{ text-align:center; }
table, td, th { width:900px; border-collapse:collapse; border:1px black solid; image
 background:white;}
td, th { padding-left:5px; padding-right:0; text-align:center; }
#content h3 { text-align:center; font-size:130%; font-weight:bold; }
img { display:block; }                                                                   #2
#header-button { margin-top:-5px; }
</style>
</head>
<body>
<div id="container">
<header>
<?php include("includes/header_found_houses.inc"); ?>
<img id="rosette" alt="Rosette" title="Rosette" height="127"
src="images/rosette-128.png" width="128">
</header>
<div id="content"><!--Start of table display content-->
<h3>To arrange a viewing please use the the Contact Us button on the menu and<br> image
quote the reference number</h3>
<p>
<?php
$loctn=$_POST['loctn'];                                                                  #3
$price=$_POST['price'];
$type=$_POST['type'];
$b_rooms=$_POST['b_rooms'];
// This code retrieves all the records from the houses table
require ('mysqli_connect.php'); // Connect to the database
// Make the query
$q = "SELECT ref_num, loctn, thumb, price, mini_descr, type, b_rooms, full_spec, image      #4
status FROM houses WHERE loctn='$loctn' AND (price <= '$price') AND image
(price >= ('$price'-100000)) AND type='$type' AND b_rooms='$b_rooms' ORDER BY image
ref_num ASC ";
$result = @mysqli_query ($dbcon, $q); // Run the query
if ($result) { // If the query ran OK, display the records
// Table header
echo '<table>
<tr>
<th><b>Ref.</b></th>
<th><b>Location</b></td>
<th><b>Thumb</b></th>
<th><b>Price</b></th>
<th><b>Features</b></th>
<th><b>Bedrms</b></th>
<th><b>Details</b></th>
<th><b>Status</b></th>
</tr>';
// Fetch and print the records
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
    echo '<tr>
    <td>' . $row['ref_num'] . '</td>
    <td>' . $row['loctn'] . '</td>
    <td>  <img src='.$row['thumb'] . '></td>
    <td>' . $row['price'] . '</td>
    <td>' . $row['mini_descr'] . '</td>
    <td>' . $row['b_rooms'] . '</td>
    <td>' . $row['full_spec'] . '</td>
    <td>' . $row['status'] . '</td>
    </tr>';
    }
    echo '</table>'; // Close the table
    mysqli_free_result ($result); // Free up the resources
} else { // If it did not run OK
// Message
echo '<p class="error">The record could not be retrieved. We apologize for any image
inconvenience.</p>';
// Debugging error message
    echo '<p>' . mysqli_error($dbcon) . '<br><br>Query: ' . $q . '</p>';
} // End of if ($result). Now display the total number of records/houses
$q = "SELECT COUNT(ref_num) FROM houses";
$result = @mysqli_query ($dbcon, $q);
$row = @mysqli_fetch_array ($result, MYSQLI_NUM);
$houses = $row[0];
mysqli_close($dbcon); // Close the database connection
?>
<p>No houses displayed? Either we have nothing that matches your requirements at the image
moment OR<br>you may have forgotten to select ALL the search fields. Please click image
the Home Page button and try again.</p>
</div><!--End of table display content-->
<?php include("includes/footer.inc"); ?>
</div>
</body>
</html>

Explanation of the Code

<link rel="stylesheet" type="text/css" href="transparent.css">
<!--Add conditional JavaScript for IE8-->                                                #1
<!--[if lte IE 8]><script src="html5.js">
</script>
<![endif]-->
<!--[if lte IE 8]>

The JavaScript enables Internet Explorer 8 to see HTML5 semantic tags. The JavaScript file is assumed to be in the same folder as the web-site pages. This block of conditional code must be the last item within the <head></head> section. The free JavaScript file was devised by Remy Sharp, and it is included in the downloadable files for this chapter. The file will work only if the <body></body> tags are included in the HTML page, even though HTML will function without the <body> tags.

img { display:block; }                                                                   #2

This little trick removes the unsightly white space beneath an image that is located in a table cell.

$loctn=$_POST['loctn'];                                                                  #3
$price=$_POST['price'];
$type=$_POST['type'];
$b_rooms=$_POST['b_rooms'];

The entries provided by the pull-down menus are assigned to variables.

// This script retrieves all the records from the houses table
require ('mysqli_connect.php'); // Connect to the database
// Make the query
$q = "SELECT ref_num, loctn, thumb, price, mini_descr, type, b_rooms, image                 #4
full_spec, status FROM houses WHERE loctn='$loctn' AND (price <= '$price') image
AND (price >= ('$price'-100000)) AND type='$type' AND b_rooms='$b_rooms' image
ORDER BY ref_num ASC ";

By now, you understand most of this query, but the price needs some explanation. The statement is as follows:

(price <= '$price') AND (price >= ('$price'-100000)

If the price was simply <= '$price', a search using a maximum price £400,000 would display every house valued at £400,000 or less. People looking for a house with maximum price of £400,000 would not be interested in houses at say £280,00 or £120,000. Therefore, the statement

    AND (price >= ('$price'-100000)

is used to give a minimum price that is £100,000 below the searcher’s maximum. The display is ordered by ascending reference numbers; however, you could change this to order it by price in descending order.

The Header for the Page of Search Results

The header is shown in Figure 8-3.

image

Figure 8-3. One of the two buttons is a ContactUs button so that the user can request an appointment to view the house

The code for the header is given in Listing 8-3.

Listing 8-3.  Creating the Search Result Header (header_found_houses.inc)

<div id="header-button">
   <ul>
     <li><a href="contact.php">Contact Us</a></li>
     <li><a href="index.php">Home Page</a></li>
   </ul>
</div>
<h1>Devon Real Estate</h1>
<h2>Try our award-winning service</h2>

Adding houses in phpMyAdmin can be rather tedious, so we will allow the user to add houses by means of a web page known only to the webmaster. The page is not accessible via the web site.

Creating the Admin/Add a House Page

The administrator’s page is shown in Figure 8-4a.

image

Figure 8-4a. The admin and add-a-house page

Figure 8-4a shows the administrator’s page (admin_page.php) that also acts as a page for adding new houses to the houses table in the database.

Let’s examine the elements on the administrator’s page. The page contains four pull-down menus, three of them are replicas of the pull downs in the index php page; these are location, type, and the number of bedrooms. The status menu is the fourth pull-down menu and is used to inform the user whether the house is available, under offer, or already sold. The price field is not a pull-down because house values are rarely set at precisely £400,000 or £300,000, or £200,000.

Concerning the status, you might wonder why we would enter Sold. Why not delete the house from the database if it is sold? Real estate agents do this for two reasons:

1.    Prospective buyers might have used the site at some earlier date and were attracted by a particular house. Later, when they see that the house is sold, they would have no need to contact the agent to see if it still on the market.

2.    If prospective vendors see several sold houses listed on the web site, they will be confident that the agent is actively selling houses.

The administrator will use phpMyAdmin to delete sold houses after a suitable time interval.

Assuming that the images are in a folder named images, the URL for the thumbnail image must be entered by the administrator in the following format:

   images/house06.gif

The price must be entered (without currency symbols) in this format: 300000

The URL for the full-specification pages must be entered in the following format:

   <a href='spec_1003.php'>Details</a>

I used the house’s reference number for convenience (in this example, it was 1003), but you can choose any full-specification page name to suit yourself. I prefer to keep the full-specification pages within a special folder. (I used a folder named descriptions in this tutorial.) I then entered the URL in the admin page’s URL for a full description field as follows:

   <a href='descriptions/spec_1003.php'>Details</a>

The fields are filled out by the administrator, and when he clicks the Add button, the details are inserted into the houses table in the database. A confirmation message is given as shown in Figure 8-4b.

image

Figure 8-4b. Showing the confirmation message

image Note  No filtering or error messages are included in the listings in order to simplify the code and to make the general principles stand out clearly. The pull-down menus remove most of the risks. In a real-world situation, the administrator’s page might be protected by either a login system using sessions or a password. Because the page is not accessible via the web site, it is reasonably secure anyway. It could even be located outside the htdocs folder. Only the administrator would be allowed to know the URL for his page. In addition, the web site’s database holds no personal or financial details; therefore, it is most unlikely to tempt hackers. Having said that, an unscrupulous rival real estate office might be tempted to interfere with the site.

The code for the administrator’s page is given in Listing 8-4.

Listing 8-4.  Creating the Administator’s Page (admin_page.php)

<!doctype html>
<html lang=en>
<head>
<title>Admin page</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="transparent.css">
<link rel="stylesheet" type="text/css" href="admin_form.css">
<style type="text/css">
p.error { color:red; font-size:105%; font-weight:bold; text-align:center;}
</style>
</head>
<body>
<div id="container">
<header>
<?php include('includes/header_admin.inc'); ?>
</header>
   <div id="content"><!--Start of admin page content-->
<?php
// This code is a query that INSERTs a house into the houses table
// Check that the form has been submitted
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
   $errors = array(); // Initialize an error array
// Check for location
   if (empty($_POST['loctn'])) {
     $errors[] = 'You forgot to select the location';
     } else {
         $loctn = trim($_POST['loctn']);
     }
// Has a price been entered?
if (empty($_POST['price'])){
$errors[] ='You forgot to enter the price.' ;
}
elseif (!empty($_POST['price'])) {
//Remove unwanted characters
//Use regex to ensure that the remaining characters are digits
$price = preg_replace('/\D+/', '', ($_POST['price']));
}
// Check for a type
   if (empty($_POST['type'])) {
   $errors[] = 'You forgot to select the type of house.';
   } else {
   $type = trim($_POST['type']);
   }
// Check for brief description
   if (empty($_POST['mini_descr'])) {
   $errors[] = 'You forgot to enter the brief description';
    } else {
$mini_descr = strip_tags(($_POST['mini_descr']));
   }
// Check for number of bedrooms
   if (empty($_POST['b_rooms'])) {
   $errors[] = 'You forgot to select the number of bedrooms';
   } else {
   $b_rooms = ($_POST['b_rooms']);
   }
// Check if a thumbnail url has been entered
   if (empty($_POST['thumb'])) {
   $errors[] = 'You forgot to enter the thumbnail url';
   } else {
   $thumb = ($_POST['thumb']);
   }
// Check for the status of the house
   if (empty($_POST['status'])) {
   $errors[] = 'You forgot to select the status of the house';
   } else {
   $status = ($_POST['status']);
   }
if (empty($errors)) { // If the query ran OK
// Register the house in the database
   require ('mysqli_connect.php'); // Connect to the database
// Make the query
$q = "INSERT INTO houses (ref_num, loctn, price, type, mini_descr, b_rooms, thumb, image
status) VALUES (' ', '$loctn', '$price', '$type', '$mini_descr', '$b_rooms', '$thumb', image
'$status' )";
   $result = @mysqli_query ($dbcon, $q); // Make the query
   if ($result) { // If the query ran OK
   echo '<h2>The house was successfully registered</h2><br>';
   } else { // If it did not run OK
   // Error message
   echo '<h2>System Error</h2>
<p class="error">The house could not be added due to a system error. We apologize image
for any inconvenience.</p>';
// Debugging message
   echo '<p>' . mysqli_error($dbcon) . '<br><br>Query: ' . $q . '</p>';
   } // End of if ($result)
   mysqli_close($dbcon); // Close the database connection
   } else { // Report the errors
   echo '<h2>Error!</h2>
   <p class="error">The following error(s) occurred:<br>';
   foreach ($errors as $msg) { // display each error
   echo " - $msg<br>\n";
   }
   echo '</p><h3>Please try again.</h3><p><br></p>';
   }// End of if (empty($errors))
} // End of the main Submit conditionals
?>
<div id="rightcol">
<nav>
<?php include('includes/menu.inc'); ?>
</nav>
</div>
<h2>Add a House</h2>
<form  action="admin_page.php" method="post">
<p><label class="label"><b>Location:</b></label>
<select name="loctn" >
   <option value="">- Select -</option>
   <option value="South_Devon">South Devon</option>
   <option value="Mid_Devon">Mid Devon</option>
   <option value="North_Devon">North Devon</option>
</select><br>
<p><label class="label" for="price"><b>Price:</b></label><input id="price" image
type="text" name="price" size="9" maxlength="9" image
value="<?php if (isset($_POST['pricee'])) echo $_POST['price']; ?>">
</p>
<p><label class="label"><b>Type:</b></label>
<select name="type" >
   <option value="">- Select -</option>
   <option value="Det-bung">Detached Bungalow</option>
   <option value="Sem-det-bung">Semi-detached Bungalow</option>
   <option value="Det-house">Detached House</option>
   <option value="Semi-det-house">Semi-detached House</option>
</select><br>
<p><label class="label" for="thumb"><b>Thumbnail:</b></label><input id="thumb" image
type="text" name="thumb" size="45" maxlength="45" value="<?php if (isset($_POST['thumb'])) image
echo $_POST['thumb']; ?>"></p>
<p><label class="label"><b>Brief Description:</b></label><textarea name="mini_descr" image
rows="3" cols="40"></textarea></p>
<p><label class="label"><b>Bedrooms:</b></label>
<select name="b_rooms" >
   <option value="">- Select -</option>
   <option value="2">2</option>
   <option value="3">3</option>
   <option value="4">4</option>
   <option value="5">5</option>
   </select><br>
<p><label class="label"><b>URL for Full Description:</b></label><input id="full_spec" image
type="text" name="full_spec" size="60" maxlength="60" image
value="<?php if (isset($_POST['full_spec'])) echo $_POST['full_spec']; ?>">
<p><label class="label"><b>Status:</b></label>
<select name="status" >
   <option value="">- Select -</option>
   <option value="Available">Available</option>
   <option value="Under offer">Under offer</option>
   <option value="Withdrawn">Withdrawn</option>
   <option value="Sold">Sold</option>
   </select></p>
   <div id="submit">
   <p><input id="submit" type="submit" name="submit" value="Add"></p>
   </div>
</form><!--End of the admin page content-->
<div><br class="clear">
</div>
</div>
<div></div></div>
</body>
</html>

image Note  We can be sure that the webmaster/administrator will not be using Internet Explorer 8; therefore, no conditionals for IE8 are included in any of the administrator’s pages.

You will have noticed that the header for the administrator’s page differs from the general header. We will examine this next.

The Header for the Administrator’s Page

The rosette is removed to allow room for more menu buttons in case the administrator needs extra facilities in the future. The buttons now allow the administrator to view the entire stock of houses or to search for one particular house.

The admin page header is shown in Figure 8-5.

image

Figure 8-5. The heading for the administrator’s page

The code for the administrator’s heading is given in Listing 8-5.

Listing 8-5.  Creating the Header for the Administrator’s Page (header_admin.inc)

The header menu needs no other buttons because the main menu is available on the admin page.

<div id="header-button">
   <ul>
   <li><a href="admin_view_houses.php">View Houses</a></li>
   <li><a href="admin_search.php">Search</a></li>
   </ul>
</div>
<h1>Devon Real Estate</h1>
<h2>Try our award-winning service</h2>

Three of the admin pages need two extra buttons because the wide table display fills the content area, leaving no room for the main menu.

The Header with Two Extra Buttons

The two extra buttons are shown in Figure 8-6.

image

Figure 8-6. Showing the two extra menu buttons

The code for the administrator’s header is given in Listing 8-6.

Listing 8-6.  Creating the Header with Two Extra Menu Buttons (header_admin_found.inc)

<div id="header-button">
   <ul>
         <li><a href="admin_view_houses.php">View Houses</a></li>
         <li><a href="admin_search.php">Search</a></li>
         <li><a href="admin_page.php">Add a House</a></li>
         <li><a href="index.php">Home Page</a></li>
   </ul>
</div>
<h1>Devon Real Estate</h1>
<h2>Try our award-winning service</h2>

The administrator can view the entire stock using a paginated display. This is discussed next.

Administrator’s View of the Entire Stock of Houses for Sale

Figure 8-7 shows the first page of the full-stock view.

image

Figure 8-7. One of the pages in a full stock display

The code for displaying the stock of houses is given in Listing 8-7a.

Listing 8-7a.  Creating a Paginated Table of the Entire Stock of Houses (admin_view_houses.php)

The code for the full-stock display uses a table and pagination very similar to those described in previous chapters. Therefore, no explanation of the code will be given.

<!doctype html>
<html lang=en>
<head>
<title>Admin view houses page</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="transparent.css">
<style type="text/css">
p{ text-align:center; }
table { width:860px; border-collapse:collapse; }
td { padding-left:5px; padding-right:5px; }
#content h3 { text-align:center; font-size:130%; font-weight:bold; }
</style>
</head>
<body>
<div id="container">
<header>
<?php include("includes/header_admin_found.inc"); ?>
</header>
<div id="content"><!--Start of table display page-->
<h3>Houses displayed four at-a-time</h3>
<p>
<?php
// This code fetches all the records from the houses table
require ('mysqli_connect.php'); // Connect to the database
//set the number of rows displayed per page
$pagerows = 4;
// Has the total number of pages already been calculated?
if (isset($_GET['p']) && is_numeric
($_GET['p'])) { //already been calculated
$pages=$_GET['p'];
}else{ //use the next block of code to calculate the number of pages
//First, check for the total number of records
$q = "SELECT COUNT(ref_num) FROM houses";
$result = @mysqli_query ($dbcon, $q);
$row = @mysqli_fetch_array ($result, MYSQLI_NUM);
$records = $row[0];
//Now calculate the number of pages
if ($records > $pagerows){ //if the number of records will fill more than one page
//Calculate the number of pages and round the result up to the nearest integer
$pages = ceil ($records/$pagerows);
}else{
$pages = 1;
}
}//page check finished. Declare which record to start with
if (isset($_GET['s']) && is_numeric
($_GET['s'])) { //already been calculated
$start = $_GET['s'];
}else{
$start = 0;
}
// Make the query
$q = "SELECT ref_num, loctn, thumb, price, mini_descr, b_rooms, status FROM houses image
ORDER BY ref_num ASC LIMIT $start, $pagerows";
$result = @mysqli_query ($dbcon, $q); // Run the query
if ($result) { // If the query ran OK, display the records
// Table header
echo '<table>
<tr>
<td><b>Ref-Num</b></td>
<td><b>Location</b></td>
<td><b>Thumb</b></td>
<td><b>Price</b></td>
<td><b>Features</b></td>
<td><b>Bedrms</b></td>
<td><b>Status</b></td>
</tr>';
// Fetch and print all the records
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
   echo '<tr>
   <td>' . $row['ref_num'] . '</td>
   <td>' . $row['loctn'] . '</td>
   <td>  <img src='.$row['thumb'] . '></td>
   <td>' . $row['price'] . '</td>
   <td>' . $row['mini_descr'] . '</td>
   <td>' . $row['b_rooms'] . '</td>
   <td>' . $row['status'] . '</td>
   </tr>';
   }
   echo '</table>'; // Close the table
   mysqli_free_result ($result); // Free up the resources
} else { // If it did not run OK
// Error message
echo '<p class="error">The record could not be retrieved. We apologize image
for any inconvenience.</p>';
// Debugging message
   echo '<p>' . mysqli_error($dbcon) . '<br><br>Query: ' . $q . '</p>';
} // End of if ($result). Now display the total number of records/houses
$q = "SELECT COUNT(ref_num) FROM houses";
$result = @mysqli_query ($dbcon, $q);
$row = @mysqli_fetch_array ($result, MYSQLI_NUM);
$houses = $row[0];
mysqli_close($dbcon); // Close the database connection
echo "<p>Total found: $houses</p>";
if ($pages > 1) {
echo '<p>';
//What number is the current page?
$current_page = ($start/$pagerows) + 1;
//If the page is not the first page, then create a Previous link
if ($current_page != 1) {
echo '<a href="admin_view_houses.php?s=' . ($start - $pagerows) . '&p=' . $pages . '">Previous</a> ';
}
//Create a Next link
if ($current_page != $pages) {
echo '<a href="admin_view_houses.php?s=' . ($start + $pagerows) . '&p=' . $pages . '">Next</a> ';
}
echo '</p>';
}
?>
</div><!--End of table display-->
</div>
</body>
</html>

The administrator can also search for individual records by using the house reference number as described in the next section.

The Administrator’s Search Page

Figure 8-8 shows the administrator’s search page.

image

Figure 8-8. The administrator can search for a specific house

The code for the administrator’s search page is given in Listing 8-8a.

Listing 8-8a.  The Administrator’s Search Page (admin_search.php)

<!doctype html>
<html lang=en>
<head>
<title>Administrator's search page</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="transparent.css">
<link rel="stylesheet" type="text/css" href="admin_search.css">
</head>
<body>
<div id="container">
<header>
<?php include('includes/header_admin_found.inc'); ?>
</header>
<div id="content"><!--Start of search page content-->
<h2 class="center" >Search for a Record</h2>
<h3>Enter the Reference Number</h3>
<form action="view_found_record.php" method="post">
<p><label for="ref_num"><b>Reference Number:</b></label><input id="ref_num" image
type="text" name="ref_num" size="6" maxlength="6" image
value="<?php if (isset($_POST['ref_num'])) echo $_POST['refnum']; ?>"></p>
<p><input id="submit" type="submit" name="submit" value="Search"></p>
</form>
<!--End of the admin search page-->
</div>
</div>
</body>
</html>

The code for styling the administrator’s search page is given in Listing 8-8b.

Listing 8-8b.  The Style for the Search Page (admin_search.css)

h2.center { width:280px; margin-left:-70px; }
h3 { text-align:center; }
label { margin-left:150px; width:250px; float:left; text-align:right; }
#submit { margin-left:398px; }

When the Search button is clicked, the record relating to the house reference number is displayed.

The Result of a Search

Figure 8-9 shows that any specified house can be displayed by the administrator.

image

Figure 8-9. The record is selected and displayed

The code for displaying a specific record is given in Listing 8-9.

Listing 8-9.  Creating the Display of Specific Record (view_found_record.php)

Note that the page contains no way of editing or deleting a house. The page exists purely so that the webmaster can check that the details are correct for a newly added house. The webmaster is the administrator, and he is the only person allowed to edit or delete a house; for these tasks, he uses phpMyAdmin.

<!doctype html>
<html lang=en>
<head>
<title>View found record</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="transparent.css">
<link rel="stylesheet" type="text/css" href="admin_form.css">
<!--Add conditional Javascript-->
<!--[if lte IE 8]><script src="html5.js">
</script>
<![endif]-->
<!--[if lte IE 8]>
<link rel="stylesheet" type="text/css" href="ie8_admin.css">
<![endif]-->
<style type="text/css">
p.error { color:red; font-size:105%; font-weight:bold; text-align:center;}
table { width:900px; border-collapse:collapse; }
</style>
</head>
<body>
<div id="container">
<header>
<?php include('includes/header_admin_found.inc'); ?>
</header>
<div id="content"><!--Start of the view found record content -->
<h2>Search Result</h2>
<?php
// This code fetches a record from the houses table
require ('mysqli_connect.php'); // Connect to the db
$ref_num=$_POST['ref_num'];
$q = "SELECT ref_num, loctn, thumb, price, type, mini_descr, b_rooms, status image
       FROM houses WHERE ref_num='$ref_num' ";
$result = @mysqli_query ($dbcon, $q); // Make the query.
if ($result) { // If the query ran OK, display the record
// Table header
   echo '<table>
   <tr>
     <td><b>Ref_Num</b></td>
     <td><b>Image</b></td>
     <td><b>Price</b></td>
     <td><b>Features</b></td>
     <td><b>Bedrms</b></td>
     <td><b>Status</b></td>
   </tr>';
// Fetch and display the record
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
   echo '<tr>
     <td>' . $row['ref_num'] . '</td>
     <td>  <img src='.$row['thumb'] . '></td>
     <td>' . $row['price'] . '</td>
     <td>' . $row['mini_descr'] . '</td>
     <td>' . $row['b_rooms'] . '</td>
     <td>' . $row['status'] . '</td>
   </tr>';
   }
   echo '</table>'; // Close the table
   mysqli_free_result ($result); // Free up the resources
   } else { // If the query failed to run
// Error message:
   echo '<p class="error">The current houses could not be retrieved. We apologize for any inconvenience.</p>';
// Debugging message:
   echo '<p>' . mysqli_error($dbcon) . '<br><br>Query: ' . $q . '</p>';
   } // End of if ($result).
?>
</div><!--End of the “view found record” content-->
</div>
</body>
</html>

When users search for a suitable house, they are shown a selection that matches their search criteria. The displayed table includes a column named Details. If they click the Details link, they will be shown a full description of a house and an enlarged picture of the house.

image Caution  Using the downloaded files, only one of the Details links is a live link. To see it in action, start at the home page and search for a detached house in South Devon with 4 bedrooms and a maximum price of £400,000. When you see the displayed table of houses, click the Detailslink in the row for the house reference number 1003.

Displaying the Full Description of a House

Figure 8-10 shows an example of a page that displays the full specification of a house.

image

Figure 8-10. Showing the full specification of house reference number 1003

A real-world full description would contain much more information, such as room dimensions and the details of the heating system.

image Note  Each house will need its own full description page. I have shown and listed just one of those pages.

When the administrator added the house reference 1003 to the houses table, the Details link for house reference 1003 was entered in the full_spec column of the houses table as

<a href='descriptions/spec_1003.php'>Details</a>.

The code for displaying the full description of the house reference 1003 is given in Listing 8-10.

Listing 8-10.  Creating a Full Description Page (spec1003.php)

This code assumes that the description pages are stored in the folder named descriptions. An internal style is included for elements that are unique to full-description pages. A piece of JavaScript is included so that IE8 can read the HTML5 semantic tags. This listing is the template for all full-description pages; the items that change with each house are shown in bold type.

<!doctype html>
<html lang=en>
<head>
<title>Spec 1003</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="../transparent.css">
<!--[if lte IE 8]>
<link rel="stylesheet" type="text/css" href="../ie8.css">
<![endif]-->
<style type="text/css">
#midcol {padding:5px; margin-left:0; margin-right:140px; background:white; color:green; }
#midcol h3 {color:green; margin-top:10px; font-size:130%; }
#midcol p { color:black; }
#leftcol {margin-left:0; width:50%; float:left; }
#leftcol h3 { margin-bottom:-10px; }
mid-right-col { width:40%; float:left; }
</style>
<!--Add conditional Javascript-->
<!--[if lte IE 8]><script src="../html5.js">
</script>
<![endif]-->
</head>
<body>
<div id="container">
<header>
<h1>Devon Real Estate</h1>
<h2>Try our award-winning service</h2>
<img id="rosette" alt="Rosette" title="Rosette" height="127"
src="../images/rosette-128.png" width="128">
</header>
<div id="content">
<div id="rightcol">
<nav>
<?php include('spec_menu.inc'); ?>                                                       #1
</nav>
</div><!--end of side menu column-->
<div id="midcol">
<div id="leftcol">
   <h3><strong>Details for House ReferenceNo 1003</strong></h3><br><br>
<img alt="house reference1003"height="255" src="../images/house10.gif" width="350"><br>
</div>
<div id="mid-right-col">
</div>
<h3>To arrange a viewing please click the Contact Us button and quote the image
reference number1003</h3>
<p>&pound;400,000</p>
<p>A large and superbly presented detached house located in a beautiful valley inimage
South Devon. Four good size bedrooms, all en-suite. Three generous reception rooms, luxury image
kitchen and main bathroom.<br>Double Garage with radio operated doors. Parking space forimage
three cars in front of the house. Large landscaped rear garden (approximately one acre)image
with green house, summer house and hot tub. Neat front garden with rockery.</p>
<br class="clear">
</div></div><!--content closed-->
</div>
<footer>footer goes here
</footer>
</body>
</html>

Explanation of the Code

The code is quite straightforward, but note that the URLs for the included items are all prefixed with two dots and a forward slash (../). This is because the includes, JavaScript, style sheets, and images are all located one level above the descriptions folder.

However, the item on line #1 is not straightforward and needs some explanation as follows:

<?php include('spec_menu.inc'); ?>                                                       #1

A copy of the main menu (menu.inc) was placed in the descriptions folder and renamed spec_menu.inc. This is because the path to the four files in the main menu is complex. By locating the modified menu file in the descriptions folder, the paths are simplified. The code forspec_menu.inc is as follows:

<ul>
   <li><a href="#" title="About Us">About Us</a></li>
   <li><a href="#" title="Frequently Asked Questions">FAQs</a></li>
   <li><a href="../contact.php" title="Contact Us">Contact Us</a></li>
   <li><a href="../index.php" title="Return to Home Page">Home Page</a></li>
</ul>

The first and second items are dead links because the downloadable files do not include the About us and FAQs files. If they were included the path would be ../about.php, which is preceded by two dots and a forward slash because the file about.php would be located one level above the file that calls it. The same applies to the path for the FAQs file.

If extra buttons are added to the main menu, the webmaster must remember to also add them to the spec_menu.inc file.

When users wish to visit and inspect a house, they are asked to click the Contact Us button. This button loads the Contact Us form, which will be described next.

The Contact Us Page

Figure 8-11 shows an example of a suitable Contact Us page. This is a cut-down version of the Contact Us page from Chapter 7.

image

Figure 8-11. The Contact Us page

The code that displays the form is given in Listing 8-11a.

Listing 8-11a.  Creating the “Contact Us” Page (contact.php)

An internal style is used to format the fields because their layout is unique to this page.

<!doctype html>
<html lang=en>
<head>
<title>Contact page - Devon Real Estate</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="transparent.css">
<!--[if lte IE 8]>
<link rel="stylesheet" type="text/css" href="ie8.css">
<![endif]-->
<style type="text/css">
span.red { color:red; }
div.cntr { text-align:center; }
form { margin-left:15px; font-weight:bold; color:black; }
#midcol h3 { font-size:130%; text-align:center;}
form { margin-left:30px; }
form h3 { text-align:center; }
label { width:250px; float:left; text-align:right; }
input { float:left; }
textarea { margin-left:190px; }
#sb { margin-left:330px; }
</style>
<!--Add conditional JavaScript for IE8-->
<!--[if lte IE 8]>
<script src="html5.js">
</script>
<![endif]-->
</head>
<body>
<div id="container">
<header>
<h1>Devon Real Estate</h1>
<h2>Try our award-winning service</h2>
<img id="rosette" alt="Rosette" title="Rosette" height="127"
src="images/rosette-128.png" width="128">
</header>
<div id="content">
<div id="rightcol">
<nav>
<?php include('includes/menu.inc'); ?>
</nav>
</div><!--End of side menu column-->
<div id="midcol">
<h3>Arrange a Viewing</h3>
<div class="cntr">
<strong>Address:</strong> 1 The Street, Townsville, AA6 8PF, <b>Tel:</b> 01111 800777
<br> <strong>To arrange a viewing:</strong> please use this form and click the image
Send button at the bottom.
</div>
<div id="form">
<form action="contact_handler.php" method="post" >
<h3 >Essential items are marked with an asterisk</h3>
<!--Start of text fields-->
<label for="username"><span class="red">*</span>Your Name: </label>
<input id="username" name="username" size="30"><br>
<br><label for="useremail" ><span class="red">*</span>Your Email:</label>
<input id="useremail" name="useremail" size="30"><br>
<br><label for="phone" ><span class="red">*</span>Telephone:</label>
<input id="phone" name="phone" size="30"><br><br>
<h3>Please enter the reference number of the house</h3>
<label for="ref_num" ><span class="red">*</span>House Reference Number: </label>
<input id="ref_num" name="ref_num" size="30"><br><br>
<h3>Please enter your message below (optional)</h3>
<textarea id="comment" name="comment" rows="8" cols="40"></textarea>
<br>
<!--The submit button goes here-->
<input id="sb" value="Send" title="Send" alt="Send" type="submit"><br>
</form>
</div
</div>
<br class="clear">
</div> <!--End of the feedback form content-->
<footer>
Footer goes here
</footer>
</div>
</body>
</html>

We will now examine the contact form handler in Listing 8-11b.

Listing 8-11b.  Creating the Contact Form Handler (contact_handler.php)

<?php
/* Contact form handler*/
// set to the email address to the recipient, eg
//$mailto = "webmaster@myisp.com" ;
$mailto = "info@devonrealestate.co.uk" ;
$subject = "Message from the Devon Real Estate contact form" ;
// list the pages to be displayed
$formurl = "http://www.devonrealestate.co.uk/contact.php" ;
$errorurl = "http://www.devonrealestate.co.uk/error.html" ;
$thankyouurl = "http://www.devonrealestate.co.uk/thankyou.html" ;
$emailerrurl = "http://www.devonrealestate.co.uk/emailerr.html" ;
$errorcommentturl =  "http://www.devonrealestate.co.uk/commenterror.html" ;
$uself = 0;
// Set the information received from the form as short variables
$headersep = (!isset( $uself ) || ($uself == 0)) ? "\r\n" : "\n" ;
$username = $_POST['username'] ;
$useremail = $_POST['useremail'] ;
$phone = $_POST['phone'];
$ref_num = $_POST['ref_num'];
$comment = $_POST['comment'] ;
$http_referrer = getenv( "HTTP_REFERER" );
$errors = array(); // Initialize an error array
//Check that all four essential fields are filled out
if (empty($username) || empty($useremail) || empty($phone)|| empty($comment)) {
header( "Location: $errorurl" );
   exit ; }
//check that no URLs have been inserted in the username text field
if (strpos ($username, '://')||strpos($username, 'www') !==false){
header( "Location: $errorsuggesturl" );
exit ; }
if (preg_match( "[\r\n]", $username ) || preg_match( "[\r\n]", $useremail )) {
header( "Location: $errorurl" );
exit ; }
#remove any spaces from beginning and end of email address
$useremail = trim($useremail);
#Check for permitted email address patterns
$_name = "/^[-!#$%&\'*+\\.\/0-9=?A-Z^_`{|}∼]+";
$_host = "([-0-9A-Z]+\.)+";
$_tlds = "([0-9A-Z]){2,4}$/i";
if(!preg_match($_name."@".$_host.$_tlds,$useremail)) {
header( "Location: $emailerrurl" );
exit ; }
if (!empty($_POST['phone'])) {
//Remove spaces, hyphens, letters and brackets
$phone = preg_replace('/\D+/', '', ($_POST['phone']));
}
if (!empty($_POST['ref_num'])) {
//Remove spaces, hyphens, letters and brackets
$ref_num = preg_replace('/\D+/', '', ($_POST['ref_num']));
}
//check that no URLs have been inserted in the comment text area
if (strpos ($comment, '://')||strpos($comment, 'www') !==false){
header( "Location: $errorcommenturl" );
exit ; }
$messageproper =
"This message was sent from:\n" .
"$http_referrer\n" .
"------------------------------------------------------------\n" .
"Name of sender: $username\n" .
"Email of sender: $useremail\n" .
"Telephone: $phone\n" .
"Reference Num: $ref_num\n" .
"------------------------- MESSAGE -------------------------\n\n" .
$comment .
"\n\n------------------------------------------------------------\n" ;
mail($mailto, $subject, $messageproper, "From: \"$username\" <$useremail>" );
header( "Location: $thankyouurl" );
exit ;
?>

When the message is sent, a Thank You page appears. The code for this is given in Listing 8-12a.

Listing 8-12a.  The “Thank You” Page (thankyou.html)

<!doctype html>
<html lang=en>
<head>
<title>Thank you for your enquiry</title>
<meta charset=utf-8>
<link rel="stylesheet" type="text/css" href="feedback.css">
</head>
<body>
<p> </p>
<div id="back-button"><a title="Return to the Home page" href="index.php">image
Return to Home Page</a>
</div>
<div><br>
<h2>Thank you for your enquiry</h2>
<h3>We will email an answer to you shortly.</h3>
</div>
</body>
</html>

Listing 8-12b.  The Styling for the “Thank You” Page (feedback.css)

/*FEEDBACK.CSS*/
/*reset browsers for cross-client consistency*/
body,h2,h3,p {margin:0; padding:0 }
body {text-align:center; background-color:#D7FFEB; color:black; image
font-family: "times new roman"; max-width:100%; min-width:960px;
font-size: medium; color: #000000; margin: auto; width:95%;}
#back-button { margin:20px auto 0 auto; text-align:center; width:200px; height:25px; image
padding:5px; background-color:brown; color:white; font-size:110%; font-weight:bold; }
#back-button a { text-decoration:none; color:white; }
#back-button a:hover { color:red; }
h2 { margin-top:15px; margin-bottom:10px; font-size:130%; font-weight:bold;}
h3 { font-size:110%; font-weight:bold; text-align:center;}

image Note  The three error-message pages are included in the downloadable files, and they are the same as those in Chapter 7.

Summary

In this chapter, you learned how to plan a database for a real estate catalog. We created a home page in which users could search for a suitable house. We provided the administrator with a page so that he could add new houses. We produced a page that allowed the administrator to view the entire stock of houses, or to search for and view a specific house. We then learned how to create a page to show users the full specification of a particular property. We created an inquiry form for users who wished to inspect a house.

In the next chapter, you will learn how to extract data from multiple tables by joining them, how to create a form to allow payments by check, and an economical method for printing online forms.