The winestore include files are shown in Example 10-6, Example 10-7, and Example 10-8. The
db.inc
include file in Example 10-6 and the
error.inc
include file in Example 10-8 are both included in the
include.inc
file in Example 10-7.
Example 10-6 shows the db.inc
file that lists the DBMS credentials for connecting to the winestore
database. The settings must be changed for a local installation of
the winestore application.
Example 10-6. The db.inc include file
<?php $hostName = "localhost"; $databaseName = "winestore"; $username = "fred"; $password = "shhh"; ?>
The db.inc
include file stores the DBMS and
database credentials to access the online winestore. The
hostName
setting is the server name of the DBMS,
the databaseName
setting is the winestore database
name, and the username
and
password
are those used to access the MySQL DBMS.
This file is identical to Example 4-7 and is
discussed in Chapter 4.
The include.inc
file shown in Example 10-7 stores the common function used throughout the
winestore application.
Example 10-7. The include.inc file
<?php // This file contains functions used in more than // one script in the cart module include 'db.inc'; include 'error.inc'; // Untaint user data function clean($input, $maxlength) { $input = substr($input, 0, $maxlength); $input = EscapeShellCmd($input); return ($input); } // Print out the varieties for a wineID function showVarieties($connection, $wineID) { // Find the varieties of the current wine, // and order them by id $query = "SELECT gv.variety FROM grape_variety gv, wine_variety wv, wine w WHERE w.wine_id = wv.wine_id AND wv.variety_id = gv.variety_id AND w.wine_id = $wineID ORDER BY wv.id"; // Run the query if (!($result = @ mysql_query($query, $connection))) showerror( ); $varieties = ""; // Retrieve and print the varieties while ($row = @ mysql_fetch_array($result)) $varieties .= " " . $row["variety"]; return $varieties; } // Show the user the details of one wine in their // cart function showWine($wineId, $connection) { global $username; global $password; global $databaseName; $wineQuery = "SELECT year, winery_name, wine_name FROM winery, wine WHERE wine.winery_id = winery.winery_id AND wine.wine_id = $wineId"; $open = false; // If a connection parameter is not passed, then // use our own connection to avoid any // locking problems if (!isset($connection)) { if (!($connection = @ mysql_connect($hostName, $username, $password))) showerror( ); if (!mysql_select_db($databaseName, $connection)) showerror( ); $open = true; } // Run the query created above on the database // through the connection if (!($result = @ mysql_query ($wineQuery, $connection))) showerror( ); $row = @ mysql_fetch_array($result); // Print the wine details $result = $row["year"] . " " . $row["winery_name"] . " " . $row["wine_name"]; // Print the varieties for this wine $result .= showVarieties($connection, $wineId); if ($open == true) @ mysql_close($connection); return $result; } // Print out the pricing information for a wineID function showPricing($connection, $wineID) { // Find the price of the cheapest inventory $query = "SELECT min(cost) FROM inventory WHERE wine_id = $wineID"; // Run the query if (!($result = @ mysql_query($query, $connection))) showerror( ); // Retrieve the cheapest price $row = @ mysql_fetch_array($result); printf("<b>Our price: </b>$%.2f", $row["min(cost)"]); printf(" ($%.2f a dozen)", ($row["min(cost)"] * 12)); } // Show the total number of items and dollar value of // the shopping cart, as well as a clickable cart icon function showCart($connection) { global $order_no; // Initialise an empty cart $cartAmount = 0; $cartCount = 0; // If the user has added items to their cart, // then the variable order_no will be registered if (session_is_registered("order_no")) { $cartQuery = "SELECT qty, price " . "FROM items " . "WHERE cust_id = -1 " . "AND order_id = " . $order_no; // Find out the number and the dollar value of // the items in the cart. To do this, we run // the cartQuery through the connection on // the database if (!($result = @ mysql_query ($cartQuery, $connection))) showerror( ); while ($row = @ mysql_fetch_array($result)) { $cartAmount += $row["price"] * $row["qty"]; $cartCount += $row["qty"]; } } // This sets up the cart picture. // The user can click on it to see the contents of // their cart. It also contains JavaScript, so that // the cart highlights // when the mouse is over it (a "roll-over") echo "<table> <tr> <td>"; echo "<a href="example.cart.2.php" " . "onMouseOut="cart.src='cart_off.jpg'" " . "onMouseOver="cart.src='cart_on.jpg'"> " . "<img src="cart_off.jpg" vspace=0 border=0 " . "alt="cart picture" name="cart"></a> "; echo " </td> "; printf(" <td>Total in cart: $%.2f (%d items)</td> ", $cartAmount, $cartCount); echo "</tr> </table>"; } // Display any messages that are set, and then // clear the message function showMessage( ) { global $message; // Is there an error message to show the user? if (session_is_registered("message")) { echo "<h3>"; echo "<font color="red">$message</font></h3>"; // Clear the error message session_unregister("message"); $message = ""; } } // Show whether the user is logged in or not function showLogin( ) { global $loginUsername; // Is the user logged in? if (session_is_registered("loginUsername")) echo "<p align="right">You are currently " . "logged in as <b>$loginUsername</b></p> "; else echo "<p align="right">You are currently " . "not logged in</p> "; } // Show the user a login or logout button. // Also, show them membership buttons as appropriate. function loginButtons( ) { if (session_is_registered("loginUsername")) { echo " <td><input type="submit"" . " name="logout" value="Logout"></td> "; echo " <td><input type="submit"" . "name="account" value="Change " . "Details"></td> "; } else { echo " <td><input type="submit" " . "name="login" value="Login"></td> "; echo " <td><input type="submit" " . "name="account" value="Become " . "a Member"></td> "; } } // Get the cust_id using loginUsername function getCustomerID($loginUsername, $connection) { global $databaseName; global $username; global $password; global $hostName; $open = false; // If a connection parameter is not passed, then // use our own connection to avoid any locking // problems if (!isset($connection)) { if (!($connection = @ mysql_connect($hostName, $username, $password))) showerror( ); if (!mysql_select_db($databaseName, $connection)) showerror( ); $open = true; } // We find the cust_id through the users table, // using the session variable holding their // loginUsername. $query = "SELECT cust_id FROM users WHERE user_name = "$loginUsername""; if (($result = @ mysql_query ($query, $connection))) $row = mysql_fetch_array($result); else showerror( ); if ($open == true) @ mysql_close($connection); return($row["cust_id"]); } // Produce a <select> list containing database // elements function selectDistinct ($connection, $tableName, $columnName, $pulldownName, $additionalOption, $defaultValue) { $defaultWithinResultSet = FALSE; // Query to find distinct values of $columnName // in $tableName $distinctQuery = "SELECT DISTINCT $columnName FROM $tableName"; // Run the distinctQuery on the databaseName if (!($resultId = @ mysql_query ($distinctQuery, $connection))) showerror( ); // Retrieve all distinct values $i = 0; while ($row = @ mysql_fetch_array($resultId)) $resultBuffer[$i++] = $row[$columnName]; // Start the select widget echo " <select name="$pulldownName">"; // Is there an additional option? if (isset($additionalOption)) // Yes, but is it the default option? if ($defaultValue == $additionalOption) // Show the additional option as selected echo " <option selected>$additionalOption"; else // Just show the additional option echo " <option>$additionalOption"; // check for a default value if (isset($defaultValue)) { // Yes, there's a default value specified // Check if the defaultValue is in the // database values foreach ($resultBuffer as $result) if ($result == $defaultValue) // Yes, show as selected echo " <option selected>$result"; else // No, just show as an option echo " <option>$result"; } // end if defaultValue else { // No defaultValue // Show database values as options foreach ($resultBuffer as $result) echo " <option>$result"; } echo " </select>"; } // end of function ?>
The include.inc
file shown in Example 10-7 contains the following functions that are used
throughout the winestore application:
string clean(string
input
, integer
maxlength
)
Untaints a user-supplied input
string by
processing it with EscapeShellCmd( )
and takes a substring of length
maxlength
. Returns the untainted string.
This function is discussed in Chapter 5.
void showVarieties(resource
connection
, int
wineID
)
Queries the winestore database through the DBMS
connection
resource. Prints the wine varieties
associated with the wine identified by the wine_id
wineID
.
string showWine(int
wineID
, resource
connection
)
Queries the winestore database through the DBMS
connection
resource. Returns the year, winery
name, wine details, and varieties of the wine identified by
wineID
. The function
showVarieties( )
is called to output the varieties. If the
connection
resource is NULL
, a
new nonpersistent connection to the DBMS is opened and closed; this
can be used to avoid having to lock the tables associated with a wine
if the calling function requires locks for other operations.
void showPricing(resource
connection
, int
wineID
)
Queries the winestore database through the DBMS
connection
resource. Prints the price of the wine
identified by wineID
and the cost of a
case of that wine where—for simplicity—a case of 12
bottles costs 12 times as much as 1 bottle.
void showCart(resource
connection
)
Produces a shopping cart icon that is an embedded link to the script
cart.2. The icon is a rollover, in which
JavaScript loads a highlighted cart image when the mouse is over the
image. The script also queries the winestore
database through the DBMS connection
resource and
sums the total number of items and the dollar value of the items in
the user’s shopping cart. These total values are
reported next to the cart.
void showMessage( )
Reports any messages registered in the session variable
message
. If a message is displayed, the session
variable message
is unregistered so that a message
appears only once.
void showLogin( )
Reports whether the user is logged in or not based on whether the
loginUsername
session variable is registered. If
the user is logged in, the message includes the
user’s login name.
void loginButtons( )
Displays <form>
buttons. If the user is
logged in, the “logout” and
“customer change details” buttons
are shown. If the user isn’t logged in, the
“login” and
“become a member” buttons are
shown.
string getCustomerID(string
loginUsername
, resource
connection
)
Returns the cust_id
associated with the
user’s email address or login name
loginUsername
. Queries the
winestore database through the DBMS
connection
resource. If the
connection
resource is
NULL
, a new, nonpersistent connection to the DBMS
is opened and closed; this can be used to avoid having to lock the
tables associated with a wine if the calling function requires locks
for other operations.
void selectDistinct (resource
connection
, string
tableName
, string
columnName
, string
pulldownName
, string
additionalOption
, string
defaultValue
)
Produces a drop-down list using the HTML
<select>
element. Values from the
columnName
attribute of the table
tableName
are used to populate the
<select>
element with the name
pulldownName
. The
<option>
defaultValue
is shown selected, and an
additional nondatabase value—such as
All
—can be added with the
additionalOption
parameter. This function
is described in detail in Chapter 5.
A custom error handler is used in the
winestore in preference to the built-in PHP error handler. Example 10-8 shows this handler incorporated in the include
file
error.inc.
Example 10-8. The error.inc custom error handler
<? // Trigger an error condition function showerror( ) { if (mysql_errno() || mysql_error( )) trigger_error("MySQL error: " . mysql_errno( ) . " : " . mysql_error( ), E_USER_ERROR); else trigger_error("Could not connect to DBMS", E_USER_ERROR); } // Abort on error. Deletes session variables to leave // us in a clean state function errorHandler($errno, $errstr, $errfile, $errline) { switch ($errno) { case E_USER_NOTICE: case E_USER_WARNING: case E_WARNING: case E_NOTICE: case E_CORE_WARNING: case E_CORE_NOTICE: case E_COMPILE_WARNING: break; case E_USER_ERROR: case E_ERROR: case E_PARSE: case E_CORE_ERROR: case E_COMPILE_ERROR: session_start( ); if (session_is_registered("message")) session_unregister("message"); if (session_is_registered("order_no")) session_unregister("order_no"); $errorString = "Winestore system error: $errstr (# $errno).<br> " . "Please report the following to the administrator:<br> " . "Error in line $errline of file $errfile.<br> "; // Send the error to the administrator by email error_log($errorString, 1, "hugh"); ?> <h2>Hugh and Dave's Online wines is temporarily unavailable</h2> The following has been reported to the administrator: <br><b><font color="red"><?=$errorString;?></b></font> <?php // Stop the system die( ); default: break; } } ?>
At the beginning of each script in the winestore application, the handler is registered:
set_error_handler("errorHandler");
After this registration, any error, warning, or notice encountered in
the script will cause the function errorHandler( )
to be called.
The function set_error_handler( )
has the following prototype:
string set_error_handler(string error_handler
)
On success, the function returns the previously defined error handler
function name as a string. The parameter
error_handler
is the name of the
user-defined handler function, in our example
errorHandler
. The returned value can be used later
to restore the previous error handler with
set_error_handler( )
.
PHP requires that the user-defined errorHandler( )
function have at least two parameters: an error number
and an error string. Three additional optional parameters can be
included in a custom error handler: the script file that caused the
error, the line number with the error, and additional variable
context information. Our handler supports the first two of the three
optional parameters.
Eight different errors, warnings, and notices can be generated by PHP
during script processing or during the precompilation process,
generated by the PHP script engine itself, or triggered manually by
the developer. Our errorHandler( )
function
ignores all notices and warnings by returning if the error number
errno
parameter falls into the
WARNING
or NOTICE
classes.
However, for all errors in the ERROR
class and for
PARSE
errors, our custom error handler carries out
several actions:
It logs out the user and deletes any registered session messages.
It creates a string that incorporates details of the error.
It emails the error message to the system administrator—in this
case to the email account hugh
—using the PHP
library error_log( )
function.
It outputs the error message to the browser.
The advantage of a custom error handler is that additional features, such as deleting session variables, closing database connections, and sending email messages, can be incorporated in the error process.
The error_log( )
function has the following
prototype:
int error_log (stringmessage
, intmessage_type
[, stringdestination
[, stringextra_headers
]])
The string message
is the error message to be
logged. The message_type
can be 0, 1, or
3. A setting of 0 sends the message
to the PHP
system error logger, which is configured using the
error_log
directive in the
php.ini
file. A setting of 1 sends an email to
the destination
email address using the
mail( )
function with any additional email
extra_headers
that are provided; the
mail( )
function and the use of extra headers is
discussed in Chapter 12. A setting of 3 appends the
message
to the file
destination
. A setting of 2
isn’t available in PHP4.
The showerror( )
function is also part of
error.inc.
This function is called whenever a
MySQL function fails throughout the winestore scripts. The function
tests if mysql_error( )
or mysql_errno( )
return nonzero values and, if so, it triggers a user-generated error
using the trigger_error( )
PHP library function:
void trigger_error (stringerror_message
[, interror_type
])
The trigger_error( )
function has two
parameters: an error_message
—which
is created using the return values of the MySQL error
functions—and an optional error_type
that’s set to E_USER_ERROR
. If
MySQL hasn’t reported an error, the
mysql_connect( )
or mysql_pconnect( )
functions have failed, and a message indicating this is manually
created. The result of calling trigger_error( )
is that the PHP script engine calls our custom
registered
handler,
errorHandler( )
.
3.145.35.194