. 49
( 132 .)


+ verify_answers.inc.php

From the top, we have a file named /book/book.php. This adds the /book/functions
directory, where we keep the general-purpose functions used across all the examples
to the default PHP include path. It also adds the /book directory itself by modify-
ing the PHP configuration variable include_path. This in turn enables us to write
include statements that refer to /book/thing/stuff.php, even if the book directory is
not in the root document directory of your server.
The example application that we are looking at in this chapter, the Survey appli-
cation, lives in the /book/survey directory. In here are the files for the pages of the
application. The administrative pages are in a subdirectory named admin/, which
helps keep the file names somewhat regular ” the header file is named header.php, the
page included at the end of every page is end_page.php, and so on. The header.php
file makes reference (via an include statement) to a second file, functions.php,
which defines the functions specific to this application. If we were using any con-
stants or global variables in this application, those would be defined in a file named
Two other subdirectories exist under survey/, standard to all the following
examples. The functions/ subdirectory is where the actual code defining our local
functions lives. Each function is in its own file in here. That™s to make it easier to
find later, mostly, but it also makes managing changes to the code a little bit simpler.
The functions.php file is just a set of require_once() calls that pull in the individ-
ual function files. (The functions under /book/functions are set up the same way.)
The db subdirectory is where we keep the SQL files that define the survey data-
base. There is a file in here named setup.bat, which runs mysql (the command-line
client) as the root user, prompting you for a password, and executes the commands
in the setup.in file. setup.in creates the database, includes the table definitions,
loads some rather silly sample data, and grants read and write access on the data-
base to the nobody account. (If your Web server runs under a different username
276 Part III: Simple Applications

you should edit this file to reflect the different credentials.) Static lookup tables, like
the states table, load the relevant data into their definition files.
We covered some of the functions defined by the /book/functions/basic.php file
in Chapter 8, so we won™t go over those again here. But we did add a few little
bonuses this time around.

HTML functions
As your applications get more complex, you™re going to need to continually use
some HTML ingredients ” forms, tables, paragraph tags, anchors, and the like. For
this reason we™ve added a series of functions that make it easier to create those
repetitive HTML elements ” and we™ve done it so as to demonstrate a variety of
ways to handle arguments to a function.

To introduce the techniques used by the HTML functions that we™ll cover here, we™ll
pick a small one ” the image_tag() function ” and show you what it™s doing.
This image_tag() function returns an HTML <img> tag.

