The searching and browsing module is implemented in the search/searchform.php and search/search.php scripts. Authentication is implemented in the auth/login.php, auth/logincheck.php, auth/logout.php, auth/password.php, and auth/changepassword.php scripts. The authentication process also uses general-purpose functions stored in includes/authenticate.inc.
The searching and browsing scripts work with the wine, winery, inventory, region, and wine_type tables. These tables are created with the following statements:
CREATE TABLE wine ( wine_id int(5) NOT NULL, wine_name varchar(50) NOT NULL, wine_type int(2) NOT NULL, year int(4) NOT NULL, winery_id int(4) NOT NULL, description blob, PRIMARY KEY (wine_id), KEY name (wine_name), KEY winery (winery_id) ) type=MyISAM; CREATE TABLE winery ( winery_id int(4) NOT NULL, winery_name varchar(100) NOT NULL, region_id int(4) NOT NULL, PRIMARY KEY (winery_id), KEY name (winery_name), KEY region (region_id) ) type=MyISAM; CREATE TABLE inventory ( wine_id int(5) NOT NULL, inventory_id int(3) NOT NULL, on_hand int(5) NOT NULL, cost decimal(5,2) NOT NULL, date_added date, PRIMARY KEY (wine_id,inventory_id) ) type=MyISAM; CREATE TABLE region ( region_id int(4) NOT NULL, region_name varchar(100) NOT NULL, PRIMARY KEY (region_id), KEY region (region_name) ) type=MyISAM; CREATE TABLE wine_type( wine_type_id int(2) NOT NULL, wine_type varchar(32) NOT NULL, PRIMARY KEY (wine_type_id) ) type=MyISAM;
The wine table stores details of wines that are for sale. Each wine is produced by a winery that's stored in the winery table, and each winery is located in a region that's stored in the region table. The available stock of a wine is stored in the inventory table: a wine has one row in the inventory table for each date it was received or for each different sale price. Wines also have a wine type (such as red or white) that's stored in the wine_type table. The grape_variety and wine_variety tables are also used in the searching process to display details of each wine through the showVarieties( ) function that's discussed in Chapter 16.
The script search/searchform.php presents a form to the user that collects search criteria. The user can choose to browse wines in all regions and of all wine types, or they can narrow their search to a specific wine type or region. The script is implemented using the same approach as the customer membership form in Chapter 17, and is based on the winestoreFormTemplate class discussed in detail in Chapter 16. Figure 20-1 shows the page rendered in a Mozilla browser.
When the user submits the search form, the script search/search.php is requested. This script finds the wines that match the search criteria, and displays them in one or more pages of twelve wines per page. On each page, hypertext links are provided for the user to move to the previous or next page, or jump to a specific page. When the user clicks on these links, the search/search.php script is re-requested, and an additional offset parameter is provided that's used to retrieve the new page of results. An example of a search to find all wines in the Margaret River region is shown in Figure 20-2.
Authentication is discussed in detail in Chapter 11. This section provides only a brief overview of the winestore authentication process.
The authentication scripts work only with the users table:
CREATE TABLE users ( cust_id int(5) NOT NULL, user_name varchar(50) NOT NULL, password varchar(32) NOT NULL, PRIMARY KEY (user_name), KEY password (password), KEY cust_id (cust_id) ) type=MyISAM;
The users table stores the user_name of the customer (which is their email address), their digested password, and their cust_id (which is used to reference their data in other tables).
The script auth/login.php shows the user a form for entering their login name and password. Similarly to almost all other form pages in the winestore, the script is based on the winestoreFormTemplate class discussed in detail in Chapter 16. The page is shown in Figure 20-3.
On submission of the login page, the auth/logincheck.php script is requested to validate the user's credentials. The script digests the user-supplied password, and compares the username and digested password credentials against those in the users table. On error (where the username and digested password don't match a row in the table) it redirects to the auth/login.php script and displays error messages. On success, the script registers a session variable $_SESSION["loginUsername"] that signifies that the user has logged in, and then the script redirects to the winestore homepage. The processes of registering the session variable and validating the credentials are performed respectively by the registerLogin( ) and authenticateUser( ) functions that are part of the includes/authenticate.inc include file.
The auth/logout.php script deletes the entire session, doesn't produce any output, and redirects to the winestore homepage. Our rationale for deleting more than the $_SESSION["loginUsername"] variable is that a user who logs out doesn't want to use the application further, and therefore would also want their shopping cart emptied. This is a particularly useful feature for users who share a web browser on a machine in, for example, an Internet cafe.
The script auth/password.php displays the password change form shown in Figure 20-4. To change their password, the user must supply their existing password (to minimize tampering) and two copies of the new password (to minimize the chances of a typing error). The script is based on the winestoreFormTemplate class discussed in detail in Chapter 16.
On submission of the form, the browser requests auth/changepassword.php . This script validates the password change, and updates the users table when validation succeeds. The script produces no output: on validation success, it redirects to the customer details page and displays a confirmation message to the user; on failure, it redirects back to the password change form and displays validation errors.
The includes/authenticate.inc file contains the authenticateUser( ) and registerLogin( ) functions described earlier. In addition, it also contains three other functions:
This function adds a new user to the users table and digests their password using the md5( ) function described in Chapter 11.
This function removes the session variables associated with a login without removing the session. This function is called whenever a user fails the authentication process.
This function checks whether a user is logged in, and also ensures that they're accessing the application from the same IP address. On failure it redirects to the page that's supplied as a parameter. The function is called at the top of any script that requires the user to be logged in.