. 69
( 132 .)


rows to record that.
Chapter 12: Catalog 405

Instead, product_style_map has only the minimal number of records needed to
represent your actual stock. If there™s a standard set of colors for all shirts, you can
just map Shirts to Colors. That way when you add a new color it automatically
shows up as available for all your shirts. If you don™t want the color to apply to
plain V-neck T-shirts you can go to that product and mark it “not available” there.
As you™ll see, this puts the onus on the application code to interpret the data cor-
rectly. You can take an alternate approach to this kind of data that can make cod-
ing a bit simpler, but that carries a correspondingly increased risk of inaccurate
information showing up on your Web pages. You can add another table to the data-
base ” something like derived_product_style_map, for example, that never gets
directly updated by the administrators of the site. Instead, the application rebuilds
it every time the main tables change. You can think of this kind of table as some-
thing like a cache ” it stores the results of applying all the varying hierarchies of
styles to all of the products, and ends up looking like the very simple mapping table
described earlier. The advantage of this approach is probably clear: All the work has
been done, and all the Web site has to do is go read the database. The disadvantage
is in the process of building it. If anything goes wrong in that process, you end up
displaying different information on the site than you see in your administration
screens, which is the kind of thing that drives site administrators nuts. Plus, while
you™re rebuilding it, what do your pages show? There are ways to solve those prob-
lems, of course. It™s a perfectly legitimate approach to take.

The thing is, every problem we had to solve in our example, which displays
pages directly from the source products and styles tables, is one you™d have
to solve to create those kinds of derived tables anyway. So if it sounds like a
good approach, consider it left as an exercise for you.

The code in Listing 12-1 shows how the Catalog application™s database tables are
set up. Pay attention to the datatypes ” they restrict what we can do later.

Listing 12-1: create Statements for the Catalog Application
# --------------------------------------------------------
create table products
product_id integer not null auto_increment
, parent_id integer not null default 0
, product varchar(255) not null
, description text null
, price decimal(10,2) null
, price_type_id smallint null

406 Part IV: Not So Simple Applications

Listing 12-1 (Continued)
, image_id integer null
, primary key (product_id)
, key (parent_id)
, key (price_type_id), foreign key (price_type_id) references
price_types (price_type_id) on delete set null
, key (image_id), foreign key (image_id) references images
(image_id) on delete set null
type = InnoDB

create table styles
style_id integer not null auto_increment
, parent_id integer not null default 0
, style varchar(255) not null
, description text null
, primary key (style_id)
, index (parent_id)
create table product_style_map
map_id int not null auto_increment
, product_id int not null
, style_id int not null
, status_id smallint null
, price decimal(10,2) null
, price_type_id smallint null
, image_id int null
, primary key (map_id)
, unique key (product_id, style_id)
, foreign key (product_id) references products (product_id) on
delete cascade
, key (style_id), foreign key (style_id) references styles
(style_id) on delete cascade
, key (status_id), foreign key (status_id) references status
, key (price_type_id), foreign key (price_type_id) references
price_types (price_type_id)
, key (image_id), foreign key (image_id) references images
Chapter 12: Catalog 407

create table status
status_id smallint not null
, status varchar(255) not null
, description text null
, primary key (status_id)
type = InnoDB
insert into status (status_id,status,description) values
(0,™Inherited™,™derived from parent™);
insert into status (status_id,status,description) values
(1,™Available™,™ok to show™);
insert into status (status_id,status,description) values (2,™Not
Available™,™not ok to show™);
insert into status (status_id,status,description) values (3,™Out of
Stock™,™temporarily unavailable - ok to show, with warning™);
create table images
image_id integer not null auto_increment
, image varchar(255) not null
, width integer null
, height integer null
, alt text null
, primary key (image_id)
type = InnoDB
create table admin
username varchar(50) not null,
password varchar(255) not null
insert into admin values (˜jay™, sha1(˜rules™));

A note on this last line: sha1() is an encryption function like md5() or
password(). It stores the password in an encrypted format so that we can still use
it for login verification, but anyone looking at the contents of the table would not
be able to see the actual password string.
408 Part IV: Not So Simple Applications

Code Overview
The code in this section is going to look substantially different from that in the
chapters you have seen so far.

