Overview
So far, you have learned quite a bit about how to work with information in your PHP programs. In this chapter, you will learn some important new skills to improve the ways you work with data. You will learn about some more sophisticated ways to work with arrays, and how to
manage text information with more flair. Specifically, you will learn how to:
Manage arrays with the foreach loop.
Create and use associative arrays.
Extract useful information from some of PHP's built-in arrays.
Build basic two-dimensional arrays.
Build two-dimensional associative arrays.
Break a string into smaller segments.
Search for one string inside another.
Introducing the Word Search Creator
By the end of this chapter, you will be able to create a fun program that generates word search puzzles. The user will enter a series of words into a list box, as shown in Figure 5.1.
Figure 5.1: The user enters a list of words, and a size for the finished
puzzle.
The program then tries to generate a word search based on the user's word list. (It isn't always possible, but the program can usually generate a legal puzzle.) One possible solution for the word list shown in Figure 5.1 is demonstrated in Figure 5.2.
Figure 5.2: This puzzle contains all the words in the
list.
If desired, the program can also generate an answer key based on the puzzle. This capability is shown in Figure 5.3.
Figure 5.3: Here's the answer key for the puzzle.
The secret to the word find game (and indeed most computer programs) is the way the data is handled. Once I had determined a good scheme for working with the data in the program, the actual programming wasn't too tough.
Using the foreach loop to Work with an Array
As I mentioned in Chapter 4, "Loops and Arrays: The Poker Dice Game,"
for loops and arrays are natural companions. In fact, PHP supplies a special kind of loop that makes it even easier to step through each element of an array.
Introducing the foreach.php Program
The program shown in Figure 5.4 illustrates how the foreach loop works.
Figure 5.4: Although it looks just like normal HTML, this page was created with an array and a foreach loop.
The HTML page is unremarkable, but it was generated by surprisingly simple code.
<html>
<head>
<title>Foreach Demo</title>
</head>
<body>
<h1>Foreach Demo</h1>
<?
$list = array("alpha", "beta", "gamma", "delta", "epsilon");
print "<ul>\n";
foreach ($list as $value){
print " <li>$value</li>\n";
} // end foreach print "</ul>\n";
?>
</body>
</html>
All the values that will be in the list are created in the $list variable using the array function.
The foreach loop works a lot like a for loop, except it is a bit simpler. The first parameter of the foreach construct is an array (in this case, $list).
The keyword as then indicates the name of a variable that will hold each value in turn. In this case, the foreach loop will step through the $list array as many times as necessary. Each time through the loop, the function will populate the $value variable with the current member of the $list array. In essence, this foreach loop:
foreach ($list as $value){
print " <li>$value</li>\n";
} // end foreach
works just like the following traditional for loop:
for ($i = 0; $i < length($list); $i++);
$value = $list[$i];
print " <li>$value</li>\n";
} // end for loop
The foreach loop can be an extremely handy shortcut for stepping through each value of an array. Since this is a common task, knowing how to use the foreach loop is an important skill. As you learn some other kinds of arrays, you'll see how to modify the foreach loop to handle these other array styles.
TRICK The main difference between a foreach loop and a for loop is the presence of the index variable ($i in this example). If you're using a foreach loop and you need to know the index of the current element, you can use the key() function.
Creating an Associative Array
PHP is known for its extremely flexible arrays. You can easily generate a number of interesting and useful array types in addition to the ordinary arrays you've already made. One of the handiest types of arrays is called an
"associative array."
While it sounds complicated, an associative array is much like a normal array. While regular arrays rely on numeric indices, an associative array has a string index. Figure 5.5 shows a page created with two associative arrays.
Figure 5.5: This page uses associative arrays to relate countries and states to their capital cities.
Examining the assoc.php Program
Imagine that you want to store a list of capital cities. You could certainly store the cities in an array. However, if your main interest is in the
relationship between a state and its capital, it could be difficult to maintain the relationship using arrays. In this particular instance, it would be nice if you could use the name of the state as the array index rather than a number.
Building an Associative Array
Here is the code from assoc.php that generates the array of state capitals:
$stateCap["Alaska"] = "Juneau";
$stateCap["Indiana"] = "Indianapolis";
$stateCap["Michigan"] = "Lansing";
The associative array is just like a normal array, except the index values are strings. Note that the indices must be inside quotes. Once you have created an associative array, it is used much like a normal array, as well.
IN THE REAL WORLD
If all this "associative array" talk is making you dizzy, don't panic. It's actually just a new name for something you're very familiar with. Think about the way HTML attributes work. Each tag has a number of
attributes that you can use in any order. For example, a standard button might look like this:
<input type = "button"
value = "Save the world.">
This button has two attributes. Each attribute is made up of a name/value pair. The keywords "type" and "value" are names(or indices, or keys, depending on how you want to think of it) and the terms "button" and "Save the world." are the values associated with those names. CSS uses a different syntax for exactly the same idea.
The CSS element
p {background-color:red;
color:yellow;
font-size:14pt}
indicates a series of modifications to the paragraph tag. While the syntax is different, the same pattern applies. The critical part of a CSS definition is a list of name/ value pairs.
There's one more place associative arrays naturally pop up. As information comes into your program from an HTML form, it comes in as an associative array. The name of each element becomes an index, and the value of that form element is translated to the value of the array element. Later in this chapter you'll see how you can take advantage of this.
An associative array is simply a data structure used when the
name/value relationship is the easiest way to work with some kind of data.
print "Alaska: ";
print $stateCap["Alaska"];
print "<br><br>";
Once again, note that the index of the array is a quoted string. The associative form is terrific for data like the state capital information. In essence, it lets you "look up" the capital city if you know the state name.
Building an Associative Array with the array() Function
If you know the values you want to have in your array, you can use the array() function to build an associative array. However, building
associative arrays requires a slightly different syntax than the garden variety arrays you encountered in the last chapter. I build the $worldCap array using the array() syntax:
$worldCap = array(
"Albania"=>"Tirana", "Japan"=>"Tokyo",
"United States"=>"Washington DC"
);
When you are building an ordinary array, the array() function requires the data, but doesn't require you to specify the indices. It automatically
generates the index of each element by grabbing the next available integer.
In an associative array, you are responsible for providing both the data and the index. The general format for this assignment uses a special kind of assignment operator. The => operator indicates an element holds some kind of value. I generally read it as "holds," so you can say "Japan holds Tokyo."
In other words, "Japan" => "Tokyo" indicates that PHP should generate an array element with the index "Japan" and store the value "Tokyo" in that
element. You can access the value of this array just like any other associative array.
print "Japan: ";
print $worldCap["Japan"];
print "<br><br>";
Using foreach with Associative Arrays
The foreach loop is just as useful with associative arrays as it is with the vanilla kind. However, it uses a slightly different syntax. Take a look at this code from the assoc.php page:
foreach ($worldCap as $country => $capital){
print "$country: $capital<br>\n";
} // end foreach
A foreach loop for a regular array uses only one variable because the index can be easily calculated. In an associative array, each element in the array will have a unique index and value. The associative form of the foreach loop takes this into account by indicating two variables. The first variable holds the index. The second variable refers to the value associated with that index. Inside the loop, you can refer to the current index and value using whatever variable names you designated in the foreach structure.
Each time through the loop, you will be given a name/value pair. In this example, the name will be stored in the variable $country, because all the indices in this array are names of countries. Each time through the loop,
$country will have a different value. In each iteration, the value of the
$capital variable contains the array value corresponding to the current value of $country.
TRAP Unlike traditional arrays, you cannot rely on associative arrays to return in any particular order when you use a foreach loop to access elements of the array. If you need elements to show up in a particular order, you'll need to call them explicitly.
Using Built-In Associative Arrays
Associative arrays are extremely handy because they reflect a kind of information storage that is very frequently used. In fact, you've been using associative arrays in disguise ever since Chapter 2 of this book. Whenever your PHP program receives data from a form, that data is actually stored in a number of associative arrays for you. A variable was automatically created for you by PHP for each form element. However, you can't always rely on that particular bit of magic. Increasingly, server administrators have been turning this "automatic variable creation" off for security reasons. In fact, the default setup for PHP is now to have this behavior (with the odd name render_globals) turned off. It's handy to know how PHP gets data from the form as a good example of associative arrays. It's also useful because you may find yourself needing to know how to get form data without the variables being created explicitly for you.
Introducing the formReader.php Program
The formReader.php program is actually one of the first PHP programs I ever wrote, and it's one I use frequently. It's very handy, because it can take the input from any HTML form and report back the names and values of each of the form elements on the page. To illustrate, Figure 5.6 shows a typical Web page with a form.
Figure 5.6: This form has three basic fields. It will call the
formReader.php program.
When the user clicks the Submit Query button, formReader responds with some basic diagnostics, as you can see from Figure 5.7.
Figure 5.7: The formReader program determines each field and its
value.
Reading the $_REQUEST Array
The formReader program does its work by taking advantage of an associative array built into PHP. Until now, you've simply relied on PHP to create a variable for you based on the input elements of whatever form calls your program. This automatic variable creation is called
register_globals. While this is an extremely convenient feature, it can be dangerous, so some administrators turn it off. Even when
register_globals is active, it can be useful to know other ways of accessing the information that comes from the form.
All the fields sent to your program are automatically stored in a special associative array called $_REQUEST. Each field name on the original form becomes a key, and the value of that field becomes the value associated with that key. If you have a form with a field called userName, you can get the value of the field by calling $_REQUEST["userName"].
The $_REQUEST array is also useful because you can use a foreach loop to quickly determine the names and values of all form elements known to the program. The source code of the formReader.php program illustrates how this is done.
<!doctype html public "-//W3C//DTD HTML 4.0 //EN">
<html>
<head>
<title>Form Reader</title>
</head>
<body>
<h1>Form Reader</h1>
<h3>Here are the fields I found on the form</h3>
<?
print <<<HERE
<table border = 1>
<tr>
<th>Field</th>
<th>Value</th>
</tr>
HERE;
foreach ($_REQUEST as $field => $value){
print <<<HERE <tr>
<td>$field</td>
<td>$value</td>
</tr>
HERE;
} // end foreach print "</table>\n";
?>
</body>
</html>
Note how I stepped through the $_REQUEST array. Each time through the foreach loop, the current field name is stored in the $field variable, and the value of that field is stored in $value.
IN THE REAL WORLD
PHP provides some other variables related to $_REQUEST. The
$HTTP_POST_VARS array holds all the names and values sent through a POST request, and $HTTP_GET_VARS array holds names and values sent through a GET request. You can use this feature to make your code more secure. If you create variables only from the
$HTTP_POST_VARS array, for example, all input sent via the GET method will be ignored. This will make it harder for users to forge data by putting field names in the browser's address bar. Of course, a clever user can still write a form that contains bogus fields, so you always have to be a little suspicious whenever you get any data from the user.
TRICK I use this script when I'm debugging my programs. If I'm not getting the form elements I expected from a form, I'll put a loop like this in at the top of my program to make sure I know exactly what's being sent to the program. Often this type of procedure can help you find misspellings or other bugs.
Creating a Multi-Dimensional Array
Arrays are very useful structures for storing various kinds of data into the computer's memory. Normal arrays are much like lists. Associative arrays are like name/value pairs. A third special type of array acts much like a table of data. For instance, imagine you were trying to write a program to help users determine the distance between major cities. You might start on paper with a table like Table 5.1:
It's reasonably common to work with this sort of tabular data in a computer program. PHP (and most languages) provides a special type of array to assist in working with this kind of information. The basicMultiArray program featured in Figures 5.8 and 5.9 illustrates how a program can encapsulate a table.
Figure 5.8: The user can choose origin and destination cities from select
groups.
Table 5.1: DISTANCES BETWEEN MAJOR CITIES
Indianapolis New York Tokyo London
Indianapolis 0 648 6476 4000
New York 648 0 6760 3470
Tokyo 6476 6760 0 5956
London 4000 3470 5956 0
Figure 5.9: The program will look up the distance between the cities and
return an appropriate value.
Building the HTML for the Basic Multi-Dimensional Array
Using a two-dimensional array is actually pretty easy if you plan well. I first wrote out my table of data on paper (actually, I have a white board in my office for exactly this kind of situation). I assigned a numeric value to each city, so
Indianapolis = 0 New York = 1 Tokyo = 2 London = 3
This will make it easier to keep track of the cities later on.
The HTML code builds the two select boxes and a Submit button in a form.
<!doctype html public "-//W3C//DTD HTML 4.0 //EN">
<html>
<head>
<title>Basic multi-dimensional array</title>
</head>
<body>
<h1>Basic 2D Array</h1>
<form action = basicMultiArray.php>
<table border = 1>
<tr>
<th>First city</th>
<th>Second city</th>
<tr>
<!-- note each option value is numeric -->
<tr>
<td>
<select name = "cityA">
<option value = 0>Indianapolis</option>
<option value = 1>New York</option>
<option value = 2>Tokyo</option>
<option value = 3>London</option>
</select>
</td>
<td>
<select name = "cityB">
<option value = 0>Indianapolis</option>
<option value = 1>New York</option>
<option value = 2>Tokyo</option>
<option value = 3>London</option>
</select>
</td>
</tr>
<tr>
<td colspan = 2>
<input type = "submit"
value = "calculate distance">
</td>
</tr>
</table>
</body>
</html>
Recall that when the user submits this form, it will send two variables. The cityA variable will contain the value property associated with whatever city the user selected, and cityB will likewise contain the value of the currently selected destination city. I carefully set up the value properties so they would coordinate with each city's numeric index. If the user chooses New York as the origin city, the value of $cityA will be 1, because I decided that New York would be represented by the value 1. The reason I'm giving numeric values is because the information will all be stored in arrays, and normal arrays take numeric indices. (In the next section I'll show you how to do the same thing with associative arrays.)
Responding to the Distance Query
The PHP code that determines the distance between cities is actually quite simple once the arrays are in place.
<!doctype html public "-//W3C//DTD HTML 4.0 //EN">
<html>
<head>
<title>Distance calculator</title>
</head>
<body>
<?
$city = array ( "Indianapolis", "New York", "Tokyo", "London"
);
$distance = array (
array (0, 648, 6476, 4000), array (648, 0, 6760, 3470),