. 48
( 132 .)



CREATE TABLE responses (
user_id int(11) NOT NULL default ˜0™,
answer_id int(11) NOT NULL default ˜0™,
PRIMARY KEY (user_id,answer_id),
KEY answer_id (answer_id),
FOREIGN KEY (`user_id`) REFERENCES `survey.users` (`user_id`) ON
FOREIGN KEY (`answer_id`) REFERENCES `survey.answers`
(`answer_id`) ON DELETE CASCADE
) TYPE=InnoDB;

-- Table structure for table ˜states™

state char(2) NOT NULL default ˜™,
statename varchar(30) NOT NULL default ˜™,
) TYPE=InnoDB;

270 Part III: Simple Applications

Listing 9-1 (Continued)
-- Table structure for table ˜users™

user_id int(11) NOT NULL auto_increment,
name varchar(50) default NULL,
email varchar(50) default NULL,
country varchar(20) default NULL,
state char(2) default NULL,
age int(11) default NULL,
remote_addr varchar(15) default NULL,
remote_host varchar(80) default NULL,
create_dt timestamp(14) NOT NULL,
PRIMARY KEY (user_id)
) TYPE=InnoDB;

-- Table structure for table ˜winners™

CREATE TABLE winners (
weekdate datetime NOT NULL default ˜0000-00-00 00:00:00™,
user_id int(11) NOT NULL default ˜0™,
claim_code char(8) NOT NULL default ˜™,
notify_dt datetime default NULL,
claim_dt datetime default NULL,
confirm_dt datetime default NULL,
PRIMARY KEY (weekdate),
UNIQUE KEY claim_code (claim_code),
KEY user_id (user_id),
FOREIGN KEY (`user_id`) REFERENCES `survey.users` (`user_id`) ON
) TYPE=InnoDB;

Code Overview
If you have already read the section of the same name in Chapter 8, the structure
we use here should be familiar to you. Items in the /functions folder are included
and ready for reuse. We™ve also taken the MySQL functions we used for the guest-
book, modified them a bit to make them more generally useful, and renamed them
my_connect() and my_query(). These can be found in the /functions/basic directory.
Chapter 9: Survey 271

It™s obvious that this survey application requires several more pages than the
guestbook: More needs to be done. Though you can include several actions in a sin-
gle page, and sort through the ones you need by passing variables and using if
statements, it can make code difficult to keep track of. Better to have several intu-
itively named files that perform specific tasks. That said, some pages in this appli-
cation make use of variables in order to decide how they should look and behave.
If you™ve done any Web work at all you know how tedious it can be to deal with
HTML tables and forms. On the one hand, putting literal HTML tags into your pages
will always be a faster procedure than any code-based method of generating them.
On the other hand, propagating changes through all those literal tags can be more
than tedious ” it™s also a great source of bugs). For that reason, in this and most of
the other applications in this book, we will try to ease the pain involved in dealing
with tables and forms. In the following sections you will see several functions that
will make life, in the long run at least, a lot easier. The functions in the coming sec-
tions will make a lot more sense if you see what they accomplish first. Here™s some
code that will work just fine if used with the following functions:

