DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP PART-03
Validating a drop-down menu with Spry
Applying a select validation widget is very simple. Highlight the menu object in Design
view, and click the Spry Validation Select button in the Insert bar. The following instructions
use the same form as throughout the rest of the chapter.
Use feedback_spry.php from the preceding exercise, or copy feedback_spry_start.php
from examples/ch09 to workfiles/ch09 and save it as feedback_spry.php.
1. In Design view, select the existing drop-down menu, and then click the List Values
button in the Property inspector. The first item (– Select one –) is an invalid choice,
so you need to take a note of its Value (0). Close the List Values dialog box.
2. With the menu still selected, click the Spry Validation Select button in the Insert bar.
3. In the Property inspector, select the Invalid value checkbox, and replace the default
-1 with 0 in the field alongside. This is the invalid value you confirmed in step 1.
Also select Validate on Change.
4. Save the page, and test it in a browser. An alert message should be displayed if you
select nothing or an invalid value.
As with the checkbox group, you can convert <span> tags to <div> tags. Spry isn’t concerned
with the type of element used, but with the class and id attributes.
Styling the alert messages follows the same principles as for a text field in the various validation
widgets. Study the style sheets in the Spry assets folder, or click the Customize this
widget link in the Property inspector to display Dreamweaver help, which explains which
style rules to change.
Next, let’s move to the server side . . .
This has been a long chapter, crammed with detail, but it’s an important one. You’ll use
forms time and again when building dynamic sites, and making sure that user input is in
the right format saves endless headaches later on. Spry does a lot to help with validation
and is fairly easy to use, but the Dreamweaver interface could still do with some improvement.
However, it’s important to remember that client-side validation is only half the story.
Applying a validation widget to an existing drop-down menu
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
292
Because JavaScript can be turned off in the browser, you also need to check user input on
the server side with PHP.
Moreover, forms are useless without a script capable of processing the data. The next
chapter serves as a crash course in PHP basics for readers new to PHP. Then in Chapter 11,
we get down to the nitty-gritty of server-side programming, using PHP to validate user
input and then send it to your mail inbox.
BUILDING ONLINE FORMS AND VALIDATING INPUT
293
9
10 INTRODUCING THE BASICS OF PHP
This chapter is a cross between a crash course in PHP and a handy reference. It’s aimed at
readers who are completely new to PHP or who may have dabbled without really getting
to grips with the language. The intention is not to teach you all there is to know but to arm
you with sufficient knowledge to dig into Code view to customize Dreamweaver code with
confidence. Dreamweaver’s automatic code generation does a lot of the hard work for
you, but you need to tweak the code to get the best out of it, and when it comes to sending
an email from an online form, you have to do everything yourself.
By the end of this chapter, you’ll learn about
Writing and understanding PHP scripts
Using variables to represent changing values
Understanding the difference between single and double quotes
Organizing related information with arrays
Creating pages that make decisions for themselves
Using loops and functions for repetitive work
If you’re already comfortable with PHP, just glance at the section headings to see what’s
covered, as you might find it useful to refer to this chapter if you need to refresh your
memory about a particular subject. Then move straight to the next chapter and start
coding.
If you’re new to PHP, don’t try to learn everything at one sitting, or your brain is likely to
explode from information overload. On the first reading, look at the headings and maybe
the first paragraph or two under each one to get a general overview. Also read the section
“Understanding PHP error messages.”
Introducing the basics of PHP
PHP is a server-side language. This means that the web server processes your PHP code and
sends only the results—usually as XHTML—to the browser. Because all the action is on the
server, you need to tell it that your pages contain PHP code. This involves two simple steps,
namely:
Give every page a PHP file name extension—the default is .php. Do not use anything
other than .php unless you are told to specifically by your hosting company.
Enclose all PHP code within PHP tags.
The opening tag is <?php and the closing tag is ?>. You may come across <? as a short version
of the opening tag. However, <? doesn’t work on all servers. Stick with <?php, which is
guaranteed to work.
Embedding PHP in a web page
When somebody visits your site and requests a PHP page, the server sends it to the PHP
engine, which reads the page from top to bottom looking for PHP tags. XHTML passes
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
296
through untouched, but whenever the PHP engine encounters a <?php tag, it starts
processing your code and continues until it reaches the closing ?> tag. If the PHP code
produces any output, it’s inserted at that point. Then, any remaining XHTML passes
through until another <?php tag is encountered.
PHP doesn’t always produce direct output for the browser. It may, for instance, check the
contents of form input before sending an email message or inserting information into a
database. So some code blocks are placed above or below the main XHTML code. Code
that produces direct output, however, always goes where you want the output to be
displayed.
A typical PHP page uses some or all of the following elements:
Variables to act as placeholders for unknown or changing values
Arrays to hold multiple values
Conditional statements to make decisions
Loops to perform repetitive tasks
Functions to perform preset tasks
Ending commands with a semicolon
PHP is written as a series of commands or statements. Each statement normally tells the
PHP engine to perform a particular action, and it must always be followed by a semicolon,
like this:
<?php
do this;
now do something else;
finally, do that;
?>
PHP is not like JavaScript or ActionScript. It won’t automatically assume there should be a
semicolon at the end of a line if you leave it out. This has a nice side effect: you can spread
long statements over several lines and lay out your code for ease of reading. PHP, like
XHTML, ignores whitespace in code. Instead, it relies on semicolons to indicate where one
command ends and the next one begins.
To save space, I won’t always surround code samples with PHP tags.
You can have as many PHP code blocks as you like on a page, but they
cannot be nested inside each other.
INTRODUCING THE BASICS OF PHP
297
10
Using variables to represent changing values
A variable is simply a name that you give to something that may change or that you don’t
know in advance. The name that you give to a variable remains constant, but the value
stored in the variable can be changed at any time.
Although this concept sounds abstract, we use variables all the time in everyday life. When
you meet somebody for the first time, one of the first things you ask is, “What’s your
name?” It doesn’t matter whether the person you’ve just met is Tom, Dick, or Harry, the
word “name” remains constant, but the value we store in it varies for different people.
Similarly, with your bank account, money goes in and out all of the time (mostly out, it
seems), but it doesn’t matter whether you’re scraping the bottom of the barrel or as rich
as Croesus, the amount of money in your account is always referred to as the balance.
Naming variables
You can choose just about anything you like as the name for a variable, as long as you keep
the following rules in mind:
Variables always begin with $ (a dollar sign).
The first character after the dollar sign cannot be a number.
No spaces or punctuation are allowed, except for the underscore (_).
Variable names are case sensitive: $name and $Name are not the same.
A variable’s name should give some indication of what it represents: $name, $email, and
$totalPrice are good examples. Because you can’t use spaces in variable names, it’s a
good idea to capitalize the first letter of the second or subsequent words when combining
them (sometimes called camel case). Alternatively, you can use an underscore (e.g.,
$total_price).
Don’t try to save time by using really short variables. Using $n, $e, and $tp instead of
descriptive ones makes code harder to understand. More important, it makes errors more
difficult to spot.
Assigning values to variables
Variables get their values from a variety of sources, including the following:
User input through online forms
A database
An external source, such as a news feed or XML file
The result of a calculation
Direct inclusion in the PHP code
Although you have considerable freedom in the choice of variable names, you
can’t use $this, because it has a special meaning in PHP object-oriented programming.
It’s also advisable to avoid using any of the keywords listed at
www.php.net/manual/en/reserved.php.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
298
Wherever the value comes from, it’s always assigned in the same way with an equal sign
(=), like this:
$variable = value;
Because it assigns a value, the equal sign is called the assignment operator. Although it’s an
equal sign, get into the habit of thinking of it as meaning “is set to” rather than “equals.”
This is because PHP uses two equal signs (==) to mean “equals”—something that catches
out a lot of beginners (experienced PHP programmers are not immune to the occasional
lapse, either).
Use the following rules when assigning a value to a variable:
Strings must be enclosed in single or double quotes (the distinction between the
different types of quotes is explained later in the chapter).
Numbers should not be in quotes—enclosing a number in quotes turns it into a
string.
You can also use a variable to assign a value to another variable, for example:
$name = ‘David Powers’;
$author = $name; // both $author and $name are now ‘David Powers’
If the value of $name changes subsequently, it doesn’t affect the value of $author. As this
example shows, you don’t use quotes around a variable when assigning its value to
another. However, as long as you use double quotes, you can embed a variable in a string
like this:
$blurb = “$author has written several best-selling books on PHP.”;
The value of $blurb is now “David Powers has written several best-selling books on PHP.”
There’s a more detailed description on the use of variables with double quotes in
“Choosing single or double quotation marks” later in the chapter.
Displaying PHP output
The most common ways of displaying dynamic output in the browser are to use echo or
print. The differences between the two are so subtle you can regard them as identical. I
prefer echo, because it’s one fewer letter to type. It’s also the style used by Dreamweaver.
Put echo (or print) in front of a variable, number, or string like this to output it to the
browser:
$name = ‘David’;
echo $name; // displays David
echo 5; // displays 5
echo ‘David’; // displays David
You may see scripts that use parentheses with echo and print, like this:
echo(‘David’); // displays David
print(‘David’); // displays David
INTRODUCING THE BASICS OF PHP
299
10
The parentheses make no difference. Unless you enjoy typing purely for the sake of it,
leave them out.
Commenting scripts for clarity and debugging
Even if you’re an expert programmer, code is not always as immediately understandable as
something written in your own human language. That’s where comments can be a lifesaver.
You may understand what the code does five minutes after creating it, but when you
come back to maintain it in six months’ time—or if you have to maintain someone else’s
code—you’ll be grateful for well-commented code.
In PHP, there are three ways to add comments. The first will be familiar to you if you write
JavaScript. Anything on a line following a double slash is regarded as a comment and will
not be processed.
// Display the name
echo $name;
You can also use the hash sign (#) in place of the double slash.
# Display the name
echo $name;
Either type of comment can go to the side of the code, as long as it doesn’t go onto the
next line.
echo $name; // This is a comment
echo $name; # This is another comment
The third style allows you to stretch comments over several lines by sandwiching them
between /* and */ (just like CSS comments).
/* You might want to use this sort of comment to explain
the whole purpose of a script. Alternatively, it’s a
convenient way to disable part of a script temporarily.
*/
As the previous example explains, comments serve a dual purpose: they not only allow you
to sprinkle your scripts with helpful reminders of what each section of code is for; they can
also be used to disable a part of a script temporarily. This is extremely useful when you are
trying to trace the cause of an error.
The important thing to remember about echo and print is that they work only with
variables that contain a single value. You cannot use them to display more complex
structures that are capable of storing multiple values.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
300
Choosing single or double quotation marks
As I mentioned earlier, strings must always be enclosed in single or double quotes. If all
you’re concerned about is what ends up on the screen, most of the time it doesn’t matter
which quotes you use, but behind the scenes, PHP uses single and double quotes in very
different ways.
Anything between single quotation marks is treated as plain text.
Anything between double quotation marks is processed.
Quotation marks need to be in matching pairs. If a string begins with a single quote, PHP
looks for the next single quote and regards that as the end of the string. Since an apostrophe
uses the same character as a single quote, this presents a problem. A similar problem
arises when a string in double quotes contains double quotes. The best way to explain this
is with a practical example.
This simple exercise demonstrates the difference between single and double quotes and
what happens when a conflict arises with an apostrophe or double quotes inside a string.
1. Create a new PHP page called quotes.php in workfiles/ch10. If you just want to
look at the finished code, use quotes.php in examples/ch10.
2. Switch to Code view, and type the following code between the <body> tags:
<?php
$name = ‘David Powers’;
echo ‘Single quotes: The author is $name<br />’;
echo “Double quotes: The author is $name”;
?>
3. Save the page, and load it into a browser. As you can see from the following
screenshot, $name is treated as plain text in the first line, but is processed and
replaced with its value in the second line, which uses double quotes.
To display the output on separate lines, you have to include XHTML tags, such as
<br />, because echo outputs only the values passed to it—nothing more.
Experimenting with quotes
INTRODUCING THE BASICS OF PHP
301
10
4. Change the text slightly in lines 3 and 4 of the code, as follows:
echo ‘Single quotes: The author‘s name is $name<br />’;
echo “Double quotes: The author‘s name is $name”;
As you type, the change in Dreamweaver syntax coloring should alert you to a
problem, but save the page nevertheless, and view it in a browser (it’s quotes2.php
in examples/ch10). You should see something like this:
As far as PHP is concerned, an apostrophe and a single quote are the same thing,
and quotes must always be in matching pairs. What’s happened is that the apostrophe
in author’s has been regarded as the closing quote for the first line; what was
intended as the closing quote of the first line becomes a second opening quote;
and the apostrophe in the second line becomes the second closing quote. All quite
different from what was intended—and if you’re confused, is it any wonder that
PHP is unable to work out what’s meant to be going on?
5. To solve the problem, insert a backslash in front of the apostrophe in the first sentence,
like this (see quotes3.php in examples/ch10):
echo ‘Single quotes: The author\‘s name is $name<br />’;
You should now see the syntax coloring revert to normal. If you view the result in a
browser, it should display correctly like this:
The meaning of parse error and other error messages is explained in “Understanding
PHP error messages” at the end of the chapter.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
302
Using escape sequences in strings
Using a backslash like this is called an escape sequence. It tells PHP to treat a character in
a special way. Double quotes within a double-quoted string? You guessed it—escape them
with a backslash.
echo “Swift’s \”Gulliver’s Travels\”"; // displays the double quotes
The next line of code achieves exactly the same thing, but by using a different combination
of quotes:
echo ‘Swift\’s “Gulliver\’s Travels”‘;
So what happens when you want to include a literal backslash? You escape it with a backslash
(\\).
The backslash (\\) and the single quote (\’) are the only escape sequences that work in a
single-quoted string. Because double quotes are a signal to PHP to process any variables
contained within a string, there are many more escape sequences for double-quoted
strings. Most of them are to avoid conflicts with characters that are used with variables,
but three of them have special meanings: \n inserts a new line character, \r inserts a carriage
return (needed mainly for Windows), and \t inserts a tab. Table 10-1 lists the main
escape sequences supported by PHP.
Table 10-1. The main PHP escape sequences
Escape sequence Character represented in double-quoted string
\” Double quote
\n New line
\r Carriage return
\t Tab
\\ Backslash
\$ Dollar sign
\{ Opening curly brace
\} Closing curly brace
\[ Opening square bracket
\] Closing square bracket
When creating strings, the outside pair of quotes must match—any quotes of the
same style inside the string must be escaped with a backslash. However, putting a
backslash in front of the opposite style of quote will result in the backslash being displayed.
To see the effect, put a backslash in front of the apostrophe in the doubledquoted
string in the previous exercise.
INTRODUCING THE BASICS OF PHP
303
10
Double quotes are obviously very useful, so why not use them all the time? Many people
do, but the official recommendation is to use the quoting method that uses the least processing
power—and that’s usually single quotes. When PHP sees an opening double quote,
it tries to process any variables first. If it finds none, it goes back and treats the string as
plain text. On short scripts, such as in this book, the difference in processing time is negligible,
but it can make a difference on long, complex scripts.
Joining strings together
PHP has a rather unusual way of joining strings. Although many other computer languages
use the plus sign (+), PHP uses a period, dot, or full stop (.) like this:
$firstName = ‘David’;
$lastName = ‘Powers’;
echo $firstName.$lastName; // displays DavidPowers
As the comment in the final line of code indicates, when two strings are joined like this,
PHP leaves no gap between them. Don’t be fooled into thinking that adding a space after
the period will do the trick. It won’t. You can put as much space on either side of the
period as you like; the result will always be the same, because PHP ignores whitespace in
code. You must either include a space in one of the strings or insert the space as a string
in its own right, like this:
echo $firstName.’ ‘.$lastName; // displays David Powers
Adding to an existing string
Very often, you need to add more text at the end of an existing string. One way to do it is
like this:
$author = ‘David’;
$author = $author.’ Powers’; // $author is now ‘David Powers’
Basically, this concatenates Powers (with a leading space) on the end of $author, and then
assigns everything back to the original variable.
Adding something to an existing variable is such a common operation, PHP offers a shorthand
way of doing it—with the combined concatenation operator. Don’t worry about the
highfalutin name, it’s just a period followed by an equal sign. It works like this:
The period—or concatenation operator, to give it its correct name—can be difficult
to spot among a lot of other code. Make sure the font size in your script editor is large
enough to read without straining to see the difference between periods and commas.
The escape sequences listed in Table 10-1, with the exception of \\, work only in double-
quoted strings. If you use them in a single-quoted string, they are treated as a literal
backslash followed by the second character.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
304
$author = ‘David’;
$author .= ‘ Powers’; // $author is now ‘David Powers’
There should be no space between the period and equal sign. You’ll find this shorthand
very useful when building the string to form the body of an email message in the next
chapter.
Using quotes efficiently
Award yourself a bonus point if you spotted a better way of adding the space between
$firstName and $lastName in the last example. Yes, that’s right . . . Use double quotes,
like this:
echo “$firstName $lastName”; // displays David Powers
Choosing the most efficient combination of quotation marks isn’t easy when you first start
working with PHP, but it can make your code a lot easier to use. Many beginners stick
rigidly to double quotes for everything, and end up peppering their scripts with backslashes
to escape double quotes in the middle of strings. It not only makes scripts difficult
to read, but usually results in PHP errors or broken XHTML.
Special cases: true, false and null
Although text should be enclosed in quotes, three special cases—true, false, and null—
should never be enclosed in quotes unless you want to treat them as genuine text (or
strings). The first two mean what you would expect; the last one, null, means “nothing” or
“no value.”
PHP makes decisions on the basis of whether something evaluates to true or false.
Putting quotes around false has surprising consequences. The following code:
$OK = ‘false’;
does exactly the opposite of what you might expect: it makes $OK true! Why? Because the
quotes around false turn it into a string, and PHP treats strings as true. The other thing
to note about true, false, and null is that they are case insensitive. The following examples
are all valid:
$OK = TRUE;
$OK = tRuE;
$OK = true;
How long can a string be? As far as PHP is concerned, there’s no limit. In practice, you
are likely to be constrained by other factors, such as server memory; but in theory,
you could store the whole of War and Peace in a string variable.
INTRODUCING THE BASICS OF PHP
305
10
Working with numbers
PHP can do a lot with numbers—from simple addition to complex math. Numbers can
contain a decimal point or use scientific notation, but they must contain no other punctuation.
Never use a comma as a thousands separator. The following examples show the
right and wrong ways to assign a large number to a variable:
$million = 1000000; // this is correct
$million = 1,000,000; // this generates an error
$million = 1e6; // this is correct
$million = 1e 6; // this generates an error
When using scientific notation, the letter “e” can be uppercase or lowercase and optionally
followed by a plus or minus sign. No spaces are permitted.
Performing calculations
The standard arithmetic operators all work the way you would expect, although some of
them look slightly different from those you learned at school. For instance, an asterisk (*)
is used as the multiplication sign, and a forward slash (/) is used to indicate division.
Table 10-2 shows examples of how the standard arithmetic operators work. To demonstrate
their effect, the following variables have been set:
$x = 20;
$y = 10;
$z = 3;
Table 10-2. Arithmetic operators in PHP
Operation Operator Example Result
Addition + $x + $y 30
Subtraction – $x – $y 10
Multiplication * $x * $y 200
Division / $x / $y 2
Modulo division % $x % $z 2
Increment (add 1) ++ $x++ 21
Decrement (subtract 1) — $y– 9
You may not be familiar with the modulo operator. This returns the remainder of a division,
as follows:
26 % 5 // result is 1
26 % 27 // result is 26
10 % 2 // result is 0
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
306
A quirk with the modulo operator in PHP is that it converts both numbers to integers
before performing the calculation. Consequently, if $z is 4.5 in Table 10-2, it gets rounded
up to 5, making the result 0, not 2, as you might expect. (Yes, it was a mistake in my previous
books.)
A practical use of the modulo operator is to work out whether a number is odd or even.
$number % 2 will always produce 0 or 1.
The increment (++) and decrement (–) operators can come either before or after the
variable. When they come before the variable, 1 is added to or subtracted from the value
before any further calculation is carried out. When they come after the variable, the main
calculation is carried out first, and then 1 is either added or subtracted. Since the dollar
sign is an integral part of the variable name, the increment and decrement operators go
before the dollar sign when used in front:
++$x
–$y
You can set your own values for $x, $y, and $z in calculation.php in examples/ch10 to
test the arithmetic operators in action. The page also demonstrates the difference
between putting the increment and decrement operators before and after the variable.
As noted earlier, numbers should not normally be enclosed in quotes, although PHP will
usually convert to its numeric equivalent a string that contains only a number or that
begins with a number.
Calculations in PHP follow exactly the same rules as standard arithmetic. Table 10-3 summarizes
the precedence of arithmetic operators.
Table 10-3. Precedence of arithmetic operators
Precedence Group Operators Rule
Highest Parentheses () Operations contained within
parentheses are evaluated first. If
these expressions are nested, the
innermost is evaluated foremost.
Next Multiplication * / % These operators are evaluated
and division next. If an expression contains
two or more operators, they are
evaluated from left to right.
Lowest Addition and + – These are the final operators to
subtraction be evaluated in an expression.
If an expression contains two
or more operators, they are
evaluated from left to right.
If in doubt, use parentheses all the time to group the parts of a calculation that you want
to make sure are performed as a single unit.
INTRODUCING THE BASICS OF PHP
307
10
Combining calculations and assignment
You will often want to perform a calculation on a variable and assign the result back to the
same variable. PHP offers the same convenient shorthand for arithmetic calculations as for
strings. Table 10-4 shows the main combined assignment operators and their use.
Table 10-4. Combined arithmetic assignment operators used in PHP
Operator Example Equivalent to
+= $a += $b $a = $a + $b
-= $a -= $b $a = $a – $b
*= $a *= $b $a = $a * $b
/= $a /= $b $a = $a / $b
%= $a %= $b $a = $a % $b
Don’t forget that the plus sign is used in PHP only as an arithmetic operator.
Addition: Use += as the combined assignment operator
Strings: Use .= as the combined assignment operator
Using arrays to store multiple values
Arrays are an important—and useful—part of PHP. You met one of PHP’s built-in arrays,
$_POST, in the last chapter, and you’ll work with it a lot more through the rest of this book.
Arrays are also used extensively with a database, as you fetch the results of a search in a
series of arrays.
An array is a special type of variable that stores multiple values rather like a shopping list.
Although each item might be different, you can refer to them collectively by a single
name. Figure 10-1 demonstrates this concept: the variable $shoppingList refers collectively
to all five items—wine, fish, bread, grapes, and cheese.
Individual items—or array elements—are identified by means of a number in square
brackets immediately following the variable name. PHP assigns the number automatically,
but it’s important to note that the numbering always begins at 0. So the first item in the
array, wine, is referred to as $shoppingList[0], not $shoppingList[1]. And although
there are five items, the last one (cheese) is $shoppingList[4]. The number is referred to
as the array key or index, and this type of array is called an indexed array.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
308
Figure 10-1. Arrays are variables that store multiple items, just like a shopping list.
Instead of declaring each array element individually, you can declare the variable name
once, and assign all the elements by passing them as a comma-separated list to array(),
like this:
$shoppingList = array(‘wine’, ‘fish’, ‘bread’, ‘grapes’, ‘cheese’);
PHP numbers each array element automatically, so this creates the same array as in
Figure 10-1. To add a new element to the end of the array, use a pair of empty square
brackets like this:
$shoppingList[] = ‘coffee’;
PHP uses the next number available, so this becomes $shoppingList[5].
Using names to identify array elements
Numbers are fine, but it’s often more convenient to give array elements meaningful
names. For instance, an array containing details of this book might look like this:
$book['title'] = ‘Essential Guide to Dreamweaver CS3′;
$book['author'] = ‘David Powers’;
$book['publisher'] = ‘friends of ED’;
$book['ISBN13'] = ’978-1-59059-859-7′;
The comma must go outside the quotes, unlike American typographic practice.
For ease of reading, I have inserted a space following each comma, but it’s not
necessary to do so.
INTRODUCING THE BASICS OF PHP
309
10
This type of array is called an associative array. Note that the array key is enclosed in
quotes (single or double, it doesn’t matter). It mustn’t contain any spaces or punctuation,
except for the underscore.
The shorthand way of creating an associative array uses the => operator (an equal sign followed
by a greater-than sign) to assign a value to each array key. The basic structure looks
like this:
$arrayName = array(‘key1‘ => ‘element1‘, ‘key2‘ => ‘element2‘);
So, this is the shorthand way to build the $book array:
$book = array(‘title’ => ‘Essential Guide to Dreamweaver CS3′,
‘author’ => ‘David Powers’,
‘publisher’ => ‘friends of ED’,
‘ISBN13′ => ’978-1-59059-859-7′);
It’s not essential to align the => operators like this, but it makes code easier to read and
maintain.
Inspecting the contents of an array with print_r()
As you saw in the previous chapter, you can inspect the contents of an array using
print_r(). This is the code that you inserted at the bottom of feedback.php:
<pre>
<?php if ($_POST) {print_r($_POST);} ?>
</pre>
It displays the contents of the array like this:
The <pre> tags are simply to make the output more readable. What really matters here is
that print_r() displays the contents of an array. As explained earlier, echo and print
work only with variables that contain a single value. However, the only real value of
print_r() is to inspect the contents of an array for testing purposes. It’s no good in a live
web page. To display the contents of an array in normal circumstances, you need to use a
Technically speaking, all arrays in PHP are associative. This means that you can
use both numbers and strings as array keys in the same array. Don’t do it,
though, as it can produce unexpected results. It’s safer to treat indexed and
associative arrays as different types.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
310
loop. This gives you access to each array element one at a time. Once you get to an element
that contains a single value, you can use echo or print to display its contents. Loops
are covered a little later.
Making decisions
Decisions, decisions, decisions . . . Life is full of decisions. So is PHP. They give it the ability
to display different output according to circumstances. Decision making in PHP uses conditional
statements. The most common of these uses if and closely follows the structure
of normal language. In real life, you may be faced with the following decision (admittedly
not very often if you live in Britain):
If the weather’s hot, I’ll go to the beach.
In PHP pseudo-code, the same decision looks like this:
if (the weather’s hot) {
I’ll go to the beach;
}
The condition being tested goes inside parentheses, and the resulting action goes between
curly braces. This is the basic decision-making pattern:
if (condition is true) {
// code to be executed if condition is true
}
The code inside the curly braces is executed only if the condition is true. If it’s false, PHP
ignores everything between the braces and moves on to the next section of code. How
PHP determines whether a condition is true or false is described in the following section.
Sometimes, the if statement is all you need, but you often want a default action to be
invoked. To do this, use else, like this:
if (condition is true) {
// code to be executed if condition is true
}
else {
// default code to run if condition is false
}
Confusion alert: I mentioned earlier that statements must always be followed by a
semicolon. This applies only to the statements (or commands) inside the curly braces.
Although called a conditional statement, this decision-making pattern is one of PHP’s
control structures, and it shouldn’t be followed by a semicolon. Think of the semicolon
as a command that means “do it.” The curly braces surround the command
statements and keep them together as a group.
INTRODUCING THE BASICS OF PHP
311
10
What if you want more alternatives? One way is to add more if statements. PHP will test
them, and as long as you finish with else, at least one block of code will run. However, it’s
important to realize that all if statements will be tested, and the code will be run in every
single one where the condition equates to true. If you want only one code block to be
executed, use elseif like this:
if (condition is true) {
// code to be executed if first condition is true
}
elseif (second condition is true) {
// code to be executed if first condition fails
// but second condition is true
else {
// default code to run if both conditions are false
}
You can use as many elseif clauses in a conditional statement as you like. It’s important
to note that only the first one that equates to true will be executed; all others will be
ignored, even if they’re also true. This means you need to build conditional statements in
the order of priority that you want them to be evaluated. It’s strictly a first-come, firstserved
hierarchy.
The truth according to PHP
Decision making in PHP conditional statements is based on the mutually exclusive Boolean
values, true and false (the name comes from a nineteenth century mathematician,
George Boole, who devised a system of logical operations that subsequently became the
basis of much modern-day computing). If the condition equates to true, the code within
the conditional block is executed. If false, it’s ignored. Whether a condition is true or
false is determined in one of the following ways:
A variable set explicitly to true or false
A value PHP interprets implicitly as true or false
The comparison of two values
Explicit true or false values This is straightforward. If a variable is assigned the value true
or false and then used in a conditional statement, the decision is based on that value. As
explained earlier, true and false are case insensitive and must not be enclosed in quotes.
Implicit true or false values PHP regards the following as false:
The case-insensitive keywords false and null
Zero as an integer (0), a floating-point number (0.0), or a string (’0′ or “0″)
An empty string (single or double quotes with no space between them)
An empty array
Although elseif is normally written as one word, you can use else if
as separate words.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
312
An object with no values or functions (PHP 4 only)
A SimpleXML object created from empty tags
All other values equate to true.
How comparisons equate to true or false is described in the next section.
Using comparisons to make decisions
Conditional statements often depend on the comparison of two values. Is this bigger than
that? Are they both the same? If the comparison is true, the conditional statement is executed.
If not, it’s ignored.
To test for equality, PHP uses two equal signs (==) like this:
if ($status == ‘administrator’) {
// send to admin page
}
else {
// refuse entry to admin area
}
Size comparisons are performed using the mathematical symbols for less than (<) and
greater than (>). Let’s say you’re checking the size of a file before allowing it to be
uploaded to your server. You could set a maximum size of 50KB like this:
if ($bytes > 51200) {
// display error message and abandon upload
}
else {
// continue upload
}
Comparison operators These compare two values (known as operands because they
appear on either side of an operator). If both values pass the test, the result is true (or to
use the technical expression, it returns true). Otherwise, it returns false. Table 10-5 lists
the comparison operators used in PHP.
Don’t use a single equal sign in the first line like this:
if ($status = ‘administrator’) {
Doing so will open the admin area of your website to everyone. Why? Because
this automatically sets the value of $status to administrator; it doesn’t compare
the two values. To compare values, you must use two equal signs. It’s an
easy mistake to make, but one with potentially disastrous consequences.
This definition explains why “false” (in quotes) is interpreted by PHP as
true. The value –1 is also treated as true in PHP.
INTRODUCING THE BASICS OF PHP
313
10
Table 10-5. PHP comparison operators used for decision making
Symbol Name Use
== Equality Returns true if both operands have the
same value; otherwise, returns false.
!= Inequality Returns true if both operands have
different values; otherwise, returns false.
<> Inequality This has the same meaning as !=. It’s rarely
used in PHP but has been included here for
the sake of completeness.
=== Identical Determines whether both operands are
identical. To be considered identical, they
must not only have the same value but also
be of the same datatype (for example, both
floating-point numbers).
!== Not identical Determines whether both operands are not
identical (according to the same criteria as
the previous operator).
> Greater than Determines whether the operand on the left
is greater in value than the one on the right.
>= Greater than or equal to Determines whether the operand on the left
is greater in value than or equal to the one
on the right.
< Less than Determines whether the operand on the left
is less in value than the one on the right.
<= Less than or equal to Determines whether the operand on the left
is less in value than or equal to the one on
the right.
Testing more than one condition
Frequently, comparing two values is not enough. PHP allows you to set a series of conditions
using logical operators to specify whether all, or just some, need to be fulfilled.
All the logical operators in PHP are listed in Table 10-6. Negation—testing that the opposite
of something is true—is also considered a logical operator, although it applies to
individual conditions rather than a series.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
314
Table 10-6. Logical operators used for decision making in PHP
Symbol Name Use
&& Logical AND Evaluates to true if both operands are true. If the lefthand
operand evaluates to false, the right-hand
operand is never tested.
and Logical AND Exactly the same as &&, but it takes lower precedence.
|| Logical OR Evaluates to true if either operand is true; otherwise,
returns false. If the left-hand operand returns true,
the right-hand operand is never tested.
or Logical OR Exactly the same as ||, but it takes lower precedence.
xor Exclusive OR Evaluates to true if only one of the two operands
returns true. If both are true or both are false, it
evaluates to false.
! Negation Tests whether something is not true.
Technically speaking, there is no limit to the number of conditions that can be tested. Each
condition is considered in turn from left to right, and as soon as a defining point is
reached, no further testing is carried out. When using && or and, every condition must be
fulfilled, so testing stops as soon as one turns out to be false. Similarly, when using || or
or, only one condition needs to be fulfilled, so testing stops as soon as one turns out to
be true.
$a = 10;
$b = 25;
if ($a > 5 && $b > 20) // returns true
if ($a > 5 || $b > 30) // returns true, $b never tested
The implication of this is that when you need all conditions to be met, you should design
your tests with the condition most likely to return false as the first to be evaluated. When
you need just one condition to be fulfilled, place the one most likely to return true first.
If you want a particular set of conditions considered as a group, enclose them in parentheses.
if (($a > 5 && $a < 8) || ($b > 20 && $b < 40))
Operator precedence is a tricky subject. Stick with && and ||, rather than and and or, and
use parentheses to group expressions to which you want to give priority. The xor operator
is rarely used.
INTRODUCING THE BASICS OF PHP
315
10
Using the switch statement for decision chains
The switch statement offers an alternative to if . . . else for decision making. The
basic structure looks like this:
switch(variable being tested) {
case value1:
statements to be executed
break;
case value2:
statements to be executed
break;
default:
statements to be executed
}
The case keyword indicates possible matching values for the variable passed to switch().
When a match is made, every subsequent line of code is executed until the break keyword
is encountered, at which point the switch statement comes to an end.
Dreamweaver uses a switch statement in the GetSQLValueString() function, which it
inserts into pages that insert or update records in a database.
The main points to note about switch are as follows:
The expression following the case keyword must be a number or a string.
You can’t use comparison operators with case. So case > 100: isn’t allowed.
Each block of statements should normally end with break, unless you specifically
want to continue executing code within the switch statement.
You can group several instances of the case keyword together to apply the same
block of code to them.
If no match is made, any statements following the default keyword will be executed.
If no default has been set, the switch statement will exit silently and continue
with the next block of code.
Using the conditional operator
The conditional operator (?:) is a shorthand method of representing a simple conditional
statement. The basic syntax looks like this:
condition ? value if true : value if false;
What this means is that, if the condition to the left of the question mark is true, the value
immediately to the right of the question mark is used. However, if the condition evaluates
to false, the value to the right of the colon is used instead. Here is an example of it in use:
$age = 17;
$fareType = $age > 16 ? ‘adult’ : ‘child’;
The conditional operator can be quite confusing when you first encounter it, so let’s break
down this example section by section.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
316
The first line sets the value of $age to 17.
The second line sets the value of $fareType using the conditional operator. The condition
is between the equal sign and the question mark—in other words, $age > 16.
If $age is greater than 16, the condition evaluates to true, so $fareType is set to the value
between the question mark and the colon—in other words, ‘adult’. Otherwise $fareType
is set to the value to the right of the colon—or ‘child’. You can rewrite the second line
using if . . . else like this:
if ($age > 16) {
$fareType = ‘adult’;
}
else {
$fareType = ‘child’;
}
The if . . . else version is much easier to read, but the conditional operator is more
compact, and it’s used frequently by Dreamweaver. Most beginners hate this shorthand,
but you need to understand how it works if you want to customize Dreamweaver code.
Because the conditional operator uses three operands, it’s sometimes called the ternary
operator.
Using loops for repetitive tasks
Loops are huge time-savers, because they perform the same task over and over again, yet
involve very little code. They’re frequently used with arrays and database results. You can
step through each item one at a time looking for matches or performing a specific task.
Loops frequently contain conditional statements, so although they’re very simple in structure,
they can be used to create code that processes data in often sophisticated ways.
Loops using while and do . . . while
The simplest type of loop is called a while loop. Its basic structure looks like this:
while (condition is true) {
do something
}
The following code displays every number from 1 through 100 in a browser (you can see it
in action in while.php in examples/ch10). It begins by setting a variable ($i) to 1, and then
using the variable as a counter to control the loop, as well as display the current number
onscreen.
$i = 1; // set counter
while ($i <= 100) {
echo “$i<br />”;
$i++; // increase counter by 1
}
INTRODUCING THE BASICS OF PHP
317
10
A variation of the while loop uses the keyword do and follows this basic pattern:
do {
code to be executed
} while (condition to be tested);
The only difference between a do . . . while loop and a while loop is that the code
within the do block is executed at least once, even if the condition is never true. The following
code (in dowhile.php in examples/ch10) displays the value of $i once, even
though it’s greater than the maximum expected.
$i = 1000;
do {
echo “$i<br />”;
$i++; // increase counter by 1
} while ($i <= 100);
Dreamweaver uses a do . . . while loop in its Repeat Region server behavior to loop
through the results of a database query (what Dreamweaver calls a recordset) and display
them on your page.
The danger with creating while and do . . . while loops yourself is forgetting to set a
condition that brings the loop to an end or setting an impossible condition. When this
happens, you create an infinite loop that either freezes your computer or causes the
browser to crash.
The versatile for loop
The for loop is less prone to generating an infinite loop, because you specify in the first
line how you want the loop to work. The for loop uses the following basic pattern:
for (initialize counter; test; increase or decrease the counter) {
code to be executed
}
The three expressions inside the parentheses control the action of the loop (note that they
are separated by semicolons, not commas):
The first expression initializes the counter variable at the start of the loop. You can
use any variable you like, but the convention is to use $i. When more than one
counter is needed, $j and $k are frequently used.
The second expression is a test that determines whether the loop should continue
to run. This can be a fixed number, a variable, or an expression that calculates a
value.
The third expression shows the method of stepping through the loop. Most of the
time, you will want to go through a loop one step at a time, so using the increment
(++) or decrement (–) operator is convenient.
The following code does exactly the same as the previous while loop, displaying every
number from 1 to 100 (see forloop.php in examples/ch10):
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
318
for ($i = 1; $i <= 100; $i++) {
echo “$i<br />”;
}
There is nothing stopping you from using bigger steps. For instance, replacing $i++ with
$i+=10 in this example would display 1, 11, 21, 31, and so on.
Looping through arrays with foreach
The final type of loop in PHP is used exclusively with arrays. It takes two forms, both of
which use temporary variables to handle each array element. If you only need to do something
with the value of each array element, the foreach loop takes the following form:
foreach (array_name as temporary_variable) {
do something with temporary_variable
}
The following example loops through the $shoppingList array and displays the name of
each item (see shopping_list.php in examples/ch10):
$shoppingList = array(‘wine’, ‘fish’, ‘bread’, ‘grapes’, ‘cheese’);
foreach ($shoppingList as $item) {
echo $item.’<br />’;
}
The preceding example accesses only the value of each array element. An alternative form
of the foreach loop gives access to both the key and value of each element. It takes this
slightly different form:
foreach (array_name as key_variable => value_variable) {
do something with key_variable and value_variable
}
This next example uses the $book array from “Using names to identify array elements” earlier
in the chapter and incorporates the key and value of each element into a simple string,
as shown in the screenshot (see book.php in examples/ch10):
foreach ($book as $key => $value) {
echo “The value of $key is $value<br />”;
}
INTRODUCING THE BASICS OF PHP
319
10
Breaking out of a loop
To bring a loop prematurely to an end when a certain condition is met, insert the break
keyword inside a conditional statement. As soon as the script encounters break, it exits
the loop.
To skip an iteration of the loop when a certain condition is met, use the continue keyword.
Instead of exiting, it returns to the top of the loop and executes the next iteration.
Using functions for preset tasks
Functions do things . . . lots of things, mind-bogglingly so in PHP. The last time I counted,
PHP had nearly 3,000 built-in functions, and more have been added since. Don’t worry:
you’ll only ever need to use a handful, but it’s reassuring to know that PHP is a fullfeatured
language capable of industrial-strength applications.
The functions you’ll be using in this book do really useful things, such as send email, query
a database, format dates, and much, much more. You can identify functions in PHP code,
because they’re always followed by a pair of parentheses. Sometimes the parentheses are
empty, as in the case of phpinfo(), which you used in test.php when setting up your testing
environment in Chapter 3. Often, though, the parentheses contain variables, numbers,
or strings, like this:
$thisYear = date(‘Y’);
This calculates the current year and stores it in the variable $thisYear. It works by feeding
the string ‘Y’ to the built-in PHP function date(). Placing a value between the parentheses
like this is known as passing an argument to a function. The function takes the value in
the argument and processes it to produce (or return) the result. For instance, if you pass
the string ‘M’ as an argument to date() instead of ‘Y’, it will return the current month as
a three-letter abbreviation (e.g., Mar, Apr, May). The date() function is covered in detail in
Chapter 17.
Some functions take more than one argument. When this happens, separate the arguments
with commas inside the parentheses, like this:
$mailSent = mail($to, $subject, $message);
It doesn’t take a genius to work out that this sends an email to the address stored in the
first argument, with the subject line stored in the second argument, and the message
stored in the third one. You’ll see how this function works in the next chapter.
You’ll often come across the term “parameter” in place of “argument.” There is
a technical difference between the two words, but for all practical purposes,
they are interchangeable.
The foreach keyword is one word. Inserting a space between for and
each doesn’t work.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
320
As if the 3,000-odd built-in functions weren’t enough, PHP lets you build your own custom
functions. Even if you don’t relish the idea of creating your own, throughout this book
you’ll use some that I have made. You use them in exactly the same way.
Understanding PHP error messages
There’s one final thing you need to know about before savoring the delights of PHP: error
messages. They’re an unfortunate fact of life, but it helps a great deal if you understand
what they’re trying to tell you. The following illustration shows the structure of a typical
error message.
The first thing to realize about PHP error messages is that they report the line where PHP
discovered a problem. Most newcomers—quite naturally—assume that’s where they’ve
got to look for their mistake. Wrong . . .
What PHP is telling you most of the time is that something unexpected has happened. In
other words, the mistake frequently lies before that point. The preceding error message
means that PHP discovered a foreach command where there shouldn’t have been one.
(Error messages always prefix PHP elements with T_, which stands for token. Just ignore it.)
Instead of worrying what might be wrong with the foreach command (probably nothing),
start working backward, looking for anything that might be missing. Usually, it’s a semicolon
or closing quote. In this example, the error was caused by omitting the semicolon at
the end of line 28 in book.php.
There are four main categories of error, presented here in descending order of importance:
Fatal error: Any XHTML output preceding the error will be displayed, but once the
error is encountered—as the name suggests—everything else is killed stone dead.
A fatal error is normally caused by referring to a nonexistent file or function.
Parse error: This means there’s a mistake in your code, such as mismatched quotes,
or a missing semicolon or closing brace. Like a fatal error, it stops the script in its
tracks and doesn’t even allow any XHTML output to be displayed.
Warning: This alerts you to a serious problem, such as a missing include file.
(Include files are covered in Chapter 12.) However, the error is not serious enough
to prevent the rest of the script from being executed.
Notice: This advises you about relatively minor issues, such as the use of a nondeclared
variable. Although you can turn off the display of notices, you should always
try to eliminate the cause, rather than sweep the issue under the carpet. Any error
is a threat to your output.
INTRODUCING THE BASICS OF PHP
321
10
Hosting companies have different policies about the level of error checking. If error checking
is set to a high level and the display of errors is turned off, any mistakes in your code
will result in a blank screen. Even if your hosting company has a more relaxed policy, you
still don’t want mistakes to be displayed for all to see. Test your code thoroughly, and eliminate
all errors before deploying it on a live website.
Another type of error, strict, was introduced in PHP 5.0.0, mainly for the benefit of
advanced developers. As of this writing, strict error messages are not displayed by default,
but there are plans to change this and introduce a new deprecated category as a prelude
to removing outdated parts of the language. If you see a strict or deprecated error message,
ignore it at your peril.
Now put it to work . . .
After that crash course, I hope you’re feeling not like a crash victim but invigorated and
raring to go. Although you have been bombarded with a mass of information, you’ll discover
that it’s easy to make rapid progress with PHP. In the next chapter, you’ll use most of
the techniques from this chapter to send user input from an online form to your email
inbox. To begin with, you’ll probably feel that you’re copying code without much comprehension,
but I’ll explain all the important things along the way, and you should soon find
things falling into place.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
322
11 USING PHP TO PROCESS A FORM
In Chapter 9, I showed you how to build a feedback form and validate the input on the
client side with Spry validation widgets. In this chapter, we’ll take the process to its next
stage by validating the data on the server side with PHP. If the data is OK, we’ll send the
contents by email and display an acknowledgement message. If there’s a problem with any
of the data, we’ll redisplay it in the form with messages prompting the user to correct any
errors or omissions. Figure 11-1 shows the flow of events.
Figure 11-1. The flow of events in processing the feedback form
Sending an email from an online form is just the sort of task that Dreamweaver should
automate, but unfortunately it doesn’t. Commercial extensions are available to automate
the process for you, but not everyone will have—or want to buy—a commercial extension
in addition to Dreamweaver CS3, so I think it’s important to show you how to hand-code
this vital feature. At the same time, it gives you practical experience working with PHP
code, which is essential unless you are willing to be limited to very basic tasks. The
Dreamweaver server behaviors and data objects that you will use in later chapters take a
lot of the hard work out of creating dynamic applications, but like the CSS layout that you
used in Chapter 6, they lay a solid foundation for you to build on, rather than do
absolutely everything for you.
This chapter shows you how to
Gather user input and send it by email
Use PHP conditional logic to check required fields
Display errors without losing user input
Filter out suspect material
Avoid email header injection attacks
Process multiple-choice form elements
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
326
The flow of events shown in Figure 11-1 is controlled by a series of conditional statements
(see “Making decisions” in the previous chapter). The PHP script will be in the same page
as the form, so the first thing that it needs to know is if the form has been submitted. If it
has, the contents of the $_POST array will be checked. If it’s OK, the email will be sent and
an acknowledgement displayed, else a series of error messages will be displayed. In other
words, everything is controlled by if . . . else statements.
Activating the form
As you saw in Chapter 9, data entered into the form can be retrieved by using
print_r($_POST); to inspect the contents of the $_POST array. This is one of PHP’s socalled
superglobal arrays. They’re such an important part of PHP, it’s worth pausing for a
moment to take a look at what they do.
Getting information from the server with PHP superglobals
Superglobal arrays are built-in associative arrays that are automatically populated with
really useful information. They all begin with a dollar sign followed by an underscore. The
most important superglobal arrays are as follows:
$_POST: This contains values sent through the post method.
$_GET: This contains values sent through the get method or a URL query string.
$_SERVER: This contains information stored by the web server, such as file name,
pathname, hostname, etc.
$_SESSION: This stores information that you want to preserve so that it’s available
to other pages. Sessions are covered in Chapter 15.
$_FILES: This contains details of file uploads. File uploads are not covered in this
book. See www.php.net/manual/en/features.file-upload.php or my book PHP
Solutions: Dynamic Web Design Made Easy (friends of ED, ISBN-13: 978-1-59059-
731-6) for details.
The keys of $_POST and $_GET are automatically derived from the names of form elements.
Let’s say you have a text input field called address in a form; PHP automatically creates
an array element called $_POST['address'] when the form is submitted by the post
method or $_GET['address'] if you use the get method. As Figure 11-2 shows,
$_POST['address'] contains whatever value a visitor enters in the text field, enabling you
to display it onscreen, insert it in a database, send it to your email inbox, or do whatever
you want with it.
Figure 11-2. The $_POST array automatically creates variables with the same name
and value as each form field.
USING PHP TO PROCESS A FORM
327
11
It’s important to realize that variables like $_POST['address'] or $_GET['address'] don’t
exist until the form has been submitted. So, before using $_POST or $_GET variables in a
script, you should always test for their existence with isset() or wrap the entire section
of script in a conditional statement that checks whether the form has been submitted.
You’ll see both of these techniques in action in this chapter and the rest of this book.
You may come across old scripts or tutorials that tell you PHP automatically creates variables
with the same name as form fields. In this example, it would be $address. This relies
on a setting called register_globals being on. The default for register_globals has
been off since 2002, but some hosting companies still switch it back on. You should never
rely on register_globals, as it leaves your site wide open to malicious attacks. Moreover,
register_globals has been removed from PHP 6, so scripts that rely on this setting will
break in the future.
Some scripts also recommend the use of $_REQUEST, which is another PHP superglobal. It’s
much less secure. Always use $_POST for data submitted using the post method and $_GET
for the get method or when values are passed through a query string at the end of a URL.
Dreamweaver code hints make it easy to type the names of superglobals. As soon as you
type the underscore after the dollar sign, it displays a list of the array names; and for arrays
such as $_SERVER with predefined elements, a second menu with the predefined elements
is also displayed, as you’ll see when you start scripting the form.
Sending email
To send an email with PHP, you use the mail() function, which takes up to five arguments,
all of them strings, as follows:
The address(es) of the recipient(s)
The subject line
The message body
A list of other email headers
Additional parameters
The first three arguments are required. Email addresses in the first argument can be in
either of the following formats:
‘user@example.com’
‘Some Guy <user2@example.com>’
To send to more than one address, use a comma-separated string like this:
‘user@example.com, another@example.com, Some Guy <user2@example.com>’
Don’t forget that PHP is case sensitive. All superglobal array names are written in
uppercase. $_Post or $_Get, for example, won’t work.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
328
The second argument is a string containing the subject line. The third argument is the message
body, which must be a single string, regardless of how long it is. I’ll come back to the
final two arguments later.
It’s important to understand that mail() isn’t an email program. It passes data to the web
server’s mail transport agent (MTA). PHP’s responsibility ends there. It has no way of knowing
if the email is delivered to its destination. It doesn’t handle attachments or HTML
email. Still, it’s efficient and easy to use.
These days, most Internet service providers (ISPs) enforce simple mail transfer protocol
(SMTP) authentication before accepting email for relay from another machine. However,
since mail() communicates directly with the MTA on the same machine, no authentication
is required. More important, since mail() doesn’t normally need to authenticate
itself, it’s not capable of doing so when you attempt to use it in your local test environment.
What happens is that mail() tries to hand the message to your local MTA. If it finds
one, and your ISP accepts the message, you’re in luck. More often than not, it can’t find
one or the ISP rejects the mail without authentication. On Windows, you can edit php.ini
(see Chapter 3) and change the SMTP command from localhost to the address of your
ISP’s outgoing mail server (it’s usually something like smtp.example.com). On a Mac, PHP
uses the MTA built into OS X, so there is no need to edit php.ini.
Scripting the feedback form
To make things simple, I’m going to break up the PHP script into several sections. To start
off, I’ll concentrate on the text input fields and sending their content by email. Then I’ll
move onto validation and the display of error messages before showing you how to handle
checkboxes, radio buttons, menus, and multiple-choice lists.
Most readers should be able to send a simple email after the following exercise, but even
if you are successful, you should implement the server-side validation described later in
the chapter. This is because, without some simple security precautions, you risk turning
your online forms into a spam relay. Your hosting company might suspend your site or
close down your account altogether. In fact, many hosting companies implement security
measures that prevent the first version of the mail script from working. However, you
should have a fully working form by the end of this chapter.
This involves a lot of hand-coding—much more than you’ll encounter in later chapters.
Even if you don’t want to do a lot of PHP programming, it’s important to get a feel for the
flow of a script, as this will help you customize the Dreamweaver code once you start
working with a database. The script uses a lot of PHP’s built-in functions. I explain the
important ones but don’t always go into the finer points of how they work. The idea is to
give you a working solution, rather than overwhelm you with detail. The finished code for
each section is in examples/ch11; and in the next chapter, I’ll show you how to put the
main part of the script in an external file so that you can reuse it with other forms without
the need to hand-code everything from scratch every time.
Local testing with mail() is very much hit and miss. The most reliable approach is to
test mail-processing scripts on your remote server. The instructions in this chapter
explain which parts of the script can be tested locally.
USING PHP TO PROCESS A FORM
329
11
The starting point is in feedback_01.php in examples/ch11. It’s the same as feedback_
fieldsets.php from Chapter 9 but with the small block of PHP code removed from the
bottom of the page. If you want to use your own form, I suggest that you remove any
client-side validation from it, as the client-side validation makes it difficult to check
whether the more important server-side validation with PHP is working correctly. You can
add the client-side validation back at the final stage.
1. Copy feedback_01.php from examples/ch11 to workfiles/ch11, and save it as
feedback.php. Also make sure you have a copy of contact.css in your styles
folder.
2. Open contact.css, and add the following style rule (it already exists in the version
in the examples/styles folder):
.warning {
font-weight:bold;
color:#FF0000;
}
This adds a class called warning, which displays text in bold red. Close
contact.css.
3. Open feedback.php in Split view, click anywhere inside the form, and use the Tag
selector to select the entire form. This should bring the opening tag of the form
into view in the Code view section of the Document window. Click inside Code view
so that your cursor is between the quotes of the action attribute. Although you
can set the action for the form through the Property inspector, doing so in Code
view greatly reduces the possibility of making a mistake.
4. Select the PHP tab on the Insert bar, and click the Echo button (the menu option is
Insert ä PHP Objects ä Echo). This will insert a pair of PHP tags followed by echo
between the quotes of the action attribute, and Dreamweaver positions your cursor
in the correct place to start typing, as shown in the following screenshot:
Processing and acknowledging the message
This is a long script. Give yourself plenty of time to absorb the details. You can
check your progress at each stage with the files in examples/ch11. The final
code is in feedback_12.php.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
330
5. To set the action attribute of the form to process itself, you need to use a variable
from the $_SERVER superglobal array. As noted before, superglobals always begin
with $_, so type just that at the current position. Dreamweaver automatically presents
you with a pop-up menu containing all the superglobals, as shown here:
You can navigate this pop-up menu in several ways: continue typing “server” in
either uppercase or lowercase until SERVER is highlighted or use your mouse or
the arrow keys to highlight it. Then double-click or press Enter/Return.
Dreamweaver will present you with another pop-up menu. Locate PHP_SELF as
shown, and either double-click or press Enter/Return:
6. Although it’s not strictly necessary for a single command, get into the habit of ending
all statements with a semicolon, and type one after the closing square bracket
(]) of the superglobal variable that’s just been entered. The code in the opening
<form> tag should look like this (new code is highlighted in bold type):
<form action=”<?php echo $_SERVER['PHP_SELF']; ?>” method=”post” å
name=”form1″ id=”form1″>
The predefined variable $_SERVER['PHP_SELF'] always contains the name of the
current page, so using echo between the quotes of the action attribute automatically
sets it to the current page, making this a self-processing form. As you saw
in Chapter 9, leaving out the value of action also results in the form attempting
to process itself. So, technically speaking, this isn’t 100 percent necessary, but
it’s common practice in PHP scripts, and it’s useful to know what
$_SERVER['PHP_SELF'] does.
7. You now need to add the mail-processing script at the top of the page. As you saw
in Chapter 9, the $_POST array contains not only the data entered into the form but
also the name and value of the submit button. You can use this information to
determine whether the submit button has been clicked. From this point onward, it
will be easier to work in Code view. Switch to Code view, and insert the following
block of PHP code immediately above the DOCTYPE declaration:
USING PHP TO PROCESS A FORM
331
11
<?php
if (array_key_exists(‘send’, $_POST)) {
// mail processing script
echo ‘You clicked the submit button’;
}
?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” å
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
This uses the PHP function array_key_exists() to check whether the $_POST array
contains a key called send, the name attribute of the form submit button. If you
don’t want to type out the function name yourself, you can press Ctrl+Space to
bring up an alphabetical list of all PHP functions. Type just the first few letters, and
then use your arrow keys to select the right one. When you press Tab or
Enter/Return, Dreamweaver finishes the rest of the typing and pops up a code hint.
Alternatively, just type the function name directly, and the code hint appears as
soon as you enter the opening parenthesis after array_key_exists, as shown here:
The mixed datatype refers to the fact that array keys can be either numbers or
strings. In this case, you are using a string, so enclose send in quotes, and then after
a comma, type $_POST. Because it’s a superglobal, you are presented with the
same pop-up menu as in step 5. If you select POST, Dreamweaver assumes that you
want to add the name of an array key and will automatically add an opening square
bracket after the T. On this occasion, you want to check the whole $_POST array,
not just a single element, so remove the bracket by pressing Backspace. Make sure
that you use two closing parentheses—the first belongs to the function
array_key_exists(), and the second encloses the condition being tested for by
the if statement.
If the send array key exists, the submit button must have been clicked, so any script
between the curly braces is executed. Otherwise, it’s ignored. Don’t worry that echo
will display text above the DOCTYPE declaration. It’s being used for test purposes
only and will be removed eventually.
8. Save feedback.php, and test it in a browser. It should look no different from
before.
Remember, an if statement doesn’t always need to be followed by else or
elseif. When the condition of a solitary if statement isn’t met, PHP simply
skips to the next block of code.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
332
9. Click the Send comments button. A message should appear at the top of the page
saying “You clicked the submit button.”
10. Reload the page without using the browser’s Reload button. Click inside the
address bar, and press Enter/Return. The message should disappear. This confirms
that any code inside the curly braces runs only if the submit button has been
clicked.
11. Change the block of code that you entered in step 7 so that it looks like this:
<?php
if (array_key_exists(‘send’, $_POST)) {
//mail processing script
$to = ‘me@example.com’; // use your own email address
$subject = ‘Feedback from Essential Guide’;
// process the $_POST variables
$name = $_POST['name'];
$email = $_POST['email'];
$comments = $_POST['comments'];
// build the message
$message = “Name: $name\n\n”;
$message .= “Email: $email\n\n”;
$message .= “Comments: $comments”;
// limit line length to 70 characters
$message = wordwrap($message, 70);
// send it
$mailSent = mail($to, $subject, $message);
}
?>
The code that does the processing consists of five stages. The first two lines assign
your email address to $to and the subject line of the email to $subject.
Next, $_POST['name'], $_POST['email'], and $_POST['comments'] are reassigned
to ordinary variables to make them easier to handle.
The shorter variables are then used to build the body of the email message, which
must consist of a single string. As you can see, I have used the combined concatenation
operator (.=) to build the message and escape sequences to add new line
characters between each section (see “Adding to an existing string” and “Using
escape sequences in strings” in Chapter 10).
Once the message body is complete, it’s passed to the wordwrap() function, which
takes two arguments: a string and an integer that sets the maximum length of each
line. Although most mail systems will accept longer lines, it’s recommended to limit
each line to 70 characters.
USING PHP TO PROCESS A FORM
333
11
After the message has been built and formatted, the recipient’s address, subject
line, and body of the message are passed to the mail() function. There is nothing
magical about the variable names $to, $subject, and $message. I chose them to
describe what each one contains, making much of the script self-commenting.
The mail() function returns a Boolean value (true or false) indicating whether it
succeeded. By capturing this value as $mailSent, you can use it to redirect the user
to another page or change the contents of the current one.
12. For the time being, let’s keep everything in the same page, because the rest of the
chapter will add further refinements to the basic script. Scroll down, and insert the
following code just after the page’s main heading (new code is highlighted in bold):
<h1>Contact us</h1>
<?php
if ($_POST && !$mailSent) {
?>
<p class=”warning”>Sorry, there was a problem sending your message.
Please try later.</p>
<?php
}
elseif ($_POST && $mailSent) {
?>
<p><strong>Your message has been sent. Thank you for your feedback.
</strong></p>
<?php } ?>
<p>We welcome feedback from visitors . . .</p>
Many beginners mistakenly think that you need to use echo or print to display
XHTML inside a PHP block. However, except for very short pieces of code, it’s more
efficient to switch back to XHTML, as I’ve done here. Doing so avoids the need to
worry about escaping quotes. Also, Dreamweaver code hints and automatic tag
completion speed things up for you. As soon as you type a space after <p in the
first paragraph, Dreamweaver pops up a code hint menu like this:
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
334
Select class. As soon as you do so, Dreamweaver checks the available classes in the
attached style sheet and pops up another code hint menu, as shown in the next
screenshot, so you can choose warning.
This makes coding much quicker and more accurate. Dreamweaver’s context sensitivity
means you get the full range of XHTML code hints only when you’re in a section
of XHTML code. When you’re inside a block of PHP code, you get a list of
XHTML tags when you type an opening angle bracket, but there are no attribute
hints or auto-completion. So it makes more sense to use PHP for the conditional
logic but keep the XHTML separate. The only thing you need to watch carefully is
that you balance the opening and closing curly braces correctly. I’ll show you how
to do that in “Using balance braces” a little later in the chapter.
So what does this code do? It may look odd if you’re not used to seeing scripts that
mix XHTML with PHP logic, but it can be summarized like this:
<h1>Contact us</h1>
<?php
if ($_POST && !$mailSent) {
// display a failure message
}
elseif ($_POST && $mailSent) {
// display an acknowledgment
}
?>
<p>We welcome feedback from visitors . . .</p>
Both parts of the conditional statement check the Boolean values of $_POST and
$mailSent. Although the $_POST array is always set, it doesn’t contain any values
unless the form has been submitted. Since PHP treats an empty array as false (see
“The truth according to PHP” in Chapter 10), you can use $_POST on its own to test
whether a form has been submitted. So the code in both parts of this conditional
statement is ignored when the page first loads.
However, if the form has been submitted, $_POST equates to true, so the next
condition is tested. The exclamation mark in front of $mailSent is the negative
operator, making it the equivalent of not $mailSent. So, if the email hasn’t been
sent, both parts of the test are true, and the XHTML containing the error message
is displayed. However, if $mailSent is true, the XHTML containing the acknowledgment
is displayed instead.
USING PHP TO PROCESS A FORM
335
11
13. Save feedback.php, and switch to Design view. The top of the page should now
look like this:
There are three gold shields indicating the presence of PHP code, and both the
error and acknowledgement messages are displayed. You need to get used to this
sort of thing when designing dynamic pages.
If you don’t see the gold shields, refer to “Passing information through a hidden
field” in Chapter 9 for details of how to control invisible elements in Design view.
14. To see what the page looks like when the PHP is processed, click the Live Data view
button (see alongside) to the right of the Design view button on the Document
toolbar.
If you have coded everything correctly, the error message and acknowledgement
should disappear. Click the Live Data view button to toggle it off again.
If you got a PHP error message, read “Using balance braces,” and then check your
code against feedback_02.php.
Using Balance Braces
Even if you didn’t encounter a problem in the preceding exercise, Balance Braces is a tool
that you definitely need to know about. Like quotes, curly braces must always be in matching
pairs, but sometimes the opening and closing braces can be dozens, even hundreds, of
lines apart. If one of a pair is missing, your script will collapse like a house of cards. Balance
Braces matches pairs in a highly visual way, making troubleshooting a breeze.
Let’s take a look at the code in step 12 that I suspect will trip many people up. I deliberately
removed an opening curly brace at the end of line 41 in the following screenshot.
That triggered a parse error, which reported an unexpected closing curly brace on line 45.
Now, that could mean either of the following:
The script in step 11 is theoretically all you need to send email from an online form.
Don’t be tempted to leave it at that. Without the security checks described in the rest
of the chapter, you run the risk of turning your website into a spam relay.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
336
There’s a missing opening brace to match the closing one.
There’s an extra closing brace that shouldn’t be there.
The way to resolve the problem is to place your cursor anywhere between a pair of curly
braces, and click the Balance Braces button in the Coding toolbar. This highlights the code
between the matching braces. I started by placing my cursor on line 37. As you can see, it
highlighted all the code between the braces on lines 35 and 40.
Next, I positioned my cursor on line 43. When I clicked the Balance Braces button again,
nothing was highlighted, and my computer just beeped. So there was the culprit. All I
needed to work out was where the opening brace should go. My first test showed that I
had a logical block on lines 35–40, so it was just a process of elimination tracking down the
missing brace. If the problem had been an extra curly brace that shouldn’t have been
there, the code would have been highlighted, giving me a clear indication of where the
block ended.
Although it can’t tell you whether your code logic is right or where a missing brace should
go, you’ll find this tool a great timesaver. It works not only with braces, but also with
square brackets and parentheses. Just position your cursor inside any curly brace, square
bracket, or parenthesis, and click the Balance Braces button to find the other one of the
pair. You may need to test several blocks to find the cause of a problem, but it’s an excellent
way of visualizing code blocks and the branching logic of your scripts.
You can also access Balance Braces through the Edit menu, and if you’re a keyboard shortcut
fan, the combination is Ctrl+’/Cmd+’ (single quote).
Testing the feedback form
Assuming that you now have a page that displays correctly in Live Data view, it’s time to
test it. As mentioned earlier, testing mail() in a local PHP testing environment is unreliable,
so I suggest that you upload feedback.php to a remote server for the next stage of
testing. Once you have established that the mail() function is working, you can continue
testing locally.
Upload feedback.php and contact.css to your remote server. Enter some text in the
Name, Email, and Comments fields. Make sure that your input includes at least an apostrophe
or quotation mark, and click Send comments. The form should clear, and you should
see a confirmation message, as in Figure 11-3.
USING PHP TO PROCESS A FORM
337
11
Figure 11-3. Confirmation that the mail() function has passed the message to the server’s mail
transport agent
Shortly afterward, you should receive the message in your inbox. Most of the time, it
should work, but there are several things that might go wrong. The next section should
help you resolve the problem.
Troubleshooting mail()
If you don’t receive anything, the first thing to check is your spam trap, because the email
may appear to come from an unknown or a suspicious source. For example, it may appear
to come from Apache or a mysterious nobody (the name often used for web servers).
Don’t worry about the odd name; that will be fixed soon. The main thing is to check that
the mail is being sent correctly.
If you see an error message saying that the From header wasn’t set or that sendmail_from
isn’t defined in php.ini, again that’s nothing to worry about and will be fixed shortly. Keep
building the script as described in each section, and I’ll tell you when you can test your
page on the remote server again.
Some hosting companies now make it a requirement to use the fifth argument to mail()
to ensure that it comes from an entrusted user. If you don’t receive mail or see a PHP error
message, check your hosting company’s instructions and find out the exact format
required for the fifth parameter. It normally consists of -f followed (without a space) by
your own email address, all enclosed in quotes. You’ll see later how to add it to your code.
Again, keep building the script as described in each section.
Some mail servers object to new line characters that are not accompanied by carriage
returns. If you receive a warning that includes SMTP server response: 451, change the
escape sequences in the section that builds the message like this:
$message = “Name: $name\r\n\r\n”;
$message .= “Email: $email\r\n\r\n”;
$message .= “Comments: $comments”;
Getting rid of unwanted backslashes
Some day back in the mists of time, the PHP development team had the “brilliant” idea of
creating a feature known as magic quotes . . . only it wasn’t so brilliant after all. When
inserting data into a database, it’s essential to escape single and double quotes. So the idea
of magic quotes was to make life simpler for beginners by doing this automatically for all
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
338
data passed through the $_POST and $_GET arrays, and cookies. While this seemed like a
good idea at the time, it has caused endless problems. To cut a long story short, magic
quotes are being officially phased out of PHP (they’ll be gone in PHP 6), but they’re still
enabled on a lot of shared servers. You will know if your server uses them if your test email
has backslashes in front of any apostrophes or quotes, as shown in Figure 11-4.
Figure 11-4. PHP magic quotes insert unwanted
backslashes in the email.
Dreamweaver’s server behaviors automatically handle magic quotes by stripping the backslashes,
if necessary, and preparing data for database input. However, when you’re handcoding
like this, you need to deal with the backslashes yourself.
I have created a Dreamweaver snippet, so that you can drop a ready-made script into any
page that needs to get rid of unwanted backslashes. It automatically detects whether
magic quotes are enabled, so you can use it safely on any server. If magic quotes are on, it
removes the backslashes. If magic quotes are off, it leaves your data untouched. It’s part of
a collection of snippets that I’ve created for this book and packaged as a Dreamweaver
extension so they can be installed in a single operation.
1. If Dreamweaver is open, you will need to close and restart the program after
installing the snippets, so save any files that are open. Access the Extension
Manager by choosing Manage Extensions from either the Commands or Help menu.
If Dreamweaver is closed, launch Adobe Extension Manager CS3 from Start ä All
Programs (Windows) or Finder ä Applications (Mac).
2. Select Dreamweaver CS3 in the drop-down menu on the Extension Manager toolbar,
and choose File ä Install Extension, or click the Install button. Alternatively,
press Ctrl+O/Cmd+O (capital “o,” not zero).
3. In the dialog box that opens, navigate to egdwcs3_snippets.mxp in the tools
folder of the download files, and click Install.
4. After the extension has been installed, close Dreamweaver if it’s open. The snippets
will be in the PHP-DWCS3 folder of the Snippets panel when you next open the
program.
Installing the PHP snippets collection
USING PHP TO PROCESS A FORM
339
11
1. Open feedback.php in Code view. Position your
cursor on line 4, just under the mail processing
script comment, and insert a couple of blank
lines.
Move your cursor onto one of the blank lines,
and open the Snippets panel by clicking the
Snippets tab in the Files panel group or selecting
Window ä Snippets. On Windows, you can also
use the keyboard shortcut Shift+F9, but this
doesn’t work on the Mac version.
Highlight the new POST stripslashes snippet in
the PHP-DWCS3 folder, as shown alongside, and
double-click it, or click the Insert button at the
bottom of the panel.
2. This inserts the following block of code into your page:
// remove escape characters from $_POST array
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value) {
$value = is_array($value) ? array_map(‘stripslashes_deep’, å
$value) : stripslashes($value);
return $value;
}
$_POST = array_map(‘stripslashes_deep’, $_POST);
}
Lying at the heart of this code is the PHP function stripslashes(), which removes
the escape backslashes from quotes and apostrophes. Normally, you just pass the
string that you want to clean up as the argument to stripslashes().
Unfortunately, that won’t work with an array. This block of code checks whether
magic quotes have been turned on; and if they have, it goes through the $_POST
array and any nested arrays, cleaning up your text for display either in an email or
in a web page.
3. Save feedback.php, and send another test email that includes apostrophes and
quotes in the message. The email that you receive should be nicely cleaned up. This
won’t work yet if you weren’t able to send the first test email.
If you have any problems, check your page against feedback_03.php.
Using the POST stripslashes snippet
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
340
Making sure required fields aren’t blank
When required fields are left blank, you don’t get the information you need, and the user
may never get a reply, particularly if contact details have been omitted. The following
instructions make use of arrays and the foreach loop, both of which are described in
Chapter 10. So, if you’re new to PHP, you might find it useful to refer to the relevant sections
in the previous chapter before continuing.
In this part of the script, you create three arrays to hold details of variables you expect to
receive from the form, those that are required, and those that are missing. This not only
helps identify any required items that haven’t been filled in; it also adds an important
security check before passing the user input to a loop that converts the names of $_POST
variables to shorter ones that are easier to handle.
1. Start by creating two arrays: one listing the name attribute of each field in the form
and the other listing all required fields. Also, initialize an empty array to store the
names of required fields that have not been completed. For the sake of this
demonstration, make the email field optional, so that only the name and comments
fields are required. Add the following code just before the section that processes
the $_POST variables:
$subject = ‘Feedback from Essential Guide’;
// list expected fields
$expected = array(‘name’, ‘email’, ‘comments’);
// set required fields
$required = array(‘name’, ‘comments’);
// create empty array for any missing fields
$missing = array();
// process the $_POST variables
2. At the moment, the $_POST variables are assigned manually to variables that use
the same name as the $_POST array key. With three fields, manual assignment is
fine, but it becomes a major chore with more fields. Let’s kill two birds with one
stone by checking required fields and automating the naming of the variables at
the same time. Replace the three lines of code beneath the $_POST variables comment
as follows:
// process the $_POST variables
foreach ($_POST as $key => $value) {
// assign to temporary variable and strip whitespace if not an array
$temp = is_array($value) ? $value : trim($value);
// if empty and required, add to $missing array
if (empty($temp) && in_array($key, $required)) {
array_push($missing, $key);
}
// otherwise, assign to a variable of the same name as $key
elseif (in_array($key, $expected)) {
Checking required fields
USING PHP TO PROCESS A FORM
341
11
${$key} = $temp;
}
}
// build the message
If studying PHP code makes your brain hurt, you don’t need to worry about how
this works. As long as you create the $expected, $required, and $missing arrays in
the previous step, you can just copy and paste the code for use in any form.
So what does it do? In simple terms, this foreach loop goes through the $_POST
array, strips out any whitespace from user input, and assigns its contents to a variable
with the same name (so $_POST['email'] becomes $email, and so on). If a
required field is left blank, its name attribute is added to the $missing array.
The code uses several built-in PHP functions, all of which have intuitive names:
is_array() tests whether a variable is an array.
trim() trims whitespace from both ends of a string.
empty() tests whether a variable contains nothing or equates to false.
in_array() checks whether the first argument is part of the array specified in
the second argument.
array_push() adds a new element to the end of an array.
At this stage, you don’t need to understand how each function works, but you
can find details in the PHP online documentation at www.php.net/manual/en/
index.php. Type the name of the function in the search for field at the top right of
the page (see Figure 11-5), and click the right-facing arrow alongside function list.
The PHP documentation has many practical examples showing how functions and
other features are used.
Figure 11-5. Refer often to the excellent PHP online documentation, and your skills will increase
rapidly.
Why is the $expected array necessary? It’s to prevent an attacker from injecting
other variables in the $_POST array in an attempt to overwrite your default
values. By processing only those variables that you expect, your form is much
more secure. Any spurious values are ignored.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
342
3. You want to build the body of the email message and send it only if all required
fields have been filled in. Since $missing starts off as an empty array, nothing is
added to it if all required fields are completed, so empty($missing) is true. Wrap
the rest of the script in the opening PHP code block like this:
// go ahead only if all required fields OK
if (empty($missing)) {
// build the message
$message = “Name: $name\n\n”;
$message .= “Email: $email\n\n”;
$message .= “Comments: $comments”;
// limit line length to 70 characters
$message = wordwrap($message, 70);
// send it
$mailSent = mail($to, $subject, $message);
if ($mailSent) {
// $missing is no longer needed if the email is sent, so unset it
unset($missing);
}
}
}
This ensures that the mail is sent only if nothing has been added to $missing.
However, $missing will be used to control the display of error messages in the
main body of the page, so you need to get rid of it if the mail is successfully sent.
This is done by using unset(), which destroys a variable and any value it contains.
4. Let’s turn now to the main body of the page. You need to display a warning if anything
is missing. Amend the conditional statement at the top of the page content
like this:
<h1>Contact us</h1>
<?php
if ($_POST && isset($missing) && !empty($missing)) {
?>
<p class=”warning”>Please complete the missing item(s) indicated.</p>
<?php
}
elseif ($_POST && !$mailSent) {
?>
<p class=”warning”>Sorry, there was a problem sending your message.
Please try later.</p>
This adds a new condition. The isset() function checks whether a variable exists. If
$missing doesn’t exist, that means that all required fields were filled in and the
email was sent successfully, so the condition fails, and the script moves on to consider
the elseif condition. However, if all required fields were filled in, but there
was a problem sending the email, $missing still exists, so you need to make sure it’s
empty. An exclamation mark is the negative operator, so !empty means “not empty.”
USING PHP TO PROCESS A FORM
343
11
On the other hand, if $missing exists and isn’t empty, you know that at least one
required field was omitted, so the warning message is displayed.
I’ve placed this new condition first. The $mailSent variable won’t even be set if any
required fields have been omitted, so you must test for $missing first.
5. To make sure it works so far, save feedback.php, and load it in a browser. You don’t
need to upload it to your remote server, because you want to test the message
about missing items. Don’t fill in any fields. Just click Send comments. The top of
the page should look like this (check your code against feedback_04.php if
necessary):
6. To display a suitable message alongside each missing required field, add a PHP code
block to display a warning as a <span> inside the <label> tag like this:
<label for=”name”>Name: <?php
if (isset($missing) && in_array(‘name’, $missing)) { ?>
<span class=”warning”>Please enter your name</span><?php } ?>
</label>
Since the $missing array is created only after the form has been submitted, you
need to check first with isset() that it exists. If it doesn’t exist—such as when the
page first loads or if the email has been sent successfully—the <span> is never displayed.
If $missing does exist, the second condition checks if the $missing array
contains the value name. If it does, the <span> is displayed as shown in Figure 11-6.
7. Insert a similar warning for the comments field like this:
<label for=”comments”>Comments: <?php
if (isset($missing) && in_array(‘comments’, $missing)) { ?>
<span class=”warning”>Please enter your comments</span><?php } ?>
</label>
The PHP code is the same except for the value you are looking for in the $missing
array. It’s the same as the name attribute for the form element.
8. Save feedback.php, and test the page again locally by entering nothing into any
of the fields. The page should look like Figure 11-6. Check your code against
feedback_05.php if you encounter any problems.
9. Try one more test. Open Code view, and amend the line that sends the email like
this:
$mailSent = false; // mail($to, $subject, $message);
This temporarily sets the value of $mailSent to false and comments out the code
that actually sends the email.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
344
Figure 11-6. The PHP script displays alerts if required information is missing, even when
JavaScript is disabled.
10. Reload feedback.php into your browser, and type something in the Name and
Comments fields before clicking Send comments. This time you should see the message
telling you there was a problem and asking you to try later.
11. Reverse the change you made in step 9 so that the code is ready to send the email.
Preserving user input when a form is incomplete
Imagine you have just spent ten minutes filling in a form. You click the submit button, and
back comes the response that a required field is missing. It’s infuriating if you have to fill
in every field all over again. Since the content of each field is in the $_POST array, it’s easy
to redisplay it when an error occurs.
When the page first loads or the email is successfully sent, you don’t want anything to
appear in the input fields. But you do want to redisplay the content if a required field is
missing. So that’s the key: if the $missing variable exists, you want the content of each
field to be redisplayed. You can set default text for a text input field by setting the value
attribute of the <input> tag.
At the moment, the <input> tag for name looks like this:
<input name=”name” type=”text” class=”textInput” id=”name” />
To add the value attribute, all you need is a conditional statement that checks whether
$missing exists. If it does, you can use echo to display value=”" and put the value held in
$_POST['name'] between the quotes. It sounds simple enough, but this is one of those situations
where getting the right combination of quotes can drive you mad. It’s made even
worse by the fact that the user input in the text field might also contain quotes. Figure 11-7
shows what happens if you don’t give quotes in user input special treatment. The browser
finds the first matching quote and throws the rest of the input away.
USING PHP TO PROCESS A FORM
345
11
Figure 11-7. Quotes within user input need special treatment before form fields can be
redisplayed.
You might be thinking that this is a case where magic quotes would be useful.
Unfortunately, they won’t work either. If you don’t use the POST stripslashes snippet, this
is what you get instead:
Magic quotes work only with input into a database (and not very well, either, which is why
they are being phased out). The browser still sees the first matching quote as the end of
the value attribute. The solution is simple: convert the quotes to the HTML entity equivalent
("), and PHP has a function called—appropriately—htmlentities(). Passing the
$_POST array element to this function converts all characters (except space and single
quote) that have an HTML entity equivalent to that entity. As a result, the content is no
longer truncated. What’s cool is that the HTML entity " is converted back to double
quotes when the form is resubmitted, so there’s no need for any further conversion.
That’s the theory—now let’s put it into practice.
1. Amend the <input> tag for the Name text field like this:
<input name=”name” type=”text” class=”textInput” id=”name”
<?php if (isset($missing)) {
echo ‘value=”‘.htmlentities($_POST['name']).’”‘;
} ?>
/>
Creating sticky form fields
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
346
This code is quite short, but the line inside the curly braces contains a tricky combination
of quotes and periods. The first thing to realize is that there’s only one
semicolon—right at the end—so the echo command applies to the whole line. You
can break down the rest of the line into three sections, as follows:
‘value=”‘.
htmlentities($_POST['name'])
.’”‘
The first section outputs value=” as text and uses the concatenation operator (a
period—see “Joining strings together” in Chapter 10) to join it to the next section,
which passes $_POST['name'] to the htmlentities() function. The final section
uses the concatenation operator again to join the next string, which consists solely
of a double quote. So, if $missing has been set, and $_POST['name'] contains Joe,
you’ll end up with this inside the <input> tag:
<input name=”name” type=”text” class=”textInput” id=”name” å
value=”Joe” />
2. Amend the email input field in the same way, using $_POST['email'].
3. The comments text area needs to be handled slightly differently, because
<textarea> tags don’t have a value attribute. You place the PHP block between
the opening and closing tags of the text area like this (new code is shown in bold):
<textarea name=”comments” id=”comments” cols=”45″ rows=”5″><?php
if (isset($missing)) {
echo htmlentities($_POST['comments']);
} ?></textarea>
It’s important to position the opening and closing PHP tags right up against the
<textarea> tags. If you don’t, you’ll get unwanted whitespace inside the text area.
4. Save feedback.php, and test the page. If the first test message earlier in the chapter
was successful, you can upload it to your remote server. If any required fields
are omitted, the form displays the original content along with any error messages.
However, if the form is correctly filled in, the email is sent, an acknowledgment is
displayed, and the input fields are cleared.
If your remote server test didn’t succeed earlier in the chapter, just test locally.
You’ll probably get a PHP error message if all required fields are filled in, but that’s
nothing to worry about. We’re almost at the stage to get your remote server
working.
You can check your code with feedback_06.php.
By default, htmlentities() leaves single quotes untouched. Since I chose to wrap the
value attribute in double quotes, this doesn’t matter. To convert a single quote to an
HTML entity as well, pass ENT_QUOTES (all uppercase) as a second argument to
htmlentities() like this: htmlentities($_POST['name'], ENT_QUOTES).
USING PHP TO PROCESS A FORM
347
11
Filtering out potential attacks
A particularly nasty exploit known as email header injection emerged in mid-2005. It seeks
to turn online forms into spam relays. A simple way of preventing this is to look for the
strings “Content-Type:”, “Cc:”, and “Bcc:”, as these are email headers that the attacker
injects into your script in an attempt to trick it into sending HTML email with copies to
many people. If you detect any of these strings in user input, it’s a pretty safe bet that
you’re the target of an attack, so you should block the message. An innocent message may
also be blocked, but the advantages of stopping an attack outweigh that small risk.
In this section, we’ll create a pattern to check for suspect phrases, and pass the form input
to a custom-built function that checks for any matches. The function is one of the snippets
that you installed earlier in the chapter, so the most complex part of the coding is already
done for you. If a match is found, a conditional statement prevents the email from being
sent.
1. PHP conditional statements rely on a true/false test to determine whether to execute
a section of code. So the way to filter out suspect phrases is to create a
Boolean variable that is switched to true as soon as one of those phrases is
detected. The detection is done using a search pattern or regular expression. Insert
the code for both of these just above the section that processes the $_POST
variables:
// create empty array for any missing fields
$missing = array();
// assume that there is nothing suspect
$suspect = false;
// create a pattern to locate suspect phrases
$pattern = ‘/Content-Type:|Bcc:|Cc:/i’;
// process the $_POST variables
The string assigned to $pattern will be used to perform a case-insensitive search
for any of the following: “Content-Type:”, “Bcc:”, or “Cc:”. It’s written in a format
called Perl-compatible regular expression (PCRE). The search pattern is enclosed in
a pair of forward slashes, and the i after the final slash makes the pattern case
insensitive.
2. You can now use $pattern to filter out any suspect user input from the $_POST
array. At the moment, each element of the $_POST array contains only a string.
However, multiple-choice form elements, such as checkboxes, return an array of
results. So you need to tunnel down any subarrays and check the content of each
element separately. In the snippets collection that you installed earlier in the chapter,
you’ll find a custom-built function to do precisely that.
Insert two blank lines immediately after the $pattern variable from step 1. Then
open the Snippets panel, and double-click Suspect pattern filter in the PHP-DWCS3
folder to insert the code shown here in bold:
Blocking emails that contain specific phrases
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
348
// create a pattern to locate suspect phrases
$pattern = ‘/Content-Type:|Bcc:|Cc:/i’;
// function to check for suspect phrases
function isSuspect($val, $pattern, &$suspect) {
// if the variable is an array, loop through each element
// and pass it recursively back to the same function
if (is_array($val)) {
foreach ($val as $item) {
isSuspect($item, $pattern, $suspect);
}
}
else {
// if one of the suspect phrases is found, set Boolean to true
if (preg_match($pattern, $val)) {
$suspect = true;
}
}
}
3. I won’t go into detail about how this code works. All you need to know is that calling
the isSuspect() function is very easy. You just pass it three values: the $_POST
array, the pattern, and the $suspect Boolean variable. Insert the following code
immediately after the code in the previous step:
// check the $_POST array and any subarrays for suspect content
isSuspect($_POST, $pattern, $suspect);
4. If any suspect phrases are detected, the value of $suspect changes to true, so you
need to set $mailSent to false and delete the $missing array to prevent the email
from being sent and to display an appropriate message in the form. There’s also no
point in processing the $_POST array any further. Wrap the code that processes the
$_POST variables in the second half of an if . . . else statement like this:
if ($suspect) {
$mailSent = false;
unset($missing);
}
else {
// process the $_POST variables
foreach ($_POST as $key => $value) {
// assign to temporary variable and strip whitespace if not an array
$temp = is_array($value) ? $value : trim($value);
// if empty and required, add to $missing array
if (empty($temp) && in_array($key, $required)) {
array_push($missing, $key);
}
// otherwise, assign to a variable of the same name as $key
elseif (in_array($key, $expected)) {
${$key} = $temp;
USING PHP TO PROCESS A FORM
349
11
}
}
}
Don’t forget the extra curly brace to close the else statement.
5. If suspect content is detected, you don’t want the code that builds and sends the
email to run, so amend the condition in the opening if statement like this:
// go ahead only if not suspect and all required fields OK
if (!$suspect && empty($missing)) {
// build the message
6. Save feedback.php, and check your code against feedback_07.php.
Because the if statement in step 4 sets $mailSent to false and unsets $missing if it
detects any suspect pattern, the code in the main body of the page displays the same message
that’s displayed if there’s a genuine problem with the server. A neutral message
reveals nothing that might assist an attacker. It also avoids offending anyone who may
have innocently used a suspect phrase.
You can use isSuspect() with any array or pattern, but it always requires the following
three arguments:
An array that you want to filter. If the array contains other arrays, the function burrows
down until it finds a simple value against which it can match the pattern.
A regular expression containing the pattern(s) you want to search for. There are
two types of regular expression, Perl-compatible (PCRE), and Portable Operating
System Interface (POSIX). You must use a PCRE. This function won’t work with a
POSIX regular expression. A good online source is http://regexlib.com.
A Boolean variable set to false. If the pattern is found, the value is switched to
true.
Safely including the user’s address in email headers
Up to now, I’ve avoided using one of the most useful features of the PHP mail() function:
the ability to add extra email headers with the optional fourth argument. A popular use of
extra headers is to incorporate the user’s email address into a Reply-To header, which
enables you to reply directly to incoming messages by clicking the Reply button in your
email program. It’s convenient, but it provides a wide open door for an attacker to supply
a spurious set of headers. With the isSuspect() function in place, you can block attacks
and safely use the fourth argument with the mail() function.
The most important header that you should add is From. Email sent by mail() is often
identified as coming from nobody@servername. Adding the From header not only identifies
your mail in a more user-friendly way, but it also solves the problem you might have
encountered on the first test of there being no setting for sendmail_from in php.ini.
You can find a full list of email headers at www.faqs.org/rfcs/rfc2076, but some of the
most well-known and useful ones enable you to send copies of an email to other
addresses (Cc and Bcc) or to change the encoding (often essential for languages other
than Western European ones).
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
350
Like the body of the email message, headers must be passed to the mail() function as a
single string. Each new header, except the final one, must be on a separate line terminated
by a carriage return and new line character. This means using the \r and \n escape
sequences in double-quoted strings.
Let’s say you want to send copies of messages to other departments, plus a copy to
another address that you don’t want the others to see. This is how you pass those additional
email headers to mail():
$headers = “From: Essential Guide<feedback@example.com>\r\n”;
$headers .= “Cc: sales@example.com, finance@example.com\r\n”;
$headers .= ‘Bcc: secretplanning@example.com’;
$mailSent = mail($to, $subject, $message, $headers);
The default encoding for email is iso-8859-1 (English and Western European). If you want
to use a different encoding, set the Content-Type header. For Unicode (UTF-8), set it
like this:
$headers = “Content-Type: text/plain; charset=utf-8\r\n”;
The web page that the form is embedded in must use the same encoding (usually set in a
<meta> tag).
Hard-coded additional headers present no security risk, but anything that comes from user
input must be filtered before it’s used.
This section incorporates the user’s email address into a Reply-To header. Although
isSuspect() should sanitize user input, it’s worth subjecting the email field to a more rigorous
check to make sure that it doesn’t contain illegal characters or more than one
address.
1. At the moment, the $required array doesn’t include email, and you may be happy
to leave it that way. So, to keep the validation routine flexible, it makes more sense
to handle the email address outside the main loop that processes the $_POST array.
If email is required but has been left blank, the loop will have already added
email to the $missing array, so the message won’t get sent anyway.
If it’s not a required field, you need to check $email only if it contains something.
So you need to wrap the validation code in an if statement that uses
!empty().
Insert the code shown in bold after the loop that processes the $_POST array.
// otherwise, assign to a variable of the same name as $key
elseif (in_array($key, $expected)) {
${$key} = $temp;
}
}
}
Adding email headers and automating the reply address
USING PHP TO PROCESS A FORM
351
11
// validate the email address
if (!empty($email)) {
}
// go ahead only if not suspect and all required fields OK
if (!$suspect && empty($missing)) {
2. Position your cursor on the blank line between the curly braces of the conditional
statement you have just inserted. Open the Snippets panel, and double-click Check
email PCRE in the PHP-DWCS3 folder. This inserts the following regular expression:
$checkEmail = ‘/^[^@]+@[^\s\r\n\'";,@%]+$/’;
Designing a regular expression to recognize a valid-looking email address is notoriously
difficult. So, instead of striving for perfection, $checkEmail, takes a negative
approach by rejecting characters that are illegal in an email address. However, to
make sure that the input resembles an email address in some way, it checks for an
@ mark surrounded by at least one character on either side.
3. Now add the code shown in bold to check $email against the regular expression:
// validate the email address
if (!empty($email)) {
// regex to ensure no illegal characters in email address
$checkEmail = ‘/^[^@]+@[^\s\r\n\'";,@%]+$/’;
// reject the email address if it doesn’t match
if (!preg_match($checkEmail, $email)) {
$suspect = true;
$mailSent = false;
unset($missing);
}
}
The conditional statement uses the preg_match(), which takes two arguments: a
PCRE and the string that you want to check. If a match is found, the function
returns true. Since it’s preceded by the negative operator, the condition is true if
the contents of $email don’t match the PCRE.
If there’s no match, $suspect is set to true, $mailSent is set to false, and
$missing is unset. This results in the neutral alert saying that the message can’t be
sent and clears the form. This runs the risk that someone who has accidentally
mistyped the email address will be forced to enter everything again. If you don’t
want that to happen, you can omit unset($missing);. However, the PCRE detects
illegal characters that are unlikely to be used by accident, so I have left it in.
Many popular PHP scripts use pattern-matching functions that begin with ereg.
These work only with POSIX regular expressions. I recommend that you always
use the PCRE functions that begin with preg_. Not only is PCRE more efficient,
there’s a strong likelihood that support for the ereg family of functions will be
removed from a future version of PHP.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
352
4. Now add the additional headers to the email. Place them immediately above the
call to the mail() function, and add $headers as the fourth argument like this:
// limit line length to 70 characters
$message = wordwrap($message, 70);
// create additional headers
$headers = ‘From: Essential Guide<feedback@example.com>’;
if (!empty($email)) {
$headers .= “\r\nReply-To: $email”;
}
// send it
$mailSent = mail($to, $subject, $message, $headers);
If you don’t want email to be a required field, there’s no point in using a nonexistent
value in the Reply-To header, so I have wrapped it in a conditional statement.
Since you have no way of telling whether the Reply-To header will be created, it
makes sense to put the carriage return and new line characters at the beginning of
the second header. It doesn’t matter whether you put them at the end of one
header or the start of the next one, as long as a carriage return and new line separates
each header. For instance, if you wanted to add a Cc header, you could do it
like this:
$headers = “From: Essential Guide<feedback@example.com>\r\n”;
$headers .= ‘Cc: admin@example.com’;
if (!empty($email)) {
$headers .= “\r\nReply-To: $email”;
}
Or like this:
$headers = ‘From: Essential Guide<feedback@example.com>’;
$headers .= “\r\nCc: admin@example.com“;
if (!empty($email)) {
$headers .= “\r\nReply-To: $email”;
}
If your hosting company requires you to supply the fifth argument to mail() for
security reasons, you should add it after the headers. Normally, it takes the form of
-f followed by your email address like this:
$mailSent = mail($to,$subject,$message,$headers,’-fdavid@example.com’);
Use this fifth argument only if instructed to do so by your hosting company.
5. Save feedback.php, upload it to your remote server, and test the form. When you
receive the email, click the Reply button in your email program, and you should see
the address that you entered in the form automatically entered in the recipient’s
address field. You can check your code against feedback_08.php.
USING PHP TO PROCESS A FORM
353
11
Handling multiple-choice form elements
You now have the basic knowledge to process text input from an online form and email it
to your inbox. The principle behind handling multiple-choice elements is exactly the same:
the name attribute is used as the key in the $_POST array. However, as you saw in Chapter
9, checkboxes and multiple-choice lists don’t appear in the $_POST array if nothing has
been selected, so they require different treatment.
The following exercises show you how to handle each type of multiple-choice element. If
you’re feeling punch drunk at this stage, come back later to study how to handle multiplechoice
elements when you need to incorporate them into a script of your own.
In Chapter 9, I showed you how to create a checkbox group, which stores all checked
values in a subarray of the $_POST array. However, the subarray isn’t even created if all
boxes are left unchecked. So you need to use isset() to check the existence of the subarray
before attempting to process it.
1. Add the name of the checkbox group to the $expected array like this:
$expected = array(‘name’, ‘email’, ‘comments’, ‘interests’);
In the form, interests is followed by square brackets like this:
<input type=”checkbox” name=”interests[]” . . .
The square brackets in the form tell the $_POST array to store all checked values in
a subarray called $_POST['interests']. However, don’t add square brackets to
interests in the $expected array. Doing so would bury the checked values in a
subarray one level deeper than you want. See “Using arrays to store multiple
values” in Chapter 10 for a reminder of how arrays are created.
2. If you want the checkboxes to be required, add the name of the checkbox group to
the $required array in the same way.
3. Because the checkbox array might never be created, you need to set a default
value before attempting to build the body of the email. The following code in bold
goes in the section that prepares the message prior to sending it:
// go ahead only if not suspect and all required fields OK
if (!$suspect && empty($missing)) {
// set default values for variables that might not exist
$interests = isset($interests) ? $interests : array(‘None selected’);
Getting data from checkboxes
When building your own forms, don’t forget to add the name of each text field to the
$expected array. Also add the name of required fields to the $required array, and add
a suitable alert as described in “Checking required fields.”
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
354
This uses the conditional operator (see “Using the conditional operator” in
Chapter 10) to check whether $interests has been set. If it has, the existing array
of checked values is reassigned to $interests. Otherwise, a single-element array
containing the string None selected is created and assigned to $interests. It
needs to be an array, even though it contains only one element, because the next
step expects an array.
4. To extract the values of the checkbox array, you can use the oddly named
implode() function, which joins array elements. It takes two arguments: a string to
be used as a separator and the array. So, implode(‘, ‘, $interests) joins the elements
of $interests as a comma-separated string. Add the following code shown
in bold to the script that builds the body of the email:
$message .= “Comments: $comments\n\n“;
$message .= ‘Interests: ‘.implode(‘, ‘, $interests);
Note that I added two new line characters at the end of the line that adds the
user’s comments to the email. On the following line, I put Interests: in single
quotes because there are no variables to be processed, and I used the concatenation
operator to join the result of implode(‘, ‘, $interests) to the end of the
email message. You cannot include a function inside a string.
5. The next listing shows the code for the first two checkboxes in the body of the
page. The code in bold preserves the user’s selections if a required field is missing.
<p>
<input name=”interests[]” type=”checkbox” id=”interests-classical” å
value=”Classical concerts”
<?php
$OK = isset($_POST['interests']) ? true : false;
if ($OK && isset($missing) && in_array(‘Classical concerts’, å
$_POST['interests'])) {
echo ‘checked=”checked”‘;
} ?>
/>
<label for=”interests-classical”>Classical concerts</label>
</p>
<p>
<input name=”interests[]” type=”checkbox” id=”interests-rock” å
value=”Rock/pop”
<?php
if ($OK && isset($missing) && in_array(‘Rock/pop’, å
$_POST['interests'])) {
echo ‘checked=”checked”‘;
} ?>
/>
<label for=”interests-rock”>Rock/pop events</label>
</p>
USING PHP TO PROCESS A FORM
355
11
The code in the first checkbox contains the following line:
$OK = isset($_POST['interests']) ? true : false;
This checks whether $_POST['interests'] exists (it won’t if the user didn’t select
any checkboxes). If it does, $OK is set to true.
The PHP code for each checkbox tests three conditions: the value of $OK, whether
the $missing variable exists, and whether the value of the checkbox is in the
$_POST['interests'] subarray. If all are true, echo inserts checked=”checked”
into the <input> tag. (If you’re using HTML instead of XHTML, use just checked.)
Although it looks like a lot of hand-coding, you can copy and paste the code after
creating the first one. Just change the first argument of in_array() to the value of
the checkbox. The complete code is in feedback_09.php.
If you want to make the checkbox group required, add an alert in the same way as
described in “Checking required fields” earlier in the chapter.
Drop-down menus created with the <select> tag normally allow the user to pick only one
option from several. One item is always selected, even if it’s only the first one inviting the
user to select one of the others. Setting the value of this first <option> to 0 has the advantage
that the empty() function, which is used to check required fields, returns true when
0 is passed to it either as a number or string.
1. Add the name of the drop-down menu to the $expected array. Also add it to the
$required array if you want a choice to be compulsory.
2. Add the value of the drop-down menu to the email message like this:
$message .= ‘Interests: ‘.implode(‘, ‘, $interests).”\n\n”;
$message .= “Visited: $visited”;
One option will always be selected, so this doesn’t need special treatment.
However, change the value of the first <option> tag in the menu to No response if
it isn’t a required field. Leave it as 0 if you want the user to make a selection.
3. The following code shows the first two items of the drop-down menu in
feedback.php. The PHP code highlighted in bold assumes that the menu has been
made a required field and resets the selected option if an incomplete form is submitted.
When the page first loads, the $_POST array contains no elements, so you
can select the first <option> by testing for !$_POST. Once the form is submitted,
the $_POST array always contains an element from a drop-down menu, so you don’t
need to test for it.
<label for=”visited”>How often have you been to London? <?php
if (isset($missing) && in_array(‘visited’, $missing)) { ?>
<span class=”warning”>Please select a value</span><?php } ?></label>
<select name=”visited” id=”visited”>
<option value=”0″
<?php
if (!$_POST || $_POST['visited'] == ’0′) {
Getting data from a drop-down menu
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
356
echo ‘selected=”selected”‘;
} ?>
>– Select one –</option>
<option value=”Never”
<?php
if (isset($missing) && $_POST['visited'] == ‘Never’) {
echo ‘selected=”selected”‘;
} ?>
>Never been</option>
. . .
</select>
When setting the second condition for each <option>, it’s vital that you use the
same spelling and mixture of uppercase and lowercase as contained in the value
attribute. PHP is case sensitive and won’t match the two values if there are any
differences.
The finished code is in feedback_10.php.
Multiple-choice lists are similar to checkboxes: they allow the user to choose zero or more
items, so the result is stored in an array. If no items are selected, the $_POST array contains
no reference to the list, so you need to take that into consideration both in the form and
when processing the message.
1. Add the name of the multiple-choice list to the $expected array. Also add it to the
$required array if you want a choice to be compulsory.
2. In the code that processes the message, set a default value for a multiple-choice list
in the same way as for an array of checkboxes.
$interests = isset($interests) ? $interests : array(‘None selected’);
$views = isset($views) ? $views : array(‘None selected’);
3. When building the body of the message, use implode() to create a comma-separated
string, and add it to the message like this:
$message .= “Visited: $visited\n\n“;
$message .= ‘Impressions of London: ‘.implode(‘, ‘, $views);
4. The following code shows the first two items from the multiple-choice list in
feedback.php. The code works in an identical way to the checkboxes, except that
you echo ‘selected=”selected”‘ instead of ‘checked=”checked”‘. You can reuse
$OK here, because its value is reset by the code in the first <option> tag.
<select name=”views[]” size=”6″ multiple=”multiple” id=”views”>
<option value=”Vibrant/exciting”
<?php
$OK = isset($_POST['views']) ? true : false;
if ($OK && isset($missing) && in_array(‘Vibrant/exciting’, å
$_POST['views'])) {
Getting data from a multiple-choice list
USING PHP TO PROCESS A FORM
357
11
echo ‘selected=”selected”‘;
} ?>
>A vibrant, exciting city</option>
<option value=”Good food”
<?php
if ($OK && isset($missing) && in_array(‘Good food’, å
$_POST['views'])) {
echo ‘selected=”selected”‘;
} ?>
>A great place to eat</option>
. . .
</select>
The completed code is in feedback_11.php.
If you want to make the multiple-choice list required, add an alert in the same way as
described in “Checking required fields” earlier in the chapter.
Radio button groups allow you to pick only one value. This makes it easy to retrieve the
selected one. All buttons in the same group must share the same name attribute, so the
$_POST array contains the value attribute of whichever radio button is selected. However,
if you don’t set a default button in your form, the radio button group’s $_POST array element
remains unset.
1. Add the name of the radio button group to the $expected array.
2. If you haven’t set a default button and you want a choice to be compulsory, also
add it to the $required array. This isn’t necessary if a default choice is set in the
form.
3. If you haven’t set a default button, you need to set a default value before building
the body of the email message. You do this in a similar way to a checkbox group or
multiple-choice list, but since a radio button group can have only one value, you
set the default as a string, not an array, as shown in this example:
$radio = isset($radio) ? $radio : ‘Not selected’;
4. Add the value of the radio button group to the body of the message like this:
$message .= ‘Impressions of London: ‘.implode(‘, ‘, $views).”\n\n”;
$message .= “Subscribe: $subscribe”;
5. Assuming a default button has been defined, amend the radio button group like
this:
<input type=”radio” name=”subscribe” id=”subscribe-yes” value=”y”
<?php
if (isset($missing) && $_POST['subscribe'] == ‘y’) {
echo ‘checked=”checked”‘;
Getting data from radio button groups
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
358
} ?>
/>
<label for=”subscribe-yes”>Yes</label>
<input name=”subscribe” type=”radio” id=”subscribe-no” value=”n”
<?php
if (!$_POST || isset($missing) && $_POST['subscribe'] == ‘n’) {
echo ‘checked=”checked”‘;
} ?>
/>
<label for=”subscribe-no”>No</label>
The conditional statement for the default radio button begins with !$_POST ||,
which means “if the $_POST array is empty or . . .” So, if the form hasn’t been submitted,
or if the user has selected No and the form is incomplete, this button will
be checked.
The completed script is in feedback_12.php.
If no default button has been defined, add the same $OK check as for a checkbox group or
multiple-choice list in the first <input> tag, as well as in the conditional statement for each
radio button. You need to add a required alert only if no default has been defined in the
original form.
Redirecting to another page
Everything has been kept within the same page, even if the message is sent successfully. To
redirect the visitor to a different page, change the code at the end of the messageprocessing
section like this:
// send it
$mailSent = mail($to, $subject, $message, $headers);
if ($mailSent) {
// redirect the page with a fully qualified URL
header(‘Location: http://www.example.com/thanks.php’);
exit;
}
}
}
The HTTP/1.1 protocol stipulates a fully qualified URL for a redirect command, although
most browsers will perform the redirect correctly with a relative pathname.
When using the header() function, you must be careful that no output is sent to the
browser before PHP attempts to call it. If, when testing your page, you see an error message
warning you that headers have already been sent, check there are no characters,
including new lines, spaces, or tabs ahead of the opening PHP tag.
USING PHP TO PROCESS A FORM
359
11
Time for a breather . . .
If that was your first encounter with PHP, your head will probably be reeling. This has been
a tough chapter. In the next chapter, you’ll adapt this script so that it can be reused as an
external file with most forms. The external file never changes, and the hand-coding is cut
down to about a dozen lines. I could, of course, have given you the external file without
explanation, but if you don’t understand the code, you can’t adapt it to your own requirements.
Even if you never write an original PHP script of your own, you should know what
the code in your page is doing. If you don’t, you’re storing up trouble for the future.
What makes PHP pages dynamic—and so powerful—is the fact that your code makes decisions,
even though you have no way of knowing in advance what is going to be input into
the form. The Dreamweaver code that you’ll encounter in subsequent chapters tries to
anticipate a lot of these unknown factors, but its beauty lies in the fact that it’s configurable.
If you know how to hand-code, you can get Dreamweaver to do a lot of the hard
work for you, and then take it beyond the basics.
However, it’s no fun spending all your time churning out code. Life becomes simpler if you
can reuse code. So that’s what the next chapter is about—saving time with includes and
Dreamweaver templates.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
360
12 WORKING WITH PHP INCLUDES
AND TEMPLATES
To give a unified look to a website, most pages have common elements, such as a header,
navigation menu, and footer. Nobody likes repeating work just for the sake of it, so the
ability to build page templates has long been one of Dreamweaver’s most popular features.
All common features can be defined and locked, but Dreamweaver propagates to all
child pages any changes that you make to the master template. The great disadvantage is
that every time you make a change all the affected pages must be uploaded again to your
remote server. On a large site, this can be a major undertaking.
Wouldn’t it be wonderful if you could make changes to just a single page and have them
reflected through the site in the same way as CSS? Well, with PHP includes, you can. As the
name suggests, the contents of an include file are included and treated as an integral part
of the page. They can contain anything that you would normally find in a PHP page: plain
text, XHTML, and PHP code. The file name extension doesn’t even need to be .php,
although for security it’s common practice to use it.
Dreamweaver makes working with includes easy thanks to its ability to display the contents
of an include in Design view (or Live Data view for dynamic content). Many people
find includes so useful that they stop using templates. Nevertheless, templates can be useful,
particularly for small sites, so this chapter covers both approaches.
In this chapter, you’ll learn how to
Use PHP includes for common page elements
Store frequently used code in the Snippets panel
Apply CSS to page fragments with Design Time Style Sheets
Export a navigation menu to an external file
Adapt the mail processing script to work with other forms
Avoid the “headers already sent” error with includes
Use Dreamweaver templates in a PHP site
To start with, let’s take a quick look at how you create a PHP include.
Including text and code from other files
The ability to include code from other files is a core part of PHP. All that’s necessary is to
use one of PHP’s include commands and tell the server where to find the file.
Introducing the PHP include commands
PHP has four separate commands for creating an include: include(), include_once(),
require(), and require_once(). Why so many? And what’s the difference?
They all do the same thing, but “require” is used in the sense of “mandatory”; everything
comes to a grinding halt if the external file is missing or can’t be opened. The “include”
pair of commands, on the other hand, soldier bravely on. The purpose of _once is to prevent
variables being accidentally overwritten. The PHP engine uses the first instance it
encounters and ignores any duplicates. If in doubt about which to use, choose
include_once() or require_once(). Using them does no harm and could avoid problems.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
364
Telling PHP where to find the external file
The include commands take a single argument: a string containing the path of the external
file. While this sounds simple enough, it confuses many Dreamweaver users. PHP looks for
the external file in what’s known as the include_path. By default, this always includes the
current directory (folder), and PHP expects either a relative or an absolute path. It won’t
work with a path relative to the site root.
If Links relative to is set to Document in the Local Info category of your site definition (see
Figure 12-1), Dreamweaver automatically uses the correct path for include files. However,
if you have selected Site root as your default style for links, includes won’t work unless you
override the default setting to change the path to a document-relative one or take alternative
measures to set the include_path.
Figure 12-1. Dreamweaver’s site definition dialog box lets you specify the default
format of internal links.
A practical exercise should clarify the situation.
In this exercise, you’ll see what happens if you use the wrong type of path for an include
file. You’ll also learn how to override the default setting, so that you can use includes successfully
even if your site definition specifies using links relative to the site root.
1. Create a new subfolder called includes in your workfiles folder, and copy
include.txt from examples/includes to the new folder.
2. Go to File ä New. Select Blank Page and PHP as the Page Type. Choose any of the
predefined layouts. The one I chose was 2 column fixed, left sidebar. This is only
going to be a test page, so you can leave Layout CSS on Add to Head. Click Create
and save the file as include_test.php in workfiles/ch12.
3. Position your cursor at the beginning of the first paragraph under the Main Content
headline. Press Enter/Return to insert a new paragraph, and then press your up
keyboard arrow to move the insertion point into the empty paragraph.
4. Select the PHP tab on the Insert bar, and click the Include button as shown in the
following screenshot (alternatively use the menu option Insert ä PHP Objects ä
Include). Dreamweaver opens Split view, inserts a PHP code block complete with an
include() command, and positions the insertion point between the parentheses,
ready for you to enter the path of the external file.
Including a text file
WORKING WITH PHP INCLUDES AND TEMPLATES
365
12
5. The path needs to be a string, so enter a quotation mark (I prefer a single quote,
but it doesn’t matter, as long as the closing quote matches). Dreamweaver’s syntax
coloring turns all the subsequent code red, but this reverts to normal once you
have finished. Position your mouse pointer over the insertion point, and right-click
to bring up a context menu. Select Code Hint Tools ä URL Browser, as shown here:
6. This places a tiny Browse icon at the insertion point like this:
7. Click the Browse icon to open the Select File dialog box. Navigate to the
workfiles/includes folder, and select include.txt. Before clicking OK, check the
setting of Relative to at the bottom of the dialog box. It displays Document or Site
Root, depending on the default in your site definition (see Chapter 4 and Figure 12-1).
If necessary, change it to Site Root, as shown here, and click OK:
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
366
8. Type a closing quote after the path that has just been entered into the include()
command. Syntax coloring turns the rest of the code back to its normal color—a
useful reminder of the importance of matching quotes. Move your cursor further
along the line to remove the just before the closing </p> tag.
9. Click inside Design view. The gold PHP shield should disappear and be replaced by
the content of the external text file. Magic . . . well, not quite.
10. Save include_test.php, and press F12/Opt+F12 to view it in a browser. You should
see something like Figure 12-2.
Figure 12-2. If PHP can’t find the include file, it displays ugly warning messages.
The first warning says there was no such file or directory, but of course, there is.
The second warning gives a cryptic clue as to why PHP can’t open the file. The
include_path is where PHP looks for include files. The default value on most web
servers is . (a period), which is shorthand for the current working directory, and
either the main PHP folder or pear (PEAR—the PHP Extension and Application
Repository—is a library of extensions to PHP). PHP doesn’t understand a leading
forward slash as meaning the site root, so it starts from the current folder and ends
up in a nonexistent part of the site.
11. Go back to the Dreamweaver Document window, and remove the current path;
right-click between the quotes, and use the URL Browser to navigate to
include.txt again, but this time make sure that Relative to is set to Document. Save
include_test.php, and reload it in a browser. The content of the include file
should now be correctly displayed, as shown in Figure 12-3.
WORKING WITH PHP INCLUDES AND TEMPLATES
367
12
Figure 12-3. The include file is displayed correctly when a relative path is used.
12. Go back to Dreamweaver, and change the command from include to require like
this:
<?php require(‘../includes/include/txt’); ?>
13. Save the page, and load it into a browser. It should look identical to Figure 12-3.
14. Change the path to point to a nonexistent file, such as includ.txt. When you save
the page and view it in a browser, it should look similar to Figure 12-2, but instead
of the second warning, you should see Fatal error. The other difference is that
there’s no text after the error message. As explained in “Understanding PHP error
messages” in Chapter 10, any output preceding a fatal error is displayed, but once
the error is encountered, everything else is killed stone dead.
Using site-root-relative links with includes
As you have just seen, PHP cannot find include files referenced by a site-root-relative link.
My recommendation is that, if you have selected links relative to the site root as your
default, you simply select Relative to Document in the Select File dialog box (as described in
step 10 of the preceding exercise) when creating an include.
Nevertheless, there are a couple of alternatives if you have a pressing reason for wanting
to use links relative to the site root. The problem is that they don’t work on all servers.
The virtual() function accepts both document-relative and site-root-relative paths and
can be used as a direct replacement for include() and require(). It works only when PHP
is run as an Apache module.
$_SERVER['DOCUMENT_ROOT'] is a predefined PHP variable that contains the path of the
server’s root folder, so adding it to the beginning of a site-root-relative link has the effect
of turning it into an absolute path. The following works on most servers:
<?php include($_SERVER['DOCUMENT_ROOT'].‘/workfiles/includes/ å
include/txt’); ?>
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
368
Unfortunately, $_SERVER['DOCUMENT_ROOT'] isn’t supported by IIS running PHP in CGI
mode.
To check whether your server supports either method, run server_check.php in
examples/ch12. If both are supported, you should see output similar to this.
If neither is supported and you still want to use site-root-relative links, you need to define
a constant containing the path to the site root. A constant is like a variable, except that
once defined in a script, its value cannot be changed. Constants don’t begin with a dollar
sign, and by convention, they are always in uppercase. You define a constant like this:
define(‘SITE_ROOT’, ‘C:\inetpub\wwwroot\egdwcs3′);
You could then use SITE_ROOT with a site-root-relative link like this:
<?php include(SITE_ROOT.‘/workfiles/includes/include/txt’); ?>
The disadvantage with this approach is that you need to include the definition of the constant
in every page that uses includes.
Lightening your workload with includes
So far, you have seen only a fairly trivial use of an include to insert a block of text inside a
paragraph. This might be useful in a situation where you want to change the content of
part of a page on a frequent basis without going to the bother of building a databasedriven
content management system. A much more practical use of includes is for content
that appears on many pages, for example a navigation menu or footer. Any changes made
to the include file are immediately reflected throughout the site.
Choosing the right file name extension for include files
As I explained at the beginning of the chapter, the external file doesn’t need to have a
.php file name extension. Many developers use .inc as the default file name extension to
make it clear that the file is an include. Although this a common convention, Dreamweaver
doesn’t automatically recognize an .inc file as containing PHP code, so you don’t get code
The restriction on site-root-relative links applies only to the include command. Inside
include files, all links should be site-root-relative. Document-relative links inside an
include file will be broken if the file is included at a different level of the site hierarchy.
See “Creating and editing a template-based page” later in the chapter.
WORKING WITH PHP INCLUDES AND TEMPLATES
369
12
hints or syntax coloring. More importantly, browsers don’t understand .inc files. So, if
anybody accesses an .inc file directly through a browser (as opposed to it being included
as part of a PHP page), everything is displayed as plain text.
This is a potential security risk if you put passwords or other sensitive information in external
files. One way around this problem is to store include files outside the server root
folder. Many hosting companies provide you with a private folder, which cannot be
reached by a browser. As long as the PHP script knows where to find the external file and
has permission to access it, include files can be outside the server root. However, this
creates problems for Dreamweaver site management.
A simpler, widely adopted solution is to use .inc.php as the file name extension. Browsers
and servers treat only the final .php as the file name extension and automatically pass
the file to the PHP engine if requested directly. The .inc is simply a reminder to you as the
developer that this is an include file.
As long as you store passwords and other sensitive information as PHP variables within PHP
code blocks, and use .php as the final file name extension, your data cannot be seen by
anyone accessing the page directly in a browser (of course, it will be revealed if your code
uses echo or print to display that information, but I assume that you have the sense not
to do that).
Displaying XHTML output
When PHP includes an external file, it automatically treats the contents of the external file
as plain text or XHTML. This means that you can cut a section out of an existing page built
in XHTML and convert it into an include file. In order to preserve your sanity, it’s important
to put only complete, logical elements in external files. Putting the opening part of a <div>
in one external file and the closing part in another file is a disaster waiting to happen. It
becomes impossible to keep track of opening and closing tags, and Dreamweaver is likely
to start trying to replace what it regards as missing tags.
Usually, I find the best approach is to build the complete page first, and then convert common
elements into include files.
This exercise shows you how to extract the menu from the “Stroll along the Thames” site
in Chapter 7 and convert it into an include file.
1. Copy stroll_horiz.html from examples/ch07 to workfiles/ch12. Also make
sure you have the dependent files: styles/stroll_horiz.css, SpryAssets/
SpryMenuBar.js, and SpryAssets/SpryMenuBarHorizontal_stroll.css.
2. Save stroll_horiz.html as stroll_horiz.php. You need to change the file name
extension so that the PHP engine knows to process it and include the external files
you are about to create. Test the page in a browser to make sure that it displays
correctly. It should look like Figure 12-4.
Converting a navigation menu into an include
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
370
Figure 12-4. The menu is the same on every page of the site, so it is a prime candidate for an
include file.
3. Create a new PHP file, and save it in the workfiles/includes folder as
menu.inc.php. You don’t need one of the CSS layouts, as you need a completely
blank page. Switch to Code view in menu.inc.php, and delete everything, including
the DOCTYPE declaration. There should be nothing left in the page.
4. Switch to stroll_horiz.php in the Document window. Click anywhere inside the
navigation menu, and click <div#nav> in the Tag selector to select the entire menu.
Switch to Code view, and then cut the menu to your computer clipboard
(Ctrl+X/Cmd+X or Edit ä Cut).
You must be in Code view when cutting the
menu to the clipboard. If you remain in
Design view, Dreamweaver cuts all the Spryrelated
code and pastes it into the include file.
You want to move only the XHTML code and
the Spry object initialization, but they’re in
different parts of the page, so it has to be
done in two steps. Click No, if Dreamweaver
displays the warning shown alongside at any
time during the next few steps. Once you
move the initialization script, the warning
message no longer appears.
WORKING WITH PHP INCLUDES AND TEMPLATES
371
12
5. Without moving the insertion point, click the Include button on the PHP tab of the
Insert bar (or use the menu alternative). This inserts a PHP code block and positions
your cursor between the parentheses of an include() command.
6. Type a single quote, right-click, and use Code Hint Tools ä URL Browser to navigate
to menu.inc.php in the workfiles/includes folder in the same way as in
“Including a text file” earlier in the chapter. In the Select File dialog box, make sure
that Relative to is set to Document. Click OK, and type a closing quote after the path.
Save stroll_horiz.php.
7. Switch to menu.inc.php in the Document window. Make sure you are in Code view,
and paste the menu that you cut from stroll_horiz.php. (If you are in Design
view, you won’t get all the XHTML code. Always cut and paste in the same view in
Dreamweaver—Design view to Design view or Code view to Code view.)
8. Go back to stroll_horiz.php, scroll down to the bottom of the page, and cut to
your clipboard the section of code highlighted on lines 54–58 in the following
screenshot.
This is the initialization script for the Spry menu bar. Make sure that you have the
opening and closing <script> tags.
9. Paste the Spry object initialization script into menu.inc.php after the closing
</div> tag. Save menu.inc.php, and close the file.
10. Switch to Design view in stroll_horiz.php. The menu should be visible as it was
before. If you can’t see the menu, open Preferences from the Edit menu
(Dreamweaver menu on a Mac), select the Invisible Elements category, and make
sure there’s a check mark in Server-Side includes: Show contents of included file.
11. Hover your mouse pointer over the navigation menu, and click the turquoise Spry
Menu Bar tab at the top left corner (see Figure 12-5). The Property inspector recognizes
it as a server-side include (SSI) and displays the name of the file, together
with an Edit button. Clicking the Edit button opens the include file in the Document
window ready for editing.
12. Test stroll_horiz.php in a browser. It should look like Figure 12-4, and the menu
should work as before. You can check your code against stroll_horiz_menu.php
in examples/ch12 and menu.inc.php in examples/includes.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
372
Figure 12-5. When you select the contents of an include file in Design view, the Property inspector
provides a direct link to edit it.
Putting the Spry object initialization script at the end of menu.inc.php results in it being
called earlier than it was in the original page, but it’s still in the right order and doesn’t
result in invalid code. It also prevents the warning in step 4 from being displayed every
time that you open the parent page.
An added advantage is that you can edit the Spry menu through the Property inspector in
the same way as in Chapter 7. Even though the include file has no direct link to the Spry
menu bar external JavaScript file, Dreamweaver automatically finds it because the
Spry assets folder is specified in the site definition.
However, what you put in an external file doesn’t always have such benign consequences.
Avoiding problems with include files
The server incorporates the content of an include file into the page at the point of the
include command. If you pasted all the Spry-related code into menu.inc.php, rather than
just the constructor, you would end up with the link to the external style sheet within the
<body> of stroll_horiz.php. Although some browsers might render the page correctly,
<style> blocks are invalid outside the <head> of a web page. If it doesn’t break now, it
probably will sooner or later as browsers get increasingly standards-compliant.
The most common mistake with include files is adding duplicate <head> and <body> tags.
Keep your include files free of extraneous code, and make sure that when everything fits
back together that you have a DOCTYPE declaration, a single <head> and <body>, and that
everything is in the right order.
Dreamweaver depends on the DOCTYPE declaration at the top of a page to determine
whether to use XHTML rules. Code added to an include will normally use HTML style, so
when editing an include, you need to keep a close eye on what is happening in Code view.
This is why I recommend extracting code into include files only toward the end of a project
or if the external file uses mainly dynamic code.
An annoying quirk in the way Dreamweaver handles PHP includes in Design view
is that the include command must be in its own PHP code block. If you put any
other PHP code in the same block—even a comment—Dreamweaver just displays
the gold PHP shield.
WORKING WITH PHP INCLUDES AND TEMPLATES
373
12
Another common problem is a broken link in an include file. Always use site-root-relative
links inside include files. As explained in Chapter 4, site-root-relative links provide a constant
reference to a page or an asset, such as an image. If you use document-relative links
inside an include file, the relationship—and therefore the link—is broken if the file is
included at a different level of the site hierarchy than where it was originally designed.
Applying styles with Design Time Style Sheets
Although Dreamweaver displays the menu normally in stroll_horiz.php, it looks completely
different in menu.inc.php. As Figure 12-6 shows, the menu is completely unstyled;
all you can see is the underlying series of nested unordered lists. Design Time Style Sheets
let you apply the styles in an external style sheet to a page or code fragment without the
need to attach the style sheet directly to the page. As the name suggests, the style sheet is
applied only at design time; in other words, in Design view.
Figure 12-6. The include file is completely unstyled.
To apply Design Time Style Sheets to a page or an include file, select CSS Styles ä Designtime
from either the Text menu or from the context menu when right-clicking in Design
view. This opens the Design Time Style Sheets dialog box, as shown in the following
screenshot:
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
374
The dialog box has two sections. The first one, Show only at design time, lets you apply a
style sheet without attaching it to the file. The second one, Hide at design time, works with
style sheets that are attached to a file, letting you hide the effect of selected style sheets
while working in Design view. It’s particularly useful when working with style sheets for different
media, such as print and screen.
Both sections work the same way: add a style sheet to the list by clicking the plus (+)
button and navigating to the style sheet in the site file system. The rules of the CSS
cascade apply, so add multiple style sheets in the same order as to the original page. To
remove a style sheet, highlight it, and click the minus (–) button. Figure 12-7 shows
menu.inc.php after applying workfiles/styles/stroll_horiz.css and SpryAssets/
SpryMenuBarHorizontal_stroll.css as Design Time Style Sheets. It now looks the same
as in the page it was extracted from.
Figure 12-7. After applying Design Time Style Sheets, the include file looks the same as in the
original page.
With the Design Time Style Sheets applied, you can manipulate the styles of the include
file by changing the class or ID of individual elements. You can also change the style rules
in the external style sheets through the CSS Styles panel. But—and it’s a rather large
one—you should remember that the code fragment that you’re working with is no longer
in the context of its parent page. As a result, the full effect of the CSS cascade may not be
accurately reflected. Also, changes made to the external style sheet may have unexpected
consequences on other parts of your design. Although useful, Design Time Style Sheets
have their limitations.
Another drawback is that Design Time Style Sheets can be applied to only one page at a
time. There is a commercial extension available that lets you apply Design Time Style
Sheets to an entire site. See www.communitymx.com/abstract.cfm?cid=61265 for details.
Dreamweaver stores details of style sheets applied to a page in this way in a subfolder
called _notes. The subfolder is hidden in the Files panel but can be inspected in Windows
Explorer or Finder.
Adding dynamic code to an include
The footer of a page frequently contains details that might change, such as company
address or telephone number, making it an ideal candidate for an include file.
The footer in stroll_horiz.php contains only a copyright notice, which normally changes
only once a year, but with a little PHP magic, you can get it to update automatically at the
stroke of midnight on New Year’s Eve every year. Continue working with the files from the
previous exercise.
Automatically updating a copyright notice
WORKING WITH PHP INCLUDES AND TEMPLATES
375
12
1. Create a PHP page, and save it in workfiles/includes as footer.inc.php. Switch
to Code view and remove all code, so the file is completely blank. Switch to Design
view.
2. Open stroll_horiz.php in Design view, and click anywhere inside the copyright
notice at the bottom of the page. Select the entire footer by clicking <div#footer>
in the Tag selector, and cut it to your clipboard.
3. Without moving the insertion point, click the Include button on the PHP tab of the
Insert bar. Dreamweaver opens Split view with the cursor placed between the
parentheses of an include() block. Type a single quote, use the URL Browser as
before to insert the path to footer.inc.php, and type a closing quote.
4. Switch to footer.inc.php, and paste the contents of your clipboard into Design
view. The footer is unstyled, but if you save footer.inc.php, switch to
stroll_horiz.php, and click in Design view, you’ll see the footer properly styled as
though you had never moved it. Click the copyright notice. The entire text is
selected, and the Property inspector displays the path of the include together with
an Edit button.
5. Click the Edit button to open footer.inc.php, and switch to Code view. It contains
the following XHTML:
<div id=”footer”>
<p>© Footsore in London</p>
<!– end #footer –>
</div>
6. A copyright notice should have a year. You could just type it in, but the PHP date()
function generates the current year automatically. Add the following code like this:
<p>©
<?php
ini_set(‘date.timezone’, ‘Europe/London’);
echo date(‘Y’);
?>
Footsore in London</p>
Chapter 17 explains dates in PHP and MySQL in detail, but let’s take a quick look at
what’s happening here. The core part of the code is this line:
echo date(‘Y’);
This displays the year using four digits. Make sure you use an uppercase Y. If you
use a lowercase y instead, only the final two digits of the year will be displayed.
The reason for the preceding line is because PHP 5.1.0 or higher requires a valid
time-zone setting. This should be set in php.ini, but if your hosting company forgets
to do this, you may end up with ugly error messages in your page.
What if your hosting company is using an earlier version of PHP? No problem.
Earlier versions simply ignore this line.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
376
Setting the time zone like this is not only good insurance against error messages, it
also allows you to override the hosting company setting, if your host is in a different
time zone from your own. The second argument for ini_set() must be one of
the time zones listed at www.php.net/manual/en/timezones.php.
7. Switch to Design view, and click the Live Data view button. You should see the current
year displayed alongside the copyright symbol, as shown here.
Click the Live Data view button again to toggle it off.
8. Copyright notices normally cover a range of years, indicating when a site was first
launched. To improve the copyright notice, you need to know two things: the start
year and the current year. Change the PHP code in the paragraph like this:
<p>©
<?php
ini_set(‘date.timezone’, ‘Europe/London’);
$startYear = 2007;
$thisYear = date(‘Y’);
if ($startYear == $thisYear) {
echo $startYear;
}
else {
echo “{$startYear}-{$thisYear}”;
}
?>
Footsore in London</p>
This uses simple conditional logic (if you’re new to PHP, see “Using comparisons to
make decisions” in Chapter 10, and take particular note of the use of two equal
signs in the conditional statement). The static value of $startYear is compared to
the dynamically generated value of $thisYear. If both are the same, only the start
year is displayed; if they’re different, you need to display both with a hyphen
between them.
I’ve used curly braces around the variables in the following line:
echo “{$startYear}-{$thisYear}”;
This is because they’re in a double-quoted string that contains no whitespace. The
curly braces enable the PHP engine to identify the beginning and end of the variables.
Since hyphens aren’t permitted in variable names, you could omit the curly
braces on this occasion. However, their presence makes the code easier to read.
WORKING WITH PHP INCLUDES AND TEMPLATES
377
12
9. Switch back to Design view, and toggle Live Data view on again. Assuming that you
used the current year for $startYear, you’ll see no difference, so experiment by
changing the value of $startYear and alternating between uppercase and lowercase
y in the date() function to see the different output, as shown here:
The values of $startYear, $thisYear, and the name of the copyright owner are the
only things you need to change, and you have a fully automated copyright notice.
You can check your code against footer.inc.php in examples/includes and
stroll_horiz_footer.php in examples/ch12.
Using includes to recycle frequently used PHP code
Up to now, all the examples in this chapter have shown you how to include plain text or
XHTML. The last example makes use of PHP code but is specific to one particular site.
Includes become really useful when you create PHP code that can be used in any site. A
simple example is the POST stripslashes snippet that you used in the last chapter. Instead
of putting the code directly inside your script, you could put it in an external file and use
include() to incorporate it.
Let’s take a look at the code again:
// remove escape characters from POST array
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value) {
$value = is_array($value) ? array_map(‘stripslashes_deep’, å
$value) : stripslashes($value);
return $value;
}
$_POST = array_map(‘stripslashes_deep’, $_POST);
}
It contains nothing but PHP code, and the code itself consists of a conditional statement
that removes backslashes from the $_POST array if magic quotes are enabled on the server.
To use it successfully as an include, you must do the following two things:
The code in the external file must be surrounded by PHP tags. Although include()
and its related commands are part of PHP, the PHP engine treats everything in an
include file as plain text or XHTML until it encounters an opening PHP tag.
The opening tag must be matched by a closing one at or before the end of the
include file.
The code must be included at the point in the script where you want to run it. In
this respect, it’s the same as the text and XHTML includes earlier in the chapter.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
378
PHP can be used in two main ways: as a procedural language and as an object-oriented
one. In a procedural language, everything is usually in the same page and the code is
executed from top to bottom. However, to avoid the need to retype frequently used sections
of script, you can package them up as custom-built functions. An object-oriented
language takes the concept of functions much further, and packages most of the code in
libraries called classes.
That’s a vast over-simplification, but in both approaches, unless the contents of an external
file define functions or classes, the include command must come at the point in the
code where you want to run it. The POST stripslashes snippet does include the definition
of the stripslashes_deep() function, but it’s buried inside a conditional statement. So,
the snippet itself is a chunk of procedural code that must be included at the point of the
script where it’s needed.
However, you can convert the snippet into a new function called nukeMagicQuotes() like
this:
<?php
function nukeMagicQuotes() {
// remove escape characters from POST array
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value) {
$value = is_array($value) ? array_map(‘stripslashes_deep’, å
$value): stripslashes($value);
return $value;
}
$_POST = array_map(‘stripslashes_deep’, $_POST);
}
}
?>
If you save this as nukeQuotes.inc.php, you can include the external file at the beginning
of your script and run this function at any stage in your script like this (you can see the
code in feedback_nuke.php in examples/ch12 and nukeQuotes.inc.php in examples/
includes):
nukeMagicQuotes();
The difference of this approach is that the include file initializes the function, but the function
doesn’t actually run until it’s called in the main body of the script. Since this particular
piece of code runs only once, there’s no immediate advantage of doing it this way.
However, let’s say that you find a way of improving this script, the changes need to be
made only in the external file, saving you the effort of hunting through every page where
it might have been used. External files can define more than one function, so you can store
frequently used functions together. In this respect, includes are the PHP equivalent of linking
external JavaScript files or style sheets.
When functions or classes are stored in an external file, the include command must
come before you use the functions or classes in your main script.
WORKING WITH PHP INCLUDES AND TEMPLATES
379
12
Although building your own function library is an important use of includes, you shouldn’t
ignore the opportunity to recycle procedural code. The next section shows you how to
adapt the mail processing script from the last chapter and make it generic, so that it can
handle the output of any feedback form.
Adapting the mail processing script as an include
The mail processing script in the last chapter performs a series of tasks, some of them specific
to the feedback form, others more generic in nature.
Analyzing the script
To make the script reusable, you need to identify what’s specific, what’s generic, and
whether any of the specific tasks can be made generic. Once you have identified the
nature of each task, you need to concentrate the generic ones into a single unit that can
be exported to an external file.
Table 12-1 lists the tasks in the order they are currently performed and identifies their
roles. You can study the code in feedback_orig.php in examples/ch12.
Table 12-1. Analysis of the mail processing script
Step Description Type
1 Check if form has been submitted Specific
2 Remove magic quotes Generic
3 Set to address and subject Specific
4 List expected and required fields Specific
5 Initialize missing array Generic
6 Filter suspect content Generic
7 Process $_POST variables and check for missing fields Generic
8 Validate email address Generic
9 Build the message body Specific
10 Create additional headers Specific
11 Send email Generic
As you can see from Table 12-1, most tasks are generic, but they don’t form a single block.
However, step 2 can easily be moved after steps 3 and 4. That leaves just steps 9 and 10
that get in the way.
Step 9 builds the body of the message, which would appear to be something that’s always
specific to each form. Let’s take another look at that part of the script:
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
380
// set default values for variables that might not exist
$interests = isset($interests) ? $interests : array(‘None selected’);
$views = isset($views) ? $views : array(‘None selected’);
// build the message
$message = “Name: $name\n\n”;
$message .= “Email: $email\n\n”;
$message .= “Comments: $comments\n\n”;
$message .= ‘Interests: ‘.implode(‘, ‘, $interests).”\n\n”;
$message .= “Visited: $visited\n\n”;
$message .= ‘Impressions of London: ‘.implode(‘, ‘, $views).”\n\n”;
$message .= “Subscribe: $subscribe”;
It doesn’t take a genius to work out that the message is built using text labels followed by
variables with the same name as the label. Since the variable names come from the name
attributes in the form, all you need is a way of displaying the name attributes as well as the
values of each input field. That’s easily done with PHP. It’s also easy to set default values for
variables that might not exist.
That leaves just step 10, the creation of additional headers. With the exception of the
return email address, it doesn’t matter when you specify the additional headers. They simply
need to be passed to the mail() function in step 11. So you can move the creation of
most headers to the form-specific section at the beginning of the script. Table 12-2 shows
the revised order of tasks.
Table 12-2. The revised mail processing script
Step Description Type
1 Check if form has been submitted Specific
2 Set to address and subject Specific
3 Set form-specific email headers Specific
4 List expected and required fields Specific
5 Remove magic quotes Generic
6 Initialize missing array Generic
7 Filter suspect content Generic
8 Process $_POST variables and check for missing fields Generic
9 Validate email address Generic
10 Build the message body Generic
11 Add return email address to headers Generic
12 Send email Generic
WORKING WITH PHP INCLUDES AND TEMPLATES
381
12
Building the message body with a generic script
Loops and arrays take a lot of the hard work out of PHP scripts, although they can be difficult
to understand when you’re new to PHP. You may prefer just to use the completed
script, but if you’re interested in the details, take a look at the following code, and I’ll
explain how it works:
// initialize the $message variable
$message = ”;
// loop through the $expected array
foreach($expected as $item) {
// assign the value of the current item to $val
if (isset(${$item})) {
$val = ${$item};
}
// if it has no value, assign ‘Not selected’
else {
$val = ‘Not selected’;
}
// if an array, expand as comma-separated string
if (is_array($val)) {
$val = implode(‘, ‘, $val);
}
// add label and value to the message body
$message .= ucfirst($item).”: $val\n\n”;
}
This replaces the code for step 9 that was listed in the preceding section. It begins by
initializing $message as an empty string. Everything else is inside a foreach loop
(see “Looping through arrays with foreach” in Chapter 10), which iterates through
the $expected array. This array consists of the name attributes of each form field (name,
email, etc.).
A foreach loop assigns each element of an array to a temporary variable. In this case, I
have used $item. So, the first time the loop runs, $item is name; the next time it’s email,
and so on. This means that you can use $item as the text label for each form field, but
before you can do that, you need to know whether the field contains any value. The code
that processes the $_POST variables (step 8 in the revised script) assigns the value of each
field to a variable based on its name attribute ($name, $email, etc.). The rather odd-looking
${$item} is what’s known as a variable variable (the repetition is deliberate, not a misprint).
Since the value of $item is name the first time the loop runs, ${$item} refers to
$name. On the next pass through the loop, it refers to $email, and so on.
In effect, what happens is that on the first iteration the following conditional statement
if (isset(${$item})) {
$val = ${$item};
}
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
382
becomes this
if (isset($name)) {
$val = $name;
}
If the variable doesn’t exist (which would happen if nothing was selected in a checkbox
group), the else clause assigns $val the string Not selected.
So you now have $item, which contains the label for the field, and $val, which contains
the field’s value.
The next conditional statement uses is_array() to check whether the field value is an
array (as in the case of checkboxes or a multiple-choice list). If it is, the values are converted
into a comma-separated string by implode().
Finally, the label and field value are added to $message using the combined concatenation
operator (.=). The label ($item) is passed to the ucfirst() function, which converts the
first character to uppercase. The concatenation operator (.) joins the label to a doublequoted
string, which contains a colon followed by the field value ($val) and two new line
characters.
This code handles all types and any number of form fields. All it needs is for the name
attributes to make suitable labels and to be added to the $expected array.
The following instructions show you how to adapt feedback.php from the previous chapter,
so that it can be recycled for use with most forms. If you don’t have a copy of the file
from the previous chapter, copy feedback_orig.php from examples/ch12 to workfiles/
ch12, and save it as feedback.php.
1. Create a new PHP file, and save it as process_mail.inc.php in workfiles/
includes. Switch to Code view, and strip out all existing code.
2. Insert the following code:
<?php
if (isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'],å
‘.inc.php’)) exit;
?>
This uses the predefined variable $_SERVER['SCRIPT_NAME'] and the strpos()
function to check the name of the current script. If it contains .inc.php, that
means somebody is trying to access the include file directly through a browser, so
the exit command brings the script to a halt. When accessed correctly as an
include file, $_SERVER['SCRIPT_NAME'] contains the name of the parent file, so
unless you also give that the .inc.php file name extension, the conditional statement
returns false and runs the rest of the script as normal.
Converting feedback.php to use the generic script
WORKING WITH PHP INCLUDES AND TEMPLATES
383
12
Calling process_mail.inc.php directly shouldn’t have any negative effect, but if
display_errors is enabled on your server, it generates error messages that might
be useful to a malicious attacker. This simple security measure prevents the script
running unless it’s accessed correctly.
3. Cut the POST stripslashes code from the top of feedback.php, and paste it on the
blank line before the closing PHP tag in process_mail.inc.php.
4. Leave $to, $subject, $expected, and $required in feedback.php. Cut the remaining
PHP code above the DOCTYPE declaration (DTD), except for the closing curly
brace and PHP tag. The following code should be left above the DTD in
feedback.php:
<?php
if (array_key_exists(‘send’, $_POST)) {
//mail processing script
$to = ‘me@example.com’; // use your own email address
$subject = ‘Feedback from Essential Guide’;
// list expected fields
$expected = array(‘name’, ‘email’, ‘comments’, ‘interests’, å
‘visited’, ‘views’, ‘subscribe’);
// set required fields
$required = array(‘name’, ‘comments’, ‘visited’);
}
?>
5. Paste into process_mail.inc.php just before the closing PHP tag the code you cut
from feedback.php.
6. Cut the line that sets the From header, and paste it in feedback.php after the
$required array. Replace the code that builds the message with the generic version.
The full listing for process_mail.inc.php follows, with the new code highlighted
in bold:
<?php
if (isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'],å
‘.inc.php’)) exit;
// remove escape characters from POST array
if (get_magic_quotes_gpc()) {
function stripslashes_deep($value) {
$value = is_array($value) ? array_map(‘stripslashes_deep’, å
$value) : stripslashes($value);
return $value;
}
$_POST = array_map(‘stripslashes_deep’, $_POST);
}
// create empty array for any missing fields
$missing = array();
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
384
// assume that there is nothing suspect
$suspect = false;
// create a pattern to locate suspect phrases
$pattern = ‘/Content-Type:|Bcc:|Cc:/i’;
// function to check for suspect phrases
function isSuspect($val, $pattern, &$suspect) {
// if the variable is an array, loop through each element
// and pass it recursively back to the same function
if (is_array($val)) {
foreach ($val as $item) {
isSuspect($item, $pattern, $suspect);
}
}
else {
// if one of the suspect phrases is found, set Boolean to true
if (preg_match($pattern, $val)) {
$suspect = true;
}
}
}
// check the $_POST array and any subarrays for suspect content
isSuspect($_POST, $pattern, $suspect);
if ($suspect) {
$mailSent = false;
unset($missing);
}
else {
// process the $_POST variables
foreach ($_POST as $key => $value) {
//assign to temporary variable and strip whitespace if not an array
$temp = is_array($value) ? $value : trim($value);
// if empty and required, add to $missing array
if (empty($temp) && in_array($key, $required)) {
array_push($missing, $key);
}
// otherwise, assign to a variable of the same name as $key
elseif (in_array($key, $expected)) {
${$key} = $temp;
}
}
}
// validate the email address
if (!empty($email)) {
// regex to identify illegal characters in email address
$checkEmail = ‘/^[^@]+@[^\s\r\n\'";,@%]+$/’;
WORKING WITH PHP INCLUDES AND TEMPLATES
385
12
// reject the email address if it deosn’t match
if (!preg_match($checkEmail, $email)) {
$suspect = true;
$mailSent = false;
unset($missing);
}
}
// go ahead only if not suspsect and all required fields OK
if (!$suspect && empty($missing)) {
// initialize the $message variable
$message = ”;
// loop through the $expected array
foreach($expected as $item) {
// assign the value of the current item to $val
if (isset(${$item})) {
$val = ${$item};
}
// if it has no value, assign ‘Not selected’
else {
$val = ‘Not selected’;
}
// if an array, expand as comma-separated string
if (is_array($val)) {
$val = implode(‘, ‘, $val);
}
// add label and value to the message body
$message .= ucfirst($item).”: $val\n\n”;
}
// limit line length to 70 characters
$message = wordwrap($message, 70);
// create Reply-To header
if (!empty($email)) {
$headers .= “\r\nReply-To: $email”;
}
// send it
$mailSent = mail($to, $subject, $message, $headers);
if ($mailSent) {
// $missing is no longer needed if the email is sent, so unset it
unset($missing);
}
}
?>
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
386
7. All that remains is to include the mail processing script. Since the form won’t work
without it, it’s a wise precaution to check that the file exists and is readable before
attempting to include it. The following is a complete listing of the amended code
above the DOCTYPE declaration in feedback.php. The new code, including the
$header pasted in the previous step, is highlighted in bold.
<?php
if (array_key_exists(‘send’, $_POST)) {
//mail processing script
$to = ‘me@example.com’; // use your own email address
$subject = ‘Feedback from Essential Guide’;
// list expected fields
$expected = array(‘name’, ‘email’, ‘comments’, ‘interests’, å
‘visited’, ‘views’, ‘subscribe’);
// set required fields
$required = array(‘name’, ‘comments’, ‘visited’);
$headers = ‘From: Essential Guide<feedback@example.com>’;
$process = ‘../includes/process_mail.inc.php’;
if (file_exists($process) && is_readable($process)) {
include($process);
}
else {
$mailSent = false;
}
}
?>
The path to process_mail.inc.php is stored in $process. This avoids the need to
type it out three times. The conditional statement uses two functions with selfexplanatory
names: file_exists() and is_readable(). If the file is OK, it’s
included. If not, $mailSent is set to false. This displays the warning that there was
a problem sending the message. Because $missing is set inside the processing
script, the user’s input won’t be redisplayed. You could move the initialization of
$missing to feedback.php, but if the script can’t be accessed, your form is broken
anyway.
8. To be super-efficient, send yourself an email alerting you to the problem with the
include file by amending the conditional statement like this:
if (file_exists($process) && is_readable($process)) {
include($process);
}
else {
$mailSent = false;
mail($to, ‘Server problem’, “$process cannot be read”, $headers);
}
You can check the final code in feedback_process.php in examples/ch12 and
process_mail.inc.php in examples/includes.
WORKING WITH PHP INCLUDES AND TEMPLATES
387
12
Because process_mail.inc.php uses generic variables, you can slot this include file into
any page that processes a form and sends the results by email. The only proviso is that you
must use the same variables as in step 7, namely $to, $subject, $expected, $required,
$headers, and $mailSent. You also need to use $missing for the error-checking routine,
as described in the previous chapter.
Programming purists would criticize this use of procedural code, arguing that a more
robust solution should be built with object-oriented code. An object-oriented solution
would probably be better, but it would also be more difficult for a PHP beginner to adapt.
The purpose of this exercise has been to demonstrate how even procedural code can be
recycled with relatively little effort. It also prepares the ground for customizing the
PHP code automatically generated by Dreamweaver. With the exception of the
XSL Transformations server behavior (covered in Chapter 18), Dreamweaver uses procedural
code.
Avoiding the “headers already sent” error
A problem that you’re bound to encounter sooner or later is this mysterious error
message:
Warning: Cannot add header information – headers already sent
It happens when you use header() to redirect a page, as described in the previous chapter,
or with PHP sessions (covered in Chapter 15). More often than not, the cause of the
problem lies in an include file.
Using header() or starting a PHP session must be done before any output is sent to the
browser. This includes not only XHTML but also any whitespace. As far as PHP is concerned,
whitespace means any space, tab, carriage return, or new line character. Why the
error message is so mysterious—and causes so much head banging—is because the whitespace
is often at the end of an include file. Use the line numbers in Code view, as shown
in Figure 12-8, to make sure there are no blank lines at the end of an include file. Also
make sure that there is no whitespace after the closing PHP tag on the final line.
Whitespace inside the PHP tags is unimportant, but the PHP code must not generate any
XHTML output before using header() or starting a session. The same applies to the parent
page: there must be no whitespace before the opening PHP tag.
On rare occasions, the error is triggered by an invisible control character at the beginning
of the file. Use View ä Code View Options ä Hidden Characters to check, and delete the
character.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
388
Figure 12-8. Eliminate whitespace at the beginning and end of include files to avoid the “headers
already sent” error.
Using Dreamweaver templates in a PHP site
Earlier in the chapter, I showed you how to extract two sections from the “Stroll along the
Thames” site and turn them into includes. You could go further, and convert the header
and fixed parts of the document <head> into includes, so that each page consists of several
includes, with just the sidebar and main content forming the actual content of the page.
As long as you keep each include as a coherent block, it’s relatively easy to manage, and
Design view preserves the unified look of the page.
However, it’s not an approach that everybody feels comfortable with. That’s where
Dreamweaver templates can be a useful alternative. A template locks the fixed elements
of the design, but lets you designate editable regions for the content that you want to
change on each page. Dreamweaver templates allow you to control what can and can’t be
edited with a great degree of precision, right down to the individual attributes of a tag. If
you change anything in a locked region of a master template, Dreamweaver automatically
updates all child pages (as long as you accept the option to do so). Although this is convenient,
you still need to upload the changed pages manually to the live website.
I don’t intend to go into the finer details of working with templates but simply give a
broad overview of creating a template, designating editable regions, and creating child
pages. I’ll also touch on issues that apply specifically to working with PHP in a
Dreamweaver template.
WORKING WITH PHP INCLUDES AND TEMPLATES
389
12
Creating a template
The easiest way to create a Dreamweaver template is to design a page in the Document
window in the normal way. It’s then a simple matter of saving the page as a template and
designating the editable regions. Let’s do that with the “Stroll along the Thames” page
from earlier in the chapter.
This exercise combines the benefits of both approaches. The menu and footer are PHP
includes, so can be edited separately, while the rest of the page as a template locks down
the main design elements.
1. Open stroll_horiz_footer.php from examples/ch12 in the Document window.
There is no need to copy or move it, because converting it into a template takes
care of that.
2. Choose Make Template from the Common tab of the Insert bar, as shown in the following
screenshot. Alternatively, use the menu option File ä Save as Template.
3. This opens the following dialog box:
In theory, you can choose to save the template in a different site, but this is likely
to cause problems with images, so leave Site unchanged. Existing templates displays
a list of templates that you have already defined, if any. Optionally enter a description
Converting stroll_horiz_footer.php into a template
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
390
of the template in the Description field. The Save as field suggests using the current
file name. You can change this, if you like, but don’t add a file name extension, as
Dreamweaver uses a special extension for templates. Click Save.
4. Dreamweaver asks if you want to update links. You must click Yes, or your template
will have broken links and cause endless trouble.
5. Although it may appear as though nothing happens, the Dreamweaver title bar
changes to display <<Template>> in front of the file name, which now has a
.dwt.php extension, as shown here.
Dreamweaver also saves the new template in the Templates folder in the site root.
If the folder doesn’t exist, Dreamweaver creates it silently.
Adding editable regions to the master template
Everything in a template is locked, except for the <title> tag and an editable region in the
<head> of the document. This is needed so that external JavaScript files and style sheets
can be added to a child page. It’s also where Dreamweaver behaviors insert the JavaScript
functions that they require.
It goes without saying that you must unlock at least one part of the page for the template
to be of any real value. Otherwise, every child page would be identical. Deciding what to
lock and unlock depends entirely on the level of control that you want over a page. For
instance, you could create separate editable regions for each of the headings on the page.
An important exception to this basic principle is that the area above the DTD and
below the closing </html> tag is not locked in templates for server-side languages,
such as PHP. I’ll come back to this issue a little later, as it causes a lot of confusion.
The file with the .dwt.php file name extension is now the master template from which
you create child pages. Any changes to the design of this page will affect all child
pages created from it—as long as you accept the option to update them. You must
not move the template from the Templates folder. This is perhaps the single most
common mistake with templates—moving the master template to another folder will
cause you endless grief. Don’t do it.
WORKING WITH PHP INCLUDES AND TEMPLATES
391
12
If you select the entire heading, including its surrounding tags, the heading can be
replaced by anything: a table, a <div>, an <iframe>, or whatever you like. If you select just
the content of an <h2> tag and convert it into an editable region, only the content can be
changed in a child page. You can’t even change it to an <h1> tag.
Since the remaining chapters of this book are about building dynamic content with PHP,
you don’t want such rigid control. So you could make everything inside the container
<div> one big editable region. However, we’ll take a slightly different approach.
This exercise shows you how to create separate editable regions for the sidebar heading
and content, as well as for the whole main content area.
1. Open stroll_horiz_footer.dwt.php in the Templates folder if it’s not already
open.
2. Open Split view. Click immediately to the left of the heading that reads The pleasures
of London. Hold down your mouse button and drag to the end of the heading.
Alternatively, hold down the Shift key while pressing the keyboard right arrow to
select the content of the heading. Make sure you have just the text and not the surrounding
<h3> tags, as shown in the following screenshot.
3. There are several ways to make this an editable region. If you’re a fan of the Insert
bar, click the down arrow next to the Make Template button on the Common tab,
and select Editable Region. The Insert bar remembers your last selection, so the
Editable Region button remains displayed, ready for the creation of more editable
regions.
Alternatively, right-click and select Templates ä New Editable Region from the context
menu, or go to Insert ä Template Objects ä Editable Region.
4. This opens the New Editable Region dialog box. It has just one field for a name for
the editable region. It can be anything you like, but each region must have a different
name. Enter sidebarHead, and click OK.
5. This wraps the contents of the <h3> tag in two special HTML comment tags, as
shown in Figure 12-9. These tell Dreamweaver to treat this as an editable region in
child pages. Dreamweaver also displays a turquoise border around the region in
Design view, with a tab at the top left indicating the name of the editable region.
Making the sidebar and main content areas editable
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
392
Figure 12-9. Editable regions are easily identified in both Code view and Design view.
6. Select the paragraphs and <blockquote> in the sidebar. If you’re still in Split view,
you’ll see that selecting the text in Design view misses the opening tag of the first
paragraph and the closing tag of the final one. This doesn’t matter. Since more than
one paragraph is selected, Dreamweaver is normally clever enough to realize that
you want the surrounding tags and includes them when you create the editable
region.
7. Use one of the previous methods to make this an editable region named
sidebarContent. Switch to Code view to make sure that the opening and closing
<p> tags were included. If they weren’t, move them inside the template comments.
8. Select all the content in the mainContent <div>, but not the surrounding <div>
tags, and create an editable region called mainContent. Check that the template
comments are in the right place in Code view, and save stroll_horiz_footer.
dwt.php.
9. Dreamweaver should display a warning that sidebarHead is inside a block tag, and
that users of the template won’t be able to create new blocks in this region. This is
because the <h3> tags are outside the sidebarHead editable region, which prevents
anything other than a level three heading being created. That’s fine. So click OK.
Creating child pages from a template
Now that you have a template, you can build pages based on it. The editable regions can
be freely changed, but the other areas remain locked and can be changed only by editing
the master template.
Always check the position of the TemplateBeginEditable and TemplateEndEditable
comments in Code view, as you can easily move them or any of the surrounding code
while still in the template. Checking now saves a lot of frustration later, when you discover
that you didn’t select the region accurately in Design view, and your child pages
don’t work the way you expect. These comments are an integral part of the template
control mechanism and are propagated to the child pages, where they remain part of
the XHTML (see Figure 12-13).
WORKING WITH PHP INCLUDES AND TEMPLATES
393
12
This exercise uses the template from the previous exercise to create a child page and
explores the way editable regions are displayed in both Design view and Code view. It also
demonstrates the importance of using site-root-relative links in PHP includes,
1. Go to File ä New. When the New Document dialog box opens, select Page from
Template from the options on the left side. Assuming that you created the template
in the preceding exercises, the dialog box should look similar to Figure 12-10.
Figure 12-10. The New Document dialog box gives you access to all the templates you have created.
If you have created templates in several sites, select the site and the template that
you want to use as the basis for a new page (you can have as many templates as
you like in a site, using different designs for pages that serve different functions).
The New Document dialog box shows a preview of the selected template, together
with the description you entered when it was first created.
The idea of a template is that all changes to common elements are propagated
automatically to child pages when the master template is updated. Unless you want
to create a page that doesn’t automatically update, make sure that there’s a check
mark in Update page when template changes, and click Create.
2. A new page is created in the Document window. At first glance, it looks identical to
the template, but several features tell you that it’s a child page (see Figure 12-11)
and that you can make changes only to the editable regions indicated by the
turquoise borders and tabs. Whenever your mouse is over a locked part of the
page, the pointer turns into a circle with a diagonal bar to warn you that no
changes can be made.
Creating and editing a template-based page
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
394
Figure 12-11. The child page is identical to the master template, but locked areas
can no longer be edited.
3. Save the page as stroll_index.php in workfiles/ch12.
4. Repeat step 1 to create another child page from the template. Save it as stroll_
restaurants.php in a new folder called workfiles/ch12/food.
5. Make some changes to stroll_restaurants.php. Experiment to see what you can
and can’t change. For instance, the sidebarHead cannot be changed to a different
format, but the <h2> at the top of the mainContent <div> can be changed or
deleted altogether. You can also change the Title field in the Document toolbar.
Give the pages different titles by adding Home to stroll_index.php and
Restaurants to stroll_restaurants.php. Make sufficient changes to one of the
pages so that you can tell them apart, and then save both of them.
6. The navigation menu contains only dummy links at the moment, so open
menu.inc.php in workfiles/includes. Update the link for Home so that it points
to stroll_index.php and for Restaurants to point to stroll_restaurants.php.
Because the navigation menu is shared by files in different levels of the site hierarchy,
you must make the links relative to the site root, even if you have set the site
default to use links relative to the current document. Use the Browse icon (it looks
like a folder) alongside the Link field in the Property inspector to select the target
files, and set the Relative to drop-down menu to Site Root as shown in Figure 12-12.
WORKING WITH PHP INCLUDES AND TEMPLATES
395
12
Figure 12-12. Links for the navigation menu must be relative to the site root.
7. Save menu.inc.php, and switch back to stroll_index.php in the Document window.
You want to test the navigation menu links, so your Dreamweaver preferences
shouldn’t use temporary files for preview. (If you’re not sure, open Preferences
from the Edit menu or Dreamweaver menu on a Mac; then select Preview in Browser,
and make sure Preview using temporary file is deselected.) Press F12/Opt+F12 to preview
stroll_index.php in a browser.
8. Test the Restaurants link. If you have followed the instructions carefully, it won’t
work. Don’t worry; I’ve done something deliberately to demonstrate an important
feature of building pages from templates.
9. Open stroll_index.php in Code view. The first thing you’ll notice is that several
parts of code are colored light gray. All the code in gray is locked. Try editing one
of these areas. Although Dreamweaver puts the insertion point wherever you click,
you cannot type anything. The only exception is between the template comments
shown on line 25 of Figure 12-13. This is where you can add extra style sheets or
JavaScript. It’s also where you should insert any other elements that normally go in
the <head> of a web page, such as keywords and description <meta> tags.
Figure 12-13. Locked areas in a child page cannot be edited (lines 8–22 and 27–35 are hidden
using Code collapse).
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
396
Another thing to note is the codeOutsideHTMLIsLocked attribute shown on line 2
of Figure 12-13. By default, this is set to false. This is to allow you to apply server
behaviors to pages created from a template. When you start working with server
behaviors in Chapter 14, you’ll see that Dreamweaver puts most of the PHP code
outside the <html> tags, so if this were set to true, you wouldn’t be able to apply
server behaviors to your pages. I’ll explain the implications of this shortly.
Finally, look at the include command for menu.inc.php (it’s on line 36 in Figure 12-13).
It’s pointing to the version of the file in examples/includes, but the menu that you
edited in step 6 is in workfiles/includes. Because this code is in a locked area,
you can’t edit it. You need to do that in the master template.
10. Open stroll_horiz_footer.dwt.php in the Templates folder, and click the navigation
menu. The Property inspector displays the name of the include file. Click the
folder icon to the right of the Filename field, and browse to the workfiles/
includes folder. Select menu.inc.php, and make sure that Relative to is set to
Document (PHP includes need a relative path).
11. Save stroll_horiz_footer.dwt.php. Dreamweaver will remind you again that
sidebarHead is inside a block tag. Just click OK. The next dialog box asks you if you
want to update all files based on the template, and lists all of the child pages. The
whole point of a template is automatic updating, so click Update.
12. When all the files have been updated, Dreamweaver displays a report like this:
If you don’t see the list of updated files at the bottom of the dialog box, select the
Show log checkbox. If anything goes wrong, Dreamweaver reports which files it
wasn’t able to update. As you can see from the preceding screenshot, the update
process is almost instantaneous with only a couple of child pages, but the time
taken depends on the number of pages and the complexity of the updates. Click
Close.
13. Reload stroll_index.php in your browser, and click the Restaurant link. You
should be taken to stroll_restaurants.php, and the Home link should take
you back to stroll_index.php. You can check your files against the versions in
examples/ch12.
WORKING WITH PHP INCLUDES AND TEMPLATES
397
12
This is only a trivial example of how a change to the master template is propagated to all
child pages, but it should be sufficient to demonstrate how templates control the look and
shape of a site. However, the real power of this sample layout lies not so much in the template,
but in the use of an include file for the navigation menu. If you were to leave the
navigation menu in the main template, you would need to update every single child page
each time you edit the menu. With an include, the edits take place in the external file but
are immediately available in all pages that include it.
Locking code outside the <html> tags
Often, questions appear in online forums from people puzzled by the fact that the code
isn’t propagated to child pages when a server behavior is applied to a template. Although
coverage of server behaviors begins in Chapter 14, it makes sense to discuss this issue
here, while still on the subject of templates.
Dreamweaver uses the space above the DTD and below the closing </html> tag to create
the PHP scripts used for server behaviors, such as inserting or updating records in a database.
This is the same technique as you used in the last chapter to build the mail processing
script. The reason for doing this is quite simple: the PHP engine reads the page from
top to bottom and processes the dynamic code in the order that it encounters it. So, if you
have a page that displays the results of a database search, it stands to reason that
you need to conduct the search before displaying the results as XHTML. Dreamweaver
uses the area after the closing </html> tag to clean up any resources used by the script.
Templates are intended to lock common elements, but dynamic code is almost always
unique to a page. As a result, Dreamweaver doesn’t lock the code outside the <html> tags.
So, even if you apply a server behavior to a master template (or write your own custom
script above the DTD), the code outside the <html> tags will not be propagated to any
child pages.
If, for any reason, you want to create a template that propagates code outside the <html>
tags, add the following code anywhere inside the <head> of the master template:
<!– TemplateInfo codeOutsideHTMLIsLocked=”true” –>
This is an all or nothing option. The PHP code will be propagated to child pages, but you
cannot apply any other server behaviors to such child pages. The circumstances in which
this option is useful are extremely rare, so use with care—if at all.
Choosing the right tool
The considerably large space I have devoted to PHP includes in this chapter should give
you a fair indication of my personal preference for includes. However, some people find
the idea of splitting a page into its various component parts a difficult concept to come to
terms with. So templates do have an important role to play. They also offer a more secure
solution if you work in a team environment. You can generate a child page and hand it to
a less experienced developer in the knowledge that only the editable regions can be
changed. With includes, nothing is locked. But as a site gets larger, so too do the efficiency
savings offered by includes.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
398
13 SETTING UP MYSQL AND
PHPMYADMIN
Dynamic websites take on a whole new meaning in combination with a database. Drawing
content from a database allows you to present material in ways that would be impractical—
if not impossible—with a static website. Examples that spring to mind are online stores,
such as Amazon.com; news sites, such as the International Herald Tribune (www.iht.com);
and the big search engines, including Google and Yahoo! Database technology allows these
websites to present thousands, sometimes millions, of unique pages with remarkably little
underlying code. Even if your ambitions are nowhere near as grandiose, a database can
increase your website’s richness of content with relatively little effort.
Although PHP is capable of interacting with most popular databases (and some less wellknown
ones, too), Dreamweaver has made the choice for you. All the server behaviors are
designed to work with MySQL—a good choice, because it’s widely available, free, very fast,
and offers an excellent range of features.
In this chapter, you will learn how to
Install MySQL on Windows and Mac OS X
Secure access to MySQL
Set up the phpMyAdmin graphical interface
Back up and transfer data to another server
Introducing MySQL
If you have ever worked with Microsoft Access, your first encounter with MySQL might
come as something of a shock. For one thing, it doesn’t have a glossy interface. As
Figure 13-1 shows, it looks like a throwback to the old days of DOS before the friendly
interfaces of Mac and Windows. Its beauty lies, however, in its simplicity. What’s more,
most of the time you’ll never see MySQL in its raw state like this. You’ll either use
Dreamweaver or a graphic front end called phpMyAdmin. Best of all, you’ll be designing
your own personalized interface by creating PHP pages.
Figure 13-1. The unadorned interface of MySQL as seen in the Windows MySQL Command
Line Client
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
402
The other thing that comes as a surprise to Access users is that your database is not kept
in a single file that you can upload to your remote server. MySQL keeps all databases in a
central data folder, and each database table normally consists of three separate files. The
way you transfer data from one server to another is by creating a text file that contains all
the necessary commands to build the database and its contents—in other words, a backup
file. All you need to know now is that there isn’t “a database file”—there are lots of them,
and normally, you should never handle them directly.
Understanding basic MySQL terminology
If you’ve not worked with a relational database before, you may find your head spinning
with some of the names that crop up throughout the rest of this book. So here’s a quick
guide:
SQL: Structured Query Language is the international standard behind all major relational
databases. It’s used to insert and otherwise manipulate data and is based on
natural English. For instance, to get the values of first_name and family_name
from a database table called members, where username is equal to dpowers, you
would use the following command (or SQL query):
SELECT first_name, family_name
FROM members
WHERE username = ‘dpowers’
As you can see, it’s very human readable, unlike many other computer languages.
Although SQL is a standard, all of the main databases have added enhancements
on top of the basic language. If you have been using Access or Microsoft SQL
Server, be prepared for some slight differences in the use of functions. Some people
pronounce SQL “sequel,” while others say “Ess-queue-ell.” Both are right.
MySQL: This refers to the entire database system created by MySQL AB of Sweden.
It’s always spelled in uppercase, except for the “y,” and the official pronunciation is
“My-ess-queue-ell.” It’s not just a single program, but also a client/server system
with a number of related programs that perform various administrative tasks. The
two main components are mysql and mysqld, with both terms entirely in lowercase.
mysqld: This is the server (or, to give it its proper technical name, daemon) that
runs in the background listening for requests made to the database. Once it has
been started, you can ignore it.
mysql: This has three distinct meanings. The first is the client program used to feed
requests to the database. mysql is also the name of the main administrative database
that controls user accounts, and on Windows, it is the name of the Windows
service that starts and stops the database server. Once you start working with
MySQL, differentiating between the different meanings of “mysql” is not as confusing
as it first seems.
SETTING UP MYSQL AND PHPMYADMIN
403
13
Installing MySQL
So, let’s press ahead and install MySQL. There are separate instructions for Windows and
Mac OS X. If you plan to use a remote server as your testing server, and already have
MySQL and phpMyAdmin set up, you can skip ahead to the next chapter.
You can get MySQL from the downloads page at http://dev.mysql.com/downloads/.
Select the Download link for MySQL Community Server, as shown in the following screenshot.
This link takes you to the latest stable version of MySQL (currently the 5.0.x series).
If, for any reason, you want to install an older version, don’t click this link, but scroll down
the page to the link to archives of older releases.
MySQL Enterprise is the commercial version, but the technical features in the Community
Server are identical. The main difference is that MySQL Enterprise comes with technical
support. With the Community Server, you’re on your own, but you have this book to guide
you. There is also a large community of MySQL users who are able to offer help online.
The installation instructions for MySQL are different for Windows and Mac OS X, so Mac
users should skip ahead to the relevant section of the chapter.
Installing MySQL on Windows
MySQL comes in a range of versions, but the one you should choose is Windows Essentials.
It contains all the important stuff and certainly everything you need for this book. If you
have a version older than MySQL 4.1.5 already installed on your computer, you must uninstall
the old version first.
Deciding whether to enable InnoDB support
MySQL is capable of storing database tables in a variety of formats. Most of the time, you
don’t need to worry about this. The default MySQL format, MyISAM, is fast and highly reliable.
Moreover, if you’re on shared hosting, this is frequently your only choice. However, if
you have your own dedicated server, you will almost certainly also have the option of
InnoDB tables, which offer extra features including foreign key constraints (see Chapter 16
for details). Some hosting companies also offer support for InnoDB, so it’s worth checking
Because new versions are coming out all the time, I recommend that you check my
website at http://foundationphp.com/egdwcs3/updates.php before going ahead.
Any major updates to the instructions will be listed there.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
404
before installing MySQL on your local computer. The Windows Essentials version of MySQL
automatically enables support for InnoDB, but you can save 60MB of disk space if you
don’t need to use it.
You can either check with your hosting company directly, or you can do a simple test by
running a SQL query on your remote server. Most companies provide phpMyAdmin to you
to administer your database(s). Launch phpMyAdmin, and click the SQL tab. Delete any
existing query in the Run SQL query field, and type the following:
SHOW VARIABLES LIKE ‘have_inno%’
Click Go. If you see a result like the one shown in Figure 13-2, it means InnoDB tables are
supported. If your remote server is very old, the Variable_name column may read
have_innobase. This is the same as InnoDB.
Figure 13-2. Confirmation that the MySQL server supports InnoDB tables
If the Value column says NO, InnoDB is not supported. The instructions in later chapters
show you how to emulate foreign key constraints by using PHP conditional logic.
Don’t worry if you can’t find out whether your remote server supports InnoDB. You can
easily add or remove InnoDB from your local setup later.
These instructions are based on the 5.0 series of MySQL, which is installed in
C:\Program Files\MySQL\MySQL Server 5.0. I expect MySQL 5.1 to become the recommended
release shortly after publication of this book. On past experience, the
default location changes for each series of Windows Essentials, so 5.1 is likely to be
installed in C:\Program Files\MySQL\MySQL Server 5.1, and Windows treats different
series as completely separate programs. If you upgrade from one series to another, any
existing databases need to be transferred to the new version as if it were a different
server (see the section titled “Backup and data transfer” near the end of this chapter).
Installing the Windows Essentials version of MySQL
SETTING UP MYSQL AND PHPMYADMIN
405
13
1. Go to the MySQL download site, and select the link for MySQL Community Server.
2. In the page that opens, scroll down to find the section marked Windows downloads.
Choose Windows Essentials, and click the download link. (You may be invited to
Pick a mirror instead. This directs you to a mirror site closer to your location and
usually offers a faster download.)
3. Download the MySQL file to your hard disk. It will have a name like mysqlessential-
x.x.x-win32.msi, where x.x.x represents the version number.
4. Exit all other Windows programs; make sure you are logged in as an administrator
(in Windows Vista; turn off User Account Control temporarily—see Chapter 3 for
instructions), and double-click the icon of the file you have just downloaded. This
is a self-extracting Windows Installer package.
5. Windows Installer will begin the installation process and open a welcome dialog
box. If you are upgrading an existing version of the same series of Windows
Essentials to a more recent one, the dialog box will inform you that it has detected
your current installation and will remove it before installing the new one. However,
all your databases will remain intact. Click Next to continue.
6. Dialog boxes will give you the opportunity to change the installation destination
and select the type of setup. Accept the defaults, and click Next.
7. If you’re happy to go ahead with installation, click Install in the next dialog box.
8. Before launching into the actual installation, MySQL invites you to sign up for a free
MySQL.com account. I suggest that you select Skip Sign-Up and click Next. After
you finish setting up everything, visit www.mysql.com/register.php to see if you’re
interested in the benefits offered. The main advantage is that you get automatic
notification of new versions and links to helpful articles about new features of
MySQL.
9. The actual installation now takes place and is normally very quick. When everything’s
finished, you’re presented with a final dialog box.
If this is a new installation or if you are upgrading from one series to another,
click Finish to launch the configuration wizard, which is described in the next
section.
If you are upgrading to a later version of the same series (such as from 5.0.10 to
5.0.37), deselect the checkbox labeled Configure the MySQL Server now before
clicking Finish. MySQL should be ready to use but needs to be restarted manually
(see “Starting and stopping MySQL manually on Windows” later in the chapter).
If you have a software firewall, you might also be prompted to allow
connections to and from MySQL. You must permit connections in order to work
with the database.
There are a lot of dialog boxes to go through, although all you usually need to do is accept
the default setting. These instructions are based on version 1.0.8 of the Configuration
Wizard.
Configuring MySQL Windows Essentials
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
406
1. The Configuration Wizard opens with a welcome screen. Click Next to proceed.
2. The first dialog box asks whether you want a detailed or standard configuration.
Choose the default Detailed Configuration option, and click Next.
3. The three options on the next screen affect the amount of computer resources
devoted to MySQL. Accept the default Developer Machine, and click Next. If you
choose either of the other options, all other programs will slow down to a crawl.
4. The next dialog box asks you to select from the following three types of database:
Multifunctional Database: Allows you to use both InnoDB and MyISAM tables.
Transactional Database Only: InnoDB tables only. MyISAM is disabled.
Non-Transactional Database Only: MyISAM tables only. InnoDB is disabled.
Your choice depends on whether your remote server supports InnoDB tables (see
“Deciding whether to enable InnoDB support” earlier in the chapter). If it does,
choose Multifunctional Database. Otherwise, choose Non-Transactional Database Only.
Do not choose Transactional Database Only. You should use InnoDB tables only
when you need the extra features they provide, so you need support for MyISAM
tables as well.
If you’re not sure which to choose, and disk space is not a problem, choose
Multifunctional Database. However, you should be aware that this option requires an
extra 60MB of disk space to create the InnoDB tablespace.
5. What you see next may vary. If you chose Non-Transactional Database Only in the
preceding step, you will probably be taken directly to step 6. However, you may see
a dialog box inviting you to select a drive for the InnoDB data file. Unless you chose
Multifunctional Database, just click Next and move on to step 6.
If you plan to use InnoDB, you need to tell MySQL where to store the data.
The InnoDB engine uses a single tablespace that acts as a sort of virtual file system.
InnoDB files, once created, cannot be made smaller. The default location for the
tablespace is C:\Program Files\MySQL\MySQL Server 5.0\data. If you want to
locate the tablespace elsewhere, the drop-down menu offers some suggested
alternatives. When you have made your choice, click Next.
6. Leave the next dialog box at the default Decision Support (DSS)/OLAP, and click
Next.
7. The next dialog box sets the networking options and SQL mode. The important settings
are in the top half. Make sure Enable TCP/IP Networking is checked, and leave
Port Number on the default setting of 3306. The lower half of the dialog box lets
you choose whether to run MySQL in strict mode. In an ideal world, you should
accept this default setting, but it may cause problems with some PHP applications
written before strict mode was introduced. Deselect the Strict mode checkbox, and
click Next.
If you choose Multifunctional Database, you need to edit the MySQL configuration file
later, as described in “Changing the default table type on Windows Essentials.”
SETTING UP MYSQL AND PHPMYADMIN
407
13
8. MySQL has impressive support for most of the world’s languages. The next dialog
box invites you to choose a default character set. In spite of what you might think,
this has no bearing on the range of languages supported—all are supported by
default. The character set mainly determines the order in which data is sorted.
Since Dreamweaver CS3 now uses Unicode (UTF-8) as the default encoding for web
pages, choosing the second option, Best Support for Multilingualism, seems the obvious
choice. However, support for Unicode was not introduced to MySQL until
version 4.1. If your hosting company is still running an earlier version of MySQL,
you should stick with the default Standard Character Set. This is also a suitable
choice if you work exclusively in English or use a completely different encoding,
such as Shift_JIS for Japanese. Click Next after you have made your choice.
9. The recommended way of running MySQL is as a Windows service. If you accept
the defaults as shown in the top half of the next dialog box, MySQL will always start
automatically when you boot your computer and run silently in the background. (If
MySQL has already been installed as a Windows service, this section will be grayed
out.) If for any reason you don’t want MySQL to start automatically, uncheck the
Launch the MySQL Server automatically option. You can easily change this option
later (see the section “Starting and stopping MySQL manually on Windows” later in
this chapter).
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
408
The lower half of the dialog box gives you the option to include the bin directory
in your Windows PATH. This option enables you to interact directly with MySQL and
its related utilities at the command line without the need to change directory every
time. You won’t need to do this very often—if at all—but selecting this option
makes life a little more convenient if the occasion ever arises. Click Next.
10. A fresh installation of MySQL has no security settings, so anyone can tamper with
your data. MySQL uses the name root to signify the main database administrator
with unrestricted control over all aspects of the database. Choose a password that
you can remember, and enter it in both boxes.
Unless you access your development server from a different computer over a network,
leave the Enable root access from remote machines checkbox unchecked.
Do not check Create An Anonymous Account. It will make your database insecure.
If you are upgrading an existing version of Windows Essentials and want to keep
your current root password, deselect the Modify Security Settings checkbox. If this is
a first-time installation, you might not have this checkbox.
Click Next when you have finished.
If you get a warning message that a Windows service with the name MySQL already
exists, you will be asked if you want to use this name. You must click No and choose a
different name from the drop-down menu in the Service Name field.
SETTING UP MYSQL AND PHPMYADMIN
409
13
11. At long last, everything is ready. Click Execute. If you have installed a software firewall,
it will probably warn you that MySQL is trying to connect to a DNS server. You
must allow the connection; otherwise, MySQL will never work. If your firewall
doesn’t list MySQL specifically, make sure that it permits local connections on port
3306, the MySQL default.
12. Assuming that all was okay, you should see a screen confirming that the configuration
process is complete. MySQL should now be running—even if you selected the
option not to start automatically (the option applies only to automatic start on
bootup).
13. If you want to change the configuration at a later date—say, to add or remove support
for InnoDB—launch the Configuration Wizard from the Windows Start menu
by choosing Programs ä MySQL ä MySQL Server 5.0 ä MySQL Server Instance
Config Wizard. The dialog box that opens offers the following two options:
Reconfigure Instance: This takes you through all the dialog boxes again. If you
add support for InnoDB, change the default table type, as described in the next
section. If you remove support for InnoDB, stop the MySQL server after the
wizard has finished, and delete any files with names that begin ibdata and
ib_logfile from C:\Program Files\MySQL\MySQL Server 5.0\data. Then
restart MySQL.
Remove Instance: This does not remove MySQL from your system but removes
the Windows service that automatically starts MySQL when you boot your computer.
Unfortunately, it also removes the MySQL configuration file. See “Starting
and stopping MySQL manually on Windows” for a less radical solution.
Changing the default table type on Windows Essentials
The instructions in this section are required only if you selected Multifunctional Database in
step 4 of “Configuring MySQL Windows Essentials.”
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
410
The Windows Configuration Wizard sets InnoDB as the default table storage engine for a
multifunctional database. This is the opposite of the standard MySQL setup, so it makes
sense to switch the default to match the way your remote server works. All it requires is a
simple change to the MySQL configuration file: my.ini.
1. Use Windows Explorer to navigate to the folder in which MySQL was installed. The
default is C:\Program Files\MySQL\MySQL Server 5.0.
2. Locate the file called my.ini, and double-click it. The file will open in Notepad.
3. Approximately 80 lines from the top, you should find a line that reads as follows:
default-storage-engine=INNODB
Change it to the following (the spelling of MyISAM is case insensitive):
default-storage-engine=MyISAM
4. Save the file, and close it. To make the change effective, restart MySQL. MySQL will
now create all new tables in the default MyISAM format. To use the InnoDB format
for a database or an individual table, you can change the table type in phpMyAdmin,
the graphical interface for MySQL that you will install later in the chapter.
Starting and stopping MySQL manually on Windows
Most of the time, MySQL will be configured to start up automatically, and you can forget
about it entirely. There are times, however, when you need to know how to start or stop
MySQL manually—usually for maintenance or to conserve resources.
1. Select Control Panel from the Windows Start menu. Double-click the Administrative
Tools icon, and then double-click the Services icon in the window that opens.
2. In the Services panel, scroll down to find MySQL, and highlight it by clicking once.
You can now use the video recorder–type icons at the top of the panel (or rightclick
to bring up the context menu) to stop or start the server.
3. To change the automatic startup option, highlight MySQL in the Services panel,
right-click to reveal a context menu, and choose Properties.
4. In the dialog box that opens, activate the Startup type drop-down menu, and
choose Automatic, Manual, or Disabled. Click OK. That’s all there is to it.
Using the MySQL monitor on Windows
Although most of your interaction with MySQL will be through phpMyAdmin or your own
PHP scripts, it’s useful to know how to access MySQL through the MySQL monitor (or the
Command Line Client, as it’s called in Windows Essentials). It’s also a good way to test that
your installation went without problems.
To start a session From the Windows Start menu, select Programs ä MySQL ä MySQL
Server 5.0 ä MySQL Command Line Client. This will open the Command Line Client, which
will ask you for your password. Type the root password that you chose in step 10 of the
section “Configuring MySQL Windows Essentials,” and press Enter. As long as the server is
SETTING UP MYSQL AND PHPMYADMIN
411
13
running—and you typed your password correctly—you will see a welcome message similar
to the one shown here (on Windows XP, the title bar says MySQL Command Line Client).
If you get your password wrong, your computer will beep and close the window. If you
find this happening repeatedly, even though you’re sure you typed in your password correctly,
there are two likely explanations. The first is that your Caps Lock key is on—MySQL
passwords are case sensitive. The other is that the MySQL server isn’t running. Refer to the
previous section on how to control MySQL manually before doing too much damage by
banging your forehead on the keyboard.
Ending your session After you finish working with the MySQL monitor, type exit or quit at
the mysql> prompt, followed by Enter. The MySQL Command Line Client window closes
automatically.
Setting up MySQL on Mac OS X
MySQL is available as a Mac PKG file, so everything is taken care of for you, apart from
some minor configuration.
When upgrading an existing installation of MySQL, the Mac installer will not move
your data files. You must first create a backup, as described at the end of this chapter,
and reload them after upgrading. You must also shut down the MySQL server. If you
have never installed MySQL before, you don’t need any special preparations; just follow
these instructions.
Being unable to connect to MySQL because the server isn’t running is probably the
most common beginner’s mistake. The MySQL server runs in the background, waiting
for requests. Opening the Command Line Client does not start MySQL; it opens the
MySQL monitor, which is a channel for you to send instructions to the server. Equally,
closing the Command Line Client does not stop MySQL. The server continues running
in the background until the computer is closed down or until you stop it manually.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
412
1. Go to www.mysql.com/downloads, and select the link for MySQL Community Server.
2. Select the Mac OS X (package format) downloads section, and choose the Standard
version for your processor and version of OS X—there are separate packages for
PowerPC, 64-bit PowerPC, and Intel Macs. The Intel Mac version is labeled x86. As
you can see from the screenshot in the next step, the PKG file name includes not
only the MySQL version number but also the version of OS X and processor for
which it has been compiled (osx10.4-powerpc).
3. Double-click the DMG icon to mount the disk image on your desktop.
4. Double-click the mysql-standard-x.x.x.pkg icon to start the installation process. The
Mac OS X installer opens. Follow the instructions onscreen.
5. Double-click the MySQLStartupItem.pkg icon, and follow the instructions onscreen.
6. Open a Finder window, and drag the MySQL.prefPane icon onto Applications ä
System Preferences. This installs a MySQL control panel. A dialog box asks whether
you want it to be available to yourself or all users. Make your choice, and click
Install.
The MySQL preference pane should open. Click Start MySQL Server, and enter your
Mac administrator password when prompted. It may take a few seconds before the
preference pane reports that the server is running, as shown here:
The Mac files are available in two formats. Make sure you don’t select a TAR package
by mistake. These instructions are for the package format, which uses a Mac installer.
Downloading and installing MySQL
SETTING UP MYSQL AND PHPMYADMIN
413
13
To start or stop the MySQL server in future, open the preference pane by clicking
the MySQL icon in the Other section of System Preferences.
Adding MySQL to your PATH
You normally access MySQL through phpMyAdmin (introduced later in this chapter) or
your own PHP scripts, but sometimes you need to access it directly in Terminal. To avoid
having to type out the full path every time, add it to the PATH in your environmental variables.
By default, Terminal uses what is known as the “bash shell.” Open Terminal (in
Applications ä Utilities), and check the title bar. If it says Terminal—bash, as shown in the
following screenshot, use the following instructions. In the unlikely event that it says
Terminal—tcsh, follow the instructions in the section titled “Amending PATH in the tcsh
shell.”
Use this set of instructions if the Terminal title bar says Terminal—bash:
1. Open BBEdit or TextWrangler.
2. From the File menu, choose Open Hidden, and browse to your home folder. If there
is a file called .profile (with a period as the first character), as shown in the
screenshot, highlight it, and click Open.
Amending PATH in the bash shell
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
414
3. The file exists only if you have already made changes to the way Terminal operates.
If .profile doesn’t exist, click Cancel, and open a blank file.
4. If you have opened an existing version of .profile, add the following code on a
separate line at the end. Otherwise, enter it in the blank page.
export PATH=”$PATH:/usr/local/mysql/bin”
5. Select File ä Save, and save the file as .profile in your own home folder. The
period at the beginning of the file name should provoke the following warning:
6. Select Use “.” and close your text editor.
SETTING UP MYSQL AND PHPMYADMIN
415
13
Use the following, alternative instructions only if the title bar says Terminal—tcsh:
1. Open Terminal, and enter the following command at the shell prompt:
echo ‘setenv PATH /usr/local/mysql/bin:$PATH’ >> ~/.tcshrc
Make sure you copy everything exactly, including the quotes and spacing as shown.
2. Press Return, and close Terminal. The next time you open Terminal, the MySQL program
directory will have been added to your PATH.
Securing MySQL on Mac OS X
Although you have a fully functioning installation of MySQL, by default it has no security.
Even if you’re the only person working on your computer, you need to set up a similar system
of passwords and user accounts as on your hosting company’s server. There’s one
important account that exists by default on all MySQL servers. It’s called root, and it is the
main database administrator with unlimited powers over database files. When you first
install MySQL, access to the root account isn’t password protected, so you need to block
this security gap. The MySQL root user, by the way, is totally unrelated to the Mac OS X
root user, which is disabled by default. Enabling root for MySQL has no effect on the
OS X root user.
1. Open Terminal, and type the following command:
mysql -u root
The command contains three elements:
mysql: The name of the program
-u: Tells the program that you want to log in as a specified user
root: The name of the user
Setting the MySQL root password
If you have just added MySQL to your PATH, you must close and reopen Terminal
before embarking on this section. Otherwise, Terminal won’t be able to find MySQL.
Amending PATH in the tcsh shell
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
416
2. You should see a welcome message like this:
3. The most common problem is getting an error message like this instead:
It means that mysqld, the MySQL server, is not running. Use the MySQL control
panel in System Preferences to start the server.
Another common problem is for Terminal to report command not found. That
means you have either mistyped the command or that you haven’t added the
MySQL program files directory to your PATH, as described in the previous section.
4. Assuming that you have logged in successfully, as described in step 2, type the following
command at the mysql> prompt:
use mysql
This command tells MySQL that you want to use the database called mysql, which
contains all the details of authorized users and the privileges they have to work on
database files. You should see the message Database changed, which means MySQL
is ready for you to work on the files controlling administrative privileges.
5. Now enter the command to set a password for the root user. Substitute
myPassword with the actual password you want to use. Also make sure you use
quotes where indicated and finish the command with a semicolon.
UPDATE user SET password = PASSWORD(‘myPassword‘) WHERE user = ‘root’;
6. Next, remove anonymous access to MySQL:
DELETE FROM user WHERE user = ”;
The quotes before the semicolon are two single quotes with no space in between.
SETTING UP MYSQL AND PHPMYADMIN
417
13
7. Tell MySQL to update the privileges table:
FLUSH PRIVILEGES;
The sequence of commands should produce a series of results like this:
8. To exit the MySQL monitor, type exit, followed by Return. This simply ends your session
with the MySQL monitor. It does not shut down the MySQL server.
9. Now try to log back in by using the same command as in step 2. MySQL won’t let
you in. Anonymous access and password-free access have been removed. To get in
this time, you need to tell MySQL that you want to use a password:
mysql -u root -p
10. When you press Return, you will be prompted for your password. Nothing will
appear onscreen as you type, but as long as you enter the correct password, MySQL
will let you back in. Congratulations, you now have a secure installation of MySQL.
Using the MySQL monitor on Windows and Mac
From this point on, 99.9 percent of everything you do is identical on both Windows and
Mac OS X. If you are used to working exclusively with a GUI like Windows or Mac OS, it can
be unsettling to work at the command line with MySQL. You won’t need to do it very
often, if at all. However, it’s not difficult, and here are a few pointers to make you feel
more at home:
When you work inside the MySQL monitor, most commands need to end with a
semicolon (;). The only exceptions are use databaseName and exit. The MySQL
monitor is quite happy if you use a semicolon after these two commands, so the
simple rule is this: if in doubt, put a semicolon on the end of each command.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
418
If you forget to put a semicolon at the end of a command that needs one, the
MySQL monitor will assume that you want to break your command over more than
one line, and that you haven’t finished typing. It will patiently wait for you to do so,
like this:
This enables you to spread long queries over a number of lines. Not only is this easier
to read onscreen, it’s also useful if you make an error. The MySQL monitor
remembers previous commands line by line, and you can retrieve them by pressing
the up and down arrow keys on your keyboard. Once a previous command has
been redisplayed, you can use your left and right arrow keys to move along the line
and edit it in the normal way. Once you have completed the command, just type a
semicolon and press Enter/Return. The MySQL monitor will then process it.
If you spot a mistake before pressing Enter/Return, use your left and right arrow
keys to edit the current line. If the mistake is on a previous line, there is no way to
go back. Abandon the command by typing \c. The MySQL monitor will ignore
everything you have entered and present you with the mysql> prompt.
Using MySQL with phpMyAdmin
Although you can do everything using MySQL monitor, it’s a lot easier to use a graphic
interface. There are several to choose from, both commercial and free. Among the free
offerings are two from MySQL itself: MySQL Administrator and MySQL Query Browser
(www.mysql.com/products/tools). Two other popular graphical front ends for MySQL are
the commercial product Navicat (www.navicat.com) and SQLyog (www.webyog.com), which
is available in both commercial and free versions.
However, the most popular graphical interface for MySQL is phpMyAdmin (www.phpmyadmin.
net). It’s a PHP-based administrative system for MySQL that has been around since 1998,
and it constantly evolves to keep pace with MySQL developments. It works on Windows,
Mac OS X, and Linux and currently supports all versions of MySQL from 3.23.32 to 5.0.
What’s more, many hosting companies provide it as the standard interface to MySQL.
Because phpMyAdmin has a very intuitive interface, I suggest that you try it first. If you
work with databases on a regular basis, you may want to explore the other graphical interfaces
later. However, since phpMyAdmin is free, you have nothing to lose—and you may
find it does everything you want.
SETTING UP MYSQL AND PHPMYADMIN
419
13
Setting up phpMyAdmin on Windows and Mac
These instructions are based on phpMyAdmin 2.10.1. Like a lot of open source applications,
phpMyAdmin is constantly evolving. Any changes of a substantial nature will be
listed on my website at http://foundationphp.com/egdwcs3/updates.php.
Since phpMyAdmin is PHP-based, all that’s needed to install it is to download the files,
unzip them to a website in your local testing environment, and create a simple configuration
file.
1. Go to www.phpmyadmin.net, and download the latest stable version. The files can
be downloaded in three types of compressed file: BZIP2, GZIP, and ZIP. Choose
whichever format you have the decompression software for.
2. Unzip the downloaded file. It will extract the contents to a folder called
phpMyAdmin-x.x.x, where x represents the version number.
3. Highlight the folder icon, and cut it to your clipboard. On Windows, paste it inside
the folder designated as your web server root (C:\htdocs, if you followed my
example). If you’re on a Mac and want phpMyAdmin to be available to all users,
put the folder in Macintosh HD:Library:WebServer:Documents rather than in your
own Sites folder.
4. Rename the folder you have just moved to this: phpMyAdmin.
5. Like Apache and PHP, phpMyAdmin uses a text file to store all the configuration
details. Since version 2.7.0, you no longer edit the phpMyAdmin configuration file
but store your personal details in a new file, which should be named
config.inc.php. There are two ways of doing this: using a built-in script called
setup.php or manually. I prefer the manual method, but instructions for both
methods follow.
Use these instructions if you want to use the built-in configuration script.
1. Create a new subfolder called config within the phpMyAdmin folder. Windows users
skip to step 3. Mac users continue with step 2.
2. On Mac OS X, use Finder to locate the config folder that you have just created.
Ctrl-click and select Get Info. In Ownership & Permissions, expand Details, and click
the lock icon so that you can make changes to the settings. Change the setting for
Others to Read & Write. Close the config Info panel.
3. Open a browser, and type the following into the address bar:
http://localhost/phpmyadmin/scripts/setup.php
If you created the phpMyAdmin folder inside your Sites folder on a Mac, use the
following address, substituting username with your Mac username:
http://localhost/~username/phpmyadmin/scripts/setup.php
Configuring phpMyAdmin with setup.php
Downloading and installing phpMyAdmin
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
420
4. You should see the page shown in Figure 13-3.
Figure 13-3. A built-in script automates the configuration of phpMyAdmin.
Ignore any warning about the connection not being secure. This is intended for
server administrators installing phpMyAdmin on a live Internet server. If, on the
other hand, you see the following warning, it means that you have not set up
the config folder correctly and should go back to step 1.
5. Click the Add button in the Servers section. This loads a form with most of the necessary
information already filled in. Check the following settings:
Server hostname: localhost
Server port: Leave blank unless your web server is running on a nonstandard
port, such as 8080
Server socket: Leave blank
Connection type: tcp
PHP extension to use: mysqli
SETTING UP MYSQL AND PHPMYADMIN
421
13
6. The default setting for Authentication type is config. If you don’t need to password
protect access to phpMyAdmin, check that User for config auth is set to root, and
enter your MySQL root password in the next field, Password for config auth.
If you want to restrict access to phpMyAdmin by prompting users for a password,
change Authentication type to http, and delete root from the User for config auth field.
7. Scroll down to the Actions field, and click Add. As shown here, there are two Add
buttons close to each other; click the one circled in the screenshot:
8. The next screen will probably warn you that you didn’t set up a phpMyAdmin database,
so you won’t be able to use all the phpMyAdmin features. This is not important.
You can set up one later if you decide to use the advanced features of
phpMyAdmin.
9. Scroll down to the Configuration section near the bottom of the page, and click
Save.
10. Open the config folder in Explorer or Finder. You should see a new file called
config.inc.php. Move it to the main phpMyAdmin folder. The official instructions
tell you to delete the config folder, but this isn’t necessary in a local testing environment.
Although setup.php automates the creation of config.inc.php, it duplicates some
default settings. If you strip out the unnecessary commands, you may find it quicker to
create the file manually.
1. If you don’t need to password protect access to phpMyAdmin, type the following
code into a blank document:
<?php
$i = 1;
$cfg['Servers'][$i]['extension'] = ‘mysqli’;
$cfg['Servers'][$i]['password'] = ‘mysqlRootPassword‘;
?>
Use your own MySQL root password in place of mysqlRootPassword.
Configuring phpMyAdmin manually
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
422
If you need password protection for phpMyAdmin, use the following code instead:
<?php
$i = 1;
$cfg['Servers'][$i]['extension'] = ‘mysqli’;
$cfg['Servers'][$i]['auth_type'] = ‘http’;
?>
2. Save the file as config.inc.php in the main phpMyAdmin folder. Erm . . . that’s it.
Launching phpMyAdmin
To use phpMyAdmin, launch a browser, and enter http://localhost/phpMyAdmin/index.php in
the address bar (on a Mac, use http://localhost/~username/phpMyAdmin/index.php if
you put phpMyAdmin in your Sites folder). If you stored your root password in
config.inc.php, phpMyAdmin should load right away, as shown in Figure 13-4. If you
chose to password protect phpMyAdmin, enter root as the username and whatever you
specified as the MySQL root password when prompted.
Figure 13-4. phpMyAdmin is a very user-friendly and stable graphical interface to MySQL.
If you’re used to glossy software design, your initial impression of phpMyAdmin may not
be all that favorable, particularly if you don’t have a large monitor. The interface is sorely
in need of a facelift, but don’t let that fool you; phpMyAdmin is both powerful and easy
to use.
If you get a message saying that the server is not responding or that the socket is not
correctly configured, make sure that the MySQL server is running.
SETTING UP MYSQL AND PHPMYADMIN
423
13
Logging out of phpMyAdmin
If you opted to password protect phpMyAdmin, the Log out link is at
the bottom left of the front page, just beneath Import (as shown in the
screenshot alongside). When you click the link, you are immediately
prompted for your username and password. Click Cancel, and you will
be presented with a screen informing you that you supplied the wrong
username/password—in other words, you have been logged out. Odd, but that’s the way
it works.
Backup and data transfer
MySQL doesn’t store your database in a single file that you can simply upload to your website.
Even if you find the right files (on Windows, they’re located in C:\Program Files\
MySQL\MySQL Server 5.0\data), you’re likely to damage them unless the MySQL server is
turned off. Anyway, most hosting companies won’t permit you to upload the raw files,
because it would also involve shutting down their server, causing a great deal of inconvenience
for everyone.
Nevertheless, moving a database from one server to another is very easy. All it involves is
creating a backup dump of the data and loading it into the other database with
phpMyAdmin. The dump is a text file that contains all the necessary Structured Query
Language (SQL) commands to populate an individual table or even an entire database
elsewhere. phpMyAdmin can create backups of your entire MySQL server, individual databases,
selected tables, or individual tables. To make things simple, the following instructions
show you how to back up only a single database.
These instructions show you how to back up an entire database. You can also back up individual
tables in the same way by selecting the tables in step 4.
Creating a backup
If you have just installed MySQL for the first time, bookmark this section for
when you need to upload files to your remote server or upgrade MySQL. If
you’re on a Mac, you must always back up your data before upgrading MySQL.
Once the new version has been installed, you can transfer your data to the new
server. Windows users need to follow this procedure only when upgrading from
one series to another, such as 5.0 to 5.1.
You cannot log back in to phpMyAdmin from the wrong username/password screen.
You must enter the original URL into the browser address bar first.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
424
1. Launch phpMyAdmin, and select the database that you want to back up from the
drop-down menu in the navigation frame.
2. When the database details have loaded into the main frame, select Export from the
tabs along the top of the screen, as shown here.
3. The rather fearsome-looking screen shown in Figure 13-5 opens. In spite of all the
options, you need to concern yourself with only a few.
Figure 13-5. phpMyAdmin offers a wide range of choices when exporting data from MySQL.
SETTING UP MYSQL AND PHPMYADMIN
425
13
4. The Export section on the left of the screen lists all the tables in your database.
Click Select All, and leave the radio buttons on the default SQL.
5. If the database has never been transferred to the other server before, the only
option that you need to set on the right side of the screen is the drop-down menu
labeled SQL compatibility mode. The setting depends on the version of MySQL on
the other server (only the first two numbers, such as 3.23, 4.0, 4.1, or 5.0, are
important):
If the other server is running the same version of MySQL, choose NONE.
If you are transferring between MySQL 4.1 and MySQL 5.0 (in either direction),
choose NONE.
If the other server is running MySQL 3.23, choose MYSQL323.
If the other server is running MySQL 4.0, choose MYSQL40.
6. If the database has already been transferred on a previous occasion, select Add
DROP TABLE in the Structure section. The existing contents of each table are
dropped and are replaced with the data in the backup file.
7. Put a check mark in the box alongside Save as file at the bottom of the screen. The
default setting in File name template is __DB__, which automatically gives the
backup file the same name as your database. So, in this case, it will become
egdwcs3.sql. If you add anything after the final double underscore, phpMyAdmin
will add this to the name. For instance, you might want to indicate the date of the
backup, so you could add 20070704 for a backup made on July 4, 2007. The file
would then be named egdwcs320070704.sql.
1. If a database of the same name doesn’t already exist on the target server, create
the database, but don’t create any tables.
2. Launch the version of phpMyAdmin that is used by the target server, and select the
database that you plan to transfer the data to. Click the Import tab in the main
frame (on versions of phpMyAdmin earlier than 2.7.0, click the SQL tab instead).
3. Use the Browse button to locate the SQL file on your local computer, and click Go.
That’s it!
Because phpMyAdmin uses PHP to upload the file, the maximum size of any backup is
normally limited to 2MB, which is the default maximum size for any file upload. If you
are transferring a very large database, use the phpMyAdmin export and import tabs to
backup and transfer individual tables. Alternatively, contact your hosting company for
advice on transferring your database.
Loading data from a backup file
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
426
Looking ahead . . .
Now that you have MySQL and phpMyAdmin installed, we can finally begin to explore
Dreamweaver’s server behaviors. In the next chapter, I’ll show you how to create a database
table in MySQL and insert into it user input from the feedback form in Chapter 9.
You’ll also learn how to combine it with the mail processing script from Chapters 11 and
12 and how to retrieve and display information stored in a database.
SETTING UP MYSQL AND PHPMYADMIN
427
13
14 STORING RECORDS
IN A DATABASE
Unlike Access or FileMaker Pro, MySQL doesn’t come with predesigned forms. Instead, you
build and design everything yourself. While this presents a challenge to the first-time user,
MySQL isn’t difficult to use, and Dreamweaver takes a lot of the hard work out of integrating
MySQL with your website.
Let’s say that you decide to start accepting orders for goods and services through your
website. As well as getting the orders by email, you need to store that information in a
database. Rather than input all the data again manually, it makes much more sense to
combine the two operations. So by the end of this chapter, you will be able to input data
directly from the feedback form from Chapters 9, 11, and 12, and then send the details to
your mail inbox. In the process, you’ll learn the basics of database construction, and how
to handle different types of data. Specifically, you’ll learn how to
Create MySQL user accounts
Define a database table
Create a database connection in Dreamweaver
Insert form input into a database
Use a recordset to retrieve data and display database results
Apply a repeat region to display multiple records
Merge the mail processing script with database input
Setting up a database in MySQL
If you set up MySQL and phpMyAdmin in a local testing environment, as described in the
last chapter, launch phpMyAdmin, and open the Database drop-down menu in the left
frame (see Figure 14-1).
MySQL isn’t a single database, but a relational database management system (RDBMS). The
first database listed, information_schema, is a virtual database that contains details of
other databases within the RDBMS. The second one, mysql, contains all the user account
and security information and should never be edited directly unless you’re really sure what
you’re doing. The final database, test, contains nothing. The numbers in parentheses indicate
how many tables each database contains.
Figure 14-1.
A new installation of MySQL contains
three default databases.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
430
If you’re using a remote server, and your hosting company provides phpMyAdmin, the list
of databases will be limited to those on your account, or you may be limited to only one
database.
Creating a local database for testing
Assuming that you have set up a local testing environment, you need to create a test database
to work with the remaining chapters. I’m going to call the database egdwcs3. To make
life easier for yourself when it comes to testing pages on the Internet, use the name of a
database on your remote server.
Type the name of the database in the field labeled Create new database in the
phpMyAdmin welcome screen, and click Create, as shown in Figure 14-2. Leave Collation in
its default position. However, if you’re working in a language other than English, Swedish,
or Finnish, and your remote server runs MySQL 4.1 or later, skip ahead to the section
“Understanding collation” before going any further.
Figure 14-2. To create a new database, just type its name into
the phpMyAdmin welcome screen, and click Create.
The database should be created instantly, and phpMyAdmin will invite you to create a new
table. Before doing that, you need to create at least one user account for the database.
Leave phpMyAdmin open.
Because phpMyAdmin is a browser-based application, the precise layout of what you
see onscreen depends on the size of your monitor and browser viewport.
STORING RECORDS IN A DATABASE
431
14
Creating user accounts for MySQL
At the moment, your installation of MySQL has only one registered user—the superuser
account called “root,” which has complete control over everything. A lot of beginners
think that once they have set up a password for the root user, they can start building databases.
This is a big mistake. The root user should never be used for anything other than
administration.
MySQL stores all databases in a common directory. So, on shared hosting, your database—
with all its precious information—rubs shoulders with everyone else’s. Clearly, you need a
way to prevent unauthorized people from seeing or altering your data. The answer is to
create user accounts that have the fewest number of privileges necessary to perform
essential tasks, preferably on a single database.
Granting the necessary user privileges
You normally want visitors to your site to be able to see the information it contains but not
to change it. However, as administrator, you need to be able to insert new records, and
update or delete existing ones. This involves four types of privileges, all named after the
equivalent SQL commands:
SELECT: Retrieves records from database tables
INSERT: Inserts records into a database
UPDATE: Changes existing records
DELETE: Deletes records but not tables or databases (the command for that is DROP)
In an ideal setup, you create two separate user accounts: one for administrators, who
require all four privileges, and another one for visitors, limited to SELECT. If your hosting
company lets you set up user accounts with different privileges, I suggest that you create
two accounts like this. However, if you have no choice, set up one account and use the
same username and password as on your remote server.
These instructions show you how to set up user accounts in a local testing environment.
You can skip this section if you are using your remote server as your testing server.
1. Click the home icon at the top of the left frame in phpMyAdmin to return to the
welcome screen, and then click Privileges, as shown in the following screenshot:
Setting up MySQL user accounts
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
432
2. The User overview screen opens. Click Add a new User halfway down the page.
3. In the page that opens, enter the name of the user account that you want to create
in the User name field. Select Local from the Host drop-down menu. This automatically
enters localhost in the field alongside. This option restricts the user to connecting
to MySQL only from the same computer. Enter a password in the Password
field, and confirm it in the Re-type field. The Login Information table should look
like this:
The Privileges tab at the top of the previous screen displays a list of current user
accounts. To create a new user account, you must use the link in the welcome screen.
STORING RECORDS IN A DATABASE
433
14
4. Beneath the Login Information table is one labeled Global privileges. Granting such
extensive privileges is insecure, so scroll past the Global privileges table, and click
the Go button right at the bottom of the page.
5. The next page confirms that the user has been created and displays many options,
beginning with the Global privileges again. Scroll down to the section labeled
Database-specific privileges. Activate the drop-down menu, as shown here, to display
a list of all databases. Select the name for the database you plan to use for
testing.
6. The next screen allows you to set the user’s privileges for just this database. You
want the admin user to have all four privileges listed earlier, so click the checkboxes
next to SELECT, INSERT, UPDATE, and DELETE (if you hover your mouse
pointer over each option, phpMyAdmin displays a tooltip describing what it’s for).
After selecting the four privileges, as shown here, click the top Go button.
Dreamweaver needs these details later to make a connection to the database.
If you want to use the download files exactly as they are, use humpty as
the password for egadmin.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
434
7. phpMyAdmin presents you with the following confirmation that the privileges have
been updated for the user account:
8. The page displays the Database-specific privileges table again, in case you need to
change anything. Assuming you got it right, click the Privileges tab at the top right
of the page. You should now see the new user listed in the User overview.
If you ever need to make any changes to a user’s privileges, click the Edit Privileges
icon to the right of the listing, as shown. You can also delete users by selecting the
checkbox to the left of the User column, then clicking Go.
9. If your hosting company permits you to create multiple user accounts, click Add a
new User, and repeat steps 3–8 to create a second user account. If you want to use
the same username and password as in the download files, call the account eguser,
and give it the password dumpty. This user will have restricted privileges, so in
step 6, check only the SELECT option.
Now that you have a database and at least one user account, you can build the table to
store the feedback information. However, first, you need to understand the principles
behind table construction.
phpMyAdmin frequently offers you a variety of options on the same page, each of
which normally has its own Go button. Always click the one at the foot of or alongside
the section that relates to the options you want to set.
STORING RECORDS IN A DATABASE
435
14
How a database stores information
All data in MySQL is stored in tables, with information organized into rows and columns
very much like a spreadsheet. Figure 14-3 shows a simple database table as seen in
phpMyAdmin.
Figure 14-3. Information in a database table is stored in rows and columns, just like in a
spreadsheet.
Each column has a name (image_id, filename, and caption) indicating what it stores.
The rows aren’t labeled, but the first column (image_id) contains a unique identifier
known as a primary key, which can be used to identify the data associated with a particular
row. Each row contains an individual record of related data. The significance of primary
keys is explained in the next section.
The intersection of a row and a column, where the data is stored, is called a field. So, for
instance, the caption field for the third record in Figure 14-3 contains the value “The
Golden Pavilion in Kyoto” and the primary key for that record is 3.
How primary keys work
Although Figure 14-3 shows image_id as a consecutive sequence from 1 to 8, they’re not
row numbers. Figure 14-4 shows the same table with the captions sorted in alphabetical
order. The field highlighted in Figure 14-3 has moved to the seventh row, but it still has the
same image_id and filename.
The terms “field” and “column” are often used interchangeably. A field holds
one piece of information for a single record, whereas a column contains the
same field for all records.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
436
Figure 14-4. Even when the table is sorted in a different order, each record can be identified
by its primary key.
Although the primary key is rarely displayed, it identifies the record and all the data stored
in it. If you know the primary key, you can update a record, delete it, or use it to display
data. Don’t worry about how you find the primary key; it’s easy using Structured Query
Language (SQL), the standard means of communicating with all major databases. The
important thing is to assign a primary key to every record.
A primary key doesn’t need to be a number, but it must be unique.
Social Security, staff ID, or product numbers make good primary keys. They may
consist of a mixture of numbers, letters, and other characters but are always
different.
MySQL will generate a primary key for you automatically.
Once a primary key has been assigned, it should never—repeat, never—be changed.
Because a primary key must be unique, MySQL doesn’t normally reuse the number when a
record is deleted, leaving holes in the sequence. Don’t even think about renumbering. By
changing the numbers to close the gaps, you put the integrity of your database at serious
risk. Some people want to remove gaps to keep track of the number of records, but you
can easily get the same information with SQL.
Although Figures 14-3 and 14-4 show the similarity between a database table and a
spreadsheet, there’s an important difference. With a spreadsheet, you can enter data without
the need to specify beforehand what type of data it is or how it’s to be structured. You
can’t do that with a database.
Designing a database table
Before entering data, you need to define the table structure. This involves the following
decisions:
The name of the table
How many columns it will have
The name of each column
What type of data will be stored in each column
Whether the column must always have data in each field
Which column contains the table’s primary key
STORING RECORDS IN A DATABASE
437
14
Don’t be tempted to choose the first thing that comes into your head. Experienced database
developers often say at least half the total development time is spent deciding the
structure of a database. Although the structure of a database can be altered, some decisions
tie your hands so badly you need to redesign everything from scratch. That’s not
much fun when the database contains several thousand records. The time spent on these
early decisions can save a lot of agony and frustration later on.
Because each database is different, it’s impossible to prescribe one simple formula, but the
next few pages should help guide you in the right direction. Don’t attempt to commit
everything to memory at the first read-through. Come back later when you need to
refresh your memory or check a particular point.
Choosing the table name
The basic MySQL naming rules for databases, tables, and columns are as follows:
Names can be up to 64 characters long.
Legal characters are numbers, letters, the underscore, and $.
Names can begin with a number but cannot consist exclusively of numbers.
Some hosting companies seem blissfully ignorant of these rules and assign clients databases
that contain one or more hyphens (an illegal character) in their name. If a name contains
spaces or illegal characters, you must surround it by backticks (`) in SQL queries.
Note that this is not a single quote (‘) but a separate character. Dreamweaver and
phpMyAdmin normally do this for you automatically.
Choose names that are meaningful. Tables hold groups of records, so it’s a good strategy
to use plural nouns. For example, use products rather than product. Don’t try to save on
typing by using abbreviations, particularly when naming columns. Explicit names make it
much easier to build SQL queries to extract the information you want from a database.
SQL is designed to be as human-readable as possible, so don’t make life difficult for yourself
by using cryptic naming conventions.
When choosing column names, there is a danger that you might accidentally choose
one of MySQL’s many reserved words (http://dev.mysql.com/doc/refman/5.0/en/
reserved-words.html), such as date or time. A good technique is to use compound
words, such as arrival_date, arrival_time, and so on. These names also tell you much
more about the data held in the column.
Case sensitivity of names Windows and Mac OS X treat MySQL names as case insensitive.
However, Linux and Unix servers respect case sensitivity. To avoid problems when transferring
databases and PHP code from your local computer to a remote server, I recommend
that you use only lowercase in database, table, and column names. Using camel case (e.g.,
arrivalDate) is likely to cause your code to fail when transferring a database from your
local computer to a Linux server.
Deciding how many columns to create
How should you store each person’s name? One column? Or one each for the family and
personal names? A commercial contacts management program like Microsoft Outlook
goes even further, splitting the name into five parts. In addition to first and last name, it
stores title (Mr., Mrs., etc.), a middle name, and suffix (I, II, III, Jr., and Sr.). Addresses are
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
438
best broken down into street, town, county, state, ZIP code, etc. Think of all the possible
alternatives, and add a column for each one. Things like company name, apartment number,
and extra lines in an address can be made optional, but you need to make provision
for them. This is an important principle of a relational database: break down complex
information into its component parts, and store each part separately.
This makes searching, sorting, and filtering much easier. Breaking information into small
chunks may seem a nuisance, but you can always join them together again. It’s much easier
than trying to separate complex information stored in a single field.
Choosing the right column type in MySQL
MySQL 5.0 has 28 different column types. Rather than confuse you by listing all of them,
I’ll explain just the most commonly used. You can find full details of all column types in the
MySQL documentation at http://dev.mysql.com/doc/refman/5.0/en/data-types.html.
Storing text The difference between the main text column types boils down to the maximum
number of characters that can be stored in an individual field, and whether you can
set a default value.
CHAR: A fixed-length width text column up to a maximum of 255 characters. You
must specify the size when building the table, although this can be altered later.
Shorter strings are OK. MySQL adds trailing space to store them, and automatically
removes it on retrieval. If you attempt to store a string that exceeds the specified
size, excess characters are truncated. You can define a default value.
VARCHAR: A variable-length character string. The maximum number must be specified
when designing the table, but this can be altered later. Prior to MySQL 5.0, the
limit is 255; this has been increased to 65,535 in MySQL 5.0. Another change in
MySQL 5.0 affects the way trailing space is treated. Prior to MySQL 5.0, trailing
space is stripped at the time of storing a record. Since MySQL 5.0, trailing space is
retained for both storage and retrieval. You can define a default value.
TEXT: Stores a maximum of 65,535 characters (slightly shorter than this chapter).
You cannot define a default value.
TEXT is convenient, because you don’t need to specify a maximum size (in fact, you can’t).
Although the maximum length of VARCHAR is the same as TEXT in MySQL 5.0, other factors
such as the number of columns in a table reduce this.
Prior to MySQL 5.0, you cannot use CHAR in a table that also contains VARCHAR, TEXT, or
BLOB. When creating the table, MySQL silently converts any CHAR columns to VARCHAR.
Storing numbers The most frequently used numeric column types are as follows:
TINYINT: Any whole number (integer) between –128 and 127. If the column is
declared as UNSIGNED, the range is from 0 to 255. This is particularly suitable for
storing people’s ages, number of children, and so on.
INT: Any integer between –2,147,483,648 and 2,147,483,647. If the column is
declared as UNSIGNED, the range is from 0 to 4,294,967,295.
Keep it simple: use VARCHAR for short text items and TEXT for longer ones.
STORING RECORDS IN A DATABASE
439
14
FLOAT: A floating-point number.
DECIMAL: A floating-point number stored as a string. This column type is best
avoided.
DECIMAL is intended for currencies, but you can’t perform calculations with strings inside a
database, so it’s more practical to use INT. For dollars or euros, store currencies as cents;
for pounds, use pence. Then use PHP to divide the result by 100, and format the currency
as desired.
Storing dates and times MySQL stores dates in the format YYYY-MM-DD. This may come as a
shock, but it’s the ISO (International Organization for Standardization) standard, and
avoids the ambiguity inherent in national conventions. The most important column types
for dates and times are as follows:
DATE: A date stored as YYYY-MM-DD. The supported range is 1000-01-01 to 9999-12-31.
DATETIME: A combined date and time displayed in the format YYYY-MM-DD
HH:MM:SS.
TIMESTAMP: A timestamp (normally generated automatically by the computer).
Legal values range from the beginning of 1970 to partway through 2037.
Storing predefined lists MySQL lets you store two types of predefined list that could be
regarded as the database equivalents of radio button and checkbox states:
ENUM: This column type stores a single choice from a predefined list, such as “yes,
no, don’t know” or “male, female.” The maximum number of items that can be
stored in the predefined list is a mind-boggling 65,535—some radio-button group!
SET: This stores zero or more choices from a predefined list, up to a maximum of
64. Although this violates the principle of storing only one piece of information in
a field, it’s useful when the items form a coherent unit (e.g., optional extras on a car).
The values stored in the ENUM and SET columns are stored as a comma-separated string.
Individual values can include spaces and other characters but not commas.
MySQL timestamps are based on a human-readable date and, since MySQL 4.1,
use the same format as DATETIME. As a result, they are incompatible with Unix
and PHP timestamps, which are based on the number of seconds elapsed since
January 1, 1970. Don’t mix them.
Don’t use commas or spaces as the thousands-separator. Apart from numerals,
the only characters permitted in numbers are the negative operator (-) and the
decimal point (.). Although some countries use a comma as the decimal point,
MySQL accepts only a period.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
440
Storing binary data Binary data, such as images, bloat your tables and cannot be displayed
directly from a database. However, the following column types are designed for binary
data:
TINYBLOB: Up to 255 bytes
BLOB: Up to 64KB
MEDIUMBLOB: Up to 16MB
LONGBLOB: Up to 4GB
With such whimsical names, it’s a bit of a letdown to discover that BLOB stands for binary
large object.
Deciding whether a field can be empty
When defining a database table, specifying a column as NOT NULL is the equivalent of designating
a required field. Since the phpMyAdmin default is NOT NULL, you need to manually
override this to make a field optional. You can change a column definition from NOT
NULL to NULL and vice versa at any time.
Storing input from the feedback form
It’s time to put the knowledge from the preceding section to practical use by building a
table to store the information from the feedback form from Chapters 9, 11, and 12. The
form is available in the download files, so you can dive straight in. Don’t be put off by the
fact that it’s a feedback form; working with it shows you all the basic techniques you need
for inserting records into a database.
The name for the database table needs to give a clear indication of what it contains, so I’ll
call the table feedback. The next step is to analyze the form and decide how the feedback
table should be structured.
Analyzing the form
There are seven fields in the form (see Figure 14-5), so you need at least seven columns.
You need another column for the primary key. Anything else?
If you set a default value for a NOT NULL column, MySQL automatically uses that
value if nothing is entered in the field. Unfortunately, Dreamweaver doesn’t
support this useful feature.
STORING RECORDS IN A DATABASE
441
14
Figure 14-5. The names of the form fields often make good names for database columns.
In a real-world situation the family and given names should be stored separately, but I’m
going to skip that here, because both are text fields, so they are handled in the same way.
The one extra field that I’m going to add will store the date and time that the form was
submitted. So that makes a total of nine columns. As for column names, the name attributes
of the form fields make a good choice, and as you’ll see shortly, using them makes it
a lot easier to use the Dreamweaver server behaviors. For the two extra fields, let’s use
message_id for the primary key, and submitted for the date.
The next step is to decide the column types (refer to “Choosing the right column type in
MySQL”). By convention, the primary key column is normally the first one in a table.
MySQL has a feature called auto_increment, which automatically assigns the next available
number. This is ideal for a primary key, so we’ll make the column an INT type. We don’t
want negative numbers, so we’ll also make it UNSIGNED. This gives a range of nearly 4.3 billion,
which is probably excessive for most tables. However, the danger of choosing a
smaller number type is that you run out of numbers, particularly if records are added and
deleted frequently. It’s much better to err on the side of caution with the primary key
column.
DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP
442
The first two form fields, name and email, contain short, variable amounts of text, so
VARCHAR is appropriate. With VARCHAR you need to specify the maximum number of characters.
For name, 50 is sufficient, but you don’t want to risk truncating an email address, so
100 is a safer choice for email.
The comments field is also text. If your remote server is running MySQL 5.0 or higher, you
can use VARCHAR and set a limit of 500 or 1000, but TEXT is appropriate for all versions, so
we’ll use that. To limit the length of comments, use the Spry Textarea Validation Widget as
described in Chapter 9.
The checkbox group interests presents a dilemma. Unless you make this a required field,
users can pick anything from none to five. Storing more than one piece of information in
a field goes against the principles of good database design, but creating five separate
columns isn’t very satisfactory either. What happens if you want to add another category
to the list, or remove one? Since interests are grouped together, and represent a series
of closely related options, this is where SET comes in handy.
The drop-down menu visited allows only one choice. Although this sounds like a good
candidate for ENUM, you may want to change the range of options later, so this is better as
VARCHAR. That way, you can change the value attributes of the <option> tags without
needing to change the table definition.
The views multiple-choice list is similar to the checkbox group, so that will be another SET.
The subscribe radio group is a straight yes/no choice, so it should be an ENUM column
type.
Finally, submitted needs to store the date and time, so we’ll make it a TIMESTAMP column.
Whenever a record is inserted or updated, the current date and time are automatically
inserted into the first TIMESTAMP column in a table. With a DATETIME column, you have to
insert the value explicitly.
Table 14-1 summarizes this analysis. You’ll use this summary to define the feedback table
in phpMyAdmin, so the table headings use the same terminology as phpMyAdmin. The
setting for Length/Values for the two SET columns is described in the instructions in
“Defining the feedback table.” Note that interests and views are specified as the only
fields not required by setting them to null. I’ve done this because the Dreamweaver Insert
Record server behavior can’t handle SET columns automatically. So we’ll come back to
these two later.
STORING RECORDS IN A DATABASE
443
14
Table 14-1. Column settings for the feedback table
Field Type Length/Values Attributes Null Extra Primary key
message_id INT UNSIGNED not null auto_increment Selected
name VARCHAR 50 not null
email VARCHAR 100 not null
comments TEXT not null
interests SET See text null
Continued
Defining a table in phpMyAdmin
Defining a database table normally requires writing a lengthy SQL query, but phpMyAdmin
makes the process a lot simpler through a form-based interface. The form is quite wide
and, unless you have a large monitor, you might need to scroll horizontally to see all the
fields. You might find the text in some screenshots hard to read, but all important information
is repeated in the instructions and Table 14-1.
1. Launch phpMyAdmin, and select the egdwcs3 database. In the main frame, type
feedback in the Name field, enter 9 as the Number of fields, and click Go.
2. This opens the form shown in Figure 14-6 with nine blank rows where you enter
the column definitions. Copy the values from Table 14-1. Designate message_id as
the table’s primary key by selecting the radio button as indicated in Figure 14-6.
Figure 14-6. Defining the columns for the feedback table in phpMyAdmin
For the SET and ENUM columns, you need to enter in Length/Values the value attributes
from the related form fields as a series of comma-separated strings. Each
string needs to be enclosed in single quotes. So, for interests, it looks like this:
‘Classical concerts’, ‘Rock/pop’, ‘Drama’, ‘Guided walks’, ‘Art’
-
Recent
- Windows Shortcut Keys
- DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP PART-03
- DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP 02
- DREAMWEAVER CS3 WITH CSS, AJAX, AND PHP 01
- Valentine Gifts & Valentine Jewelry
- Java Help, Java Tutorials, Java Programming, Java Tricks
- Java Help, Java Tutorials, Java Programming, Java Tricks
- Java Help, Java Tutorials, Java Programming, Java Tricks
- Java Help, Java Tutorials, Java Programming, Java Tricks
- C Language Help, C Language Tutorials, C Language Programming, C Language Tricks { The C# Language }
- C Language Help, C Language Tutorials, C Language Programming, C Language Tricks { The C# Language }
- C Language Help, C Language Tutorials, C Language Programming, C Language Tricks { The C# Language }
-
Links
- Sherawat Building Construction Jaipur
- Web Designing Company Jaipur
- world news update
- It Education
- it education video
- hindi online movie
- rajasthan election 2008
- rajasthan election
- Diamond Jewelry,Diamond Rings,Diamond Engagement Rings,Diamond Earrings,Diamond Pendants at DiamondJewelry4u.
- Tourism oF Rajasthan
- World News Update
- EDUCATION HEALTH CARE
- Rajasthan Tourism
- Best Songs
- Information Technology Education
- Rajasthan Election 2008
- Information Technology Video Education
- IT Service
- Web Solution
- SHERAWAT WEB SOLUTION
- Sherawat Web Solution
- World News Update – B
- About Diamond & Diamond Jewelry – b
- Education Health Care – b
- Best Songs – B
- Rajasthan Tourism -B
- Information Technology Education – B
- Information Technology Video Education – B
- sbinfosystem – B
- Web Solution – B
- Online Hotel Booking
- National Network of Tourism
- Hotels in India
- Hotels in Goa
- Hotels in Jammu & Kashmir
- Hotels in Madhya Pradesh
- Hotels in Pune
- Hotels in Rajasthan
- Hotels in Orissa
- Hotels in Karnataka
- Hotels in West Bengal
- Hotels in Andhra Pradesh
- Hotels in Nagaland
- Hotels in Tamilnadu
- Hotels in Assam
- Hotels in Kolkata
- Hotels in Mumbai
- Hotels in Arunachal
- Hotels in Bangalore
- Hotels in Uttar pradesh
- Hotels in Punjab
- Hotels in Lakshdweep
- Hotels in Delhi
- Hotels in Pondicherry
- Hotels in Himachal
- Hotels in Uttaranchal
- Hotels in Chennai
- Hotels in Chhattisgarh
- Hotels in Hyderabad
- Hotels in Kerala
- Hotels in Andaman
- Hotels in Gujarat
- Hotels in Haryana
- Hotels in Sikkim
- Movie Tickets Booking
- Programming Code
- Designing Templates
- Tourism in Bharat
- Andhra Exam Results
- Arunachal Exam Results
- Assam Exam Results
- Bihar Exam Results
- Chhattisgarh Exam Results
- Delhi Exam Results
- Goa Exam Results
- Gujarat Exam Results
- Haryana Exam Results
- Himachal Exam Results
- Jharkhand Exam Results
- Jammu Kashmir Exam Results
- Karnataka Exam Results
- Kerala Exam Results
- Maharashtra Exam Results
- Manipur Exam Results
- Meghalaya Exam Results
- Mizoram Exam Results
- MP Exam Results
- Orissa Exam Results
- Punjab Exam Results
- Rajasthan Exam Results
- Sikkim Exam Results
- Tamil Nadu Exam Result
- Tripura Exam Results
- UP Exam Results
- Uttaranchal Exam Results
- Westbengal Exam Results
-
Archives
- May 2009 (1)
- February 2009 (1)
- January 2009 (2)
- February 2008 (1)
- January 2008 (4)
- December 2007 (15)
- November 2007 (4)
-
Categories
-
RSS
Entries RSS
Comments RSS