The Product Catalog
For customers to be able to purchase products, they'll need to view them first. To this end, I'll create two scripts for accessing the product catalog. The first,
browse_prints.php
, will display a list of the available prints. If a particular artist has been selected, only that artist's work will be shown;
otherwise
, every print will be listed.
The second script,
view_print.php
, will be used to display the information for a single print, including the image. On this page customers will find an
Add to Cart
link, so that the print may be added to the shopping cart. Because the print's image is stored outside of the Web root directory,
view_print.php
will use a separate scriptvery similar to
download_file.php
from Chapter 12, "ExampleContent Management"for the purpose of displaying the image.
|
The structure of this database makes for a
fairly
easy search capability, should you
desire
to add it. As it stands, there are only three logical fields to use for search purposes: the print's name, its description, and the artist's last
name
. A
LIKE
query could be run on these using the following syntax:
SELECT...WHERE prints.description LIKE
'%
keyword
%' OR prints.print_name
LIKE '%
keyword
%' ...
Another option would be to create an advanced search, wherein the
user
selects whether to search the artist's name or the print's name (similar to what the Internet Movie Database, www.imdb.com, does with people versus movie titles).
Finally, you could make use of MySQL's full-text search capability to return results in their order of relevance.
|
To make browse_prints.php
|
1.
|
Create a new PHP document in your text editor (
Script 14.6
).
<?php # Script 13.6 - browse_prints.
php
$page_title = 'Browse the Prints';
include ('./includes/header.html');
require_once ('../mysql_connect.
php);
|
|
2.
|
Build the query.
if (isset($_GET['aid'])) {
$aid = (int) $_GET['aid'];
if ($aid > 0) {
$query = "SELECT artists.
artist_id, CONCAT_WS(' ',
first_name, middle_name,
last_name) AS name, print_
name, price, description,
print_id FROM artists, prints
WHERE artists.artist_id =
prints.artist_id AND prints.
artist_id =$aid ORDER BY
prints.print_name;
} else {
$query = "SELECT artists.
artist_id, CONCAT_WS(' ',
first_name, middle_name,
last_name) AS name, print_
name, price, description,
print_id FROM artists, prints
WHERE artists.artist_id =
prints.artist_id ORDER BY
artists.last_name ASC,
prints.print_name ASC;
}
} else {
$query = "SELECT artists.
artist_id, CONCAT_WS(' ',
first_name, middle_name, last_
name) AS name, print_name,
price, description, print_id
FROM artists, prints WHERE
artists.artist_id = prints.
artist_id ORDER BY artists.
last_name ASC, prints.print_name
ASC;
}
The query is a standard join across the
artists
and
prints
tables (to retrieve the artist name information with each print's information). The first time the page is
viewed
, every print by every artist will be returned. If a user clicks one artist's name, the user will be returned back to this page, but now the URL will be, for example,
browse_prints.php?aid=529
. In that case, the clause
AND prints.artist_id = $aid
is added to the query and the
ORDER BY
is slightly modified so that just that artist's works are displayed.
So the two different roles of this scriptshowing every print or just those for an individual artistare defined by this conditional, while the rest of the script works the same in either case.
For security purposes, I use type casting on the author ID and make sure that it's a positive integer prior to using it in a query.
|
|
3.
|
Create the table head.
echo '<table border="0" width="90%"
cellspacing="3 cellpadding="3"
align="center>
<tr>
<td align="left" width="20%">
<b>Artist</b></td>
<td align="left" width="20%">
<b>Print Name</b></td>
<td align="left" width="40%">
<b>Description</b></td>
<td align="right" width="20%">
<b>Price</b></td>
</tr>';
|
|
4.
|
Display every returned record.
$result = mysqli_query ($dbc, $query);
while ($row = mysqli_fetch_array
($result, MYSQLI_ASSOC)) {
echo " <tr>
<td align=\"left\"><a href=\
"browse_prints.
php?aid={$row['artist_id']}\">{$row
['name]}</a></td>
<td align=\"left\"><a href=\
"view_print.php?pid={$row
['print_id]}\">{$row
['print_name]}</td>
<td align=\"left\">{$row
['description]}</td>
<td align=\"right\">${$row
['price]}</td>
</tr>\n";
}
I want the page to display the artist's full name, the print name, the description, and the price for each returned record. Further, the artist's name should be linked back to this page (with the artist's ID appended to the URL), and the print name should be linked to
view_print.php
(with the print ID appended to the URL).
Figure 14.22
shows some of the resulting HTML source code.
Remember that if you are not using the Improved MySQL Extension functions, you'll need to change your function calls here.
|
|
5.
|
Close the table, the database connection, and the HTML page.
echo '</table>';
mysqli_close($dbc);
include ('./includes/footer.html');
?>
|
|
6.
|
Save the file as
browse_prints.php
, upload to your Web server, and test in your Web browser (
Figures 14.23
and
14.24
).
|
Tips
-
You could easily take the dynamically generated pull-down menu from
add_print.php
and use it as a navigational tool on the public side. Set the form's action attribute to
browse_print.php
, change the name of the pull-down menu to
aid
, use the
get
method, and when users select an artist and click Submit, they'll be taken to, for example,
browse_print.php?aid=5
.
-
Although I did not do so here, you could
paginate
the returned results using the technique described in Chapter 8, "Web Application Development" (see the
view_users.php
script).
-
Another feature you could add to this page is the option to choose how the prints are displayed. By adding links to the column headings (e.g., to
browse_prints.php?order=price
), you could change the
ORDER BY
in the query and therefore the resulting display. Again, this idea was demonstrated in Chapter 8.
To make view_print.php
|
1.
|
Create a new PHP document in your text editor (
Script 14.7
).
<?php # Script 14.7 - view_print.php
$problem = FALSE;
I'll use the
$problem
variable to track whether or not a problem occurred on this page.
|
|
2.
|
Validate that a print ID has been passed to this page.
if (isset($_GET['pid'])) {
This script won't work if it does not receive a valid print ID, so I check for the ID's existence first.
|
|
3.
|
Retrieve the information from the database.
$pid = (int) $_GET['pid'];
require_once ('../mysql_connect.
php);
$query = "SELECT CONCAT_WS(' ',
first_name, middle_name, last_name)
AS name, print_name, price,
description, size, image_name
FROM artists, prints WHERE artists.
artist_id = prints.artist_id AND
prints.print_id = $pid;
$result = mysqli_query ($dbc, $query);
The query is a join like the one in
browse_prints.php
, but it selects only the information for a particular print. I'm type-casting the print ID as an integer prior to using it in the query for security purposes (so that a malicious user doesn't try to break my query using invalid
$_GET['pid']
values).
|
|
4.
|
If a record was returned, retrieve the information, set the page title, and include the HTML header.
if (mysqli_num_rows($result) == 1) { $row = mysqli_fetch_array ($result,
MYSQLI_ASSOC);
$page_title = $row['print_name'];
include ('./includes/header.html');
The browser window's title (
Figure 14.25
) will be the name of the print.
|
|
5.
|
Begin displaying the print information.
echo "<div align=\"center\">
<b>{$row['print_name']}</b> by
{$row['name']}
<br />{$row['size']}
<br />${$row['price']}
<a href=\"add_cart.php?pid=
$pid\">Add to Cart</a>
</div><br />";
The header for the print will be the print's name (in bold), followed by the artist's name, the size of the print, and its price. Finally, a link is displayed giving the customer the option of adding this print to the shopping cart (
Figure 14.26
). The shopping cart link is to the
add_cart.php
script, passing it the print ID.
|
|
6.
|
Display the image and description.
if ($image = @getimagesize
("../uploads/{$row['image_name]
}")) {
echo "<div align=\"center\">
<img src=\"show_image.php?
image={$row['image_name]}\"
$image[3] alt=\"{$row
['print_name]}\" />";
} else {
echo "<div align=\"center\">No
image available.";
}
echo "<br />{$row['description']}
</div>";
This section of the script will first attempt to retrieve the image's dimensions by using the
getimagesize()
function. If it is successful in doing so, the image itself will be displayed. This process is a little unusual in that the source for the image calls the
show_image.php
page. This script, to be written
next
, retrieves and displays the
$_GET['image']
passed to it.
If the script could not retrieve the image information (because the image is not on the server or no image was uploaded), a message is displayed instead.
Finally, the print's description is added (
Figure 14.27
).
|
|
7.
|
Complete the two main conditionals.
} else {
$problem = TRUE;
}
mysqli_close($dbc);
} else {
$problem = TRUE;
}
The first
else
clause is in case one record is not returned by the query. The second is in case no print ID is passed to this page. Under both circumstances the
$problem
variable is set to
TRUE
, which will be used by the script in the next step.
|
|
8.
|
If a problem occurred, display an error message,
if ($problem) {
$page_title = 'Error';
include ('./includes/header.html');
echo '<div align="center">
This page has been accessed in
error!</div>';
}
If the print's information could not be retrieved from the database for whatever reason, an error should be displayed. Because the HTML header would not have already been included if a problem occurred, it must be included here first.
|
|
9.
|
Complete the page.
include ('./includes/footer.html');
?>
|
|
10.
|
Save the file as
view_print.php
and upload to your Web server.
|
Tips
-
Many e-commerce sites use an image for the
Add to Cart
link. To do so in this example, replace the text
Add to Cart
(within the
<a>
link tag) with the code for the image to be used. The important consideration is that the
add_cart.php
page gets passed the product ID number.
-
If you want to show the availability of a product, add an
in_stock
field to the
prints
table. Then display an
Add to Cart
link or
Product Currently Out of Stock
message according to the value in this column for that print.
-
Depending upon the Magic Quotessetting of your PHP installation, you may or may not need to make use of the
stripslashes()
function when displaying the print information in this and the previous script.
To write show_image.php
|
1.
|
Create a new PHP document in your text editor (
Script 14.8
).
<?php # Script 14.8 - show_image.php
|
|
2.
|
Check for an image name.
if (isset($_GET['image'])) {
Before continuing, I want to ensure that the script received a valid image name, which should be part of the HTML
src
attribute for each print (
Figure 14.28
) in
view_print.php
.
|
|
3.
|
Check that the image is a file on the server.
$image = "../uploads/{$_GET
['image]}";
if (file_exists ($image) && (is_file
($image))) {
$name = $_GET['image'];
Before attempting to send the image to the Web browser, I want to make sure that it exists and that it is a file (as opposed to a directory). If so, I create a new variable called
$name
that will be used when the image is sent to the Web browser.
As a security measure, I hard-code the image's full
path
as a combination of
../uploads
and the received image name. Even if someone were to attempt to use this page to see
/path/to/secret/file
, this script would look for
../uploads//path/to/secret/file
(including the double-slash), which is safe. You could also validate the MIME type (
image/jpg, image/gif
) of the file here.
|
|
4.
|
Complete the two validation conditionals.
} else {
$image = './images/unavailable.
gif;
$name = 'unavailable.gif';
}
} else {
$image = './images/unavailable.
gif;
$name = 'unavailable.gif';
}
If the image doesn't exist or isn't a file, the first
else
clause comes into effect. If no image name was passed to this script, the second
else
clause applies. In either case, a default image will be used (
Figure 14.29
).
|
|
5.
|
Retrieve the image information.
$ft = mime_content_type($image);
$fs = filesize($image);
To download the file, I'll need to know the file's type and size. I retrieve this information using the
mime_content_type()
and
filesize()
functions. The first one was added in PHP 4.3 but needs to be enabled on Windows in order to work.
|
|
6.
|
Send the file.
header ("Content-Type: $ft\n");
header ("Content-disposition:
inline; filename=\"$name\"\n);
header ("Content-Length: $fs\n");
readfile ($image);
These
header()
calls will send the file data to the Web browser, much as they did in Chapter 12. The key difference between that example and this one is that the
Content-disposition
is now set as
inline
, as opposed to
attachment
. Because of this distinction, the sent file (the image) will be displayed in the browser, whereas previously the browser was prompted to download the file to the user's computer.
To
revisit
the overall syntax, the first line prepares the browser to receive the file, based upon the MIME type. The second line sets the name of the file being sent.
The last
header()
function indicates how much data is to be expected. The file data itself is sent using the
readfile()
function, which reads in a file and immediately sends the content to the Web browser.
|
|
7.
|
Complete the page.
?>
Notice that this page contains no HTML. It only sends an image file to the Web browser.
|
|
8.
|
Save the file as
show_image.php
, upload to your Web server, and test in your Web browser by viewing any print (
Figure 14.30
).
|
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}
Tip
-
If the
view_print.php
page does not show the image for some reason, you'll need to debug the problem by running the
show_image.php
directly in your Web browser. View the HTML source of
view_print.php
and find the value of the
img
tag's
src
attribute. Then use this as your URL (in other words, go to http://localhost/show_image.php?image=BirthOfVenus.jpeg). If an error occurred, running
show_image.php
is the best way to find it.
|