The object-oriented approach
In the preceding applications we made use of a procedural approach. That is, there
is a series of functions, and each function performs a fairly specific procedure. In
the actual application, little remains to be done but to call these functions. But in
an application such as this, in which the data are largely hierarchical, it™s helpful to
make use of OO programming™s inheritance. It enables you to solve some
problems ” like how to upload an image file ” once, not just for this application, but
for subsequent ones as well, by creating a common library of classes much like the
sets of functions we™ve used up until now. In fact, you can even let other people
solve your problems for you, by using publicly available class libraries like the ones
available from PEAR.
Problems more specific to this application are handled by a single common
class, and those specific to each set of data ” here, products and styles ” are
addressed in individual classes. Your code maps more directly to your data.
If you use objects, the contents within the files called by URLs will be even
sparser. Almost all the work is performed within the classes. Once you understand
what actions the class files perform, there is little else for you to do.
To advocates of OO programming, this is a major advantage. You, the program-
mer, can get a class file and not really know what happens inside it. All you need to
know is what attributes it has and what its methods do. Then you can just include it
in your application and painlessly make use of its sophisticated functionality.

We said it in Chapter 7, but it™s worth repeating here: You can write proce-
dural code that encompasses most of the benefits discussed here. If you™re
not careful with OO programming, your code can end up being much more
difficult to maintain and use.

Accessing the file system
You have probably noticed by now that in this book almost all of our data are
stored within the MySQL database. But even when you™re using MySQL you are
sometimes better off using the file system for storage. Images (.jpegs, .gifs, .pngs)
are a perfect example. Even if your database supports binary data, there™s little
advantage in putting an image in a database. You need a database for storing and
querying normalized data. In your database you are much better off maintaining
the path to the image stored in your file system. That way it is easy enough to fill
in the src attribute in your <img> tag.
Chapter 12: Catalog 409

Uploading files
This is the first application that enables users to upload files; specifically, the
administrators of the catalog need to be able to upload images of their products.
Uploading files is easy enough in PHP, but before you understand how the upload
works you need to know how PHP handles uploaded files.
In your HTML page you have a form like the following:

<form action=”admin_product.php” method=”post”
enctype=”multipart/form-data” >
<input type=file name=”imagefile”>

When you allow file uploads, you open yourself up to denial-of-service (DoS)
attacks. If you™re not careful, someone could send many multi-megabyte
files to your system simultaneously, which could bring your machine to a
crashing halt.There are two things you can do about this.The first is to put a
hidden form field before your <INPUT TYPE=”file”> tag. The hidden
field should look like this:
<INPUT TYPE=”hidden” name=”MAX_FILE_SIZE” value=”1000”>
where value indicates the maximum size allowed, in bytes.This is a reason-
able first step and can be of help in stopping someone who didn™t know you
have a size limit. However, this measure will not stop anyone with stronger
malicious intent. All that person has to do is look at the source code of your
page and make the needed changes.
The other security measure has to do with altering the php.ini file, which
contains the upload_max_filesize item. If you have access to your
php.ini, you can set the value of this item to a number that you think is rea-
sonable. (By default php.ini will allow 2MB uploads.) By making the change
in the php.ini file you prevent the attacker from altering it.

When a file is specified and this form is submitted, PHP automatically creates a
few variables. They are as follows:

— $_FILES[yourfieldname][tmp_name] ” The name of the file as stored in
the temporary directory on the server
— $_FILES[yourfieldname][name] ” The name of the file as it was on the
user™s machine
410 Part IV: Not So Simple Applications

— $_FILES[yourfieldname][size] ” The size of the file, in bytes

— $_FILES[yourfieldname][type] ” The MIME type, in this case
image/gif, image/png, or image/jpg (if it was provided by the browser)

The image is stored in the temp directory specified in the php.ini file; if no temp
directory is specified in php.ini, the operating system™s default temporary directory
is used.

The Paths and Directories category of php.ini controls many of the file-
upload options.

Code Breakdown
In OO coding, good documentation is your best friend because, as has already been
stated, it almost shouldn™t matter how the classes you are using accomplish their
tasks. You just need to know that they work.

PHPBuilder has an excellent article on software that can help document
classes: http://www.phpbuilder.com/columns/stefano20000824.

Objects in theory
For example, if we were to tell you about a class named Product, we could just tell
you the following:

Class Product:
Inherits CatalogBase


. 69
( 132 .)