print start_table();
print table_row(
table_cell(˜Cell text™)
print end_table();

or even just this:

print table(˜Cell text™);

This will create a table with one cell. You could build on the complexity of the
unicellular table by adding additional table_cell() calls within the table_row()
function call. You can do this because of PHP™s ability to deal with a variable num-
ber of arguments. We designed the table_row() function to loop through all of the
arguments (some of which are calls to the table_cell() function). You may be
wondering how these functions deal with table attributes, like width, align, and
others. How could you alter those for particular tables_or for all your tables at once?

If you don™t like the functions we™ve created for tables, forms, and other
HTML elements, don™t use them. It is perfectly acceptable (and perhaps even
more common) to type out HTML elements rather than create them
through functions. Like many things in programming, it comes down to a
matter of preference. For the question of whether to hard-code HTML or
programmatically generate it, there™s no right answer. It is true, though, that
dynamically generating HTML on a high-traffic site can put a big load on the
272 Part III: Simple Applications

server. In that situation, you probably will want to put literal HTML in your
pages ” at least in your live pages ” or look into a caching system of some

Here we come to another question of style. You can write your functions to
expect certain attributes as arguments, in a particular order, like this:

function table_cell ($value=™™, $align=™left™, $valign=™top™, $width=™™)

That™s straightforward, and calling the function is pretty simple too:

print table_cell(˜This will be in the upper left corner™);
print table_cell(˜This will end up in the lower right corner™,
˜right™, ˜bottom™);

But the drawback is that you have to remember what attribute goes where. And
reading code like this six months later, after you™ve forgotten you wrote it, or when
you didn™t write it all, can be a problem. For an example like the table_cell()
function above, it™s not so bad ” “right” and “bottom” are clear enough. But a line

print image_tag(˜/images/b129.gif™, 10, 20, 5, 1, 0);

is not so clear. As an alternative, you can specify your arguments as named values
in an array:

print image_tag(array(˜src™=>™/images/b129.gif™, ˜width™=>10,
, ˜vspace™=>5, ˜hspace™=>1, ˜border™=>0

That makes the function call easier to read, but the tradeoff is that the function
itself is a bit less so:

function image_tag ($attributes=NULL)

Now the work of figuring out what values are being passed to the function takes
place inside the function itself. Still, that keeps it in one place. The function calls
are a little more tedious to write, and the functions a little trickier. The benefit is
code that™s easier to read, easier to maintain, and less ambiguous in the writing;
this means fewer bugs. (Unless you™re prone to forget parentheses, like some of us.)
Chapter 9: Survey 273

The functions we™ll use with these examples make something of a lazy compro-
mise between these two approaches. When there™s a single most common use of a
tag, involving one or two attributes, the function assumes that™s what you mean if
you hand it an unnamed simple value, like this:

print table_cell(˜This is the stuff that goes between the opening
and closing td tags.™);

If you want to specify other attributes, then everything has to be in an array:

print table_cell(array(˜value™=>™This is the content of the cell™
, ˜align™=>™right™, ˜valign™=>™bottom™

A more complex function call might look like this:

print table_row(array(
˜bgcolor™ => $bgcolor
, ˜cells™=>array(
˜value™=>™<b>New entry</b>™
, ˜align™=>™right™
, text_field(array(
, ˜value™=>™™
, ˜size=>10
, submit_field(˜Insert Record™)

Here the arguments to table_row() specify the row™s background color
(˜bgcolor”=> $bgcolor) and an array of values to be set up as table cells. Some of
those are nothing more than the contents of the cell, and so we can just list them,
even when the contents themselves are the results of other function calls to create
form fields. But we want the first cell to be aligned to the right, so we make an
explicit call to the table_cell() function ourselves to build it.
Keep in mind that the methods for achieving nested function calls will be
explained later in the “Code Breakdown” section. Throughout the process of creating
this application we make more extensive use of MySQL functions than you saw in
Chapter 8.
274 Part III: Simple Applications

Code Breakdown
As with the guestbook application, the code here is divided for convenience. We™ve
added some final touches to the structure that we™ll use for the rest of the book. It™s
worth taking a minute or two to go over it. Here™s a picture:

* db_dsnlist.php
* dsn.ini

* autoload.php
* book.ini
* book.php
* classes.php
* functions.php
* index.html
* phpinfo.php
* sitemap.php
* source.php
* survey/
+ admin/
o block_domain.php
o end_page.php
o get_winner.php
o header.php
o index.php
o login.php
o questions.php
o winners.php
+ age_results.php
+ claim.php
+ complex_results.php
+ country_results.php
+ db/
o admin.sql
o age_ranges.sql
o answers.sql
o blocked_domains.sql
o grants.sql
o load_questions.sql
o questions.sql
o responses.sql
o setup.bat
Chapter 9: Survey 275

o setup.in
o states.sql
o users.sql
o winners.sql
+ functions/
o check_domain.php
o fetch_question.php
o fetch_user.php
o get_answers.php
o weekstart.php
+ functions.php
+ header.php
+ index.php
+ results.php
+ state_results.php
+ thanks.php


. 48
( 132 .)