function image_tag()
static $_defaults = array(
˜src™ => ˜™
, ˜alt™ => ˜™
, ˜border™ => 0
, ˜allowed™ =>

static $_simple = array(˜src™);
$p = func_get_args();
$p = parse_arguments($p, $_simple, $_defaults);
if (empty($p[˜alt™]))
$p[˜alt™] = $p[˜src™];
$attlist = get_attlist($p);
$output = “<img $attlist />”;

return $output;

The first thing this function does is declare a couple of static variables (the
underscores in their names ” $_defaults and $_simple ” are just a convention
we™ve used for these particular variable names, to make them distinct from other
variable names; they have nothing to do with the variables being static or not).
Chapter 9: Survey 277

Static variables aren™t reinitialized every time the function is called. Instead, they
retain their values from one call to the next, including any changes. So if we have
a function like

function count_sales($newsales=0)
static $total_sales = 0;
$total_sales += $newsales;
print “Total sales to date: $total_sales\n”;

we can use it to keep a running total, like so:

OUTPUT ---> Total sales to date: 10.00
OUTPUT ---> Total sales to date: 15.00

Besides serving as a place to store data, statics are also useful when you have
something like a big array that gets used every time you call the function, but that
never changes. (Or doesn™t change much.) Especially when your function is one that
gets called over and over again, it can pay to not have to create those variables
from scratch each time. One thing to be aware of: Statics are handled just like ref-
erences, and that affects how they behave. For instance, you can™t store another
reference in a static variable. For more information, see the PHP manual section at
In image_tag() the two static arrays we define are storing two kinds of data:

— $_defaults is an associative array that describes attributes of the HTML
tag and their default values. Sometimes attributes are listed in here
because we really do have default values for them ” for example, the
default value for the ˜border™ attribute of an <IMG> tag should be zero.
Most of the time, they™re here to establish the name of the attribute for
later use. In fact, many of the “attributes” listed in the $_defaults array
in other HTML tag functions aren™t strictly attributes of the tag at all. The
˜value™ attribute of a <textarea> tag, for instance, turns into the string
between the opening <textarea> and closing </textarea> tags.
— $_simple sets out how we want to interpret arguments to this function
when they don™t come neatly labeled in an array. As we mentioned earlier,
most of the time we™ll be using an array to pass arguments into these
functions, so that when we look at the function calls we™ll know what we
meant to do:
image_tag(array(˜src™=>™/images/chimp.jpg™, ˜height™=>50,
278 Part III: Simple Applications

But we™d also like to be lazy:

$_simple is what lets us get away with simplified coding style ” it™s a list
of attribute names to be assigned to unlabeled values. Here, setting it to
array(˜src™) specifies that if we get just a plain string as an argument,
it™s meant to be the value of the src attribute of the <img> tag.

Look at the functions being called here.
First up is the parse_arguments() function. We call it with three parameters: an
array containing the arguments that were passed into image_tag() and the two
static arrays. You might notice that even though the arguments are declared as ref-
erences to the passed-in variables we can still initialize them to default values. This
is a very useful feature of the new PHP engine release. Being able to define a
default value means that the caller can ignore arguments that don™t apply.
In the function itself, we use casting operators to make sure that these are arrays,
and set up some variables that we™ll use to hold values as we go through the argu-
ments (note that in PHP 5, you can assign default values to by-reference argu-
ments; this makes calling the functions much easier):


$args = (array)$args;
$simple = (array)$simple;
$defaults = (array)$defaults;
$key = NULL;
$result = $defaults;
$result[˜_defaults™] = $defaults;
$result[˜_simple™] = $simple;

We start out the $result variable, which is what the function will eventually
return, as a copy of $defaults. This ensures that everything defined in the
$_defaults array will come back as an attribute for the tag. Then we put those
arrays themselves into $result so that they can be modified or replaced by argu-
ments passed in to the original function. This will let us change the default and
simple values in the code of a page, setting up a default image size or border width,
for example_ without having to rewrite the function itself.
Next we™ll walk through the list of arguments. Associative arrays are merged
into $result, empty arguments are ignored, and other arguments are assigned to
the named parameters from the $_simple array:

$i = 0;
$sc = count($simple);
foreach ($args as $arg)
Chapter 9: Survey 279


if ($arg === NULL || (is_array($arg) && count($arg) == 0))
// do nothing
elseif (is_object($arg))
$result = array_merge($result, get_object_vars($arg));
elseif (is_assoc($arg))
$result = array_merge($result, $arg);
if ($i < $sc)
$key = $simple[$i++];
if (!empty($arg) || !isset($result[$key]))
$result[$key] = $arg;
if ($key === NULL)
user_error(“Argument ˜$arg™ was passed with no
available target - aborting...\n”, E_USER_ERROR);
if (isset($result[$key]))
if (!is_array($result[$key]))
$result[$key] = array($result[$key]);
$result[$key][] = $arg;
$result[$key] = $arg;
280 Part III: Simple Applications

Two things are worth pointing out here. If a simple argument is encountered
after we™ve run out of parameter names from $_simple, it™s added into an array by
means of the last simple name. This is how a function like paragraph() works. It
has just one simple argument name, ˜values™, so a list of simple arguments passed
in to the function ends up as elements in the $values array:

paragraph(˜One line™,™Another line™,$variable,™Yet another line™);


˜values™ => array(˜One line™, ˜Another line™, $variable, ˜Yet
another line™);

If there are no names passed in, however, we won™t have anywhere to put any
arguments that aren™t associative arrays. In this case we use PHP™s user_error()
function to raise an error. This prints out our error message and stops the script,
just like a normal PHP error. (The user_error() function is one you™ll be seeing
more of in later examples.)
Finally, to clean up, we take any changes to our list of default and simple argu-
ments and pass them back to the calling function. Because the two arrays are passed
in by reference, changes made to them here will update the original variables. And
because they™re declared as static, those changes will still be there the next time the
function is called.

$defaults = array_merge($defaults, $result[˜_defaults™]);
$simple = $result[˜_simple™];
return $result;

Changes to $_defaults are merged into the original list, while a new value for
$_simple will replace the old one.
After calling parse_arguments() in the image_src() function, like this,

$p = parse_arguments($p, $_simple, $_defaults);

we have an array, $p, containing all the attribute values and other parameters
from the original call. For example, from this line in the Web page ”


” we would end up with the following values in $p:

$p = array(˜src™=>™/image/monkey.jpg™, ˜alt™=>™™, ˜border™=>0);
Chapter 9: Survey 281

For the <IMG> tag specifically, if the ˜alt™ attribute is empty, we™ll use the name
of the image file (from the ˜src™ attribute) as a default:

if (empty($p[˜alt™]))
$p[˜alt™] = $p[˜src™];


. 49
( 132 .)