Chapter 46 ✦ A Trivia Game

\$guess ((pow(\$guess, \$n) - \$product) / (\$n * pow(\$guess, \$n-1))); return(nth_root_aux(\$product, \$n, \$new_guess, \$iterations_left - 1, \$desired_difference)); } } } function create_randomized_array (\$in_array) { // Assumes input is simple list, with keys // equal to 0,...,n // Returns similar list, with keys as in input // but values in randomized order // Assumes prior call to srand() \$in_array_length = count(\$in_array); \$working_array = array(); for (\$i = 0; \$i < \$in_array_length; \$i++) { \$rand_value = rand(); \$working_array[\$i] = \$rand_value; } asort(\$working_array); // orders by random value \$return_array = array(); \$working_keys = array_keys(\$working_array); foreach (\$working_keys as \$int_key) { array_push(\$return_array, \$in_array[\$int_key]); } return(\$return_array); } ?>

The functions in certainty_utils.php take care of figuring out all the intermediate guesses between the lowest value offered to the user and the highest value. In addition, there’s a scaling option, which determines whether the intermediate values grow linearly or geometrically. (If you think that the number “between” 10 and 1000 is 100, you are scaling geometrically; if you think the number between 10 and 1000 is 505, you are scaling linearly.) The functions for finding nth roots are used in doing the geometric scaling. The create_randomized_array() function is what we use to scramble the order of questions within a level.

question_class.php Finally, we get down to the actual questions that are pulled from our database of questions to ask. The definition of the Question class is shown in Listing 46-7. The public functions here are: ✦ The constructor, which is given the question, correct answer, the upper and lower bounds, the number of steps in the guesses, and the type of scaling (linear or geometric). ✦ Various accessor functions, such as getAnswer(), getQuestion(), getScalingType().

901

902

Part V ✦ Case Studies

✦ updateWithAnswer(), which bottoms out here by actually translating the Web form’s step numbers to values for the guesses, comparing those guesses to the real answer. ✦ getAnswerSpread(), which returns a measure of how narrow the guess was.

Listing 46-7: question_class.php <?php include_once(“certainty_utils.php”); class Question { // PRIVATE VARIABLES private \$_id; // ID in database private \$_question; // text of question private \$_answer; // correct numeric answer private \$_lowerLimit; // smallest value in distractors private \$_upperLimit; // largest value in distractors private \$_distractorCount; // number of dist. presented private \$_scalingType; // representing linear vs. geometric private \$_distractorArray; // contains all dist presented private \$_lowerGuess = NULL; // player’s lower bound private \$_upperGuess = NULL; // player’s upper bound private \$_correct = NULL; // TRUE or FALSE after guess // CONSTRUCTOR function __construct(\$id, \$question, \$answer, \$lower_limit, \$upper_limit, \$distractor_count, \$scaling_type) { \$this->_id = \$id; \$this->_question = \$question; \$this->_answer = \$answer; \$this->_lowerLimit = \$lower_limit; \$this->_upperLimit = \$upper_limit; \$this->_distractorCount = \$distractor_count; \$this->_scalingType = \$scaling_type; \$this->_distractorArray = \$this->_makeDistractors(\$lower_limit, \$upper_limit, \$distractor_count, \$scaling_type); } // PUBLIC FUNCTIONS // accessors function getId () {return(\$this->_id);} function getQuestion () {return(\$this->_question);}

Chapter 46 ✦ A Trivia Game

903

904

Part V ✦ Case Studies

Listing 46-7 (continued) max(0.0001, abs(\$lower_value / 1000000.0)); \$upper_value_raised = \$upper_value + max(0.0001, abs(\$upper_value / 1000000.0)); if ((\$lower_value_lowered <= \$this->_answer) && (\$upper_value_raised >= \$this->_answer)) { \$this->_correct = TRUE; } else { \$this->_correct = FALSE; } } else { \$this->_correct = NULL; } } // PRIVATE FUNCTIONS private function _makeDistractors (\$lower, \$upper, \$distractor_count, \$linear_or_geometric) // Create the array of intermediate values between // the upper bound and the lower bound on guesses // that the player can choose from. Depending on // a flag in each row of the question database, // the scaling of possible answers (“distractors”) // can be linear (10, 20, 30 ...) or geometric // (10, 20, 40, 80 ...) // Code for construction of geometric distractors can // blow up for some arguments, so arguments are // checked before calls to make_distractors_geometric // are allowed. Failures default back to linear. { if ((\$linear_or_geometric == CERTAINTY_GEOMETRIC) && (\$this->safeGeometricArguments(\$upper, \$lower))) { return(\$this->_makeDistractorsGeometric( \$lower, \$upper, \$distractor_count)); } else { return(\$this->_makeDistractorsLinear( \$lower, \$upper, \$distractor_count)); } } private function safeGeometricArguments (\$upper, \$lower) { // should probably really also include the number // of distractors as an argument. Only tested for // # of distractors approx 10. return ((\$upper > 0) && (\$lower > 0) &&

Chapter 46 ✦ A Trivia Game

(\$upper > \$lower) && ((\$upper / \$lower) < 10000000000)); } private function _makeDistractorsLinear (\$lower, \$upper, \$distractor_count) { \$return_array = array(); array_push(\$return_array, round_to_digits(\$lower, 3)); \$current = \$lower; \$increment = ((\$upper - \$lower) / \$distractor_count); // add in all the intermediate values for (\$x = 1; \$x < \$distractor_count; \$x++) { array_push(\$return_array, round_to_digits(\$lower + (\$x * \$increment), 3)); } array_push(\$return_array, round_to_digits(\$upper, 3)); return(\$return_array); } private function _makeDistractorsGeometric (\$lower, \$upper, \$distractor_count) { if ((\$lower >= \$upper) || (\$distractor_count < 2)) { die(“Args to _makeDistractorsGeometric should be “ . “1) a lower limit, 2) an upper limit, “ . “3) a count (>= 2) of divisions between them.<BR>” . “Args were 1) \$lower, 2) \$upper, 3) \$distractor_count<BR>”); } \$return_array = array(); array_push(\$return_array, round_to_digits(\$lower, 3)); \$limit_ratio = \$upper / \$lower; \$root = nth_root(\$limit_ratio, \$distractor_count); \$current = \$lower; // add in the intermediate values for (\$x = 1; \$x < \$distractor_count; \$x++) { \$distractor = round_to_digits( \$lower * pow(\$root, \$x), 3); array_push(\$return_array, \$distractor); } array_push(\$return_array, round_to_digits(\$upper, 3)); return(\$return_array); } } ?>

905

906

Part V ✦ Case Studies

dbvars.php When we actually query the database, we need to have access information. The file shown in Listing 46-8 is loaded by GameParameters.php, and sets up the variables necessary for making a MySQL connection. Note that the current values are dummies and will not work on your system! You need to fill in the correct values for your own MySQL configuration. If your Web server is connected to the Internet, it’s also a good idea to move this file somewhere outside the Web-server document tree and to change the reference in GameParameters.php to point to its new location.

Listing 46-8: dbvars.php <?php \$host \$user \$pass \$db = ?>

Creating the database The trivia game is fueled by a database of questions. So far, we have said nothing about how to create such a database.

Table definitions Listing 46-9 shows a MySQL dump file of all the table definitions used in the code, along with a few sample entries. Before loading it, you need to create a database called certainty; after that is done, you should be able to simply cat or pipe the contents of this file to the mysql command. Note that the question table includes several fields that are not actually used in the current code. One of them is attribution, useful for recording the book or Web site that served as the authority for the answer. Another is include, which we intended for filtering out questions in development that were not ready to be displayed. A third is subjectID, which we use to tag questions according to subject area (Science, Geography, History, and so on). although that association is not actually displayed anywhere. A final as-yet unused column is unitID, which could be used to record the unit (kilometers, years, furlongs, bushels) of the answer in case the unit affects how guesses should be displayed.

Listing 46-9: Table definitions # MySQL dump 7.1 # # Host: [host deleted] Database: certainty #-------------------------------------------------------# Server version 3.22.32 # # Table structure for table ‘high_scores’ #

Chapter 46 ✦ A Trivia Game

CREATE TABLE high_scores ( id int(11) DEFAULT ‘0’ NOT NULL auto_increment, name varchar(30), answer_count int(11), credit double(16,4), PRIMARY KEY (id) ); # # Dumping data for table ‘high_scores’ # INSERT INTO high_scores VALUES (8,’Ben Stein’,15,-3.0000); # # Table structure for table ‘question’ # CREATE TABLE question ( ID int(11) DEFAULT ‘0’ NOT NULL auto_increment, answer double(16,4), unitID int(11), level int(11), subjectID int(11), include tinyint(4), upper_limit double(16,4), lower_limit double(16,4), scaling_type tinyint(4), question varchar(255), attribution varchar(255), PRIMARY KEY (ID) ); # # Dumping data for table ‘question’ # INSERT INTO question VALUES (1,5283755345.0000,1,1,1,1,200000000000.0000,1000000.0000,2, ‘What was the human population of the world in the middle of 1990?’, ‘http://www.census.gov/ipc/www/worldpop.html’); INSERT INTO question VALUES (2,70.0000,1,1,1,1,95.0000,5.0000,1, ‘What percentage of the Earth\’s surface is covered by water?’, ‘http:/www.sciencenet.org.uk/database/Geography/ Original/g00057d.html’); INSERT INTO question VALUES (4,1969.0000,NULL,1,2,NULL,2000.0000,1950.0000,1, ‘In what year did human beings first walk on the moon?’,’’); # # Table structure for table ‘subject’ # Continued

907

908

Part V ✦ Case Studies

Listing 46-9 (continued) CREATE TABLE subject ( id int(11) DEFAULT ‘0’ NOT NULL auto_increment, subject varchar(255), PRIMARY KEY (id) ); # # Dumping data for table ‘subject’ # INSERT INSERT INSERT INSERT INSERT

INTO INTO INTO INTO INTO

subject subject subject subject subject

VALUES VALUES VALUES VALUES VALUES

(1,’Geography’); (2,’History’); (3,’Science’); (4,’Mathematics’); (5,’Miscellaneous’);

The MySQL dump includes only three sample questions. You can always add more through a direct interaction with MySQL, but it’s more convenient to do it via a Web form.

entry_form.php Listing 46-10 shows a bare-bones Web form for entering more questions into the question database. This simply takes typed input (except for a pull-down association with the subject table) and trusts the results. Note that there is neither security nor error-checking here — this is intended for use only by the game creator, and if misuse is a concern you should probably add password protection or some other kind of authentication. (See Chapter 44 for more on creating authentication systems.)

Listing 46-10: dbvars.php <?php include_once(“certainty_utils.php”); include_once(“game_parameters_class.php”); \$params = new GameParameters(); \$connection = \$params->getDbConnection(); if (get_post_value(‘POSTCHECK’)) { handleEntryForm(); } displayEntryForm(); function handleEntryForm () { \$question = get_post_value(‘QUESTION’); \$answer = get_post_value(‘ANSWER’); \$lower_limit = get_post_value(‘LOWER_LIMIT’); \$upper_limit = get_post_value(‘UPPER_LIMIT’); \$level = get_post_value(‘LEVEL’); \$subject = get_post_value(‘SUBJECT’);

Chapter 46 ✦ A Trivia Game

\$scaling_type = get_post_value(‘SCALING_TYPE’); \$attribution = get_post_value(‘ATTRIBUTION’); if (\$upper_limit > \$lower_limit) { \$query = “insert into question (question, answer, lower_limit, upper_limit, level, subjectID, scaling_type, attribution) values (‘\$question’, \$answer, \$lower_limit, \$upper_limit, \$level, \$subject, \$scaling_type, ‘\$attribution’)”; \$result = mysql_query(\$query); if (\$result) { print(“Entry was successful<BR>”); } else { print(“Entry was not successful<BR>”); } } else { print(“Upper limit must be > lower<BR>”); } } function displayEntryForm () { global \$PHP_SELF; \$linear = CERTAINTY_LINEAR; \$geometric = CERTAINTY_GEOMETRIC; \$subject_string = make_subject_string(); \$form_string = <<<EOT <FORM METHOD=POST TARGET=”\$PHP_SELF” > Question: <INPUT TYPE=TEXT NAME=QUESTION SIZE=60 ><BR> Answer: <INPUT TYPE=TEXT NAME=ANSWER><BR> Lower: <INPUT TYPE=TEXT NAME=LOWER_LIMIT><BR> Upper: <INPUT TYPE=TEXT NAME=UPPER_LIMIT><BR> Level: <INPUT TYPE=TEXT NAME=LEVEL><BR> Subject: \$subject_string<BR> Scaling type: <SELECT NAME=SCALING_TYPE> <OPTION VALUE=\$linear>Linear <OPTION VALUE=\$geometric>Geometric </SELECT><BR> Attribution: <INPUT TYPE=TEXT NAME=ATTRIBUTION><BR> Continued

909

910

Part V ✦ Case Studies

Listing 46-10 (continued) <INPUT TYPE=SUBMIT NAME=SUBMIT VALUE=SUBMIT> <INPUT TYPE=HIDDEN NAME=POSTCHECK VALUE=1> </FORM> EOT; echo \$form_string; } function make_subject_string () { \$result_string = “<SELECT NAME=SUBJECT>”; \$query = “select id, subject from subject order by id”; \$result = mysql_query(\$query); while (\$row = mysql_fetch_row(\$result)) { \$id = \$row[0]; \$display = \$row[1]; \$result_string .= “<OPTION VALUE=\$id>\$display”; } \$result_string .= “</SELECT>”; return(\$result_string); } ?>

General Design Considerations What follows is a brief list of issues that we were forced to consider while writing the code in this chapter.

Separation of code and display The question of separating code and display is a vexing one, especially in situations where you have different personnel assigned to maintaining logic and appearance. Our own view on this is that perfect separation of code and display is like a perfect vacuum — you can get asymptotically closer to the ideal as you expend infinite effort. For large Web sites employing many people, some pretty good techniques exist for making a strong separation, including templating systems and database storage of graphics and display text. For this relatively small and informal example, we were satisfied by simply segregating all HTML into two display-oriented classes, leaving the remainder of the code focused on logic and data.

Persistence of data There are several kinds of data in this game that survive longer than the execution time of a page. We chose to use PHP’s session mechanism for all the data particular to a particular game invocation and a backend database for everything else (questions, answers, and highscore lists).

Chapter 46 ✦ A Trivia Game

For reasons of efficiency, we didn’t want to store too much data via the session mechanism. So we separated out the most important data (that could not be easily recreated) into the Game class and stored only an instance of that class. Everything else (question text, boilerplate HTML text, high scores, and so on) was either embedded in code files or easily retrievable from the database.

Exception handling We used the new (as of PHP5) exception mechanism to bail out whenever we encountered a problem that the code could not recover from. Failures to recover session info, failures to find cookies, and database interaction problems were all grounds for giving up. In general, when we threw an exception, we sent a string suitable for display to a user and then caught all thrown exceptions at the point of display. This has the disadvantage of not providing a lot of rich debugging information (particularly since several different code paths can throw a “No database connection” exception), but has the advantage that we can tell the user something reasonable and fairly cosmetic, while giving the developer a hint.

Summary The Certainty Quiz is a small, simple, self-contained PHP application that you should be able to install and enjoy in the privacy of your own home (after connecting it to your favorite Web server and a MySQL database, of course). Although small, the code relies on database interaction, OOP features, use of sessions, string processing, object serialization, exceptionhandling, and non-trivial arithmetic to achieve its effects. Although PHP has many capabilities that we didn’t come close to touching on, this chapter uses a fair cross-section of its most popular features — if you understand everything in this example, you are well on your way to exploiting the power of PHP.

911

47 C H A P T E R

Converting Static HTML Sites

In This Chapter

A

lmost everything we’ve discussed in this book so far assumes that you are designing your PHP-enabled site from scratch, including any database schemas that may be required. The truth, however, is that many of the most common and valuable PHP projects involve converting a pre-existing HTML site to a more maintainable PHP version. Here we describe in detail how this is accomplished, using a real site as an example.

The information in this chapter may also be valuable if you need to transfer data from one format to another (tab-delimited file to database, one database to another), or if you want to take a bunch of text files and turn them into a Web site.

Dumping data into a database

Redesigning the UI Planning a new database schema

Templating Performance and caching

914

Part V ✦ Case Studies

The baby and the bathwater The first step to recoding a site is to step back and take inventory of what is working well and what the most important fix-it items may be. Our experience has been that teams often skip this step through impatience and live to regret it later when they are confronting huge, difficult-to-reverse architectural issues. You already have a lot of good things going for you, and you know a lot of invaluable information about your needs and your audience — make sure you capture this information in a usable format. As we took stock of MysteryGuide’s code, content, and mission, this is what we found. Audience characteristics: ✦ Audience is composed of all ages and an equal gender split. ✦ No internationalization needs — all visitors can be assumed to read English competently. ✦ Unusually large percentage of older people and a heavy number of readers with poor vision. ✦ New visitors may land on any page because most come from search engines. ✦ Fairly large and vocal percentage of Macintosh users. ✦ MysteryGuide does not collect user data. ✦ Users often print out pages for offline viewing (for example, taking to library, sharing with friends). Things that are working well: ✦ Navigation scheme (for example, dividing books into subgenres). ✦ Reviews and other data. ✦ Features (for example, book ratings, games, interviews). ✦ Heavily crawled by search engines. Things that need work: ✦ Very difficult to change page layouts. ✦ Database is offline, nonrelational, and can’t be searched by users. ✦ Forums — not much traffic, spam magnet. ✦ Some users can’t find the author or book they’re looking for. ✦ Need tools to add and edit data. ✦ Site design lacks professional look. What does all this stock-taking tell us? Actually, the news is very good in this case. The content is fine, and the big-picture navigation is working for now. In this case, our three major goals are very clear: ✦ Move data into a new database. ✦ Create dynamic page-generation with PHP and database. ✦ Initiate a cosmetic look-and-feel upgrade.

Chapter 47 ✦ Converting Static HTML Sites

If we accomplish these three tasks and also drop the forum (which is an entirely separate subsystem), we can be in a good technical position to add new features desired by our users, such as search and printable versions of the book reviews.

Technical assessment In addition to strategic insights about the site, we should assess the logical, physical, and software requirements of MysteryGuide.com and consider whether we need to upgrade them too.

Site architecture MysteryGuide currently consists of approximately 900 pages, of which the vast majority (about 800) could be made dynamic. There are actually only a few types of pages: ✦ Front page ✦ Complete author list ✦ Genre pages ✦ Genre history pages ✦ Book pages ✦ Feature pages (interviews, games, and so forth) ✦ Miscellaneous pages (top-rated books, FAQ, and so forth) Of these, by far the most numerous and important are the book pages. We expect to spend at least half the time required by the whole project on just the book page template; the big data dump we plan is almost all for the book pages. After that, the genre page is the most important; and then the front page. Feature pages and single pages are the least important, and if push comes to shove, we could launch the redesigned site without them.

Hardware and software requirements Obviously, we’re using PHP for the scripting language and Apache for the Web server (because we run on Unix). For a purpose like this, moving from a static HTML site, MySQL is a no-brainer as the database. All we care about are very fast reads and the ability to scale to thousands of rows per table because we don’t collect user data and perform writes only very occasionally (essentially just when someone reviews a book). If you needed to make a lot of writes, and especially if you needed rollbacks and triggers, you would have to evaluate other databases. (See Chapter 12 for more information on choosing a database.) Because we’re already using all these programs for the current version of MysteryGuide.com, we require no new hardware or software. After the upgrade is complete, we will actually be using fewer system resources and less disk space than before. Our upgrade actually makes the site (marginally) cheaper to run and more portable, as well as much more maintainable and scalable. Tip

You need a standalone version of PHP to perform some of the tasks described in this section. If you don’t have one already, compile and install it now. Refer to Chapter 3 for instructions.

915

916

Part V ✦ Case Studies

Redesigning the User Interface You want to get your designers working on the new look and feel as soon as possible, because they need some lead time to iterate on their ideas, and little UI code can be usefully written before they deliver their piece of the puzzle. If you don’t know any good designers, finding some should be your first priority. If you’re lucky enough to be in this position, having a usability team contribute from the beginning can also be helpful. Our experience has been that most designers do best if you (or your usability people) give them the basic layout you want on each page — in the case of a working site, they can simply look at the old site or you can draw a little wireframe. You should also explain clearly any special factors that must be taken into account, such as (in our case) the stricture against tiny or light-colored fonts. You’re actually helping them do their jobs more efficiently by imposing some structure at the beginning, and you have only yourself to blame if you give a designer carte blanche and end up with some bizarre art-school production. We were very lucky to work with a designer, Mimi Yin of Mydesignco.com, who is deeply interested in data-rich sites, has a knack for using shape to add movement and interest to the page, and believes in getting client feedback early and often. She started working on the most important and pressing parts of the site (book and genre pages) and then harmonized the rest of the site to match. This is exactly what you want — the designer should not automatically begin working on the most visually appealing or prominent parts of the site (for example the front page or splash screen) just because that is the most interesting piece for him or her. She or he should work on the part that is most important for the site. These are before and after screenshots of a MysteryGuide.com book page. As we noted in the preceding “Site architecture” section, the book page is the most important and numerous of our types of pages. Figure 47-1 shows the old design. (Keep a kind thought — it was designed in 1997.)

Figure 47-1: MysteryGuide.com book page before

Chapter 47 ✦ Converting Static HTML Sites

Figure 47-2 shows the new design in the mockup phase. Notice how cleverly our designer has framed the various elements to set them off visually.

917

918

Part V ✦ Case Studies

Planning a New Database Schema As your designers are iterating away, you need to do some design of your own — designing a database schema, that is. If you already have a workable database, feel free to skip to the “Templating” section that follows. CrossReference

For basic information on working with SQL, see Chapter 13.

Besides the book reviews, MysteryGuide’s main feature is a book recommendation system. This subsystem depends upon a questionnaire that our reviewers fill out for each book, detailing such things as the settings in which the action took place, the name of the protagonist, and how violent the book was. It is this data that we are seeking to represent in a SQL format. Although we previously kept our data in a database, it was not truly relational. Each book had one big monolithic database record that listed everything that we wanted to know about that book. Relationality didn’t matter that much for one-to-one fields, such as year of first publication — every book is only published for the first time once, after all. But for many-toone fields, such as setting, we were forced to make some awkward compromises. Basically these boiled down to two methods. The first was setting a fixed number of fields of a certain type (for example: Subgenre1, Subgenre2, Subgenre3), which may or may not be filled in for any given book. The second was enabling multiple entries to be placed in a single field, separated by commas (for example: “UK, Germany, Switzerland” as the setting of one book). These multiple fields had to be untangled and redrawn as many-to-many SQL relationships in the new database. Furthermore, a nonrelational database inevitably has repetition that can be eliminated in a relational database. We want to know, for example, the name, sex, and nationality of each author. There are some authors whom we’ve reviewed multiple times, and this information is entered separately in each book’s record. Besides causing inefficiency and duplication of effort, this practice resulted in a higher incidence of mistakes. Our old nonrelational database table looked something like this: Title Author name Author gender Author nationality Year of first publication Subgenre1 Subgenre2 Subgenre3 Settings (multiple) Time period (multiple) Rating Protagonist name Protagonist gender Protagonist age Protagonist nationality Protagonist occupation Protagonist organization Action (1 - 5) Humor (1 - 5)

Chapter 47 â&#x153;Ś Converting Static HTML Sites

Romance (1 - 5) Sex (1 - 5) Violence (1 - 5) Type of crime (multiple) Reviewer Number of pages Review completion date Book ISBN Movies (multiple) Awards (multiple) Review Blurb Author interview

Starting from this schema, itâ&#x20AC;&#x2122;s pretty easy to divide these fields into three main buckets: Author, Protagonist, and Book information. The new Author table follows. Notice that we changed the field names to a more SQL-like naming style. A_id A_firstname A_lastname A_gender A_nationality A_interview

The Protagonist table looks like this: P_id P_firstname P_lastname P_gender P_age P_nationality P_occupation P_organization

The main Book table contains these fields: B_id B_title B_year B_rating B_action B_humor B_romance B_sex B_violence B_reviewer B_pages B_reviewdate B_ISBN B_movie B_awards B_review B_blurb

919

920

Part V ✦ Case Studies

Notice that we have removed most of the multiple-entry fields, which must now get their own definition tables and also tables relating them to books. Subgenre information, for example, is now stored in a simple table: Sub_id Sub_name

A matching table, Book_Subgenre, is required to store the relationships: BSub_id B_id Sub_id

Settings, time periods, and type of crimes would also need similar new tables. We decided, however, not to make new tables for Movies and Awards. Although a given book can have several film adaptations — for instance, The Maltese Falcon was filmed at least three times and won several awards — these are many-to-one relationships and treated by MysteryGuide basically as strings rather than categorizable information. Now that you’ve worked out your schema on paper, go implement it as a bunch of SQL commands. You could also write a PHP script to do this, but a SQL file is actually much easier after you’re comfortable with the concept. A SQL file is just a text file that strings together a bunch of SQL commands so you don’t need to enter them one by one on the command line — instead you can read the whole file into MySQL with a single command. Listing 47-1 creates a database definition file.

Listing 47-1: Database definition file (newmg_structure.sql) # MySQL dump file # MysteryGuide SQL structure only # # Table structure for table ‘author’ # CREATE TABLE author ( A_id int(11) DEFAULT ‘0’ NOT NULL auto_increment, A_firstname tinytext, A_lastname tinytext, A_gender tinyint(4), A_nationality tinytext, A_interview tinytext, PRIMARY KEY (A_id) ); # # Table structure for table ‘book’ # CREATE TABLE book ( B_id int(11) DEFAULT ‘0’ NOT NULL auto_increment,

Chapter 47 ✦ Converting Static HTML Sites

B_title tinytext, B_year year(4), B_rating tinyint(4), B_action tinyint(4), B_humor tinyint(4), B_romance tinyint(4), B_sex tinyint(4), B_violence tinyint(4), B_reviewer tinytext, B_pages smallint(6), B_reviewdate date, B_ISBN tinytext, B_movie text, B_awards text, B_review text, B_blurb text, PRIMARY KEY (B_id) ); # # Table structure for table ‘book_author’ # CREATE TABLE book_author ( BA_id int(11) DEFAULT ‘0’ NOT NULL auto_increment, B_id int(11), A_id int(11), PRIMARY KEY (BA_id) ); # # Table structure for table ‘subgenre’ # CREATE TABLE subgenre ( Sub_id int(11) DEFAULT ‘0’ NOT NULL auto_increment, Sub_name tinytext, PRIMARY KEY (Sub_id) ); # # Table structure for table ‘book_subgenre’ # CREATE TABLE book_subgenre ( BSub_id int(11) DEFAULT ‘0’ NOT NULL auto_increment, B_id int(11), Sub_id int(11), PRIMARY KEY (BSub_id) ); ...

921

922

Part V ✦ Case Studies

Whenever you’re ready, you can dump this file into a MySQL database by typing the following commands (plus the password, when you’re prompted for it) on the command line: mysqladmin –u root –p create mysteryguide mysql –u root –p mysteryguide < newmg_structure.sql

If you make a mistake, don’t panic! You can keep dropping the database, fixing your SQL errors in the file, re-creating the database, and reloading. Remember to grant privileges for this database to nonroot MySQL users as soon as you finish creating the database permanently. The principle to follow is to give each database user the lowest level of privileges necessary to get the job done. In this case, your default MySQL user needs only read privileges; ordinary visitors do not write to our database. You must create a different MySQL user with write privileges for reviewers, and possibly another for editors or administrators. These come into play in the “Tools” section later in this chapter.

Dumping Data into a Database Now that you have a nice fresh database, you’re ready to dump information into it. We mainly assume that you are starting with another database (as we are) or possibly a spreadsheet. In the section “Harvesting data,” later in this chapter, we discuss how to adapt these tasks if you’re starting with multiple text files (for example, HTML files or Word documents) instead.

Data-massaging So we begin by dumping the data from FileMaker (or any data store) into a tab-delimited file. Most small databases and spreadsheets have some way to do this automatically — the command may be called something such as Export or Dump. It’s very important to write down or print out the order in which the fields exported, which may be considerably different from their display order. At this point you should check over the tab-delimited file and make sure that the data is basically good. You may need to fix it up a little bit at this point. We needed to turn some old-style Macintosh linebreaks, for example, into Unix-compatible newlines. The easiest way to do so is to break out Perl regex on the command line: perl –pi –e ‘s/\r/\n/g’ tabdelimitedfile.txt

If you’re going from Windows to Unix or Unix to Windows, you probably must do something similar. Windows to Unix is: perl –pi –e ‘s/\r\n/\n/g’ tabdelimitedfile.txt

Unix to Windows is: perl –pi –e ‘s/\n/\r\n/g’ tabdelimitedfile.txt

Converting from Macintosh or Unix to Windows is a bit more problematic because the toolkits are different. You may want to use something like Perl for Windows (ActiveState distributes a well-regarded version without cost, www.activestate.com/Products/ActivePerl). Alternatively, you could do the conversion on the Unix side before shipping over to Windows.

Chapter 47 ✦ Converting Static HTML Sites

Another thing you may want to do at this point is cut up your data file into pieces. This is probably a good idea in any case, because you want to break off a chunk of data for testing anyway. Also, it’s a lot easier to recoup from errors when working with a smaller data set — if your script chokes on some unexpected error, this may mean the difference between having to redo 100 entries and having to redo the entire data dump. You must cut up the file if your data file is more than 2GB large, because most Unix applications and utilities have a limited capability to deal with files greater than that size. You probably must use special 32-bit versions tools such as split or Perl to accomplish this task. To cut up a file into manageable pieces, you want to use the Unix utility split like this: split --lines=100 tabdelimitedfile.txt chunk_

This results in a bunch of 100-line files called chunk_aa, chunk_ab, chunk_ac, and so on. Obviously you can substitute a different integer value for the number of lines. If you leave off the final argument, the files are just called aa, ab, ac, and so on. Remember that these are 100 lines as Unix counts them, which means 100 units of text between (invisible) newline characters (\n). If you are using a Windows or Macintosh format file with different line breaks, they may look like line-breaks in the text file but are not necessarily counted correctly by split. If you have newlines within some field entry, split also gets confused.

Data dumping Now you’re ready to write a script to dump the data into the database. You have two choices: Either you can use the standalone version of PHP, which is fast and does not time out, or you can use the normal module version in the browser, which may be easier for Windows users or anyone not comfortable with the command line. The actual scripts in standalone or module versions are not hugely different. The biggest issue is probably that the module version can only handle smallish data sets because most Web servers are configured to timeout after 60 seconds or so. And the standalone version must echo to the terminal in text, whereas the module version outputs to the browser in HTML. Either way, the basic steps are clear: 1. Read in the data file. 2. Split it into an array, where each array element is one row of data. 3. Cycling through the array, split each row into fields. 4. Cycling through the array, arrange the field data into one or more SQL queries and send it to the database. 5. Repeat until all data is stored. Tip

Work with a test batch of representative data while you write and debug your script.

The following code, Listing 47-2, should be saved under some name like dumpdata.php. It runs in either the browser or on the command line (/usr/local/bin/php dumpdata.php). It inserts data into the database tables that we defined in Listing 47-1.

923

924

Part V ✦ Case Studies

Listing 47-2: Script to dump data ino MySQL (dumpdata.php) <?php /********************************************* * Script to dump data into the MG database. * *********************************************/

// Read in the file as an array // ---------------------------\$filename = ‘tabdelimitedfile.txt’; \$farray = file(\$filename) or die(“Can’t read in file”);

// Open up a database connection \$db = mysql_connect(‘localhost’, ‘editor’, ‘sesame’) or die(“Can’t connect to the database”); mysql_select_db(‘mg’);

// Loop through each entry // ----------------------foreach (\$farray as \$val) { \$l_arr = explode(“\t”, \$val); print_r(\$l_arr); // Tidy up the entries // ------------------// Author info \$Author = \$l_arr[1]; // Divide name into first and last \$A_array = explode(‘, ‘, \$Author); \$A_firstname = addslashes(\$A_array[1]); \$A_lastname = addslashes(\$A_array[0]); \$A_gender = addslashes(\$l_arr[2]); if (\$A_gender == ‘F’) { \$A_gender = 0; } elseif (\$A_gender == ‘M’) { \$A_gender = 1; } else { echo “\$A_firstname \$A_lastname has gender issues”; } \$A_nationality = addslashes(\$l_arr[3]); \$A_interview = addslashes(\$l_arr[31]); // Book info \$B_title = addslashes(\$l_arr[0]); \$B_year = \$l_arr[4];

Chapter 47 ✦ Converting Static HTML Sites

\$B_rating = \$l_arr[10]; \$B_action = \$l_arr[17]; \$B_humor = \$l_arr[18]; \$B_romance = \$l_arr[19]; \$B_sex = \$l_arr[20]; \$B_violence = \$l_arr[21]; \$B_reviewer = addslashes(\$l_arr[23]); \$B_pages = \$l_arr[24]; \$B_reviewdate = \$l_arr[25]; // Reformat the review date from m/d/yy to yyyy-mm-dd \$date_arr = explode(‘/’, \$B_reviewdate); \$B_reviewdate = date(‘Y-m-d’, mktime(12, 30, 0, \$date_arr[0], \$date_arr[1], \$date_arr[2])); \$B_ISBN = \$l_arr[26]; \$B_movie = addslashes(\$l_arr[27]); \$B_awards = addslashes(\$l_arr[28]); \$B_review = addslashes(\$l_arr[29]); \$B_blurb = addslashes(\$l_arr[30]); // Subgenre info \$Subgenre[1] = addslashes(\$l_arr[5]); \$Subgenre[2] = addslashes(\$l_arr[6]); \$Subgenre[3] = addslashes(\$l_arr[7]);

// Enter data into database // -----------------------// Author data // First see if this author is already in the database \$query = “SELECT A_id FROM author WHERE A_firstname = ‘\$A_firstname’ AND A_lastname = ‘\$A_lastname’ “; \$result = mysql_query(\$query); if (mysql_num_rows(\$result) == 0) { // If not already there, add the author \$query = “INSERT INTO author VALUES( NULL, ‘\$A_firstname’, ‘\$A_lastname’, \$A_gender, ‘\$A_nationality’, ‘\$A_interview’ )”; \$result = mysql_query(\$query); if (mysql_affected_rows() != 1) { echo “Problem inserting author data for \$A_firstname \$A_lastname”; } else { Continued

925

926

Part V ✦ Case Studies

Listing 47-2 (continued) \$author_id = mysql_insert_id(); //Need this for book_author } } else { \$author_id = mysql_result(\$result, 0, 0); } // Book data // We can assume each book is unique \$query = “INSERT INTO book VALUES( NULL, ‘\$B_title’, ‘\$B_year’, \$B_rating, \$B_action, \$B_humor, \$B_romance, \$B_sex, \$B_violence, ‘\$B_reviewer’, \$B_pages, ‘\$B_reviewdate’, ‘\$B_ISBN’, ‘\$B_movie’, ‘\$B_awards’, ‘\$B_review’, ‘\$B_blurb’ )”; \$result = mysql_query(\$query); \$book_id = mysql_insert_id(); //Need this for book_author if (!\$book_id || \$book_id == “”) { echo “Problem inserting book data for \$B_title”; } // Associate book and author \$query = “INSERT INTO book_author VALUES( NULL, \$book_id, \$author_id )”; \$result = mysql_query(\$query); if (mysql_affected_rows() != 1) { echo “Problem inserting book_author data for \$B_title”; } // Subgenres for (\$i = 1; \$i <= 3; \$i++) { if (\$Subgenre[\$i] == “”) { continue; } else {

Chapter 47 ✦ Converting Static HTML Sites

// First see if this subgenre is already in the database \$query = “SELECT Sub_id FROM subgenre WHERE Sub_name = ‘\$Subgenre[\$i]’ “; \$result = mysql_query(\$query); if (mysql_num_rows(\$result) == 0) { // If not already there, add the subgenre \$query = “INSERT INTO subgenre VALUES( NULL, ‘\$Subgenre[\$i]’ )”; \$result = mysql_query(\$query); if (mysql_affected_rows() != 1) { echo “Problem inserting subgenre \$Subgenre[\$i]”; } else { \$subgenre_id = mysql_insert_id(); } } else { \$subgenre_id = mysql_result(\$result, 0, 0); } // Now associate the subgenre with the book \$query = “INSERT INTO book_subgenre VALUES( NULL, \$book_id, \$subgenre_id )”; \$result = mysql_query(\$query); if (mysql_affected_rows() != 1) { echo “Problem inserting book_subgenre data for \$B_title and \$Subgenre[\$i]”; } } } } ?>

Notice that we deal with several problematic but common situations in this script, such as: ✦ Changing strings (M/F) into integers (1/0) for more compact storage. ✦ Turning one field into two fields (Author_name into A_firstname and A_lastname). ✦ Handling duplicate information (same author for multiple books). ✦ Turning three different fields (Subgenre1, Subgenre2, Subgenre3) into three rows in the same table. ✦ Making a nonrelational database truly relational (book_author and book_subgenre tables).

927

928

Part V ✦ Case Studies

Chapter 47 ✦ Converting Static HTML Sites

who Knew Too Much is a long review in text here. <p ALIGN=RIGHT><b>Reviewer:</b> JP </font><br><br></td></tr></table>

<br><table BORDER=0 CELLPADDING=5> <tr BGCOLOR=”#A32242” WIDTH=100%><td> <font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF” COLOR=”#FFFFFF”><b>Further reading</b></font> </td></tr> <tr BGCOLOR=”#FFFECC” WIDTH=100%> <td><font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF”> <aHREF=”http://www.amazon.com/exec/obidos/ASIN/0898706297/ troutworksmyster/”> <P><b>Wisdom and Innocence: a life of GK Chesterton</b></a> (1997) by Joseph Pearce<BR>Bio focussing on Chesterton’s Catholicism.</td></tr></table> <table BORDER=0 CELLPADDING=5><tr BGCOLOR=”#A32242” WIDTH=100%> <td> <font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF” COLOR=”#FFFFFF”> <b>Summary information</b></font> </td></tr> <tr BGCOLOR=”#FFFECC” WIDTH=100%> <td><font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF”> <b>Main character name:</b><br> Horne Fisher<br> <b>Year published:</b> 1922<br> <b>Time period:</b> 1910’s<br> <b>Subgenres:</b> <a HREF=”classic-whodunit.html”>Classic whodunit</a>, <a HREF=”political.html”>Political</a><br> <b>Setting:</b> UK(West Country), Ireland<br> </font></td></tr></table> <br> <table BORDER=0 CELLPADDING=5><tr BGCOLOR=”#A32242” WIDTH=100%> <td> <font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF” COLOR=”#FFFFFF”> <b>Top 5 most similar books</b></font> </td></tr> <tr BGCOLOR=”#FFFECC” WIDTH=100%> <td><font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF”> 1. <a HREF=bkCopperPons.html TARGET=_top><strong>The Further Adventures of Solar Pons</strong></a> by Basil Copper and August Derleth <br> 2. <a HREF=bkOrczyCorner.html TARGET=_top><strong>The Old Man in the Corner</strong></a> by Emma Orczy <br> 3. <a HREF=bkHareBodkin.html TARGET=_top><strong>With a Bare Bodkin</strong></a> by Cyril Hare <br> 4. <a HREF=bkRossLove.html TARGET=_top><strong>Whom the Gods Love</strong></a> by Kate Ross <br> 5. <a HREF=bkSayersBody.html TARGET=_top><strong>Whose

929

930

Part V ✦ Case Studies

Body?</strong></a> by Dorothy L. Sayers <br> </font></td></tr></table> <br> <table BORDER=0 CELLPADDING=5><tr BGCOLOR=”#A32242” WIDTH=100%> <td> <font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF” COLOR=”#FFFFFF”> <b>By the same author</b></font> </td></tr> <tr BGCOLOR=”#FFFECC” WIDTH=100%> <td><font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF”> <a HREF=bkChestertonThursday.html TARGET=_top><strong> The Man Who Was Thursday</strong></a> (1908) <br> </font></td></tr></table> <br> <table BORDER=0 CELLPADDING=5> <tr BGCOLOR=”#A32242” WIDTH=100%> <td> <font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF” COLOR=”#FFFFFF”> <b>Movies</b></font> </td></tr> <tr BGCOLOR=”#FFFECC” WIDTH=100%> <td> <font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF”>Neither Alfred Hitchcock movie of this title has any relation to the book </td></tr></table> <p ALIGN=RIGHT> <font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF”>&#169 1999 Troutworks, Inc. All rights reserved. <br> Revised July 6, 1999</font></p></body></html>

Say that you want to harvest some information from this page — for example, information about movies that were made from this book. First, you’d probably want to divide up the page into chunks corresponding to tables. From here, there are many ways to accomplish your goal using string, array, and possibly regex functions. Caution

Do not let yourself be intimidated by people who write self-aggrandizing comments on PHP mailing lists or Web sites claiming that all smart people use a certain method to perform these tasks! This type of grungy no-glory parsing is all about getting the job done and producing code you can read — it’s not a programming style contest. It may be true that, in theory, you could use one line of regex instead of five lines of string functions, but who cares?

Listing 47-3 shows one straightforward method of getting the movie information you want.

Chapter 47 ✦ Converting Static HTML Sites

Listing 47-3: Script to harvest data from HTML files (harvest.php) <?php // harvest.php – get movie information from a MysteryGuide HTML // file \$file = ‘sample_HTML_for_harvesting.html’; \$fp = fopen(\$file, “r”); \$file_str = fread(\$fp, filesize(\$file)); // Divide the page into chunks corresponding to tables \$tables = explode(‘</td></tr></table>’, \$file_str); // Not every page will have all tables, so we need to // rename our array in a more informative way. If all your // pages have all identical sections, you don’t need to do this. foreach (\$tables as \$table_val) { if (strpos(\$table_val, ‘SIZE=+3’) > 30) { \$chunk[‘review’] = \$table_val; } elseif (strpos(\$table_val, ‘<b>Further reading</b>’) > 1) { \$chunk[‘further’] = \$table_val; } elseif (strpos(\$table_val, ‘<b>Summary information</b>’) > 1) { \$chunk[‘summary’] = \$table_val; } elseif (strpos(\$table_val, ‘<b>Top 5’) > 1) { \$chunk[‘top5’] = \$table_val; } elseif (strpos(\$table_val, ‘<b>By the same’) > 1) { \$chunk[‘sameauthor’] = \$table_val; } elseif (strpos(\$table_val, ‘<b>Movies</b>’) > 1) { \$chunk[‘movie’] = \$table_val; } }

// Now we’ll get the movie information if (isSet(\$chunk[‘movie’])) { // Get everything after the word “Movies” \$movie_str = strstr(\$chunk[‘movie’], ‘Movies’); // Now get the actual string value of the movie data \$movie_data_str = strstr(\$movie_str, ‘<font SIZE=-2 FACE=”ARIAL, GENEVA, SANS-SERIF”>’); \$movie_data = substr(\$movie_data_str, 47); //get rid of the font tag above //echo \$movie_data; // Now you can escape this string and put it in a database // or whatever... } ?>

931

932

Part V ✦ Case Studies

You could use this same code with a few additions to harvest all the data on this page — just copy the movie part, and replace the array names and substrings you want to select on. Now say that you want to harvest data from a whole bunch of HTML or text files. Copy them to an empty directory to minimize unintended consequences. Then you want to iterate over the files by wrapping the following cases around the preceding code: \$path = ‘/path/to/directory’; if (\$dir_handle = opendir(\$path)) { while (false !== (\$file = \$path . readdir(\$dir_handle))) { if (\$file != “.” && \$file != “..”) { // Code from harvest.php above } } }

This snippet opens a directory (which must have the proper read and execute permissions for the Web server user), iterates through all the files in that directory, and executes the harvest.php code on data from any file that isn’t a special Unix directory file. You are almost certainly going to want to run a script such as this from the command line rather than the browser because iterating over a large number of files almost guarantees ugly timeouts.

Templating Now comes the fiddly bit. This is the moment where you must take a mockup and a database, and turn them into a working Web page. There are various methods to do this, including use of a full-templating extension such as Smarty templates. Our style, however, is to lay out the main HTML in heredoc syntax, with replacement variables defined on the same page. This is one of the fastest methods, and it still maintains satisfactory separation between logic and display. Listing 47-4 shows a full-page template, in this case the one for book reviews.

Listing 47-4: Book page template (review.php) <?php /******************** * Book review page. * *********************/ // For now, pass in the id in the URI \$book_id = \$_GET[‘book_id’]; if !isSet(\$book_id) || !isNumeric(\$book_id) { echo “You did not pass in a valid book ID”; exit; } // -----------// GET THE DATA // ------------

Chapter 47 ✦ Converting Static HTML Sites

\$db = mysql_connect(‘localhost’, ‘mg_user’, ‘sesame’); mysql_select_db(‘mg’); // Book data \$query = “SELECT B_id, B_title, B_year, B_rating, B_movie, B_awards, B_review, B_similar FROM book WHERE B_id = \$book_id”; \$result = mysql_query(\$query); if (mysql_num_rows(\$result) == 1) { \$book_arr = mysql_fetch_array(\$result); } else { echo mysql_error(); } \$title = stripslashes(\$book_arr[‘B_title’]); \$year = \$book_arr[‘B_year’]; \$rating = \$book_arr[‘B_rating’]; \$movie = stripslashes(\$book_arr[‘B_movie’]); \$awards = stripslashes(\$book_arr[‘B_awards’]); \$review = stripslashes(\$book_arr[‘B_review’]); \$review_words = explode(“ “, \$review); \$chunk = array_slice(\$review_words, 0, 200); \$review = implode(‘ ‘, \$chunk); \$similar = stripslashes(\$book_arr[‘B_similar’]); // Author data \$query = “SELECT author.A_id, author.A_firstname, author.A_lastname FROM author LEFT JOIN book_author USING (A_id) WHERE book_author.B_id = \$book_id”; \$result = mysql_query(\$query); if (mysql_num_rows(\$result) == 1) { \$author_arr = mysql_fetch_array(\$result); \$author_id = \$author_arr[‘A_id’]; \$a_firstname = stripslashes(\$author_arr[‘A_firstname’]); \$a_lastname = stripslashes(\$author_arr[‘A_lastname’]); \$author = “\$a_firstname \$a_lastname”; } else { echo mysql_error(); } // Potential multiple other books by the same author \$query = “SELECT book.B_title FROM book LEFT JOIN book_author USING (B_id) Continued

933

934

Part V ✦ Case Studies

Listing 47-4 (continued) WHERE book_author.A_id = \$author_id AND book.B_id != \$book_id”; \$result = mysql_query(\$query); if (mysql_num_rows(\$result) >= 1) { while (\$titles_arr = mysql_fetch_array(\$result)) { \$titles[] = stripslashes(\$titles_arr[‘B_title’]); } \$title_str = implode(‘<BR>\n’, \$titles); } else { \$title_str = ‘None’; } // Protagonist data \$query = “SELECT protagonist.P_firstname, protagonist.P_lastname FROM protagonist LEFT JOIN book_protagonistUSING (P_id) WHERE book_protagonist.B_id = \$book_id”; \$result = mysql_query(\$query); if (mysql_num_rows(\$result) == 1) { \$prot_arr = mysql_fetch_array(\$result); \$p_firstname = stripslashes(\$prot_arr[‘P_firstname’]); \$p_lastname = stripslashes(\$prot_arr[‘P_lastname’]); \$protagonist = “\$p_firstname \$p_lastname”; } else { echo mysql_error(); } // Multiple subgenres \$query = “SELECT Sub_name FROM subgenre LEFT JOIN book_subgenre USING (Sub_id) WHERE book_subgenre.B_id = \$book_id”; \$result = mysql_query(\$query); if (mysql_num_rows(\$result) >= 1) { while (\$sub_arr = mysql_fetch_array(\$result)) { \$sub_name[] = stripslashes(\$sub_arr[‘Sub_name’]); } \$subgenre = implode(‘, ‘, \$sub_name); } else { echo mysql_error(); } // Multiple settings \$query = “SELECT Set_name FROM setting LEFT JOIN book_setting USING (Set_id) WHERE book_setting.B_id = \$book_id”; \$result = mysql_query(\$query);

Chapter 47 ✦ Converting Static HTML Sites

if (mysql_num_rows(\$result) >= 1) { while (\$set_arr = mysql_fetch_array(\$result)) { \$set_name[] = stripslashes(\$set_arr[‘Set_name’]); } \$setting = implode(‘, ‘, \$set_name); } else { echo mysql_error(); }

// -----------// DISPLAY PAGE // -----------\$php_self = \$_SERVER[‘PHP_SELF’]; // Superglobal arrays don’t work with heredoc \$page_str = <<< EOPAGESTR <HTML> <HEAD> <STYLE> TD.textblock { padding-left: 20; padding-top: 20; padding-right: 20; } P.td { font-family: arial, verdana, font-size: 8pt; } P.td_med { font-family: arial, verdana, font-size: 10pt; line-height:125% } P.title { font-family: arial, verdana, font-size: 10pt; font-weight: bold; } P.tab_links { font-family: arial, verdana, font-size: 10pt; margin-top: 17; } a { color:#006400; text-decoration:none; } a:link {color:#006400;}

sans-serif;

sans-serif;

sans-serif;

sans-serif;

Continued

935

936

Part V ✦ Case Studies

Listing 47-4 (continued) a:visited {color:#800080;} </STYLE> </HEAD> <BODY BACKGROUND=”background.gif”> <!-- Begin main table --> <TABLE BORDER=0 WIDTH=815> <TR> <TD> <IMG SRC=”spacer.gif” WIDTH=815 HEIGHT=8> </TD> </TR> <TR> <TD> <!-- Begin banner table --> <TABLE BORDER=0> <TR> <TD WIDTH=48 HEIGHT=90> <IMG SRC=”spacer.gif” WIDTH=48 HEIGHT=90> </TD> <TD WIDTH=472 HEIGHT=90 ALIGN=”center” VALIGN=”middle””> <IMG SRC=”red.png” WIDTH=460 HEIGHT=60> </TD> <TD WIDTH=14 HEIGHT=90> <IMG SRC=”spacer.gif” WIDTH=14 HEIGHT=90> </TD> <TD WIDTH=292 HEIGHT=90 VALIGN=”top” class=”textblock”> <P class=”td”>a Troutworks, Inc. site<BR> &#169; 1994 - 1999 Troutworks, Inc.</P> <P class=”td”>Last updated July 6, 1999</P> </TD> </TR> </TABLE> <!-- End banner table --> </TD> </TR> <TR> <TD> <!-- Begin title table --> <TABLE BORDER=0> <TR> <TD WIDTH=140 HEIGHT=30> <IMG SRC=”spacer.gif” WIDTH=140 HEIGHT=30> </TD> <TD WIDTH=330 HEIGHT=30 ALIGN=”center” VALIGN=”bottom”>

Chapter 47 ✦ Converting Static HTML Sites

<P class=”title”>\$title</P> </TD> <TD WIDTH=345 HEIGHT=30> <IMG SRC=”spacer.gif” WIDTH=345 HEIGHT=30> </TD> </TR> </TABLE> <!-- End title table --> </TD> </TR> <TR> <TD> <!-- Begin info table --> <TABLE BORDER=0> <TR> <TD WIDTH=135 HEIGHT=350 ROWSPAN=2 ALIGN=”left” VALIGN=”top” style=”padding-left:22; padding-top:40”> <P class=”td”> <A HREF=”newbooks.html”>New Reviews</A><BR> <A HREF=”readerratings.html”>Reader ratings</A></P> <P class=”td”> GENRES<BR> <A HREF=”caper.html”>Caper</A><BR> <A HREF=”classic-whodunit.html”>Classic whodunit</A><BR> <A HREF=”cozy.html”>Cozy</A><BR> <A HREF=”espionage.html”>Espionage</A><BR> <A HREF=”forensic.html”>Forensic</A><BR> <A HREF=”hard-boiled.html”>Hard-boiled</A><BR> <A HREF=”historical.html”>Historical</A><BR> <A HREF=”legal.html”>Legal</A><BR> <A HREF=”military.html”>Military</A><BR> <A HREF=”police-procedural.html”>Police procedural</A><BR> <A HREF=”political.html”>Political</A><BR> <A HREF=”private-eye.html”>Private eye</A><BR> <A HREF=”serial-killer.html”>Serial killer</A><BR> <A HREF=”sf-mystery.html”>SF mystery</A><BR> <A HREF=”special-subject.html”>Special subject</A><BR> <A HREF=”suspense.html”>Suspense</A><BR> <A HREF=”thriller.html”>Thriller</A></P> </TD> <TD WIDTH=15 HEIGHT=350 ROWSPAN=2> <IMG SRC=”spacer.gif” WIDTH=15 HEIGHT=350> </TD> <TD> <TABLE BORDER=0 WIDTH=665> <TR> <TD WIDTH=350 HEIGHT=240 ALIGN=”left” VALIGN=”top” style=”padding-left:11”> Continued

937

938

Part V ✦ Case Studies

Listing 47-4 (continued) <P class=”tab_links”>Read Reviews</P> <P class=”tab_links”>Browse by:&nbsp;&nbsp;&nbsp; Genre | <A HREF=”authorlist.html”>Author</A> | <A HREF=”authorlist.html”>Title</A> | <A HREF=”readerratings.html”>Ratings</A></P> <P class=”tab_links”>Author: \$author<BR> Protagonist name: \$protagonist<BR> Year published: \$year<BR> Subgenres: \$subgenre<BR> Setting: \$setting</P> </TD> <TD WIDTH=334 HEIGHT=240 ALIGN=”left” VALIGN=”top” style=”padding-left:13”> <P class=”td”><B>Other Reviewed Titles By This Author</B><BR>\$title_str </P> <P class=”td”><B>Top 5 Most Similar Titles</B><BR>\$similar </P> <P class=”td”><B>Movie versions</B><BR>\$movie</P> </TD> </TR> </TABLE> </TD> </TR> <TR> <TD WIDTH=665 HEIGHT=100> <TABLE BORDER=0 WIDTH=665> <TR> <TD WIDTH=250 HEIGHT=100 ALIGN=”left” VALIGN=”top” style=”padding-left:13”> <P class=”title”>Our rating: \$rating <BR>Community rating: \$comm_rating</P> <P class=”td_med”><B>Awards:</B> \$award</P> </TD> <TD WIDTH=415 HEIGHT=100 ALIGN=”left” VALIGN=”top” style=”padding-left:40; padding-top:7”> <IMG SRC=”red.png” WIDTH=350 HEIGHT=80> </TD> </TR> </TABLE> </TD> </TR> </TABLE> <!-- End info table --> </TD>

Chapter 47 ✦ Converting Static HTML Sites

</TR> <TR> <TD> <!-- Begin review table --> <TABLE BORDER=0> <TR> <TD WIDTH=40 HEIGHT=250> <IMG SRC=”spacer.gif” WIDTH=40 HEIGHT=250> </TD> <TD WIDTH=560 HEIGHT=250 class=”textblock”> <P CLASS=”td_med”>\$review <A HREF=”\$php_self?format=review_only”> ...READ COMPLETE REVIEW...</A></P> </TD> <TD WIDTH=155 HEIGHT=250 ALIGN=”left” VALIGN=”top” style=”padding-left:10; padding-top:5”> <P class=”title”>What did YOU think?</P> <P class=”td”>Read this book? Rate it!</P> <FORM><INPUT TYPE=”submit” VALUE=”5 - Superb”></FORM> <FORM><INPUT TYPE=”submit” VALUE=”4 - Very Good”></FORM> <FORM><INPUT TYPE=”submit” VALUE=”3 - Good”></FORM> <FORM><INPUT TYPE=”submit” VALUE=”2 - Mediocre”></FORM> <FORM><INPUT TYPE=”submit” VALUE=”1 - Poor”> </TD> <TD WIDTH=40 HEIGHT=250> <IMG SRC=”spacer.gif” WIDTH=40 HEIGHT=260> </TD> </TR> </TABLE> <!-- End review table --> </TD> </TR> <TR> <TD> <!-- Begin credits table --> <TABLE BORDER=0 HEIGHT=65> <TR> <TD WIDTH=25> <IMG SRC=”spacer.gif” WIDTH=25 HEIGHT=65> </TD> <TD WIDTH=790 HEIGHT=65 VALIGN=”bottom” style=”padding-left:25;padding-bottom:28”> <P class=”td”>FAQs | Team Trout | Privacy | Advertising | Email Us</P> </TD> </TR> Continued

939

940

Part V ✦ Case Studies

Listing 47-4 (continued) </TABLE> <!-- End credits table --> </TD> </TR> </TABLE> <!-- End main table --> </BODY> </HTML> EOPAGESTR; echo \$page_str; ?>

The results of the preceding book review page are shown in Figure 47-3. If you compare this figure with Figure 47-2, it is immediately obvious that we’ve simplified the elements somewhat. Inevitably, as you move toward a final layout in actual HTML, you find that not everything envisioned by the designer can be easily implemented. In this case, we found that the small visual elements such as the title area and “Browse By” navbar are extremely fiddly and difficult to lay out decently in HTML without enormous overhead in pixel-level layout. It’s difficult to know these things until you actually begin work on a production template. Your designers should be willing to work with you to make small tweaks at this point.

Figure 47-3: Templated version of book review page

Chapter 47 ✦ Converting Static HTML Sites

Performance and Caching At this stage you should do some performance testing and evaluation. You want to get decent estimates of: ✦ Server latency: How long the code takes your server to produce. ✦ Network latency: How long it takes to get the code down the pipe to you. ✦ Browser latency: How long it takes a browser to completely render the page. You can measure server latency by putting microtime() calls at the beginning and end of each page, like this: <?php \$begin_time = microtime(); // Your script here \$end_time = microtime(); \$duration = \$end_time - \$begin_time; echo \$duration; ?>

941

942

Part V ✦ Case Studies

Finally, take a look at browser latency. The best way to do this is to get on a known slow browser — Internet Explorer 5.1 for Macintosh is supposedly the market leader in this category — and actually time how long it takes from the initial request to the moment you see a complete Web page in your browser. Because a lot of this is controlled by the particular browser, there’s not much you can do — except to realize that complicated layouts featuring massive tables, immense amounts of nonbreaking spaces, and hundreds of transparent single-pixels add to rendering time.

Chapter 47 ✦ Converting Static HTML Sites

Summary PHP books usually assume that you are starting a site from scratch — but in the real world, another very common scenario is to upgrade an existing static site. PHP and a database can be used to take large, messy, hard-to-maintain HTML sites and make them dynamic. This makes the sites much easier to maintain, because they are assembled by PHP from data in a database. Instead of maintaining hundreds of HTML files, you can just work on one template and let PHP assemble the pages on-the-fly. Before you do any work, you should take the time to assess your site’s strategy and map out the goals you wish to accomplish. You should also gain a clear understanding of your site’s structure and the resources you will need to support your new design. After that, you must test your new design, create a new database, load data from possibly disparate sources into the database, and create PHP template pages. Finally, you should assess the performance of your new dynamic site and possibly take steps to improve it.

943

48 C H A P T E R

Data Visualization with Venn Diagrams

In This Chapter

I

n this chapter’s case study, we show one way to use PHP to combine MySQL databases with graphic images. We build a complete system that starts with a database and uses the gd library to produce a kind of visualization of the data. The portions of the book we draw on for this are: ✦ Part II: We use PHP to interrogate a MySQL database. ✦ Chapter 42 (Graphics): Our end-product is an image produced with the gd library. ✦ Chapter 27 (Mathematics): We need a bit of trigonometry as we create the images.

Scaled Venn Diagrams The visualization we have in mind is something like the Venn diagram. If you’ve ever been in an academic setting where set intersection was being discussed, then you’ve probably seen these diagrams — they’re the circles that may or may not have overlapping portions representing intersections. We say “something like” the Venn diagram, because scale has no significance in a traditional Venn diagram. If you want to illustrate the fact that there are people who use both BeOS and Windows, then you might draw two circles of equal size (representing Windows users and BeOS users) that happen to have a region of overlap. In our version, which you might call a scaled or proportional Venn diagram, the sizes of both circles and intersections matter; the Windows/BeOS example would become one large circle and one much smaller circle, with an overlap area proportional to the number of people in both sets. (To see an example of this kind of diagram, please skip ahead to Figure 48-5.)

The task The job of our code is to start with a database, provide a way to query that database about sets and their overlap, and then display the results as a scaled Venn diagram, generated by using the gd library. As a sample database, we use the pseudosurvey dataset that we used in the “HTML Graphics” section of Chapter 42.

From database to image Scaled Venn diagrams Planning the display Putting it all together

946

Part V ✦ Case Studies

If we’re going to offer a way to query the database, then it may as well be via a Web form. So the end-to-end view of our task is that we start with a Web form and end up with a picture to display. Let’s start the design by enumerating the things that need to happen for this to come about. We’ll need to: 1. Generate (or at least present) the Web form itself. 2. Receive the submitted form data and transform it into appropriate SQL queries for submission to the database. 3. Receive results from the SQL queries. 4. Use the SQL results to decide on the locations and sizes of all the elements in our graphic. 5. Actually generate the graphic and send it back to the user. Note

All of the code in this chapter should work with either PHP4 or PHP5, but it assumes that your PHP installation has access to the gd image library and is configured to produce PNG images. Any version of gd later than 1.8, bundled or unbundled, should be OK. (See Chapter 42 for details of configuration and installation of gd.)

Outline of the Code Our system contains the following code files: ✦ visualization_form.php: This is essentially a hard-coded form that enables the user to choose two different restrictions on the data in our table. The restrictions chosen map directly to where clauses loaded from an auxiliary file called query_clauses.php. ✦ db_visualization.php: This code handles the form data sent by visualization_ form.php and builds three SQL statements: one with only the first where clause, one with the second where clause, and a third with both clauses joined by an and. It collects resulting three counts and displays the numbers in a graphic by calling functions loaded from venn.php. ✦ venn.php: This actually produces the Venn diagram graphic and ships it back to the user. Its primary function takes as input the three amounts (the sizes of the two sets and their intersection), decides the sizes and locations of corresponding circles, and does all the drawing and shading necessary. For the complicated case of sets that actually have an overlapping area, it uses functions loaded from trig.php to calculate areas. ✦ trig.php: This code actually calculates the intersection area whenever circles overlap. We discuss these code files in reverse order, from the bottom up. By the way, although we like this example, we don’t want to give the impression that you need to do trigonometry to do computer graphics in PHP, or even vector graphics in PHP. If you want to understand every bit of this example, then you need to go through the trig, but we encourage those who don’t care to skip the next section (“Necessary trigonometry”). The core of the graphics code itself is in venn.php, and that example code really is important to understand if you want to do gd-based graphics in PHP.

Chapter 48 ✦ Data Visualization with Venn Diagrams

Necessary Trigonometry Let’s get the math out of the way first. Unavoidably, because we’re talking about circles and areas, we’re going to be talking about trigonometry. (As we’ve said, though, if you’re not interested and are willing to trust us that we have code to calculate the area of circle intersections, please do skip ahead to the section “Planning the display,” later in this chapter.) The eventual task for our system is to start with three quantities (items in set A, items in set B, and items in the intersection) and produce a diagram containing two circles, with areas proportional to the set sizes, and positioned so that the area of overlap is proportional to the size of the intersection. For this section, we go in the other direction and calculate intersection area from given circles. Our starting information will be the radii of the two circles and the distance between their centers. With reference to Figure 48-1, say that our circles have centers at points C and D, respectively, and that we know the radius of the circle on the left (segment CA or segment CB) and the radius of the circle on the right (DA or DB). What we’d like to know is the size of that odd lens-shaped object in the middle.

Area of intersecting circles A

C

D

B Figure 48-1: Area of intersection The lens-shaped intersection area is split into two “halves” by segment AB (not quite halves because the circle sizes may be different), and we can calculate the area of each half independently. The crucial thing to notice is that the area of each of these half-lenses is the area that you get after you subtract the area of a triangle from the area of a pizza-slice-shaped sector of a circle. The right-hand lens half, for example, has an area equal to the sector of the left-hand circle determined by angle ACB, minus the area of the triangle ACB. So if we can calculate the areas of sectors and triangles, then we are nearly done. The area of a sector is straightforward — it’s just the area of the circle multiplied by the fraction of that circle that the angle of the sector sweeps over.

947

948

Part V ✦ Case Studies

It takes a little more work and trigonometry to get the areas of the triangles. In our code, we make the job more straightforward by drawing a line from point C to point D, and considering only the half of the diagram above that line — then at the end, we multiply by two to get the real area. If we say that the intersection of segments AB and CD is point E, what we eventually care about is the area of triangles CAE and DAE. We start by calculating the angles of triangle CDA (whose side lengths are known to us) and, by using that information, determining the lengths of CE, DE, and AE. After we know these lengths, we know the bases and heights, and the areas of the right triangles CAE and DAE are just 1⁄2 (base × height). Listing 48-1 shows code to do this kind of area calculation. Its main “public” function is circle_intersection_area(), which expects as arguments the radii of two circles and the

distance between them. The simplest case is where the distance is greater than the sum of the radii: The circles do not touch; there is no intersection, and the answer is zero.

Listing 48-1: trig.php <?php function angle_given_sides (\$opposite, \$other_1, \$other_2) { if ((\$opposite <= 0) || (\$other_1 <= 0) || (\$other_2 <= 0) || (\$opposite >= (\$other_1 + \$other_2)) || (\$other_1 >= (\$opposite + \$other_2)) || (\$other_2 >= (\$other_1 + \$opposite))) { die(“Triangle with impossible side lengths in “. “angle_given_sides: \$opposite, \$other_1, \$other_2”); } else { \$numerator = (((\$other_1 * \$other_1) + (\$other_2 * \$other_2)) (\$opposite * \$opposite)); \$denominator = 2 * \$other_1 * \$other_2; return(acos(\$numerator / \$denominator)); } } function area_to_radius (\$area) { return (sqrt (\$area / M_PI)); } function circle_intersection_area (\$radius_left, \$radius_right, \$distance) { if (\$radius_right + \$radius_left <= \$distance) { return(0); } else { // first, we find the angle measures of a triangle

Chapter 48 â&#x153;Ś Data Visualization with Venn Diagrams

test for obtuseness --- the sector angle can be obtuse, but the triangle angle should not be. Also save the result as a sign for the eventual area calculation

if (\$left_sector_angle < M_PI / 2) { \$left_triangle_angle = \$left_sector_angle; \$left_triangle_sign = 1; } else { \$left_triangle_angle = M_PI - \$left_sector_angle; \$left_triangle_sign = -1; } if (\$right_sector_angle < M_PI / 2) { \$right_triangle_angle = \$right_sector_angle; \$right_triangle_sign = 1; } else { \$right_triangle_angle = M_PI - \$right_sector_angle; \$right_triangle_sign = -1; } // next, find the height of that triangle, assuming // the distance is the base \$height = (\$radius_left / sin(M_PI_2)) * sin(\$left_triangle_angle); \$base_left = (\$radius_left / sin(M_PI_2)) * sin(M_PI_2 - \$left_triangle_angle); \$base_right = (\$radius_right / sin(M_PI_2)) * sin(M_PI_2 - \$right_triangle_angle); // // // // //

finally find triangle and sector areas, and subtract (or add) appropriately to get the intersection area. Multiply by 2 to reflect areas on both sides of the segment connecting the circle centers

\$left_triangle_area = \$base_left * \$height / 2; \$right_triangle_area = \$base_right * \$height / 2; \$left_sector_area = Continued

949

950

Part V ✦ Case Studies

Listing 48-1 (continued) (\$left_sector_angle / (2 * M_PI)) * (M_PI * \$radius_left * \$radius_left); \$right_sector_area = (\$right_sector_angle / (2 * M_PI)) * (M_PI * \$radius_right * \$radius_right); \$intersection_area = 2 * ((\$left_sector_area (\$left_triangle_sign * \$left_triangle_area)) + (\$right_sector_area (\$right_triangle_sign * \$right_triangle_area))); return(\$intersection_area); } } ?>

Note that all the angle calculations are in radians, rather than degrees. In radians, a right angle is pi/2, and a complete revolution around a circle is 2 × pi. We tend to use PHP constants for these values whenever we can, in particular M_PI (the value of pi), and M_PI_2 (pi/2). There’s one final wrinkle that we’ve ignored in our discussion so far, but which we had to deal with in the code. The problem is that it’s possible for either angle ACE or angle ADE (as we call them in Figure 48-1) to be obtuse — that is, more than 90 degrees in size. To see this, look at that diagram and imagine what happens as you make the circle on the right smaller, and move its center D progressively closer to C. At some point D actually moves to the left of segment AB. In this case, the circle intersection area to the left of AB is actually the sum of a sector and a triangle rather than a difference. The sector determined by DA and DB sweeps out more than half of the circle centered at D, and the remaining portion we want to include is the area of the triangle ADB. We handle this in the code by testing if the angles are obtuse, and multiplying the triangle areas by either 1 or -1, depending on the result of the test.

Planning the Display Now we pop up a couple of levels and think about actually generating a diagram. We assume that we have as input three numbers (size of set 1, size of set 2, and size of intersection), along with some textual labels. We want to scale and locate these circles so that everything has the right area, labels get associated with the right circles, and everything fits within the size of the diagram we’re creating.

Simplifying assumptions We start off with some totally arbitrary decisions that, after being made, simplify everything. We decree that: ✦ All the images that we generate are the same size, and that size is 300 pixels high and 600 pixels wide.

Chapter 48 ✦ Data Visualization with Venn Diagrams

✦ The centers of the circles are always on the same horizontal line. This means that their y-coordinate is decided in advance, and we change the area of intersection just by changing the x-coordinates. ✦ The circles always fit within the top two-thirds of the diagram (reserving the lower third for labels). So put the y-coordinate of the centers one-third of the way down the image from the top. And because the circles may not intersect at all, they shouldn’t be larger than half of the width of the image, so we have room to display two of them. We also make sure that the circles are no greater than 90 percent of the room available given everything we’ve said so far, so that they don’t touch the image borders. Finally, we decide that, regardless of the actual numbers as input, the larger of the two circles is as large as it can be. (Scale is consistent within the diagram, but not between diagrams.)

The easy cases Where we decide to put the circle centers depends on the extent to which our sets overlap. There are some cases that we can dispense with, that don’t need all this trigonometry we’ve been spending our time on. Those are: ✦ No items are in the intersection. In this case, we don’t want the circles to touch at all. We simply locate the centers at default locations in the middles of the two halves of the diagram. Because of the way that we limited the maximum radius, the circles are completely separated.

951

952

Part V ✦ Case Studies

✦ One set is completely contained in the other — that is, one of the sets has the same size as the intersection. For this case, we just choose to put the center of the larger circle in the middle of the diagram and the middle of the other circle offset a bit from it but not so much that any of the smaller circle is outside the larger one. ✦ The two sets are the same (and all three input numbers are the same). For this, we just draw one circle with an x-coordinate right in the middle of the picture.

The hard case Now the hard one: If the sets only partially overlap, where should we put the circle centers? At this point, we have some math in our pocket from the “Necessary trigonometry” section: Given two circles and the distance between their centers, we can figure out the area of overlap. Unfortunately, this is not the direction we need the calculation go in — we start with the desired area of intersection, and we must work backwards to the desired locations of the circle centers. Now if we were good and diligent mathematicians but lazy programmers, we would just invert the trigonometric equations we used in trig.php, to solve for center distance rather than for intersection area. As it is, though, we’re enthusiastic programmers, and if we’re any kind of mathematicians at all we’re definitely the lazy kind. So what we’re going to do instead is search for the answer. The function find_circle_centers() in Listing 48-2 implements a binary search for the answer: It starts with a middling distance, asks our trigonometry code what the resulting area would be, and successively refines the distance to zero in on the desired area. (The rest of the code in Listing 48-2 is discussed in the next section.)

Listing 48-2: venn.php <?php include_once(“trig.php”); \$IMAGE_WIDTH = 600; \$IMAGE_HEIGHT = 300; \$CENTER_FINDING_ITERATIONS = 20; function imagecircle (\$image, \$center_x, \$center_y, \$radius, \$color) { \$diameter = \$radius * 2; imagearc(\$image, \$center_x, \$center_y, \$diameter, \$diameter, 0, 360, \$color); } function venn_visualization (\$left_amount, \$left_name, \$right_amount, \$right_name, \$intersection_amount) { global \$IMAGE_HEIGHT, \$IMAGE_WIDTH, \$CENTER_FINDING_ITERATIONS;

Chapter 48 ✦ Data Visualization with Venn Diagrams

We now have all necessary info except where to locate the centers of the circles. Four cases: 1) no intersection, 2) partial intersection 3) left is strict subset of right, 4) right is subset of left.

if (\$intersection_amount == 0) { // No intersection Continued

953

954

Part V â&#x153;Ś Case Studies

Chapter 48 ✦ Data Visualization with Venn Diagrams

} else if ((\$intersection_area == \$area_left_side) && (\$intersection_area < \$area_right_side)) { // The right set completely contains the left set // We need to place the left circle somewhere // inside the right circle. \$center_x_right = \$middle_x; \$center_x_left = \$middle_x (\$radius_right_side - \$radius_left_side) / 2; \$left_fill_x = -1; \$right_fill_x = ((\$center_x_left + \$radius_left_side) + (\$center_x_right + \$radius_right_side)) / 2.0; \$intersection_fill_x = \$center_x_left; } else if (\$intersection_area == \$area_right_side) { \$center_x_left = \$middle_x; \$center_x_right = \$middle_x + (\$radius_left_side - \$radius_right_side) / 2; \$right_fill_x = -1; \$left_fill_x = ((\$center_x_left - \$radius_left_side) + (\$center_x_right - \$radius_right_side)) / 2.0; \$intersection_fill_x = \$center_x_right; } // now, actually draw and fill regions imagecircle(\$image, \$center_x_left, \$center_y, \$radius_left_side, \$black_color); imagecircle(\$image, \$center_x_right, \$center_y, \$radius_right_side, \$black_color); if (\$left_fill_x > 0) { imagefill(\$image, \$left_fill_x, \$center_y, \$left_color); } if (\$right_fill_x > 0) { imagefill(\$image, \$right_fill_x, \$center_y, \$right_color); } if (\$intersection_fill_x > 0 ) { imagefill(\$image, \$intersection_fill_x, \$center_y, \$intersection_color); } \$left_hand_text = “\$left_name (\$left_amount)”; \$right_hand_text = “\$right_name (\$right_amount)”; \$intersection_text = “Intersection: \$intersection_amount”; left_label(\$image, \$left_hand_text, \$left_color); Continued

955

956

Part V ✦ Case Studies

Listing 48-2 (continued) right_label(\$image, \$right_hand_text, \$right_color); intersection_label(\$image, \$intersection_text, \$black_color); // send off the image header(“Content-type: image/png”); imagepng(\$image); imagedestroy(\$image); } function left_label (\$image, \$label_string, \$color) { global \$IMAGE_WIDTH, \$IMAGE_HEIGHT; imagestring(\$image, 5, (\$IMAGE_WIDTH / 4.0 (imagefontwidth(5) * strlen(\$label_string)) / 2), \$IMAGE_HEIGHT - 55.0, \$label_string, \$color); } function right_label (\$image, \$label_string, \$color) { global \$IMAGE_WIDTH, \$IMAGE_HEIGHT; imagestring(\$image, 5, (\$IMAGE_WIDTH * 3 / 4.0 (imagefontwidth(5) * strlen(\$label_string)) / 2), \$IMAGE_HEIGHT - 55.0, \$label_string, \$color); } function intersection_label (\$image, \$label_string, \$color) { global \$IMAGE_WIDTH, \$IMAGE_HEIGHT; imagestring(\$image, 2, (\$IMAGE_WIDTH / 2.0 (imagefontwidth(2) * strlen(\$label_string)) / 2), \$IMAGE_HEIGHT - 30.0, \$label_string, \$color); } function find_center_distance (\$r1, \$r2, \$desired_area, \$iterations) { // The greatest possible distance is r1 + r2, and // the smallest is abs(r1 - r2) Let’s start in the middle. \$distance_guess = ((\$r1 + \$r2) + abs(\$r1 - \$r2)) / 2.0; \$distance_increment = ((\$r1 + \$r2) - abs(\$r1 - \$r2)) / 4.0; for (\$x = 0; \$x < \$iterations; \$x++) { \$calculated_area =

Chapter 48 ✦ Data Visualization with Venn Diagrams

circle_intersection_area(\$r1, \$r2, \$distance_guess); if (\$calculated_area < \$desired_area) { // move centers closer \$distance_guess -= \$distance_increment; \$distance_increment *= 0.5; } else if (\$calculated_area > \$desired_area) { // move centers apart \$distance_guess += \$distance_increment; \$distance_increment *= 0.5; } else { // unlikely, but ya never know break; } } return(\$distance_guess); } ?>

Display Now we know exactly where we want to put our circles, and how large they should be. What remains is the graphics code to actually make the display happen. This is also in Listing 48-2 (venn.php). To produce the graphic, we go through the following steps by using the gd library (which is covered in Chapter 42): 1. We create an image by using ImageCreate(). (At this point, the image is not any particular image format, such as PNG or JPEG, but just an internal gd image.) 2. We allocate colors within the image by using ImageColorAllocate(). We care about five colors: the background color (white), a color for borders and regular text (black), a color for the interior of the left hand circle (which we decide is bluish), a color for the interior of the right-hand circle (reddish), and a color for the intersection (gray). All these colors are specified by using a red-green-blue scale of 0 to 255. 3. We draw the circles in black by using a function of our own, imagecircle(), that takes as arguments the image, the radius, the location of the centers, and a color. (See the “Notes on circles” section about drawing circles in gd.) 4. Now, we want to fill in the three areas (the intersection and the two non-intersection portions of the circles) with the appropriate colors. We use ImageFill() for this, which flood-fills outward from a specified point until the fill encounters previously drawn lines. Choosing the starting points for the fills is somewhat tricky because it depends on the different intersection cases. In general, though, we start with a y-coordinate that is the same as the circle centers and calculate an x-coordinate that’s right in the middle of the area we are trying to color.

957

958

Part V ✦ Case Studies

5. We use ImageString() to draw the appropriate labels for each circle, centering each one in the middle of the lower-third of the image and in the middle of the appropriate left-right half. We also create and display a count label for the intersection and display it in the middle of the image. 6. Now, we have a complete gd image, and what remains is to ship it off to the user. We send an HTTP header advising the browser that a PNG image is on the way. Then we use ImagePng() to convert the gd image to PNG and send it off. 7. Finally, we call ImageDestroy() to free any resources associated with the temporary image we created. More recent versions of PHP should be handling this already, assuming that the image is of type resource, but either way calling ImageDestroy() does no harm.

Notes on circles One thing that puzzles people sometimes, if confronted with the gd functions, is that there seems to be no way to draw a circle (or at least there is no function name with circle in its name). This is because there are at least two functions that generalize circle-drawing: imageellipse() (available only with gd 2.0.1 and later) and imagearc. The former draws an ellipse (which can be a circle if the width and height are the same), and the latter draws a circular arc portion (which can be a circle if you specify a full 360 degrees of arc). In our code, we chose the latter because we wanted to remain compatible with earlier versions of gd.

Notes on centering text As we wrote textual labels in the image code, we actually didn’t bother centering the text around any horizontal axis, but we did do some left-right centering. We simply used a built-in numbered font from gd, calculated the width of our text as displayed by that font (by using imagefontwidth()) and ensured that the left-hand starting point for the text was our desired center minus half the width of the text. This was easy, in part because the built-in fonts we used were monospace, and so imagefontwidth() was able to calculate width by referring only to the length of the string. Things get slightly more complicated if you’re using a variable-width font — any calculation of string width then needs to know the actual string that is printed, not just the number of characters in it.

Visualizing a Database We can now produce these Venn-like diagrams on demand, given some numbers and text to start with. Our final task is to hook this up appropriately to a database via a Web form. Note

For this application, we assume exactly the same sample MySQL table (programmers) as we used in Chapter 42. See Listing 42-1 for a description of the data.

The goal is to let the user choose exactly two restrictions on our database’s table, extract counts corresponding to how many rows survive each restriction, count how many rows survive both restrictions, and then pass the results off to our diagramming code. Listing 48-3 shows code for a form designed around our particular database, mostly just hardcoded HTML. It loads an auxiliary file called query_clauses.php (shown in Listing 48-4), which is extremely hard-coded. This file lists and numbers all the restrictions that we want to offer to users, in the form of both an SQL where clause and in an English translation.

Chapter 48 ✦ Data Visualization with Venn Diagrams

Listing 48-3: visualization_form.php <HTML><HEAD><TITLE>DB Visualization</TITLE></HEAD> <BODY> <B>Choose one from each column, and we’ll<B> display the intersection from the survey data:<BR> <FORM METHOD=POST ACTION=”db_visualization.php” TARGET=_new > <TABLE> <?php include(“query_clauses.php”); for (\$x = 0; \$x < count(\$QUERY_CLAUSES); \$x++) { print(“<TR><TD><INPUT TYPE=RADIO NAME=\”left_clause\” VALUE=\$x>”. \$QUERY_DESCRIPTION[\$x] .”</TD> <TD><INPUT TYPE=RADIO NAME=\”right_clause\” VALUE=\$x>”. \$QUERY_DESCRIPTION[\$x] .”</TD></TR>”); } ?> </TABLE> <INPUT TYPE=HIDDEN NAME=”table” VALUE=”programmers”> <INPUT TYPE=SUBMIT NAME=SUBMIT> </FORM> </BODY> </HTML>

Notice that this form is not self-submitting. For this example, we’ve chosen to completely separate PHP-generated HTML pages from PHP-generated PNG pages and avoid the complexity of embedding images in HTML. We’ve also chosen a _new target type for the form submission so that the image appears in a new browser window.

Listing 48-4: query_clauses.php <?php \$QUERY_CLAUSES = array(); \$QUERY_DESCRIPTION = array(); \$QUERY_CLAUSES[0] = “sex = ‘F’”; \$QUERY_DESCRIPTION[0] = “Female”; \$QUERY_CLAUSES[1] = “sex = ‘M’”; Continued

959

960

Part V ✦ Case Studies

Listing 48-4 (continued) \$QUERY_DESCRIPTION[1] = “Male”; \$QUERY_CLAUSES[2] = “language = ‘PHP’”; \$QUERY_DESCRIPTION[2] = “likes PHP”; \$QUERY_CLAUSES[3] = “language = ‘Java’”; \$QUERY_DESCRIPTION[3] = “likes Java”; \$QUERY_CLAUSES[4] = “language = ‘Lisp’”; \$QUERY_DESCRIPTION[4] = “likes Lisp”; \$QUERY_CLAUSES[5] = “language = ‘C’”; \$QUERY_DESCRIPTION[5] = “likes C”; \$QUERY_CLAUSES[6] = “language = ‘Perl’”; \$QUERY_DESCRIPTION[6] = “likes Perl”; \$QUERY_CLAUSES[7] = “os = ‘Linux’”; \$QUERY_DESCRIPTION[7] = “uses Linux”; \$QUERY_CLAUSES[8] = “os = ‘Solaris’”; \$QUERY_DESCRIPTION[8] = “uses Solaris”; \$QUERY_CLAUSES[9] = “os = ‘MacOS’”; \$QUERY_DESCRIPTION[9] = “uses MacOS”; \$QUERY_CLAUSES[10] = “os = ‘Windows’”; \$QUERY_DESCRIPTION[10] = “uses Windows”; \$QUERY_CLAUSES[11] = “age < 20”; \$QUERY_DESCRIPTION[11] = “is less than 20 years old”; \$QUERY_CLAUSES[12] = “age > 30”; \$QUERY_DESCRIPTION[12] = “is over 30 years old”; \$QUERY_CLAUSES[13] = “continent = ‘North America’”; \$QUERY_DESCRIPTION[13] = “lives in North America”; \$QUERY_CLAUSES[14] = “continent = ‘South America’”; \$QUERY_DESCRIPTION[14] = “lives in South America”; \$QUERY_CLAUSES[15] = “continent = ‘Antarctica’”; \$QUERY_DESCRIPTION[15] = “lives in Antarctica”; \$QUERY_CLAUSES[16] = “continent = ‘Asia’”; \$QUERY_DESCRIPTION[16] = “lives in Asia”; \$QUERY_CLAUSES[17] = “continent = ‘Europe’”; \$QUERY_DESCRIPTION[17] = “lives in Europe”; ?>

Chapter 48 ✦ Data Visualization with Venn Diagrams

A screenshot of the form itself is shown in Figure 48-2.

Figure 48-2: DB visualization Web form One last code file and we’re done. We have our image creation code and a form for requesting an image. The last piece of the puzzle is code to handle the form submission, perform the appropriate counts on the database, and call the image code. This code is shown in Listing 48-5.

Listing 48-5: db_visualization.php <?php include_once(“dbconnect.php”); include_once(“query_clauses.php”); include_once(“venn.php”); if (IsSet(\$_POST[‘table’]) && IsSet(\$_POST[‘left_clause’]) && IsSet(\$_POST[‘right_clause’])) { \$table = \$_POST[‘table’]; \$left_clause_id = \$_POST[‘left_clause’]; \$right_clause_id = \$_POST[‘right_clause’]; \$left_clause = \$QUERY_CLAUSES[\$left_clause_id]; Continued

961

962

Part V ✦ Case Studies

Listing 48-5 (continued) \$right_clause = \$QUERY_CLAUSES[\$right_clause_id]; visualize_intersection (\$table, \$left_clause, \$right_clause); } else { print(“Form submission not handled correctly.<BR>”. “Did you choose all options?”); } function visualize_intersection (\$table, \$left_clause, \$right_clause) { \$left_query = “select count(*) from \$table where \$left_clause”; \$right_query = “select count(*) from \$table where \$right_clause”; \$intersection_query = “select count(*) from \$table where \$left_clause and \$right_clause”; \$result = mysql_query(\$left_query) or die(“Query was \$left_query:” . mysql_error()); \$row = mysql_fetch_row(\$result); \$left_count = \$row[0]; \$result = mysql_query(\$right_query) or die(mysql_error()); \$row = mysql_fetch_row(\$result); \$right_count = \$row[0]; \$result = mysql_query(\$intersection_query) or die(mysql_error()); \$row = mysql_fetch_row(\$result); \$intersection_count = \$row[0]; venn_visualization(\$left_count, \$left_clause, \$right_count, \$right_clause, \$intersection_count); } ?>

The submission form passes in index numbers of SQL clauses, rather than the clauses themselves, so we don’t need to worry about escape characters in the submission. The formhandling code includes the same query_clauses.php file, so the index numbers should always agree. The form handler collects the two clauses, creates three SQL statements out of them, executes the statements to get counts, and uses the results as arguments to the venn_visualization() function.

Chapter 48 ✦ Data Visualization with Venn Diagrams

Note that Listing 48-5 refers to one auxiliary code file we haven’t mentioned yet: dbconnect. php. We assume that this file contains (or refers to a file containing) your MySQL username and password, and also makes a call to mysql_connect() to create a global DB connection for the rest of the script. Something like the following should suffice: <?php \$user = ‘USER’; \$pass = ‘PASS’; \$db = ‘venn’; mysql_connect(‘localhost’, \$user, \$pass) or die(“Couldn’t make DB connection:” . mysql_error()); mysql_select_db(\$db); ?>

This assumes that your username and password are replaced appropriately, and that you have a MySQL database called venn, which contains a table called programmers, as described in Chapter 42.

Trying it out Now that our system is complete, let’s give it a spin. Bringing up visualization_form.php, we choose the first option from the left-hand column (Female), and the second option from the right-hand column (Male), and submit. The result is shown in Figure 48-3 — two separate circles because, given the database schema, it’s impossible for anyone to be both male and female. (Please, no e-mails about the narrowness of our views — it’s just an example!)

Figure 48-3: No intersection On a color monitor the left-hand circle is bluish while the right-hand circle is reddish. Because this is a grayscale book, though, you probably see two gray or black circles. Now a different query: uses Solaris on the left, and lives in Antarctica on the right. (We chose this deliberately, knowing that our lone South Pole correspondent sees only one kind of Sun during the winter.)

963

964

Part V ✦ Case Studies

The result is shown in Figure 48-4: one small gray circle inside a larger blue one, indicating that all Antarcticans are Solaris users but not vice versa.

Figure 48-4: Subset Finally, for the more typical case, let’s choose likes PHP from the left, and uses Linux from the right. The result, in Figure 48-5, is two mostly overlapping circles. (Again, please no letters — we have no idea if these proportions match the world as it is or just the world as we would like it to be.)

Figure 48-5: Partial intersection

Chapter 48 ✦ Data Visualization with Venn Diagrams

Extensions This example works nicely, but as always there are countless ways in which it could be tweaked, improved, and especially extended. Naturally, there is a lot you could do to change the cosmetics of the images or to make the look more configurable. The weakest part right now in our view is the form submission, which is hard-coded to pertain only to a particular known MySQL table. Much cooler would be code that, armed only with a table (or view) name and the appropriate login, would quiz the database about column names and types and the distribution of values, and then develop such a form on its own. One extension that may immediately occur to you doesn’t work, unfortunately, at least without substantial changes to the display code. There is no good way to involve a third set (and circle) in the diagram, cover all the cases, and be assured that all the shapes can still be circular. If you have any doubt about this, try diagramming the following three sets: people who were born in Europe, people who currently live in Europe, and people who currently live in a continent different from the one they were born in.

Summary We’ve shown you a small but complete system for visualizing data in a MySQL database. It allows the user to select aspects to compare, makes corresponding SQL queries, and transforms the results into a scaled Venn diagram, showing how the database records overlap. In addition to using MySQL techniques from Part II of this book, we drew on the image techniques from Chapter 42, and as little math as we could get away with from Chapter 27.

965

A

A P P E N D I X

PHP for C Programmers ✦

I

n this appendix, we assume that you have more C (or C++) programming experience than PHP experience and are looking to get up to speed in PHP quickly. First we’ll give a quick overview of PHP from a C perspective; then we’ll break down the similarities and differences, and finally we’ll point out which parts of the book you are likely to benefit from the most.

The simplest way to think of PHP is as interpreted C that you can embed in HTML documents. The language itself is a lot like C, except with untyped variables, a whole lot of Web-specific libraries built in, and everything hooked up directly to your favorite Web server. The syntax of statements and function definitions should be familiar, except that variables are always preceded by \$, and functions do not require separate prototypes.

Similarities In this section, we offer some notes (by no means exhaustive) on ways in which PHP can be expected to be C-like.

Syntax Broadly speaking, PHP syntax is the same as in C: Code is blank insensitive, statements are terminated with semicolons, function calls have the same structure (my_function(expression1, expression2)), and curly braces ({ and }) make statements into blocks. PHP supports C and C++-style comments (/* */ as well as //), and also Perl and shell-script style (#).

Operators The assignment operators (=, +=, *=, and so on), the Boolean operators (&&, ||, !), the comparison operators (<, >, <=, >=, ==, !=), and the basic arithmetic operators (+, -, *, /, %) all behave in PHP as they do in C.

968

Appendix A ✦ PHP for C Programmers

Control structures The basic control structures (if, switch, while, for) behave as they do in C, including supporting break and continue. One notable difference is that switch in PHP can accept strings as case identifiers.

Many function names As you peruse the documentation, you’ll see many function names that seem identical to C functions. It’s a safe bet that these functions perform the exact same tasks, although they may sometimes take a slightly different form in terms of arguments or the way results are returned. Most string-modifying functions, for example, return new strings as the value of the function rather than modifying a string passed as an argument. Note, however, that function names are not case sensitive in PHP.

Differences Although PHP has quite a bit of C ancestry, it also has some other ancestors (Perl, shell scripts), as well as some unique features not at all C-like.

Those dollar signs All variables are denoted with a leading \$. Variables do not need to be declared in advance of assignment, and they have no intrinsic type — the only type a variable has is the type of the last value assigned to it. The PHP version of the C code: double my_number; my_number = 3.14159;

would simply be: \$my_number = 3.14159;

Types PHP has only two numerical types: integer (corresponding to a long in C) and double (corresponding to a double in C). Strings are of arbitrary length. There is no separate character type. (Functions that might take character arguments in their C analogues typically expect a one-character string in PHP (ord(), for example.) Beginning with PHP4, there is also a genuine Boolean type (TRUE or FALSE). See the following sections for arrays and objects.

Type conversion Types are not checked at compile time, and type errors do not typically occur at runtime either. Instead, variables and values are automatically converted across types as needed. This is somewhat analogous to the way arithmetic expressions in C will “promote” numerical arguments as needed, but it is extended to the other types as well. (See Chapter 25 for details of the conversion rules.)

Appendix A ✦ PHP for C Programmers

Arrays Arrays have a syntax superficially similar to C’s array syntax, but they are implemented completely differently. They are actually associative arrays or hashes (with some additional supporting machinery), and the “index” can be either a number or a string. They do not need to be declared or allocated in advance.

No structure type There is no struct in PHP, partly because the array and object types together make it unnecessary. The elements of a PHP array need not be of a consistent type.

Objects PHP4 had a very basic OOP syntax, which allowed definition of classes with member data items and member functions. PHP5 introduces a much fuller object model, although in approach and syntax it owes more to Java than to C++. Some highlights: abstract classes, private/protected members, constructors/destructors, and interfaces (but no multiple inheritance as in C++).

No pointers There are no pointers per se in PHP, although the typeless variables play a similar role. PHP does support variable references. You can also emulate function pointers to some extent, in that function names can be stored in variables and called by using the variable rather than a literal name.

No prototypes Functions do not need to be declared before their implementation is defined, as long as the function definition can be found somewhere in the current code file or included files.

Memory management The PHP engine is effectively a garbage-collected environment (reference-counted), and in small scripts there is no need to do any deallocation. You should freely allocate new structures — such as new strings and object instances — especially because they will reliably go away when your script terminates. If you need to free memory within a script’s execution, call unset() on the variable that refers to it, which will release the memory for collection. External resources (such as database result sets) can also be explicitly freed within a script, but doing so is worth it only if the script would use an unacceptable amount of the resource before terminating. In PHP5, it is possible to define destructors for objects, but there is no free or delete. Destructors are called when the last reference to an object goes away, before the memory is reclaimed.

969

970

Appendix A ✦ PHP for C Programmers

Compilation and linking There is no separate compilation step for PHP scripts — the development cycle is simply editreload. Errors and warnings show up in the browser output by default, although there is also an error-logging capability. Typically, there is no dynamic loading of libraries (although such a capability exists) — you decide at PHP configuration time which function families to include in your module, and they are then available to any script.

Permissiveness As a general matter, PHP is more forgiving than C (especially in its type system) and so will let you get away with new kinds of mistakes. Unexpected results are more common than errors. In particular, under the default error-reporting level, PHP does not warn you if you use a variable that has not yet been assigned (although it does supply reasonable default values rather than garbage). If you would rather be warned, you can set the error-reporting level by evaluating error-reporting(E_ALL) early in your script, or set the error-reporting level to E_ALL permanently by editing the php.ini file.

Guide to the Book In writing this book, we very intentionally did not assume that the reader had prior knowledge of C. Because PHP resembles C in many aspects, some of the chapters may cover familiar ground. This is especially true of Part I, which is essentially a language introduction. In Table A-1, we label the chapters of Part I according to how familiar they are likely to be to C programmers. Parts III, IV, and V are more PHP-specific and likely to be novel, but you may also find portions of Part II to be familiar if you have some experience with SQL databases.

Table A-1: Guide to Part I for C Programmers Chapter

Chapter Title

Verdict?

Notes

1

Why PHP?

Novel

The chapter you need to justify PHP to your boss.

2

Server-side Web Scripting

Novel

Important if you have not seen Webscripting languages before.

3

Getting Started with PHP

Novel

Installation, hosting, and so on.

4

Novel but easy

“Hello world” for PHP.

5

Syntax and Variables

Mostly familiar

Skimmable until the section on variables (which really are different in PHP).

6

Control and Functions

Mostly familiar

All the PHP control structures (if, while, switch, for) work the same way as in C. Some differences in function behavior, particularly with scoping of variables.

7

Passing Information between Pages

Novel

Specific to Web-scripting.

Appendix A ✦ PHP for C Programmers

Chapter

Chapter Title

Verdict?

Notes

8

Strings

Mostly familiar

Doubly quoted strings do automatic interpolation of variable values.

9

Arrays

Novel

Deceptively familiar — PHP arrays are syntactically like C arrays but behave totally differently.

10

Numbers

Familiar

Two numerical types, corresponding to the long and double types. Numerical operators are as in C.

11

Basic PHP Gotchas

Novel

Error messages and stumbling blocks do not have much overlap with C.

A Bonus: Just Look at the Code! As a final bonus, C programmers are uniquely qualified to benefit from the open-source nature of PHP. Although the combination of this book and the online manual should answer almost all your questions, if you have the PHP source available you may be able to gain some extra insight by poking around in it and seeing how things are implemented. Although you would need to be familiar with lexing/parsing technology to get much out of the parser code itself, many PHP functions are simple wrappers around their similarly named C counterparts, and some others that have no C counterparts are at least implemented in clear and simple C. It’s also easy for C programmers to add new capabilities to the language, whether for their own use or eventual use by the PHP community. Most PHP programming tasks are addressed by writing PHP (often by defining functions in PHP), but you can also pop the hood and add functionality to the underlying language by adding a new module, written (of course) in C.

971

B

A P P E N D I X

PHP for Perl Hackers ✦

I

n this appendix, we assume that you know Perl, but not PHP, and are looking to quickly get up to speed in PHP. The good news is that the two languages are very similar indeed.

This is by no means a comprehensive guide to how Perl and PHP compare. Although similar, and sharing some ancestry, they really are distinct languages with distinct syntaxes and feature sets, and there is no replacement for getting to know them individually. Our main goal for this appendix is to save you some time up front — to warn you, for example, that elsif means nothing in PHP (but that elseif, however, is significant) rather than letting you debug your way to that realization.

Similarities In this section, we discuss some ways in which PHP and Perl are similar.

Compiled scripting languages First, the obvious: Both Perl and PHP are scripting languages. This means that (unlike compiled languages such as C) they are not used to produce native standalone executables in advance of execution, which can then be run without reference to the language they were written in. Instead, Perl or PHP source files are both fed to an appropriate engine at execution time. This does not mean, however, that Perl/PHP code is interpreted line-by-line at execution time; in both Perl and PHP, scripts are quickly and automatically compiled at execution time and then executed. But it does mean that the development cycle for PHP/Perl programmers is edit-execute, rather than edit-compile-execute, as in C.

Syntax PHP’s basic syntax is very close to Perl’s, and both share a lot of syntactic features with C. Code is insensitive to whitespace, statements are terminated by semicolons, and curly braces organize multiple statements into a single block. Function calls start with the name of the function, followed by the actual arguments enclosed in parentheses and separated by commas.

974

Appendix B ✦ PHP for Perl Hackers

Dollar-sign variables All variables in PHP look like scalar variables in Perl: a name with a dollar sign (\$) in front of it. (See the “Differences” section for what happened to @ and %.)

No declaration of variables As in Perl, you don’t need to declare the type of a PHP variable before using it. The following line is legal in both languages, with no prior mention of the variable called \$the_answer: \$the_answer = 42;

Loose typing of variables As in Perl, variables in PHP have no intrinsic type other than the value they currently hold. This is different from languages such as C and Java, in which once a variable is declared to be for holding, say, strings, you get into trouble if you try to use it to store an integer. The following sequence of two lines is legal in both Perl and PHP: \$the_answer = 42; \$the_answer = “the answer”;

The variable \$the_answer is assigned sequentially to an integer and a string. This would not be legal in more strongly typed languages such as C, Pascal, or Java.

Strings and variable interpolation Both PHP and Perl do more interpretation of double-quoted strings (“string”) than of singlequoted strings (‘string’). In particular, the value of \$ variables is spliced into double-quoted strings at the time the strings are read. The following code fragment is both legal Perl and legal PHP, and it has the same behavior in both languages. \$the_answer = 42; \$the_statement = “the answer is \$the_answer”;

At the end of the second line, the variable \$the_statement contains the string: the answer is 42

Differences This section warns you (again, not exhaustively) about some ways that Perl and PHP diverge from each other.

PHP is HTML-embedded Although it is possible to use PHP for arbitrary tasks by running it from the command line, it is more typically connected to a Web server and used for producing Web pages. The code for these pages can consist partially (or even completely!) of straight HTML, with fragments of PHP embedded in them to produce the dynamically generated portions.

Appendix B ✦ PHP for Perl Hackers

If you are used to writing CGI scripts in Perl, the main difference in PHP is that you no longer need to explicitly print large blocks of static HTML using print or heredoc statements and instead can simply write the HTML itself (outside of the PHP code block). Also, for typical pages, there is no need to explicitly send HTTP headers from PHP code.

No @ or % variables PHP has one only kind of variable, which starts with a dollar sign (\$). Any of the datatypes in the language can be stored in such variables, whether scalar or compound. For example, the expression \$my_array[0] refers to the first element in an array, while \$my_array refers to the array itself.

Arrays versus hashes PHP has a single datatype called an array that plays the role of both hashes and arrays/lists in Perl. For all the details, see Chapter 9; the short version is that a PHP array acts like a Perl hash when you supply keys and like a Perl (nonassociative) array when keys are omitted. Values can be extracted by key (as in Perl hashes) or by iteration through the array (as with Perl arrays). There is, however, a list() function in PHP. It’s used to extract the contents of an array into a set of separate variables. The list() function works like this: \$myArray = (‘a’, ‘b’,’c’); list(\$var1, \$var2, \$var3) = \$myArray

After that runs, \$var1 contains a, \$var2 contains b, and \$var3 contains c.

Specifying arguments to functions Function calls in PHP look pretty much like subroutine calls in Perl. Function definitions in PHP, on the other hand, typically require some kind of list of formal arguments as in C or Java. For example, although the typical syntax for a two-argument subroutine in Perl might look like: sub two_arg_sub () { my (\$first_arg, \$second_arg) = @_; ... }

The corresponding PHP function definition would be: function two_arg_function (\$first_arg, \$second_arg) { ... }

Although your humble authors try hard not to be partisan, we feel strongly that subroutine arguments in Perl are a bug and that function arguments in PHP are a feature. Two kinds of silliness common in Perl that don’t usually arise in PHP are: 1) popping the argument stack at various points in a subroutine (so that it is hard for a reader of the code to figure out what the formal arguments are supposed to be) and 2) compound arguments bleeding into one another because arguments are passed as a list of scalars. PHP arguments arrive intact and without confusion regardless of number and type.

975

976

Appendix B ✦ PHP for Perl Hackers

Variable scoping in functions In Perl, the default scope for variables is global. This means that top-level variables are visible inside subroutines. Often, this leads to promiscuous use of globals across functions. In PHP, the scope of variables within function definitions is local by default. This means that (with some exceptions) the only variables visible within functions are the formal parameters and variables assigned locally within the function. If you want to refer to a variable from the global context within a function, you must declare it by name in the function definition itself, using the global keyword. The exceptions to that rule in PHP are the so-called superglobals, the most popular of which is \$_POST. Representing the variables that arrived at a PHP script as a result of an HTTP POST operation, \$_POST and its contents are accessible anywhere, without the need to use the global keyword. For example, if we called a PHP script with this URL: http://localhost/quoteStooges.php?stooge1=Curly&stooge2=Shemp

these calls would be legal anywhere in quoteStooges.php: lookupQuote(\$_POST[‘stooge1’]); lookupQuote(\$_POST[‘stooge2’]);

No module system as such In PHP there is no real distinction between normal code files and code files used as imported libraries. To import a PHP code file full of function or class definitions, simply use include(), require(), or require_once(), which have much the same effect as splicing the definitions in at the point of the statement.

Break and continue rather than next and last Perl has some idiosyncratic language keywords, which are not the same as the corresponding C constructs. In general, if Perl and C disagree about such a name, you will find that PHP follows C rather than Perl. In particular, if you want to skip to the end of a for or while iteration, use continue (not next); if you want to break out of the loop altogether, use break (not last).

No elsif A minor spelling difference: Perl’s elsif is PHP’s elseif. Also, its use is not mandatory. In PHP, the following is legal: if (\$boolean_var) { # case 1 } else if (\$other_boolean) { # case 2 }

Appendix B ✦ PHP for Perl Hackers

In Perl, on the other hand, if you for some reason decline to use elsif, your other alternative is the more awkward form: if (\$boolean_var) { # case 1 } else { if (\$other_boolean) { # case 2 } }

More kinds of comments Perl people like the phrase “There’s more than one way to do it,” and yet they suffer with a really impoverished set of options for comments. In addition to Perl-style (#) single-line comments, PHP offers C-style multiline comments (/* comment */ ) and Java-style single-line comments (// comment).

Regular expressions PHP does not have a built-in syntax specific to regular expressions, but has most of the same functionality in its “Perl-compatible” regular expression functions. See Chapter 22 for the details.

Miscellaneous Tips Following are answers to a couple of questions that Perl programmers might have on their minds.

What about use strict “vars”? Like Perl, PHP allows you to use variables without declaring them or initializing them, and (as in Perl) this capability is a frequent source of bugs. If you would like a declaration like Perl’s use strict “vars”, try error_reporting(E_ALL), which will at least warn you about the use of any unassigned variables.

Where’s CPAN? PHP doesn’t yet have a code repository as comprehensive as the Comprehensive Perl Archive Network (CPAN), but a good effort is under way in the PEAR project (http://pear.php.net).

Guide to the Book As in Appendix A (PHP for C Programmers), in this section we offer Perl hackers a quick guide to Part I of the book to give a sense of which chapters are likely to already be familiar.

977

978

Appendix B ✦ PHP for Perl Hackers

Table B-1: Guide to Part I for Perl Programmers Chapter

Chapter Title

Verdict?

Notes

1

Why PHP?

Novel

The chapter you need to justify PHP to your boss

2

Server-Side Web Scripting

Possibly novel

Familiar to Perl CGI and mod_perl programmers; important if you have not seen Web scripting before

3

Getting Started with PHP

Novel

Installation, hosting, and so on

4

Novel but easy

“Hello world” for PHP

5

Syntax and Variables

Mostly familiar

Basic syntax is very familiar; variables are different

6

Control and Functions

Somewhat familiar

Basic constructs are similar, with syntactic differences

7

Passing Information between Pages

Mostly familiar

Specific to Web scripting

8

Strings

Somewhat familiar

Treatment of single-quoted and double-quoted strings essentially the same; functions are mostly novel

9

Arrays

Novel

No exactly corresponding datatype in Perl

10

Numbers

Mostly familiar

Novel section on arbitraryprecision (BC) math functions.

11

Basic PHP Gotchas

Novel

Same gotchas around unintentionally unassigned variables; other gotchas specific to PHP parsing

C

A P P E N D I X

PHP for HTML Coders ✦

T

his appendix contains specific advice for HTML-only jocks looking to trade up to something a little more powerful on the server side. If you already know ASP, JavaScript, or almost any real programming language, this appendix is not going to help you much.

The Good News If you’re already proficient at HTML, starting to use PHP is not a huge step. Because PHP is usually embedded in HTML, extending the functionality of static Web pages with a programming language can be a very natural progression. There are plenty of reasons to believe that you can learn PHP fairly quickly, such as the following factors.

You already know HTML Because PHP is often embedded in HTML, and because PHP generally uses HTML for display to the browser, you won’t be able to see anything that your scripts are doing unless you output HTML. In fact, you can think of PHP as simply adding functionality to Web pages — it can do other things, but lots of people use it mostly for form handling and dynamic page generation. You presumably have a lot of practice debugging HTML, which is all to the good. Many errors occur within the HTML parts of scripts or during the transitions between modes, so the ability to read and write HTML with great facility is crucial. If you’re strong on the design side, as are many HTML coders, you have the ability to produce a good-looking and well-laid-out product. This skill is important for the community because a lot of early PHP developers were not exactly known for their UI skills (including ourselves, we hasten to admit). So go out there and show the world that PHP sites don’t need to be ugly, clunky, or, at best, really plain — you can make us all proud.

980

Appendix C ✦ PHP for HTML Coders

PHP is an easy first programming language to learn Unlike many major programming languages, PHP enables you to do useful stuff from the very beginning instead of making you play endless games of tic-tac-toe or code up incomprehensible math problems. The Web browser and markup languages, however primitive and clunky they are now, point the way to the universal I/O, windowing, and multimedia solution that the world has been waiting for. PHP takes full advantage of the Web’s power; plus, it has very little overhead and takes a loose, inclusive approach to issues such as types, variables, and syntax. All the nitpicky angst that programmers used to put into these areas you can now apply more directly to functionality. And frankly, PHP enables you to learn just those parts that are useful to you and ignore the rest. Unlike some programming languages, which pretty much require a firm grasp of all the basic principles before you can do anything useful (try telling a C programmer that you just haven’t seen a need for structs yet if you want a laugh), no one is going to give you a quiz on all the hundreds of PHP functions before entrusting you with a text editor. So if you don’t need to write some huge math function right off the bat, go ahead and skip that chapter — we promise not to tell. If you ever need them, the math capabilities will still be there.

Web development is increasingly prefab anyway Finally, the Web is increasingly making development a matter of altering prefab open source code rather than hacking it all up yourself. Much of this work is about changing how the page looks rather than how it functions. Learn to be a smart script shopper, and you’re more than halfway there.

The Bad News Before we get too carried away, honesty compels us to admit that you may face a few hurdles before you become a power PHP user.

If programming were that easy, you’d already know how PHP is a real programming language, similar to C (albeit generally Web-server dwelling), rather than a tag-based markup concept such as HTML or ColdFusion. This point introduces whole new levels of complexity. It simply takes time and practice to develop a bag of tricks, work out routines for solving problems, and just get better at development — and there are no shortcuts for these skills. So here’s the bottom line: Most of PHP is probably completely new to you. Unlike new PHP developers who are already proficient with ASP, JavaScript, or C, you can’t expect to pick up any specific points here that are highly similar to things you already know how to do. Uh, sorry. However, if you already know some JavaScript or have taken an “Intro to C” class in school — even if you wouldn’t describe yourself as a JavaScript or C guru — you’re ahead of the curve. Some of the logic is sure to come back to you as you begin to work with PHP. Also, PHP training courses are beginning to pop up for those who are comfortable learning in the classroom. Check out the following Web sites: ✦ www.phpbootcamp.com (USA) ✦ www.academyx.com/training/san_francisco/php/introduction/ (SF)

Appendix C ✦ PHP for HTML Coders

✦ http://training.gbdirect.co.uk/courses/php/ (UK) ✦ www.thinkphp.de (Germany)

Back end servers can add complexity PHP is mostly useful in conjunction with back end servers, such as database and mail servers, which have their own syntax and implementation issues that you need to learn about. Because open source software such as PHP is commonly used in noncorporate settings, most PHP developers probably don’t have the luxury of a team of database, network, and design experts doing their various things while they just worry about the middle and front tiers. If possible, don’t try to learn everything at once. The most important task is to become comfortable with the Web server itself; Apache, in particular, is an extremely powerful but involved piece of software that rewards study. (This advice may not be relevant if you have IT staff to install and maintain the Web server for you.) After that, you will almost certainly want to learn SQL if you don’t know it already. Mail service is also a very rewarding subject. After you master those three, other new servers should be easier to learn.

Concentrate On . . . Learning PHP quickly requires a strategy. Here are some things you might want to concentrate on doing when you’re first learning.

Reading other people’s code Learning to read other people’s code can be harder than it sounds. One of the best things about PHP is its loose syntax and inclusive “don’t worry, be happy” design — but that can also mean that different scripts can look very different, even if they return similar results. Beginners can be boggled by stylistic issues and may find it difficult to sort out which parts of a script are functionally irreducible and which are the products of one individual’s programming quirks. But regardless of difficulty, the sooner you can parse other people’s PHP and the more code you can look at, the better off you’ll be. One potentially helpful exercise is to visit the mailing-list archive or a code exchange (see Appendix D) and print out multiple examples of code that solve the same issue (preferably one you’re interested in). Then lay the sheets side by side, take a big ol’ red pen and go through it all, circling the common parts. Give extra brownie points to any scripters who comment their code well (which doesn’t necessarily mean the most voluminous comments but rather the most useful) and look for more code from those people. Also look for code that is generally well laid out and logically organized, even if it isn’t extensively commented.

Working on what interests you We firmly believe that learning is motivation. If you find tasks that you want to accomplish, you will automatically be motivated to learn what you need to know to accomplish them. Don’t let anyone tell you that the right way to learn programming is through some highly structured program of math problems, games, and stock-market simulations. Wanting to put pictures of your dog on the Internet is much more important than making sure that you know what’s in every byte of memory your program is using.

981

982

Appendix C ✦ PHP for HTML Coders

2. Break the mission statement down into steps and substeps, as in a recipe. Rearrange these if necessary. Following is an example of this step: 1. Get the User ID that is passed from the login screen; if none, don’t display anything. 2. Display the HTML form. 3. Make any old values from the database appear in the form. a. Connect to the database server. b. Download data about this item. c. Put the data into the HTML form’s “value=X” variables. 4. Change the values and put them into the database too. 5. Pass the User ID to the next page.

3. Pick one of the steps and turn it into actual PHP code. Starting with a core PHP task — such as sending e-mail or returning something to the screen — is generally easier than beginning with peripheral tasks, such as connecting to a database. Any time you might want to connect to a database, use a commented variable, array, or include file for the moment. The following example illustrates this step: 1. Get the User ID that is passed from the login screen; if none, don’t display anything. <?php // Dummy UserID pretending to be passed from login. // Will be superseded later. \$UserID = 1; ?> 2. Display the HTML form. <HTML><HEAD></HEAD> <BODY> <FORM> First name: <input type=”text” size=30 name=”FirstName”><BR>

Appendix C ✦ PHP for HTML Coders

Last name: <input type=”text” size=30 name=”LastName”><BR> E-mail: <input type=”text” size=30 name=”Email”> 3. Make any old values from the database appear in the form. <?php // I’m using these variables now, but later I’ll get // them from the database instead. \$FirstName = “Joyce”; \$LastName = “Park”; \$Email = “root@localhost” ?> Oh, I think I need to put them in before the form is rendered. 4. Change the values and put them into the database, too. 5. Pass the User ID to the next page.

4. Gradually fill in more and more of the code, fixing any new issues that arise. You may want to keep some of the pseudocode, suitably edited, as comments, as shown in the following example: /* Pass the User ID to the next page. The best way is to have it show up as a hidden input type and PHP variable in the form; then HTML can pass it with the rest of the POST values. */

Learning SQL and other protocols Spending some time interacting with back end servers directly, via whatever interface the server provides, is generally a good idea before you add the complexity of PHP between you and the server. You can kill two birds with one stone by using the back end server’s own interface to construct the database (or whatever), even though there may be nice PHP tools for some of these tasks. For instance, even though the phpMyAdmin and MySQL Control Center are both very slick and handy ways to deal with the MySQL database, the newbie database administrator can learn a heck of a lot more by using MySQL’s deliberately primitive command-line interface. Beginning with PHP5, a lightweight, embedded database engine called SQLite is included and ready for you to use. SQLite is rudimentary and not up to the task of replacing MySQL and other database engines on a production site; however, you may find it an excellent tool for getting your feet wet before moving on to MySQL.

Making cosmetic changes to prefab PHP applications One common way to ease into using PHP is to enlist your front end Web development skills to customize a pre-existing PHP package. ✦ First try just changing the colors — that’s generally pretty safe. If that goes well, try customizing the buttons. The next safest thing is spacing — table widths, columns, and so on. You can also add graphics, add links, or play around with style sheets pretty much without worries.

983

984

Appendix C ✦ PHP for HTML Coders

✦ If the application has include files (especially header.inc), the cosmetic part is often in there. Look first in headers and footers for colors, the basis of page layouts, and so on. Remember to match header changes with corresponding footer changes and vice versa. ✦ Never, ever erase a line beginning with a conjunction (such as if, while, or for). If you are not 100 percent sure of what you’re doing, comment out code blocks rather than deleting them.

Debugging is programming Few people truly enjoy debugging; as one of our colleagues once observed, “I’d rather implement new features than eat someone else’s leftovers.” Debugging can turn out to be a useful learning experience, however, because you can fix things at the edges of a big project instead of jumping into writing the whole thing from scratch. One of the most efficient ways to debug is in pairs. If you’re tired or have seen a piece of code too many times, focusing on every detail can prove difficult. At this point, talking through your logic becomes very helpful — one of you briefly stating why you’re doing what you’re doing and the other checking each step off very deliberately. A fresh set of eyes can often find cheap mistakes such as misspelled variable names or missing brackets more quickly, too. If you get an opportunity to debug with a more experienced programmer, take it.

Avoid at First . . . A few things in PHP are extremely unfamiliar to HTML coders and generally are not extremely necessary to writing functional PHP. Try to avoid the elements that we describe in the following sections if you can, at least at first.

Objects and interfaces Objects can prove confusing even for experienced nonobject-oriented programmers, so do yourself a favor and avoid them if at all possible. Because PHP is not even a truly objectoriented language, the “object notation” can also cause problems later. Much of the object model has drastically changed from PHP4 to PHP5 as well and continues to be heavily revised. If you don’t plan on programming with objects right away, it may be best not to have to unlearn a methodology that has been rendered obsolete.

Maximal PHP style See Chapter 33 on PHP style. The maximal style is deprecated by Rasmus Lerdorf himself, and only hardcore C programmers have the slightest excuse to use it, except in very specific, brief instances. It includes too many single quotes, double quotes, forward slashes, backslashes, ASCII line breaks, and HTML line breaks for most coders. Beginners are better off if they don’t waste their time worrying about stray punctuation when they could be spending the time and effort grasping larger concepts instead.

Appendix C ✦ PHP for HTML Coders

Programming large applications from scratch Why reinvent the wheel? In Open-sourceland, you don’t need to. Becoming a good customizer and recycler of other people’s code is often more efficient than trying to become the world’s greatest programmer from scratch. Learn to shop for what you need.

Consider This . . . The ideas in the following sections are completely optional but may prove helpful. You may not agree with them all, but we offer them for what they’re worth.

Reading a book on C programming Unfortunately, we can’t write a complete programming tutorial. Part I of this book explains programming topics but necessarily very briefly. We’ve tried to comment our code samples extensively, but we can do only so much to explain these techniques in passing. Mailing-list regulars frequently counsel new PHP developers to buy a book on C programming — but in a snotty, RTFM way that too often elicits a naturally passive-aggressive response. Nevertheless, if you separate it from the unspoken message that you must be a clueless idiot, it’s good advice and something to seriously consider if you’re having trouble with the programming aspect of PHP. A clearly written, brief tutorial book is Patrick Henry Winston’s On to C (Addison-Wesley, 1994). It’s fewer than 300 pages, and a lot of the PHP-relevant material is right at the beginning. The standard reference is The C Programming Language, by Brian W. Kernighan and Dennis M. Ritchie (Prentice Hall, 1988), which is quite definitive but more reference-oriented and, therefore, perhaps less appropriate for HTML-only coders. A friendlier introduction might be Dan Gookin’s two-volume C For Dummies (Wiley, 1997), which has cartoons and dry humor.

Minimal PHP style Of the range of PHP styles, the easiest for the HTML coder to work with at first is the most minimal. In other words, we suggest that you separate the HTML and PHP sections completely. Not only does this technique avoid many stylistic difficulties, but by using this method, you avoid mixing PHP and HTML glitches on the same page, which makes diagnosing problems more than twice as hard. We discuss this topic thoroughly in Chapter 33. Perhaps the easiest way to use the minimal style is to finish the HTML pages first, using whatever tool you’re most enamored of. Take the time to debug your HTML completely and perhaps run it through a tidying utility. Then, and only then, tackle the PHP parts, secure and comfy in the knowledge that any difficulties you encounter are certainly on the PHP side rather than the HTML side. One downside of this style is that you can’t have pages pass their variables back to themselves. This is particularly relevant with forms, so if your site has a lot of forms, you may want to change your style a bit as your PHP skills improve.

985

986

Appendix C ✦ PHP for HTML Coders

Use the right tools for the job Finally, you want to consider using a PHP-enabled text editor for the PHP parts of your scripts. (See Chapter 4 for a discussion of text editors versus WYSIWYG tools.) Some people can do wonders with just Notepad or emacs, but a lot of frustrated beginners are certainly using those tools just because someone told them that’s what the cool programmers do. As Zsa Zsa Gabor said (in a slightly different context), macho does not mean mucho. If you work more effectively with vim or Visual SlickEdit, by all means use those tools. Syntax highlighting (printing different parts of the code in different colors) can help you a lot, as it will usually make clearer when you have failed to close off a parenthesis or double-quote mark. Some programmer’s text editors will automatically line up your curly braces for you, which helps you verify that you’ve closed off all of a set of nested cases. We would not even consider using a text editor without line numbering, since PHP’s built-in error messages always refer to lines in your code. And last but not least, do not forget the power of “View Source” in the browser — this will help you verify that the output you are producing is in fact what you intended. Caution

This advice does not apply to WYSIWYG editors, the use of which we deprecate. Sooner or later, you need to fix up the HTML into a human-readable form, which no WYSIWYG editor can yet produce. If it’s your choice to use one, fine — but you should in no way think of this tool as a substitute for understanding and writing clean HTML by hand.

D

A P P E N D I X

PHP Resources ✦

T

his appendix lays out some basic resources that can help you learn more about the language. We have also tried to mention specific resources and products throughout the text.

The PEAR manual, which used to be a chapter of the general PHP manual, has now been moved to its own server. You can find it at http://pear.php.net/manual/.

But when people talk about “the PHP manual,” they mean the big annotated online version for which PHP is famous. Users from around the world have added notes and comments to each page. These additions are often clarifications of points made in the main text, additional insights, and reports of PHP’s behavior on various platforms.

988

Appendix D ✦ PHP Resources

You may want to keep a couple of points in mind when using this manual: ✦ The canonical manual text is written in a super-terse programmer’s style, and it is organized in a not particularly discursive, notebook-like format. Note

The online manual is not the place to ask questions! It’s intended for meaningful comments and observations only. Send e-mail to one of the previous commentators who provide their addresses — many of them will be happy to help you. Or subscribe to the mailing list or post to a PHP forum, which is faster anyway. Remember, a stupid question posted to the manual errata will go down on your (semi)permanent record.

Appendix D ✦ PHP Resources

✦ The comments are edited, weeded, and verified only on an episodic (not to say extremely infrequent) basis. Proceed with extreme caution — there have been numerous instances of problems actually getting worse because a user uncritically followed the advice in the manual notes. You can write to the person to make sure that the advice is appropriate for you or even to determine whether the person really knows what he or she is talking about. ✦ The manual may lag behind development by a considerable time period.

The PHP Mailing Lists The “official” PHP community meets and greets on the PHP mailing lists. With the advent of PHP4, a decision was made to split up the lists into more specific topics. These topics will continue to proliferate with the addition of new features in PHP5 and beyond.

Signing up To subscribe to any of the PHP mailing lists, go to www.php.net/mailing-lists.php. You should see a large form listing the various mailing lists and options for viewing them. Just choose the list that you want, specify normal or digest versions, enter your e-mail address, and click the Subscribe button. You can also unsubscribe from a list here. The PHP mailing list manager almost instantaneously sends you an e-mail message asking you to confirm your subscription. You aren’t subscribed until you reply to this e-mail. Tip

You also find links to local (non-English) mailing lists and newsgroups at the bottom of this page. If you want to discuss PHP in Turkish or Japanese, this page is the place to start!

Users’ lists and developers’ lists Many of the user-oriented lists are new with PHP4 or later. The following are the most popular PHP users’ mailing lists: ✦ php.general: Main mailing list — very heavy traffic, 80+ e-mail messages per day ✦ php.windows: Specific mailing list for Windows users ✦ php.install: An installation-related mailing list, mostly for new users ✦ php.db: The database-related issues mailing list ✦ php.i18n: Internationalization and localization mailing list ✦ php.pear: The PEAR users’ list ✦ php.gtk.general: The PHP-GTK users’ list ✦ php.smarty.general: The Smarty templates users’ list ✦ php.bugs: Bug reporting related to PHP itself ✦ php.announce: Announces new releases — very occasional

989

990

Appendix D ✦ PHP Resources

Lists also are available for popular PHP-based projects such as Midgard and phpNuke; you subscribe to those lists through the products’ own Web sites. We list the URLs of some of these sites in the “Major PHP Projects” section of this chapter below. The following four lists are mostly intended for active developers and very early adopters — people who are going to get down in the C code and battle bugs to the death: ✦ php.dev: The main PHP developers’ list ✦ php.version5.dev: Mailing list during the ongoing development of PHP5 ✦ php.gtk.dev: The PHP-GTK developers’ list ✦ php.pear.dev: The PEAR developers’ list These lists are low-to-medium volume, meaning approximately 100 to 1,000 messages a month. They are highly technical and mostly not enlightening unless you’re an active team member. Various CVS lists for developers are also available, which mail out all CVS commits on a particular branch to all subscribers; special lists for documentation writers and QA team members also exist. If you’re comfortable with Internet newsgroups (which many newer users are not), you can access the PHP mailing lists at the news gateway at news.php.net. This option has one great advantage: You can send messages to the mailing lists without subscribing to them. Many new users, however, should think in terms of searching the archives for answers to old questions before (or rather than) asking new questions anyway. Most of these mailing lists, and many others on a variety of topics, are archived and searchable at http://marc.theaimsgroup.com. This archive dates back to at least 1998, although the older posts are usually less complete. Tip

Trying a quick keyword search on the PHP site, mail archives, and perhaps some of the other major PHP Web sites before contacting the mailing lists is the polite thing to do. It’s actually faster for you, plus the less time the developers must spend answering the same questions over and over, the more time they have to implement new features in the language. Actually, searching the archives is no longer just polite — it’s a necessity. With so many new users, socalled “RTFM” (read the effing manual) questions are not (politely) answered on the PHP lists anymore. Also, try to ask your question on a specific list if it exists — especially installation-related questions.

Regular and digest The main PHP user list is so high-volume that it has a twice-daily digest version. The new specialized mailing lists also typically have digest versions. The raw and digested versions each have advantages and disadvantages. If you’ve never had 100+ e-mail messages a day pouring into your mailbox, you have no idea how distracting and time-consuming this experience can be. Just reading-and-deleting can take up a couple hours, whereas actually answering them can easily become a full-time job. Under no circumstance should you request the full user list if your primary mailbox is a Web-based free e-mail service such as Yahoo! mail or Hotmail. Tip

Setting up a separate mailbox for PHP mail is almost mandatory if you’re subscribing to the full user mailing list, unless you’ve set up good mail filters. Otherwise, you quickly start to lose mail from other sources in the flood of similarly named threads.

Appendix D ✦ PHP Resources

On the other hand, the digest version makes getting into the flow more difficult. The few brave community members who get the full user list seem to answer all the questions on the halfvolley before you even get the digest, making participation difficult for the time-stressed community member. For beginners, we recommend the digest version. You can always trade up later, whenever you’re ready to stop lurking and participate actively. Everyone should also consider using one of the PHP forums (see the following section on “Other PHP Web Sites”) instead of or in addition to the user mailing list. These forums are great for those who dislike mailing lists. The downside is that PHP developers generally don’t hang out here, so extremely abstruse infrastructure questions usually go unanswered. The upside is that they tend to be friendlier, especially to repetitive newbie questions, because the answerers can control the amount of contact they prefer and go away if they start to become annoyed.

Mailing list etiquette Open-source mailing lists can be intimidating places, and the PHP general-users list is particularly active and fast-paced. The denizens of the mailing lists are people, and learning about their different personalities and plans over time can be fun — but they can get annoyed and fed up, too. A little netiquette can take the user a long way. The following sections offer a few tips to follow.

Remember, the community does all this work for free! Before you turn on the flamethrower, remind yourself of your last experience with commercial-software tech support. Did it solve your problem the same day? Did it cost money? How long did it take? At what point did you get to talk to the developers of the program?

People might be sick of your question Perhaps you’re trying to install PHP for the first time and can’t get it working as an Apache module — but we can assure you that tens of thousands of iterations of that question have appeared on the mailing lists over the years. People on the mailing lists are experiencing fatigue at answering questions that they and others have answered in a lot of other information sources — the FAQs, the online manual, the mailing-list archives, and any number of other Web sites. If you ask one of these basic questions on the general mailing list, it proves that you didn’t take seriously the numerous polite requests on the PHP site to search for an answer to your question before posting. You may get an irritated e-mail informing you of all the above — or you may get no responses at all. Neither response means that the PHP community is cold-hearted and unhelpful. Try to see things from the point of view of community members of longer standing, and avoid these problems by searching for the answer to your question before you post.

Give detailed descriptions Say as much as you can about your platform, the problem, and any steps you’ve already tried. Don’t worry about being concise; you’re far better off meandering on a little than making everyone go back and forth an extra time. Code fragments are the very most efficient way to state your problem for debugging by the community. Many people edit their raw code to make it more anonymous and/or abstract. Remember to take out any passwords! Tip

Copy and paste your code fragments; don’t retype them. List participants often post perfect code, only to be frustrated that nobody can find anything wrong with it — because they corrected their errors while retyping!

991

992

Appendix D ✦ PHP Resources

Make sure that you use a specific subject line — the more specific the better. “Subject: PHP Help” gets you ignored by most of the mailing-list regulars. You want to say something more descriptive such as, “Subject: mysql_connect arguments not being passed in 4.0.0.”

PHP is international PHP is developed and used by people literally all over the world. In fact, the active development team has only a smallish minority of native English speakers on it at any given time. Native English speakers should feel supremely lucky that theirs is the lingua franca of the Internet in general and the PHP world specifically. They should feel awed by the linguistic dexterity of all the citizens of other nations and perhaps slightly abashed that they can’t return the favor in Finnish or Urdu. In other words, cut people some slack already! Don’t assume that someone is an idiot because his or her messages aren’t couched in perfectly grammatical and smooth English. Instead, you might spend the time learning how to write “Thank you” in all the languages of the various PHP community members — it makes a nice sig file for your mailing list posts. Tip

If you don’t know English well, you may want to write your question twice — once in English, once in your native language. This will increase the odds that someone will be able to decipher your meaning.

Do it yourself Open-source software may be free to use, but you should not consider it free of all responsibilities. You are technically a “free rider” until you give back — or pay forward — to the community at large. It’s your task to figure out where and how to best deploy your talents, and then to do that thing as you can. We don’t mean that every casual PHP user must become a C developer, but you can contribute in many other ways. Answering questions on the PHP mailing lists or Web sites is always a good thing, because it lightens the load on the core developers. If you figure something out that seemed obscure in the online PHP manual, be sure to post your findings to the User-contributed notes section of the manual. Use the PHP bug-tracker according to the instructions. Simple steps like these, in aggregate, contribute to the healthy community that has made PHP so successful.

It’s probably you If you experience a failure to communicate, you need to ask yourself whether the problem could possibly lie with you. If you do find yourself in the middle of a flame war, which happens occasionally on any mailing list, people enjoy nothing more than a little public acknowledgment of what a jerk you’ve (unknowingly) been.

Appendix D ✦ PHP Resources

There are now commercial alternatives If the whole ethos of the PHP mailing lists is driving you crazy, remember that you can now pay to play instead. Many companies are now staffed by well-known PHP developers who are willing to do everything from answering single questions to building a custom PHP extension for you. ThinkPHP (www.thinkphp.de), for example, is a German consultancy, associated with PHP team member Thies Arntzen, that offers support, training, and performance evaluations. In the United States, the supremely helpful Richard Lynch of PHP-mailing-list fame takes requests at www.l-i-e.com.

Other PHP Web Sites Besides the official PHP resources that we mention in the preceding sections, some wellknown community members have put up some extraordinarily helpful Web sites. Some of these enjoy a special relationship with PHP, and are “quasi-official.” The following sections describe some of these sites.

Core scripting engine and tools The core of PHP is the Zend scripting engine. It is produced by an Israeli company called Zend, and besides being a free part of PHP, it can be embedded in other applications. Zend also produces various PHP tools and add-ons, such as a graphical debugger and a precompiler. You can find information on Zend products at www.zend.com. Zend.com is the home of the core PHP5 scripting engine, as well as a center of PHP commercialization. Although the company sells support and custom development services to larger companies, the vast majority of PHP developers are most interested in the add-on products being developer by core developers Zeev Suraski and Andi Gutmans and their team. For most PHP users, the most useful product is the Zend Studio IDE, now in 3.0.1 release. (See Chapters 3 and 32 for more information and screenshots.) This program is the first PHP-specific development tool available, with many well-designed features for the PHP professional. Because of Zend’s unique relationship to PHP development, the company understands the language completely and can design an editing tool that is customized to the needs of hardcore PHP users. Two other Zend products are primarily of value to companies. PHP consulting firms should find the Zend Encoder useful, as it enables them to ship their code in a platform-independent, optimized intermediate representation. Large PHP sites can get a quick return on investment by using the Zend Accelerator, which boosts performance by optimizing and caching, thereby requiring less capital investment in hardware. The Zend site also offers unique content on a regular basis, including biographies of major figures in the PHP world, a handy weekly newsletter summarizing current issues in the development of our beloved programming language, and great articles on advanced topics in PHP development. Zend.com is one of the few Web sites that consistently offers articles of interest to corporate PHP developers and architects, often showcasing the finer points of PHP functionality, such as reference counting, output buffering, and changes to the include functions. Topics such as these may seem abstruse at first, but advanced users usually enjoy learning about the underlying structure and logic of the programming language so that they can write the tightest, cleanest, most secure, best-architected, and most well-thought-out PHP code possible. C programmers who want to contribute to PHP can also find inspiration and information in these articles — because Zeev and Andi are driving the course of PHP core development, getting a feeling for their aesthetic and decision making is important if you want to delve into the heart of PHP.

993

994

Appendix D ✦ PHP Resources

PHP knowledgebase PHP has a great knowledgebase, something like a FAQ-o-matic but more full-featured, called PHP Faqts (previously known as E-gineer). It is available at http://php.faqts.com. PHP Faqts is an interesting and nicely executed concept: an archived knowledgebase of answered and unanswered questions from real PHP users with a decent search function. For common questions, this site is much easier to use than the mailing lists or even many forums — and for that reason, we recommend it to new PHP users. The way that Faqts (brainchild of Australian PHP whiz Nathan Wallace) works is that community members ask questions in one of several “buckets,” such as Installation and Setup, Common Problems, Database Backed Sites, and the extremely cool Not Quite PHP. Other community members come along and add multiple answers to these questions. They can also associate other questions (basically other ways of stating the same thing) with that question/answer pair. Everyone can vote anonymously on whether the question/answer was useful or not. Thus, you get an accretion of knowledge over time and some way to discern whether a particular answer is good at a glance. Going to this site, however, is not the fastest way to get your question answered, and it remains to be seen whether Faqts can scale indefinitely — but it’s a cool idea and definitely a resource to try.

Articles and tutorials Articles and tutorials take a “teach a man to fish . . .” approach. Often they can’t really walk you through all the steps involved in building your Web site; instead, they attempt to guide you in thinking about what to do. Following are two sites that we recommend for such information. ✦ PHPBuilder (www.phpbuilder.com/). Founded by Tim Perdue, the top PHP app developer responsible for Sourceforge.net and Geocrawler.com, this site has long been one of the most comprehensive and well-run PHP sites. The specialty of the site is a deep backlog of articles that focus on the correct architecture of PHP sites, with subjects such as user authentication, cross-platform development, database abstraction, and documentation and style. PHPBuilder also boasts one of the most active PHP-related Web forums, with excellent response times to most questions. One downside to the site is that articles are not dated, so determining whether the advice is still relevant to current versions of the programming language can prove difficult. Despite this drawback, PHPBuilder is a must-visit for the more conceptual PHP programmer who wants to read well-argued position papers on the right way to code PHP. ✦ Devshed (www.devshed.com/Server_Side/PHP and www.devshed.com/Server_ Side/MySQL). A big commercial site with good tutorials and a forum, Devshed covers all the scripting languages (ASP, JavaScript, Python, and so on) as well as MySQL, making it the best one-stop for those still in the shopping phase.

PHP codebases Codebases take a “give a man a fish . . .” approach, simply offering their donated wares to all takers. The code quality can vary widely, from first scripts to elegant classes contributed by experts in a particular area. The following sections describe a few such sites that you can visit.

Appendix D ✦ PHP Resources

Caution

Although codebases can seem attractive to new developers and do embody the power of open source, there are reasons to be wary. For one thing, no one is guaranteeing the quality or safety of this code. If you’re more comfortable cutting and pasting than writing it yourself, you may not have sufficient skill at reading other people’s PHP to use contributed code in an intelligent way. Proceed with caution!

✦ PHP Classes Repository (www.phpclasses.org). Originally a collection of classes by Manuel Lemos, this site is now a hotbed of OOP PHP. We would probably not recommend this site to beginners, both because of the heavy use of object-oriented programming and the strong leaning toward code in the “Sure you can, but is it a good idea?” category. You should also possess an understanding of the changes in the object model from PHP4 to PHP5. If you’re good at intelligently reading other people’s code and adapting it to your own needs, however, this site can prove instructive. ✦ PX: PHP Code Exchange (http://px.sklar.com/). A super-plain and uninformative site design nonetheless leads to a large variety of scripts — mostly smaller ones. Look here for a standalone snippet or function in a specialized area, such as graphics or math. ✦ EvilWalrus (www.evilwalrus.com). This site is very attractive and well laid out with a bit of a Windows orientation and a fresh, growing code base. It also offers chatty news write-ups of interest to PHP developers. Tip

A quick rule of thumb in judging contributed code: If you can’t follow along pretty well just by reading the comments, take a pass and look for another code sample. It’s pretty rare for a good commenter to be a bad or malicious programmer.

Major PHP projects These are the more ambitious standalone projects based on PHP that are becoming wellknown in their own right. Even organizations that are not necessarily in love with PHP are beginning to consider these projects as the best-of-breed and/or most cost-effective option in their various categories. ✦ PHPMyAdmin (www.phpmyadmin.net). Originated by Tobias Ratschiller, this program is a graphical front-end to MySQL that has brought database administration to the ranks of the command-line phobic. See Chapter 14 for more detailed information on how to use it. ✦ PHP-Nuke (http://phpnuke.org). This site offers a newslog-style content management system that enables multiple users on an intranet or the Web to post stories and comments on an on-going basis. You can find lots of add-on packages written by enthusiastic users as well. ✦ PHPSlash (http://phpslash.sourceforge.net). This site also offers a newslog-style content management system. It was originally a rewrite of Slashcode (the Perl codebase behind Slashdot) in PHP, although PHPSlash development has now diverged somewhat. ✦ Midgard (www.midgard-project.org). This site offers a highly customizable content management system, similar to Vignette Story Server. Midgard doesn’t simply enable users or editors to post short pieces in a constant format on a Web page; you can also use the program to manage workflow on all kinds of content-rich sites.

995

996

Appendix D ✦ PHP Resources

✦ phpBB (www.phpbb.com). This is an object-oriented, template-based bulletin-board system offering threaded or flat view, skins, avatars, and other attractive display features. ✦ Phorum (www.phorum.org). Phorum is a lighter-weight bulletin-board system with no graphics. Unlike most other PHP bulletin boards, Phorum displays an outline of the thread, plus the current message, plus a form to reply to that message on a single page. ✦ SquirrelMail (www.squirrelmail.org). IMAP Web mail client ✦ Serendipity (www.s9y.org). Full-featured blogware, comparable to (commercial and Perl-based) Movable Type and Blogger. One of the authors of this book is a team member. ✦ PHPWiki (http://phpwiki.sourceforge.net). Popular Wiki system. ✦ PHPGroupware (www.phpgroupware.org). This large integrated suite of PHP programs offers you Web-based group-scheduling and interaction tools, including Web mail, a calendar, to-do lists, chat, forums, and more. ✦ Sourceforge.net (http://sourceforge.net/projects/alexandria-dev). This is a Web-based engineering management toolkit that includes a task tracker, a bug tracker, a CVS front end, forums, a documentation manager, and news releases. The codebase went closed-source in 2001.

Our Web site We’ve set up a Web site for this book at www.troutworks.com/phpbook/. There you can find most of the larger chunks of code from this book in a convenient source format, which saves you from retyping them. You can also find corrections for the few paltry errors that slipped through the eagle eyes and sharp electronic red pencils of our editors. We will also try to put up information about new features and new code samples as they become available. Tip

Unfortunately, we are pretty much monolingual in English — although we’re extremely impressed with all the e-mail we’ve received from PHP users around the world who are nonnative English speakers. All the text on our Web site is in English. If you write to us in a language other than English, we will attempt to put your e-mail through a Web translator. If we can understand the question after that, we will write an answer and put it through the translator; otherwise, we’ll just write back and tell you that we can’t parse your e-mail. So if you get an e-mail from us in terrible, mechanical French or Italian, now you know why. If you write to us in an encoding that we can’t read, such as Mandarin or Arabic, we can’t reply at all — apologies in advance.

Last but not least, you can also contact us on the site and flame away! (Or maybe just ask us a few questions.) We love to hear from readers, so please visit and drop us a line.

Index SYMBOLS & NUMERICS & (ampersand) in GET strings of URLs, 120 logical operator (&&), 84, 85 < > (angle brackets) heredoc syntax for strings (<<<), 140 in PHP comparison operators, 86, 194 in PHP tags, 54–55 ’ (apostrophe) in strings, 355. See also ’ (single quotation marks) * (asterisk) in Perl-compatible regular expressions, 428 as PHP arithmetic operator, 192 for PHP comments (/* and */), 66 in POSIX-style regular expressions, 425 @ (at sign), silent mode indicated by, 280 \ (backslash). See also specific escape sequences for strings addslashes() function (PHP), 149–150 as escape character in strings, 78, 137 literal, in singly quoted strings (\\), 77, 78 in Perl-compatible regular expressions, 428 in POSIX-style regular expressions, 425 stripslashes() function (PHP), 150 ^ (caret) in Perl-compatible regular expressions, 428 in POSIX-style regular expressions, 425 : (colon) with control structures (PHP), 101 , (comma) in SQL statements, 358 { } (curly braces) for blocks of statements (PHP), 65–66 for retrieving characters in strings, 139 for variable interpolation in strings (PHP), 138 - (dash) —disable-url-fopen-wrapper compile-time option (Unix), 559 —enable-bcmath compile-time option (Unix), 559 —enable-calendar compile-time option (Unix), 559 —enable-discard-path CGI compile-time option (Unix), 561 —enable-force-cgi-redirect CGI compile-time option (Unix), 561 —enable-safe-mode CGI compile-time option (Unix), 560–561 —enable-url-includes compile-time option (Unix), 559 as printf() and sprintf() alignment character, 151 —with-apache[=DIR] or —with-apache2[=DIR] compile-time option (Unix), 556–557

—with-apx[=DIR] or —with-apx2[=DIR] compile-

time option (Unix), 557 —with-config-file-path[=DIR] compile-time

option (Unix), 559 —with-[database][=DIR] compile-time option

(Unix), 557–558 —with-dom[=DIR] compile-time option (Unix), 559 —with-exec-dir[=DIR] CGI compile-time option

(Unix), 561 —with-java[=DIR] compile-time option (Unix),

558 —with-mcrypt[=DIR] compile-time option (Unix),

558 —with-xmlrpc compile-time option (Unix), 558

\$ (dollar sign) C language versus PHP, 968 literal, in doubly quoted strings (\\$), 78 missing, parse error from, 217 in Perl-compatible regular expressions, 428 \$_SESSION superglobal array (PHP), 459–460, 462–464 for variables (Perl), 974 for variables (PHP), 9, 67 . (dot) combining concatenation and assignment (.=), 139–140 as concatenation operator, 139 in POSIX-style regular expressions, 425 as printf() and sprintf() precision specifier, 151 = (equal sign) for assigning variables (PHP), 67 combining concatenation and assignment (.=), 139–140 in PHP comparison operators, 86, 194–195 ! (exclamation mark) as PHP logical operator, 84 in PHP not equal operator (!=), 86, 195 - (minus sign) as PHP arithmetic operator, 192 ( ) (parentheses) with mathematical operators (PHP), 195 in Perl-compatible regular expressions, 428 % (percent sign) as modulus operator (PHP), 192, 193 in PHP tags (ASP-style), 55 in printf() and sprintf() format strings, 150 . (period). See . (dot) + (plus sign) in Perl-compatible regular expressions, 428 as PHP arithmetic operator, 192 in POSIX-style regular expressions, 425

998

Index ✦ Symbols & Numerics–A

# (pound sign) for PHP comments, 66–67 ? (question mark) for GET strings in URLs, 120 in Perl-compatible regular expressions, 428 in PHP tags, 54 ” (quotation marks) literal, in doubly quoted strings (\”), 78, 355 magic-quotes setting, 355 single quotation marks versus, 78–79, 137 for strings (Perl), 974 for strings (PHP), 68, 78, 137 unescaped, errors from, 219, 353–354 ; (semicolon) missing, parse error from, 217 terminating statements (PHP), 63 ’ (single quotation marks) apostrophes in strings and, 355 double quotation marks versus, 78–79, 137 literal, in singly quoted strings (\’), 77, 355 magic-quotes setting, 355 for strings (Perl), 974 for strings (PHP), 77–78, 137 / (slash) in Perl-compatible regular expressions, 427–428 as PHP arithmetic operator, 192 for PHP comments, 66–67 [ ] (square brackets) in POSIX-style regular expressions, 425 for retrieving characters in strings (deprecated), 139 _ (underscore character) camelcaps versus, 604 _checksumChecks() function (GameDisplay class), 885 _construct() function, 372–373, 879, 887, 888, 891 _currentQuestionString() function (GameDisplay class), 883 _distractorString() function (GameDisplay class), 883–884 _gameStateString() function (GameDisplay class), 887 _getQuestionIdsAtLevel() function (Game class), 893–894 _highScoreEligible() function (GameDisplay class), 884–885 _highScoreString() function (GameDisplay class), 886–887 _installQuestion() function (Game class), 892–893 _makeChecksum() function (GameDisplay class), 885 _makeDistractors() function (Question class), 904 _makeDistractorsGeometric() function (Question class), 905 _makeDistractorsLinear() function (Question class), 905

_makeTopMatter() function (GameDisplay class),

882–883 _maybeChangeLevel() function (Game class),

894–895 _postHighScoreString() function (GameDisplay

class), 885–886 _rightString() function (GameDisplay class),

884 _safeGeometricArguments() function (Question

class), 904–905 _setupQuestionIds() function (Game class), 893 _sleep() function, 385–387, 895, 896 _updateScores() function (Game class), 894 _wakeup() member function (PHP), 386–387 || (vertical bars) as PHP logical operator, 84 20000101.txt Weblog dated entry, 804–805 0 (zero) as default start for index numbering, 161 division-by-zero warning, 225 numerical variable unexpectedly zero, 221 as printf() and sprintf() padding character, 151

Index ✦ A

ampersand (&) in GET strings of URLs, 120 logical operator (&&), 84, 85 and logical operator (PHP), 84 angle brackets (< >) heredoc syntax for strings (<<<), 140 in PHP comparison operators, 86, 194 in PHP tags, 54–55 angle_given_sides() function (PHP), 948 ANSI Web site, 246 answer_string() function (PHP), 616 AOL mail client, 684 Apache HTTP Server Apache1 versus Apache2, 40 basic auth, 851 building on Unix, 42 Common Log Format, 586 configuration files, 561–563 downloading source distribution, 41 installing PHP on Mac OS with, 44–45 installing PHP on Unix with, 42–44 installing PHP on Windows with, 46–47 log files, 585–587 PHP as official module of, 4 restarting, 43 stability, 12 tail log monitoring tool, 586–587 Apache Server 2 Bible (Kabir, Mohammed J.), 551 APIs for database access, 237–238 apostrophe (’) in strings, 355. See also single quotation marks (’) appendChild() method (DomNode class), 742 applets (Java), 23, 26 arbitrary precision (BC) checking if included with PHP, 511 converting code to, 513–515 example, 512 math functions, 511–512 overview, 511 area_to_radius() function (PHP), 948 arguments of functions (Perl), 975 arguments of functions (PHP) arrays as multiple-argument substitutes, 490–491 default, 489–490 formal versus actual parameters, 109 multiple, in PHP4 and above, 491–492 number mismatches, 109–110, 225 Perl differences, 975 recovering the number and value of, 491–492 variable numbers of, 489–492 arithmetic operators (PHP) overview, 192, 206 types and, 192–193 array() construct, 160 array transformation functions (PHP) flipping, reversing, and shuffling, 410–412 merging, padding, slicing, and splicing, 412–413

overview, 409 retrieving keys and values, 410 table summarizing, 413–414 array_count_values() function (PHP), 410, 413 array_flip() function (PHP), 410–411, 413 array_keys() function (PHP), 410, 413 array_merge() function (PHP), 412, 414 array_pad() function (PHP), 412–413, 414 array_pop() function (PHP), 415–416 array_push() function (PHP), 415–416 array_reverse() function (PHP), 411, 414 arrays. See also arrays (PHP) C language, 969 Perl, 975 arrays (PHP). See also iterating arrays (PHP) array variables with forms, 129–131 array/variable-binding functions, 416–417 associative versus vector, 158, 159 C language differences, 969 C++ template libraries versus, 158 creating, 160–161 default start for index numbering, 161 defined, 72, 480 deleting elements from, 165 direct assignment, 160 exercise calculator example, 175–188 flipping, 410–411 functions returning, 161 imitating vector arrays, 159 indexes, 161, 162 inspecting, 164–165 internal structure, 165–166 iterating, 165–175 merging, 412 mimicking other data structures, 159 multidimensional, 158, 163–164 as multiple-argument substitutes in functions, 490–491 overview, 157–159, 189 padding, 412–413 Perl differences, 975 Perl hashes compared to, 158 printing functions, 418–419 retrieving keys and values, 410 retrieving values, 162 reversing, 411 shuffling, 411–412 slicing, 413 sorting functions, 417–418 specifying indices using, 161 splicing, 412–413 stack and queue functions, 415–416 superglobal, 111, 132–133, 459–460 table summarizing, 413–414 transformations of, 409–420 uses for, 157 array_shift() function (PHP), 416

999

1000

Index ✦ A–B

array_shuffle() function (PHP), 411–412, 414 array_slice() function (PHP), 413, 414 array_splice() function (PHP), 413, 414 array_to_bar_graph() function (PHP), 777 array_unshift() function (PHP), 416 array_values() function (PHP), 410, 413

array/variable-binding functions (PHP), 416–417 array_walk() function (PHP), 173–174, 175 arsort() function (PHP), 417–418 ASCII (American Standard Code for Information Interchange), 745 Asin() function (PHP), 507 asort() function (PHP), 417–418 ASP (Microsoft Active Server Pages) ASP-style PHP tags, 55 cost compared to PHP, 6 performance, 12 PHP as open source ASP, 3 popularity compared to PHP, 16 programming versus scripting and, 32 scripting language and, 27 ASP.NET, 8 ASP-style PHP tags, 55 assigning variables (PHP) as arrays, 160 automatic, with GET or POST, 125 checking assignment, 68–69 combining concatenation with, 139–140 overview, 67–68 reassigning, 68 scope and, 69 unassigned variables, 68–69 unassigning, 69 assignment expressions (PHP), 65 assignment operators (PHP), 194, 207, 611 associative arrays. See arrays (PHP) associativity (PHP) of expressions, 63–64 of logical operators, 85 asterisk (*) in Perl-compatible regular expressions, 428 as PHP arithmetic operator, 192 for PHP comments (/* and */), 66 in POSIX-style regular expressions, 425 at sign (@), silent mode indicated by, 280 Atan() function (PHP), 508 Atan2() function (PHP), 508 atomic paradigm, 240 attachments to e-mail, sending, 694–695 authentication (MySQL) config method, for PHPMyAdmin, 271 http or cookie-based, for PHPMyAdmin, 270 MySQL versions and, 261 authentication, user. See user authentication

authorization administrator, 851–852 authentication versus, 851 auto-append-file setting (PHP), 565 auto-prepend-file setting (PHP), 565

B back end servers, 981 backing up databases by copying the data directory, 272 mysqldump for, 272–274 security and, 258 backslash (\). See also specific escape sequences for strings addslashes() function (PHP), 149–150 as escape character in strings, 78, 137 literal, in singly quoted strings (\\), 77, 78 in Perl-compatible regular expressions, 428 in POSIX-style regular expressions, 425 stripslashes() function (PHP), 150 bandwidth, 38 bar_graph_form.php script for graphing form, 778–779 bar_graph.php script for graphics, 777–778 base case for recursive functions (PHP), 117 base class. See parent class base conversion functions (PHP), 503–506 base_convert() function (PHP), 504–505 basename() function (PHP), 448 batch editor project. See product batch editor project (Oracle) batch e-mail custom PHP application, 696–698 sending from a cronjob, 699–700 batch_upload_new.php spreadsheet upload script (Oracle), 662–666 BBEdit text editor, 50 BC. See arbitrary precision bcadd() function (PHP), 511 bcdiv() function (PHP), 511 bcmod() function (PHP), 511 bcmul() function (PHP), 511 bcpow() function (PHP), 512 bcscale() function (PHP), 512 bcsqrt() function (PHP), 512 bcsub() function (PHP), 511 BDB tables, 262 Bernstein, Dan (tcpserver programmer), 682 better_deal function (PHP), 108–109 BIGINT type (MySQL), 290 BinDec() function (PHP), 503 Bison software, 41 BIT type (MySQL), 290 BLOB type (MySQL), 291

Index ✦ B–C

blocks of statements (PHP) curly braces for, 65–66 nesting, 66 book page template (Mystery Guide Web site), 932–940 bookmarking GET method and capability for, 122 POST method and, 124 The Bookstore at Harvard.com (PHP deployment), 5 BOOL type (MySQL), 290 Boolean expressions (PHP) Boolean constants, 75, 84 comparison operators, 86–87, 88 conciseness and, 612–613 in if-else statements, 89 logical operators, 84–86 ternary conditional operator, 87–88, 103 for tests, 84 BOOLEAN type (MySQL), 290 Booleans (PHP) conciseness and, 612 constants, 75, 84 defined, 72, 75, 480 doubles as, avoiding, 76 examples, 75 interpreting other types as, 75 bounded loops (PHP). See also loops (PHP) for loop example, 96–98 unbounded loops versus, 94 Boutell company Web site, 781, 782 box_query() function (PHP), 338 braces. See curly braces ({ }) brackets. See angle brackets (< >); square brackets ([ ]) branches (PHP). See also loops (PHP) defined, 83 HTML mode and, 91–92 if versus switch structure, 88 overview, 88–93 ternary conditional operator and, 87–88, 103 break command for loops Perl, 976 PHP, 99–100 breakpoints, 595 Browse() function (JavaScript), 706, 708 browser latency, 941, 942 browsers client-side scripting dependence on, 25–26 embedded images from scripts and, 787 error reporting to, 533 image formats and, 780–781 Java applets and, 26 linebreaks and, 82 performance and, 941, 942 PHP script displayed in, 209–210, 214–215 prompt you to save file, 210 server-side browser sniff, 707 user interface design and, 917

browsersniff.php server-side browser sniff, 707 bugs. See debugging; error messages; troubleshooting building forms from queries comment_edit.php form, 322–325 date_prefs.php form, 328–331 editing data with HTML forms, 322–334 form handler for newsletter sign-up form, 313–314 form submission to a database, 312–314 HTML forms overview, 311 newsletter_signup.html form, 312–313 newsletter_signup.php form, 316–317 optout.php form, 325–327 self-submission, 314–321 skills_profile.php form, 332–334 three-part form example, 317–321

C C For Dummies (Gookin, Dan), 985 C language further information, 985 guide to this book, 970–971 multiline comments (PHP) and, 66 PHP differences, 968–970 PHP for C programmers, 967–971 PHP similarities, 967–968 PHP source code and, 971 PHP syntax and, 62, 967 printf function, 81–82 types versus PHP types, 72–73 The C Programming Language (Kernighan, Brian W. and Ritchie, Dennis M.), 985 C++ template libraries, 158 caching Mystery Guide site example, 942 Oracle and, 643 Oracle and data caching, 643 products, 567 Web services issues, 763 Calculator class, 381–382 calculator example. See exercise calculator example calendar conversion functions (PHP), 453–454 calendar_form_string() function (PHP), 617 call-by-reference behavior for functions (PHP), 493–495, 499 call-by-value behavior for functions (PHP), 493, 499 call_user_method() function (PHP), 389 call_user_method_array() function (PHP), 389 calorie burning calculator. See exercise calculator example camelcaps versus underscores, 604 canonical PHP tags, 54 capitalization in Oracle, 645 capitalization sensitivity. See case sensitivity caret (^) in Perl-compatible regular expressions, 428 in POSIX-style regular expressions, 425–426

1001

1002

Index ✦ C

carriage-return character (\r), 78 cartoons database example (PostgreSQL), 630–637 cascading deletes, 240 Cascading Style Sheets. See CSS case changing functions for strings (PHP), 148–149 case folding (SAX), 745–746 case sensitivity comparison operators with strings and, 87 of PHP, 62–63 unbound variables and, 222 of variables (PHP), 62–63, 125 CBC (cipher block chaining) cipher mode, 547 ceil() function (PHP), 196, 485, 505–506 centering text, 958 CERT (Computer Emergency Response Team) Web site, 552 certainty_utils.php file (trivia game), 875, 898–901 certificates for public-key encryption, 546 CFB (cipher feedback) cipher mode, 547 CGI ease of use, 8 module PHP versus CGI PHP, 36 CGI compile-time options (Unix), 559–561 cgi-bin directory for PHP, 534 chained subclassing, 375–376 chained_code() function (PHP), 498–499 changeemail.php e-mail change form, 842–844 changepass.php password change form, 844–846 CHAR type (MySQL), 291 character arguments, 138 characterData() function (SAX), 744 characterData() method (SOAP), 773 check boxes in exercise calculator example, 179–182 CHECKBOX form elements, 324–327 checkdate() function (PHP), 453 checkdnsrr() function (PHP), 450 _checksumChecks() function (GameDisplay class), 885 check_user() function (PHP), 541–542 chgrp() function (PHP), 448 child classes chained subclassing, 375–376 defined, 370 overriding functions, 375 chmod() function (PHP), 448 choke_and_die() function (Oracle), 650 chop() function (PHP), 145–146, 148 chown() function (PHP), 448 chr() function (PHP), 111, 485 cipher block chaining (CBC) cipher mode, 547 cipher feedback (CFB) cipher mode, 547 ciphertext. See encryption circle_intersection_area() function (PHP), 948–950 Clark, James (expat creator), 743

class genealogy example (OOP), 390–392 classes abstract, 381 creating instances in PHP, 372 defined, 369 defining in PHP, 371–372 designing for inheritance, 406–407 Exception, 113–114, 571–572 introspection functions, 387–390 simulating functions in PHP, 381–382 TextBoxBoldHeader, 375–376 TextBoxHeader, 374 TextBox.php, 372, 373 for trivia game, 875 XML DOM, 741–742 class_exists() function (PHP), 388 ClassToSerialize class, 385 ClassToSerialize2 class, 386–387 cleanup functions for strings (PHP), 145–146 clearstatcachecopy() function (PHP), 448 client commands (MySQL) basic commands, 265 PHPMyAdmin GUI versus MySQL command-line client, 269 client computers, simple HTTP request and response for, 21 client libraries (MySQL), 261 client-side Java. See Java applets client-side scripting browser dependence, 25–26 characteristics, 26 HTML example using, 23–25 HTML extensions (table), 22–23 limitations, 25–26 programming versus scripting, 32 server-side scripting versus, 31 closelog() function (PHP), 450 closing files, fclose() PHP function for, 446–447 code forking, 14 codebases (PHP), 994–995 ColdFusion (Macromedia) cost compared to PHP, 6 fee structure, 13 performance, 12 popularity compared to PHP, 16 as proprietary alternative to PHP, 3 as tag-based language, 11 colocation, 39 colon (:) with control structures (PHP)/y0, 101 color allocation functions (gd toolkit), 785 color matching functions (gd toolkit), 785 colors, gd toolkit and, 783–784 comma (,) in SQL statements, 358 comment_edit.php form, 322–325 comments (Perl), 977

Index ✦ C

comments (PHP) defined, 66 multiline (C-style), 66 need for, 602 Perl differences, 977 for readability, 602 single-line, 66–67 commercial Web hosting, 37 Common Log Format (Apache), 586 Community Rating code, 942 compact() function (PHP), 416–417 comparison functions for strings (PHP), 143, 144 comparison operators (PHP) arithmetic comparison, 194–195 arithmetic operators (PHP), 207 precedence, 87 strcmp() function versus, 88 strings with, 87, 88 table summarizing, 86 compatibility cross-platform, of PHP, 11 HTML with PHP, 53 short-open PHP tags and, 54, 733 compile-time bugs, 585. See also debugging compile-time options (Unix), 556–561 compiling C language, 970 embedded scripting versus, 10 Java, 720 Perl, 973 Zend Encoder for PHP, 11 Comprehensive Perl Archive Network (CPAN), 977 compressing files, 40, 781 computeChecksum() member function (OOP), 395–396 Computer Emergency Response Team (CERT) Web site, 552 concatenation operator for strings, 139 conciseness advantages, 599 disadvantages, 610–611 efficiency versus, 608, 610–611 readability versus, 610–611 tips, 611–613 config.inc.php file (MySQL), 271 configuration (PHP). See also installing PHP; php.ini file Apache configuration files, 561–563 compile-time options (Unix), 556–561 improving performance, 566–568 overview, 555–556, 568 session configuration variables, 468–469 viewing environment variables, 555 Windows options, 555–556 confirmOne() function (JavaScript), 714 confirm.php new-user confirmation page, 830–831

connect() member function (PEAR DB), 678

connecting to MySQL custom function for, 280 functions for, 279–280 multiple connections, 285–287 multiple results from single connection, 338–339 once per statement, avoiding, 337–338 performance issues, 337–339 persistent connections, 339 troubleshooting, 351–353 connecting with PEAR DB, 675 consolidating forms with form handlers. See self-submission constants (OOP), 380–381 constants (PHP) Boolean, 75, 84 creating, 71 mathematical, 501–502 overview, 70–71 _construct() function Game class, 891 GameDisplay class, 879, 887 GameText class, 888 PHP, 372–373 constructors automatic calls to parent constructors, 384 calling parent constructors, 382–383 _construct function for (PHP), 372–373 defined, 369 PHP support for, 370 consumer ISPs, 37 content_functions.php quotation contents presentation file, 862–864 continue statement for loops Perl, 976 PHP, 99–100 control structures (PHP). See also branches (PHP); loops (PHP) alternate syntaxes, 101 Boolean expressions, 84–88 branches, 83, 88–93 C language similarities, 968 dependent code, 84 exit() construct, 102, 103 loops, 83, 94–101 overview, 118 PEAR coding style for, 526–527 table summarizing, 103–104 terminating execution, 102–104 tests, 84 types of, 83 converting. See also converting static HTML sites assigned by context, 71–72 base conversion functions, 503–506 between calendar systems, 453–454 Continued

1003

1004

Index ✦ C–D

converting (continued) code to arbitrary-precision, 513–515 to integers or doubles, 191 types automatically (PHP), 71, 191, 481–482 types (C language), 968 types explicitly (PHP), 482–484 types, integer overflow and, 486 converting static HTML sites. See also Mystery Guide Web site caching, 942 dumping data into the database, 922–932 overview, 943 performance, 941–942 planning the database schema, 918–922 planning the upgrade, 913–915 redesigning the user interface, 916–917 templating, 932–940 cookies for authorization, 852 defined, 457, 469 deleting, 472 encrypting, 548–549 overview, 469, 478 for PHPMyAdmin authorization, 270–271 pitfalls, 474–475 privacy and, 471 reading or getting, 469, 472–473 refusal of, 475 reverse-order interpretation of, 475 sending something else first, avoiding, 474–475 server-side storage versus, 469 sessions versus, 457–458 set_cookie() function, 469–473 superglobal arrays and, 133 copying backing up databases, 258, 272–274 data directory for backup, 272 replication, 241, 274–276 Cos() function (PHP), 507 cosmetic changes for displaying queries in HTML tables, 300 for learning PHP, 983–984 costs fee structures for software, 13 open source software viability and, 7 outsourcing Web hosting, cost effectiveness, 36 PHP/MySQL compared to proprietary solutions, 6 count() function (PHP), 164 count_chars() function (PHP), 437 countdown_first() function (PHP), 117 countdown_second() function (PHP), 117 CPAN (Comprehensive Perl Archive Network), 977 crackers, 533 CREATE statement, 254 createElement() method (DomDocument class), 742

create_randomized_array() function (trivia game),

901 createTextNode() method (DomDocument class), 742 cronjob, sending e-mail from, 699–700

cross-platform compatibility of PHP, 11 CSS (Cascading Style Sheets) methods of applying, 618 for separating code from design, 618 uses and effects, 22 Weblog stylesheet, 806–807 curly braces ({ }) for blocks of statements (PHP), 65–66 for retrieving characters in strings, 139 for variable interpolation in strings (PHP), 138 current() function (PHP), 168–169, 174 _currentQuestionString() function (GameDisplay class), 883 cursors (Oracle), 646–647 Cygwin framework, 624, 625 Cyrus IMAP server, 685

D dash (-) —disable-url-fopen-wrapper compile-time

option (Unix), 559 —enable-bcmath compile-time option (Unix), 559 —enable-calendar compile-time option (Unix),

(Unix), 561 —enable-force-cgi-redirect CGI compile-time

option (Unix), 561 —enable-safe-mode CGI compile-time option

(Unix), 560–561 —enable-url-includes compile-time option

(Unix), 559 as printf() and sprintf() alignment character, 151 —with-apache[=DIR] or —with-apache2[=DIR] compile-time option (Unix), 556–557 —with-apx[=DIR] or —with-apx2[=DIR] compiletime option (Unix), 557 —with-config-file-path[=DIR] compile-time option (Unix), 559 —with-[database][=DIR] compile-time option (Unix), 557–558 —with-dom[=DIR] compile-time option (Unix), 559 —with-exec-dir[=DIR] CGI compile-time option (Unix), 561 —with-java[=DIR] compile-time option (Unix), 558 —with-mcrypt[=DIR] compile-time option (Unix), 558 —with-xmlrpc compile-time option (Unix), 558 data caching. See caching

Index ✦ D

data manipulation statements (SQL). See also specific statements DELETE statements, 252 INSERT statements, 251 overview, 246 SELECT statements, 247–251 UPDATE statements, 251 data munging Oracle for, 640–641 Web services for, 757–758 data sets fetching (MySQL), 282–284 for HTML graphics (MySQL), 776–777 huge, Oracle for, 640 Data Source Names (DSNs), 674–675 data types. See types; types (MySQL); types (PHP) data visualization with Venn diagrams centering text, 958 database connection, 958–963 db_visualization.php form handler, 946, 961–963 displaying the graphics, 957–958 extensions, 965 outline of the code, 946 planning the display, 950–957 query_clauses.php file, 959–960 scaled Venn diagrams, 945–946 simplifying assumptions, 950–951 size and scale issues, 951–952 trigonometry for, 947–950 trig.php intersection area calculator, 946, 948–950 using the program, 963–964 venn.php Venn diagram functions, 946, 952–957 visualization_form.php form, 946, 958–961 database abstraction advantages and disadvantages, 242–243 database administration (MySQL) backups, 272–274 basic client commands, 265 installing MySQL, 260–264 licensing, 259–260 PHPMyAdmin GUI for, 269–272 recovery, 276–278 replication, 274–276 user administration, 265–269 database design choosing field types for tables, 345 constructing the database, 254–255 many-to-many data and, 253–254 one-to-many or many-to-one data and, 252, 253–254, 342 one-to-one data and, 252, 253 performance and table design, 344–345 database independence advantages and disadvantages, 670–673 database abstraction and, 671, 673 native database functions and, 672–673

1005

1006

Index ✦ D

debugging (continued) exception and error handling and, 580–581 general strategies, 583–584 isolating the problem, 584 learning from, 984 monitoring variable values, 595 overview, 596–597 in pairs, 984 PHP error reporting and logging for, 587–593 queries in PHP code, 361–362 re-testing after fixing, 584 simplifying, then building up, 584 stepping through programs, 595 types of bugs, 584–585 variety of tools for, 583 visual tools for, 593–596 Web server logs for, 585–587 DEC type (MySQL), 291 DecBin() function (PHP), 503 DecHex() function (PHP), 504 DECIMAL type (MySQL), 291 declaration (XML), 733 declaring variables (PHP), 67 DecOct() function (PHP), 503 decryption. See encryption dedicated servers for Web hosting, 39 defaults arguments of functions, 489–490 index numbering, 161 unassigned variable values, 68 default.txt Weblog default message, 805 define() function (PHP), 71 delete() function (PHP), 448 DELETE statements condition needed for, 252 overview, 252 permissions for, 255 slowed by indexes, 340–341 syntax, 252 deleting array elements (PHP), 165 cascading deletes, 240 cookies, 472 database tables, 254 MySQL database with PHP, 288–289 PEAR packages, 524 revoking permissions (MySQL), 268 denormalized data, 250 derived classes. See child classes deselectAllOther() function (JavaScript), 714 designing. See also database design browsers and, 917 data visualization display, 950–952 database schema, 918–922 for inheritance (OOP), 406–407

separating code from design, 618–619 user interface redesign, 916–917 user-authentication system, 819–820 destructors defined, 369 PHP support for, 370 development different operating system for production, 49 Oracle and, 642 self-hosting, while outsourcing production, 39 development tools (PHP) diversity of usages and, 47 market changes for, 48 on operating system different from server, 49 for readability, 600–601 text editors, 49–50 Zend Studio, 48–49 Devshed Web site, 994 dicing strings (PHP), 144–145 die() construct (PHP), 102, 104, 287 die_silently() function (Oracle), 650 digitally signing files, 550–551 directory functions. See filesystem functions (PHP) directory permissions (PHP), 440 dirname() function (PHP), 448 disable_functions setting (PHP), 564 —disable-url-fopen-wrapper compile-time option (Unix), 559 disabling mysql extension, 261 PHPMyAdmin GUI when not in use, 270 register_globals directive, 821 short-open PHP tag setting, 54, 55 disconnect() member function (PEAR DB), 679 disconnecting with PEAR DB, 676 disk space index requirements, 343 with Web hosting service plan, 38 disk_free_space() function (PHP), 448 display() function (GameDisplay class), 879, 880–882 display() function (PHP), 372 display() member function (TextBoxHeader class), 375 display_cities() function (PHP), 303–304, 305–306 display_db_query() function (PHP), 300–301 display_db_table() function (PHP), 297, 301 displayEntryForm() function (trivia game), 909–910 display_errors setting (PHP), 351, 356, 533, 587–588, 589 display_func_results() function (PHP), 508–510 displaying queries in HTML tables choosing between techniques for, 295 complex mappings, 302–307 complex printing example, 305–307

Index ✦ D

cosmetic issues, 300 creating the sample tables, 307–309 displaying arbitrary queries, 300 displaying column headers, 299 error-checking, 299 HTML tables versus database tables, 295–296 multiple queries versus complex printing, 302–303 multiple-query example, 303–305 one-to-one mapping, 296 query displayer example, 300–302 reusing functions for, 295 sample tables, 298–299, 307–309 single-table displayer example, 296–298 views and stored procedures, 303 display_path() function (PHP), 790, 794 _distractorString() function (GameDisplay class), 883–884 distributed computing, 758 DivisibleByBad() function (PHP), 612 DivisibleByBetter() function (PHP), 612 division table for loop example, 96–98 DNS functions (PHP), 450 doc_root setting (PHP), 565 Document Object Model. See DOM document type declaration (XML), 737 document type definitions (DTDs). See DTDs documentation of functions (PHP) finding information in the manual, 106–107 finding the online manual, 105 function reference, 106 headers in the manual, 106 DocumentRoot Apache configuration setting, 562 dollar sign (\$) C language versus PHP, 968 literal, in doubly quoted strings (\\$), 78 missing, parse error from, 217 in Perl-compatible regular expressions, 428 \$_SESSION superglobal array (PHP), 459–460, 462–464 for variables (Perl), 974 for variables (PHP), 9, 67 DOM (Document Object Model) bugs database, 755 functions, 741–742 further information, 740 other XML APIs versus, 739–740 overview, 739 PHP parser (gnome-libxml2), 739, 740 simple example, 740–741 troubleshooting, 755 using, 740–741 DomAttr class, 741 DomDocument class, 741 DomNode class, 741 dom_polledit.php XML editor, 752–755

domxml_new_doc() function (DOM), 741 domxml_open_file() function (DOM), 741 domxml_open_mem() function (DOM), 741 domxml_xmltree() function (DOM), 741

1007

1008

Index ✦ D–E

dumping data into a database basic steps, 923 data-massaging for, 922–923 harvesting data, 928–932 script for, 923–927 dynamic HTML. See also converting static HTML sites definitions of dynamic, 22 uses and effects, 22 dynamically generated forms dyn_navigation.html, 708 JavaScript for, 708–713

E e, mathematical constants for, 501–502 each() function (PHP), 172–173, 175 E_ALL constant (PHP), 70–71

early binding and PHP, 371 ease of use, 8–9 ECB (electronic code book) cipher mode, 547 echo function (PHP) overview, 80–81 for variables and strings, 81–82 ECMA Web site, 246 editing data with HTML forms CHECKBOX data elements, 324–327 comment_edit.php form, 322–325 date_prefs.php form, 328–331 optout.php form, 325–327 PHP advantages for, 322 RADIO data elements, 327–331 SELECT fields, 332–334 skills_profile.php form, 332–334 TEXT and TEXTAREA data elements, 322–324 edit.php example (PostgreSQL), 634–636 edit_userinfo.php form, 846–851 Edmunds, Keith (Webmaster), 50 efficiency or performance. See also caching algorithms and, 609 browser latency and, 941, 942 conciseness versus, 608, 610–611 database connections and, 337–339 database design and, 344–345 database disadvantages, 235–236 estimating for Web site, 941–942 improving PHP performance, 566–568 indexing tables for, 340–344 Java and, 729 making the database work for you, 345–349 network latency and, 941 optimization tips, 609–610 optimizing and caching products, 567 overview, 350 PHP with Apache HTTP Server and, 4 server latency and, 941 style for, 599, 608–610

user-rating system, 869 Web services issues, 763 electronic code book (ECB) cipher mode, 547 elements (XML) DTDs and, 736, 738 overview, 733 short-open PHP tags and, 54 elm MUA, 684 else clause for if statements (PHP), 89, 90 elseif construct (PHP), 90, 92 emacs text editor, 50, 986 e-mail custom batch mail application, 696–697 implementing from scratch, avoiding, 686 mail retrieval utilities, 685 mail spool, 683 Mail Transfer Agents (MTAs), 682–683 Mail User Agents (MUAs), 684 mailing list managers, 685–686 mail-retrieval programs, 684–685 modifying other’s PHP for, 686–687 overview, 681–682, 701 POP/IMAP servers, 685 receiving with PHP, 686–687 sending attachments with MIME mail, 694–695 sending from a cronjob, 699–700 sending from a database, 693–694 sending from a form, 690–693 sending with PHP, 687–690 TCP/IP server, 682 troubleshooting, 701 Unix configuration, 688 Windows configuration, 688 e-mail security, 538–539 emailpass_funcs.inc e-mail and password functions, 839–842 email_send.php batch e-mail form handler, 697–698 embedded HTML Java and, 721–722 Perl and, 974–975 PHP’s embeddedness, 9–11 Empress databases, PHP support for, 241 —enable-bcmath compile-time option (Unix), 559 —enable-calendar compile-time option (Unix), 559 —enable-discard-path CGI compile-time option (Unix), 561 —enable-force-cgi-redirect CGI compile-time option (Unix), 561 —enable-safe-mode CGI compile-time option (Unix), 560–561 —enable-url-includes compile-time option (Unix), 559 enabling register_globals directive, 133, 460 short-open (SGML-style) PHP tags, 54

Index ✦ E

encapsulation overview, 369 PHP support for, 370 encodings for internationalization, 745 encryption for cookies, 548–549 defined, 545 digitally signing files, 550–551 hashing, 549–550 for passwords, 256, 536–537, 822–823 public-key, 545–546 single-key, 546–548 SSL, 270, 551 end() function (PHP), 171, 174 endElement() function (SAX), 744 endElement() method (SOAP), 772–773 ending statements for control constructs, 101 end-of-line characters as whitespace (PHP), 62 entry_form.php file (trivia game), 875, 908–909 ENUM type (MySQL), 291 environment variables, viewing, 555 Epinions.com (PHP deployment), 5 equal sign (=) for assigning variables (PHP), 67 combining concatenation and assignment (.=), 139–140 in PHP comparison operators, 86, 194–195 ereg() function (PHP), 425–426 eregi() function (PHP), 427 eregi_replace() function (PHP), 427 ereg_replace() function (PHP), 427 error handling (PHP). See also error reporting and logging (PHP); exceptions (PHP) defining a custom error handler, 578–579 die() construct for, 102, 104, 287 displaying queries in HTML tables, 299 Exception class for functions, 113–114 exceptions versus errors, 569 include functions and, 57 MySQL error checking, 287–288 native PHP errors, 576–577 overview, 581 in PHP5, 569–575 in PHP4 and older versions, 576–579 for queries, 357–358 triggering a user error, 579 for unassigned variables, 68 using exceptions, 571–575 without exceptions, 570–571 error messages. See also debugging; logging; troubleshooting avoiding errors, IDE help for, 594–595 call to undefined function, 224 call to undefined function array, 224–225 cannot declare function, 225 division-by-zero warning, 225 document contains no data, 211–212

error reporting and logging (PHP), 587–593 failed opening [file] for inclusion, 216 fatal error during connection, 351–352 Headers already sent error (HTTP), 786, 796 HTTP error 403, 220 HTTP response codes (Apache), 586 include warning, 220 Java, 727–728 mail-related, 701 native PHP errors, 576–577 No Connection warning, 351, 352–353 page cannot be found, 215 parse error, 216 reporting to browsers, 533 Server or host not found/Page cannot be displayed, 210 SQL syntax errors, 356–359 error reporting and logging (PHP). See also error handling (PHP); exceptions (PHP) choosing errors to report or log, 588–589 custom location for log messages, 592 diagnostic print statements for, 589–590 error reporting overview, 587–588 error_log() function for, 592–593 error-reporting functions, 589–593 logging overview, 588 printr() function for, 590 syslog() function for, 590–592 error reporting (Oracle), 644 error.log file (Apache), 585, 586 error_log() function (PHP), 580–581, 592–593 error_msg() function (PHP), 578, 580 error_prepend_string setting (PHP), 564 error_reporting setting (PHP), 564, 588–589 error_reporting() statement, 110 errors. See debugging; error messages; troubleshooting escape strings (PHP) escaping from HTML into PHP versus, 53 escaping functions, 149–150 Oracle and, 644 overview, 78 string cleanup functions and, 78 escape_html() function (Oracle), 649 escape_sq() function (Oracle), 648 escaping from HTML into PHP escape strings versus, 53 examples, 53–54 overview, 56–57 troubleshooting, 218–219 escaping functions for strings (PHP), 149–150 etiquette for PHP mailing lists, 991–993 Eudora Light (Qualcomm), 684 evaluating (PHP) expressions, 63–64 function calls, 104 logical operators, 85

1009

1010

Index ✦ E–F

event hooks (SAX), 743 EvilWalrus Web site, 995 Exception class (PHP) defining your own subclasses, 573–575 overview, 113–114, 571–572 Exception object (Java), 728 exceptions (Java), 727–728 exceptions (PHP). See also error handling (PHP); error reporting and logging (PHP) defining your own Exception subclasses, 573–575 error handling using, 571–575 errors versus, 569 examples, 113–114 Exception class, 113–114, 571–572 limitations of, 575 logging and debugging, 580–581 recovering using custom exceptions, 574–575 throwing an exception, 572–573 trivia game example, 878, 911 try/catch construct for, 113, 572 exclamation mark (!) as PHP logical operator, 84 in PHP not equal operator (!=), 86, 195 exercise calculator example entry form with check boxes, 179–181 form submission code for fitness calculator, 201–203 for multidimensional arrays, 183–185 with radio buttons, 175–177 with revised form-handling target, 151–152 simple HTML form, 134–135 workout_calc_var.html, 134–135 exercise_include.php file, 201 form handler for check boxes, 181–182 for fitness calculator, 203–206 for multidimensional arrays, 186–188 for radio-button selection, 177–179 for simple form, 135–136 using string functions, 152–156 wc_handler_math.php, 204–206 wc_handler_var.php, 135–136 using arithmetic calculation, 200–206 using arrays, 175–188 using string functions, 151–156 exercise_include.php file, 201 exit() construct (PHP), 102, 104 exp() function (PHP), 506–507 expat XML parser toolkit, 743 explode() function (PHP), 423–424, 485–486 exponential functions (PHP), 506–507 exporting functions (gd toolkit), 786 expressions (PHP) assignment, 65 Boolean, 84–88

evaluation of, 63–64 as function arguments, 109 indivisible tokens in, 63 matching types in, 64 precedence rules, 64 reasons for writing, 65 regular, 421, 424–433 as statement building blocks, 63 treatment as strings, forcing, 68 extends clause (PHP), 373–374 eXtensible Markup Language. See XML extensions to PHP. See also PEAR (PHP Extension and Application Repository) for Java, 724–726 mysqli versus mysql extension, 261 wide variety of, 14 for XML, internationalization encodings supported, 745 external DTDs (XML), 736, 738 extract() function (PHP), 416–417 ezmlm MLM, 686

F failover, Oracle and, 642–643 fatal error during connection, 351–352 favorites.php static Weblog page, 805 fclose() function (PHP), 446–447 feof() function (PHP), 447 fetching data sets (MySQL), 282–284 data sets (Oracle), 645 null values (Oracle), 644 fetchInto() member function (PEAR DB), 679 Fetchmail mail retrieval utility, 685 fetchRow() member function (PEAR DB), 679 fgetc() function (PHP), 444 fgetcsv() function (PHP), 448 fgets() function (PHP), 444, 450 fgetss() function (PHP), 448 file compression, 40, 781 file() function (PHP), 444 file permissions (PHP), 439–440 file reading and writing functions (PHP) closing files, 446–447 constructing file downloads, 444–445 file manipulation session overview, 440–441 opening files, 441–443 reading files, 443–444 writing files, 445–446 file upload security, 542–545 fileatime() function (PHP), 448 filectime() function (PHP), 448 file_exists() function (PHP), 447 file_get_contents() function (PHP), 444 filegroup() function (PHP), 448 fileinode() function (PHP), 448

Index ✦ F

filemtime() function (PHP), 448 fileowner() function (PHP), 448 fileperms() function (PHP), 448 filesize() function (PHP), 447

filesystem functions (PHP) feof(), 447 file_exists(), 447 filesize(), 447 overview, 447, 454 table summarizing, 448–449 using fopen() from the filesystem, 443 filetype() function (PHP), 448 filling functions (gd toolkit), 785 financial data, Oracle for, 640 find_center_distance() function (PHP), 956–957 finding. See also queries (MySQL) characters and substrings (PHP), 141–142 database advantages for, 234–235 largest integer supported by PHP, 486 online manual information (PHP), 105, 106–107 searching strings (PHP), 143–144 Web hosting services, 38 fitness calculator. See exercise calculator example FIXED type (MySQL), 291 Flash animations, 23 flat-file databases, 236–237 flex software, 41 flipping arrays (PHP), 410–411 float type. See doubles (PHP) FLOAT types (MySQL), 290 floatval() function (PHP), 483 flock() function (PHP), 448 floor() function (PHP), 196, 485 FLUSH PRIVILEGES command (MySQL), 268 footer.inc Weblog footer, 806 fopen() function (PHP) for FTP connection, 442 for HTTP connection, 442 modes, 441, 445 overview, 441–442 for standard I/O, 442–443 using from the filesystem, 443 for construct (PHP) bounded loop example, 96–98 break and continue with, 99–100 endfor construct with, 101 overview, 95–96, 104 syntax, 95, 104 foreach construct (PHP), 167–168 foreign keys, choosing a database and, 240 forgiving nature of PHP, 61, 970 forgot.php forgotten password form, 837–839 form handlers for batch e-mail application, 697–698 consolidating with forms (self-submission), 128–129, 314–321 for data visualization example, 946, 961–963

exercise calculator example for check boxes, 181–182 for fitness calculator, 203–206 for multidimensional arrays, 186–188 for radio-button selection, 177–179 for simple form, 135–136 using string functions, 152–156 for navigation form, 706 for newsletter sign-up form, 313–314 for sending e-mail, 692–693 formhandler.php for newsletter sign-up form, 313–314 form_printer.php program, 398–404 forms (HTML). See HTML forms formulaic writes, Oracle and, 640–641 fpassthru() function (PHP), 444–445, 448 fputs() function (PHP), 445–446, 450 fractal images program display_path() function, 794 fractal image defined, 788 fractal1.php program, 795 fractal2.php program, 796 make_large_rectangle() function, 793–794 make_small_rectangle() function, 793 overview, 788–789 path_display.php defining datatypes, 789–790 path_manipulation.php program, 791–794 path_tranform.php program, 790–791 point_along_segment() function, 793 spike() function, 791–792, 794, 795 top-hat() function, 791, 792, 795 transform_path() function, 790–791, 794 fractal1.php program, 795 fractal2.php program, 796 fread() function (PHP), 443–444 free() member function (PEAR DB), 679 free Web hosting, 37 fseek() function (PHP), 449 fsockopen() function (PHP), 450, 451 ftell() function (PHP), 449 FTP fopen() function for (PHP), 442 scp versus, 807 FULLTEXT indexes, 344 func_args_as_array() function (PHP), 492 func_get_arg() function (PHP), 491–492 func_get_args() function (PHP), 491–492 func_num_args() function (PHP), 491 function calls (PHP) basic syntax, 104 PEAR coding style for, 538 to undefined function arrays, 224–225 to undefined functions, 224 functions. See also functions (PHP); functions (PHP/MySQL); member functions (methods) C language, 968 DOM, 741–742 Continued

1011

1012

Index ✦ F–G

functions (continued) gd toolkit, 784–786 Oracle OCI8, 643–647 SAX, 746–747 SimpleXML API, 748 functions (PHP). See also functions (PHP/MySQL); specific functions and types of functions advanced features example, 495–499 arbitrary precision (BC) math functions, 511–512 argument number mismatches, 109–110, 225 array printing functions, 418–419 array sorting functions, 417–418 array transformation functions, 409–414 array/variable-binding functions, 416–417 base conversion functions, 503–506 basic math functions, 196, 207 building in error checking with MySQL, 287–288 C language similarities, 968 calendar conversion functions, 453–454 call-by-reference behavior, 493–495 call-by-value behavior, 493 case insensitivity, 63 for cookies, 469–473 date and time functions, 451–453 defined, 107 defining with default arguments, 489–490 documentation, 105–107 for e-mail, 688–690 error-reporting functions, 589–593 exceptions, 113–114 exponential and logarithmic functions, 506–507 file reading and writing functions, 440–447 filesystem and directory functions, 447–449 formal versus actual parameters, 109 gd toolkit interface functions, 784–786 global versus local variables and, 111–112 hashing functions, 550 headers in documentation, 106 implementation of, 505–506 include functions, 57–58 for inspecting arrays, 164–165 introspection functions, 387–390 iteration functions, 167, 168–175 maintainability and, 606 network functions, 450–451 OCI8 functions (PHP/Oracle), 643–644 output functions, 80–82, 150–151 PEAR coding style for, 538 procedural abstraction and, 83 program-execution functions, 538 random number functions, 197 for recovering the number and value of arguments, 491–492 recursive, 116–117 regular expression functions, 426–427, 429–430 return statements in, 108, 109

return values versus side effects, 105 returning arrays, 161 reusing, 295, 611 scope of, 110, 115–117 for sending HTTP headers, 475–476 separating code from design, 618 session functions, 465–468 for single-key encryption (Unix), 547–548, 549 stack and queue functions, 415–416 static variables and, 112–113 string functions, 140–151, 421–424, 434–438 syntax for calling, 104 syslog functions, 450, 590–592 tests on numbers, 502–503 tokenizing and parsing functions, 421–424 trigonometric functions, 507–510 troubleshooting, 224–225 type conversion functions, 482–483, 485–486 type testing functions, 481 user-defined, 107–110 using regular expressions in, 432–433 variable function names, 495 variable numbers of arguments, 489–492 variable scope and, 70, 110–114 for viewing environment variables, 555 functions (PHP/MySQL). See also functions (PHP); specific functions connecting to MySQL, 279–280, 284–287 creating MySQL databases with PHP, 289–291 custom connect function, 280 custom, opening and closing connections within, 338 fetching MySQL data sets, 282–284 getting information about MySQL data, 284–285 making MySQL queries, 281–282 multiple MySQL connections, 285–287 overview, 293–294 table summarizing, 291–293 troubleshooting, 360–361 fwrite() function (PHP), 445–446

G Game class (trivia game)

code, 890–895 data members, 889–890 database interaction, 890 described, 875 handling an answer, 895–896 public functions, 890 serialization and sleep() function, 896 game_class.php file (trivia game), 889–896 GameDisplay class (trivia game), 875, 878–887 game_display_class.php file (trivia game), 878–887 gameLostText() function (GameText class), 889 GameParameters class (trivia game), 875, 896–898 game_parameters.php file (trivia game), 896–898

Index ✦ G

_gameStateString() function (GameDisplay

class), 887 GameText class (trivia game), 875, 888–889 game_text_class.php file (trivia game), 888–889 gameWonText() function (GameText class), 889 gd toolkit circle drawing with, 958 downloading, 781 drawing coordinates and commands, 784 embedded images and, 787 format translation, 784 freeing resources, 784 full-page images and, 786 functions, 784–786 image formats and browsers, 780–781 installing, 782 overview, 780 transparency for images, 784 truecolor versus palette-based colors, 783 versions, 781–782 geek_quiz.php form example, 129–132 generalized test methods example (OOP), 395–398 GET method (HTTP), REST and, 760 GET method (PHP) ACTION attribute, 120 advantages and disadvantages, 122 automatic variable assignment with, 125 bookmarking capability and, 122 deprecation and reinstatement of, 122 examples, 120–121, 122–124 for form handling, 120–122 POST method versus, 122, 124 POST method with, 124 query string length limits and, 122 recommended for idempotent usages only, 122 for site navigation, 122–124 in templates, 122–124 URL construction by, 120–121 getAll() member function (PEAR DB), 679 getAnswerSpread() function (Question class), 902, 903 getAssoc() member function (PEAR DB), 679 getBlueColor() function (GameDisplay class), 879 get_categories.sql stored procedure (Oracle), 657–658 get_child_classes() member function (OOP), 391 get_class() function (PHP), 388, 389 get_class_methods() function (PHP), 388, 390 get_class_vars() function (PHP), 388, 389–390, 394 getCol() member function (PEAR DB), 679 getCorrectAnswers() function (Game class), 891 getCredit() function (Game class), 891 getCurrentQuestion() function (Game class), 891 getCurrentQuestionText() function (Game class), 892 getdate() function (PHP), 452

get_day_of_week() function (PHP), 616 getDbConnection() function (Game class), 892 get_declared_classes() function (PHP), 388, 391 getFormNum() function (JavaScript), 710 getGame() function (GameDisplay class), 880 getGameLost() function (Game class), 891 getGameParameters() function (Game class), 891 getGameWon() function (Game class), 892 getHighScorePosted() function (GameDisplay

class), 880 gethostbyaddr() function (PHP), 450 gethostbyname() function (PHP), 450 gethostbynamel() function (PHP), 450 get_html_translation_table() function (PHP), 435 getLevel() function (Game class), 891 getmxrr() function (PHP), 450 get_object_vars() function (PHP), 388, 389–390 getOne() member function (PEAR DB), 679 getPageTitle() function (GameDisplay class), 879 get_parent_class() function (PHP), 388, 389, 390 get_post_value() function (trivia game), 899 getPreviousQuestion() function (Game class), 891 _getQuestionIdsAtLevel() function (Game class),

class), 891 getrandmax() function (PHP), 197, 199 getRecipe() method (SOAP), 771 getRedColor() function (GameDisplay class), 879 getRow() member function (PEAR DB), 679 getservbyname() function (PHP), 451 getservbyport() function (PHP), 451 get_session_value() function (trivia game), 899

getting cookies, 469, 472–473 getTotalQuestions() function (Game class), 891 gettype() function (PHP), 481 get_user_key() function (PHP), 550–551 GIF format issues for browsers, 781 global variables (PHP) automatic, superglobal arrays versus, 132–133 functions and, 111–112 overwritten, troubleshooting, 223–224 registering, avoiding, 133 scope of, 69 superglobal arrays, 111 gmdate() function (PHP), 453 gmmktime() function (PHP), 453 gmstrftime() function (PHP), 453 gnome-libxml2 PHP DOM parser, 739, 740 Gnu, downloading, 41 Gnu inetd TCP/IP server, 682 Goodman, Danny (JavaScript Bible), 703 Gookin, Dan (C For Dummies), 985 gotchas. See debugging; error messages; troubleshooting GRANT statement permissions, 255

1013

1014

Index ✦ G–H

graphics fractal images example, 788–795 gd toolkit for creating, 780–786 HTML, 775–780 HTTP and, 786–787 options for creating, 775 troubleshooting, 795–797 GROUP BY construct, 346 GUIs, choosing a database and, 238 Gutmans, Andi (PHP developer), 4

H hackers, 533 handle_EntryForm() function (trivia game), 908–909 handleHighScore() function (GameDisplay class),

882 harvesting data, 928–932 harvest.php script, 931–932 hashing encryption algorithms, 549–550 MD5 algorithm, 435–436, 823, 824 mhash function library, 550 hashing (flat-file) databases, 236–237 header() function (PHP), 475–476, 477 header_download.php script (Oracle), 657, 658–662 header.inc Weblog header file, 805–806 headingElementBreak() member function (OOP), 400 Hello World program, 55–56 heredoc syntax for strings (PHP), 140, 616–617 HexDec() function (PHP), 504 hidden variables, session alternative using, 457 hiddenVariablesString() member function (OOP), 400 _highScoreEligible() function (GameDisplay class), 884–885 _highScoreString() function (GameDisplay class), 886–887 history MySQL, 5–6 Mystery Guide Web site, 913 PEAR, 518 PHP, 4–5 HomeSite text editor, 50 Horde.org Web site, 687 hosting. See Web hosting Hotmail mail-retrieval program, 684 HTML. See also converting static HTML sites; displaying queries in HTML tables; HTML forms client-side technologies, 22–26 embedded, Java and, 721–722 embeddedness of PHP, 9–11 embedding images, 787 graphics, 775–780 limitations and XML, 731–732 linebreaks and, 82

Index ✦ H–I

sending e-mail from, 690–693 server-side browser sniff, 707 skills_profile.php form, 332–334 stateless nature of HTTP and, 119 submitting data to database via, 312–314 superglobal arrays for, 111, 132–133 TEXT and TEXTAREA data elements, 322–324 for user authentication login, 834–836 user authentication registration form, 827–829 VALUE attribute of variables and, 126 XML application example, 748–755 HTML mode. See also PHP mode branches and, 91–92 escaping into PHP mode from, 53–54, 56–57, 218–219 PHP mode versus, 613–617 scope of variables and switching modes, 70 troubleshooting mode issues, 218–219 HTML script tags (PHP), 55 HTML Tidy program, 600 HTML validators, 600 htmlentities() function (PHP), 435 htmlspecialchars() function (PHP), 434, 533 HTTP authentication, 476–477 error 403, 220 fopen() function for (PHP), 442 graphics and, 786–787 for PHPMyAdmin authorization, 270–271 response codes (Apache), 586 sending HTTP headers, 470, 475–477, 786 simple request and response, 21 as stateless protocol, 119, 455–456 httpd.conf Apache configuration file, 561–563 Hughes, David (Hughes mSQL developer), 5 Hughes mSQL (MySQL precursor), 5–6

I IBM DB2 databases, PHP support for, 241 idempotent usages, 122 ideological rigor and static HTML, 22 IESetup() function (JavaScript), 712 if-else statements (PHP) Boolean constants in, 75, 84 Boolean expressions with, 89 else clause, 89, 90 elseif construct versus, 90, 92 endif construct with, 101 HTML mode and, 91–92 nesting, 89 overview, 89, 103 PEAR coding style for, 527 Perl differences, 976–977 switch structure versus, 88, 93 syntax, 89, 103 ignore_user_abort setting (PHP), 566, 567

IIS (Microsoft Internet Information Server) installing PHP with, 45–46 logs, debugging using, 587 SSL information, 270 troubleshooting information, 587 ImageArc() function (PHP), 785, 958 imagecircle() function (PHP), 952, 957 ImageColorAllocate() function (PHP), 783, 784, 785, 957 ImageColorAllocateAlpha() function (PHP), 785 ImageColorClosest() function (PHP), 785 ImageColorClosestAlpha() function (PHP), 785 ImageColorClosestExact() function (PHP), 785 ImageColorClosestExactAlpha() function (PHP), 785 ImageColorDeallocate() function (PHP), 785 ImageCreate() function (PHP), 783, 785, 957 ImageCreateFromGd() function (PHP), 785 ImageCreateFromJpeg() function (PHP), 785 ImageCreateTrueColor() function (PHP), 783, 785 image-creation functions (gd toolkit), 785 ImageDashedLine() function (PHP), 785 ImageDestroy() function (PHP), 784, 958 image-destruction functions (gd toolkit), 786 ImageEllipse() function (PHP), 785, 958 ImageFill() function (PHP), 785, 957 ImageFilledArc() function (PHP), 785 ImageFilledEllipse() function (PHP), 785 ImageFilledPolygon() function (PHP), 785 ImageFilledRectangle() function (PHP), 785 imagefontwidth() function (PHP), 958 ImageJpeg() function (PHP), 784, 786 ImageLine() function (PHP), 785 ImageLoadFont() function (PHP), 786 ImagePng() function (PHP), 784, 786, 794, 958 ImagePolygon() function (PHP), 785 ImageRectangle() function (PHP), 785 images. See graphics ImageSetStyle() function (PHP), 785 ImageSetThickness() function (PHP), 785 ImageString() function (PHP), 786, 958 IMAP servers for e-mail, 685 immutability of strings (PHP), 142 IMP POP client, 687 impersonate.php administrator form, 852–855 implode() function (PHP), 423–424, 485–486 in_array() function (PHP), 164 include files (PHP) included as text (not PHP mode), 58 maintainability and, 606–607 PHP tags in, 58 in single-table displayer example, 297–298 storing passwords outside the Web tree and, 256 include functions (PHP) error handling and, 57 files included as text (not PHP mode), 58 Continued

1015

1016

Index ✦ I

include functions (PHP) (continued)

INSERT statements

for headers and footers, 57–58 include_path field, 116 other include functions versus, 57 php.ini file for, 58 scope and, 115–116 types of, 57 include_once() function (PHP). See also include functions (PHP) other include functions versus, 57 scope and, 116 include_path setting (PHP), 565 incrementing operators (PHP), 193–194, 206, 611 indenting in PEAR coding style, 526 for readability, 601 SQL, 247 indexes (database) candidates for, 343 choosing a database and, 240 default numbering for, 161 defined, 240, 340 FULLTEXT, 344 joins and, 342–343 performance and, 340–344 primary keys, 341–342 storage requirements for, 343 trade-offs, 340–341 UNIQUE, 343–344 indexes (PHP) for multidimensional arrays, 164 retrieving values from arrays using, 162 specifying using arrays, 161 for strings, 139 index.php example (PostgreSQL), 630–631, 633–634, 636–637 index.php file (trivia game), 875, 876–878 Indianapolis 500 Web site (PHP deployment), 5 indices. See indexes (PHP) indivisible tokens (PHP), 63 infinite loops (PHP), 101, 227 info.php file, 44, 46, 47 Informix databases, PHP support for, 241 inheritance chained subclassing, 375–376 defined, 370 designing for, 406–407 extends clause for (PHP), 373–374 overview, 367–368 PHP support for, 370 inner joins, 250 innerFunction() function (PHP), 589 InnoDB tables, 262 inputFormsString() member function (OOP), 400 Insecure.Org Web site, 552 INSERT INTO...SELECT statements, 251

overview, 251 permissions for, 255 slowed by indexes, 340–341 syntax, 251 insert.php example (PostgreSQL), 631–633 inspecting arrays (PHP), 164–165 strings (PHP), 141 installing. See also installing MySQL; installing PHP gd toolkit, 782 Java extension for PHP, 724–725, 728 Java SAPI, 723–724 PEAR Package Manager, 520–522 PEAR packages, 524 PostgreSQL, 624–627 installing MySQL downloading MySQL, 262 on Mac OS X, 264 post-installation housekeeping, 264 preinstall considerations, 260–262 on Unix, 263–264 on Windows, 262–263 installing PHP building in mysqli extension, 279 changes in Windows product line and, 41 development tools, 47–50 further information, 40, 41 Mac OS and Apache configuration, 44–45 on other Web servers, 47 outsourcing and, 39 prerequisites, 40–41 troubleshooting installation-related problems, 209–210 Unix and Apache configuration, 42–44 Windows and Apache configuration, 46–47 Windows and IIS configuration, 45–46 installing PHPMyAdmin GUI, 270 _installQuestion() function (Game class), 892–893 instances (OOP), 372 INT type (MySQL), 290 INTEGER type (MySQL), 290 integers (PHP) automatic conversion of, 191 defined, 72, 73, 480 doubles versus, 74 finding the largest integer, 486 integer overflow, 486 overview, 73 range for, 73 read formats, 73 integrity constraints, choosing a database and, 240 Interbase databases, PHP support for, 241 interfaces (OOP), 380 internal DTDs (XML), 736, 737–738

Index ✦ I

PHP-related sites, 993–996 POP servers, 685 PostgreSQL site, 625 PowerGres site, 625 precedence information, 85 pscp file uploader, 807 public deployments of PHP, 5 REST information, 760 SAX information, 743 security information, 552 SQL standards organizations, 246 SSL encryption information, 270 TCP/IP servers, 682 text editors, 50 UDDI information, 764 Unix file permission information, 440 updating PEAR Package Manager, 523 Web services examples, 764 WinSCP file uploader, 807 World of Windows Networking, 40 WSDL information, 764 XML validation, 739, 755 Zend.com, 4, 993 interoperability issues for .NET services, 763 intersection_label() function (PHP), 956 introduction() function (GameText class), 888 introspection functions (PHP) class genealogy example, 390–392 generalized test methods example, 395–398 matching variables and columns example, 392–395 overview, 389–390 table summarizing, 387–389 intval() function (PHP), 191, 483 IP address, session alternative using, 456 IP-based permissions, 852 is_a() function (PHP), 388 is_array() function (PHP), 164, 481 is_bool() function (PHP), 481 Is_dir() function (PHP), 449 is_double() function (PHP), 481, 503 isError() member function (PEAR DB), 678 Is_executable() function (PHP), 449 Is_file() function (PHP), 449 is_float() function (PHP), 481, 503 is_int() function (PHP), 481, 503 is_integer() function (PHP), 481 Is_link() function (PHP), 449 is_long() function (PHP), 481, 503 is_nan() function (PHP), 226, 503 is_null() function (PHP), 481 is_numeric() function (PHP), 502 is_object() function (PHP), 481 ISP services for Web hosting, 35–38 Is_readable() function (PHP), 449 is_real() function (PHP), 481

1017

1018

Index ✦ I–L

is_resource() function (PHP), 481 IsSet() function (PHP)

checking variable assignment, 68–69 for inspecting arrays, 164 is_string() function (PHP), 481 is_subclass_of() function (PHP), 388 is_valid_user() function (PHP), 570–571, 572–573, 575 isWarning() member function (PEAR DB), 678 is_writable() function (PHP), 449 iterating arrays (PHP) array_walk() function for, 173–174, 175 current() function for, 168–169, 174 empty values and the each() function, 172–173, 175 extracting keys with key() function, 171–172 foreach looping for, 167–168 next() function for, 169–170, 174 reset() function for starting over, 170–171, 174 reversing order with end() function, 171, 174 reversing order with prev() function, 171, 174 sample array for, 167 support for, 165–166

JAWmail mail client, 687 JDBC (Java Database Connectivity), 237–238 jmp() function (JavaScript), 711 joins choosing a database and, 239, 250 defined, 239 indexes for, 342 inner, 250 left outer, 250 outer, 250 overview, 247–250 purpose of, 249 right outer, 250 self-join, 250 JPEG format issues for browsers, 781 JSP (Java Server Pages by Sun) cost compared to PHP, 6 ease of use, 8 with Java, 722 performance, 12 as proprietary alternative to PHP, 3 Julian Day Number, 453–454 JVM (Java Virtual Machine), 26

J

K

Java errors and exceptions, 727–728 further information, 724 guide to this book, 722–723 integrating PHP and, 723–729 Java object, 726–727 overview, 729 PHP differences, 720–721 PHP extension, 724–726, 728 PHP for Java programmers, 719–723 PHP similarities, 719–720 Service Access Point Identifier (SAPI), 723–724 troubleshooting, 728–729 Java applets, 23, 26 Java Database Connectivity (JDBC), 237–238 Java object, 726–727 Java Server Pages (Sun). See JSP Java Virtual Machine (JVM), 26 javadoc tool, 603 JavaScript for dynamically generated forms, 708–713 further information, 703 HTML script tags and, 55 object-oriented model for, 704 outputting with PHP, 703–705 overview, 717 passing data to PHP from, 714–717 PHP as backup for, 705–707 static versus dynamic, 707 uses for, 705 JavaScript Bible (Goodman, Danny), 703

Kabir, Mohammed J. (Apache Server 2 Bible), 551 Kernighan, Brian W. (The C Programming Language), 985 key() function (PHP), 171–172 King, Andrew (JavaScript programmer), 709 knowledgebases (PHP), 994 Kriegel, Alex (SQL Bible), 245 krsort() function (PHP), 418 ksort() function (PHP), 418

L LAMP (Linux Apache MySQL PHP) combo, 40 late binding, PHP support for, 371 latency, estimating, 941–942 left outer joins, 250 left-before-right evaluation (PHP), 64, 85 left_label() function (PHP), 956 legal liability, Oracle for, 641 legibility. See readability Lemos, Manuel (e-mail class teacher), 687 Lerdorf, Rasmus (PHP creator), 4 letter_cipher() function (PHP), 497 levenshtein() function (PHP), 438 libraries (Java), 720 libxml2 PHP SAX parser, 739, 743 licensing MySQL, 7–8, 13, 259–260 open source software, 7–8, 13–14 PHP, 7–8, 13 PHP versus MySQL, 13 Web sites for information about, 7

Index ✦ L–M

Weblog database login screen, 811 Weblog entry login screen, 808–809 log10() function (PHP), 507 long type. See integers (PHP) LONGBLOB type (MySQL), 291 LONGTEXT type (MySQL), 291 loops (PHP) bounded for loop example, 96–98 bounded versus unbounded, 94 break command for, 99–100 continue statement for, 99–100 defined, 83 do-while construct for, 95 for construct for, 95–98 foreach construct for, 167–168 infinite, 101, 227 optimizing, 610 overview, 94–101 for queries, restricting with WHERE clause instead, 345–346 unbounded while loop example, 98–99 while construct, 94 while construct for, 98–99 L0pht Heavy Industries Web site, 552 lossless versus lossy compression, 781 lstat() function (PHP), 449 ltrim() function (PHP), 145–146, 148 Lynch, Richard (PHP expert), 993

M Macintosh OS X installing MySQL on, 264 installing PHP with Apache on, 44–45 text editors, 50 Macromedia ColdFusion. See ColdFusion magic numbers, avoiding, 605–606 magic-quotes settings (PHP), 355 magic_quotes_gpc setting (PHP), 565 magic_quotes_runtime setting (PHP), 565 magic_quotes_sybase setting (PHP), 565 mail. See e-mail mail() function (PHP) additional header field, 690 formatting e-mail, 689–690 multiple recipients and, 689 for sending e-mail attachments, 694 for sending e-mail from a database, 693 for sending e-mail from a form, 690 simple example, 688 variables with, 689 mail retrieval utilities, 685 mail spool, 683 Mail Transfer Agents (MTAs), 682–683 Mail User Agents (MUAs), 684 maildir mailbox format, 683 mailing list managers (MLMs), 685–686

1019

1020

Index ✦ M

mailing lists (PHP) developer-oriented lists, 990 digest versions, 990–991 etiquette, 991–993 for PHP-based products, 990 signing up, 989 user-oriented lists, 989 mailinglist.php mailing list script, 693–694 MailMan MLM, 686 mail-retrieval programs, 684–685 maintainability avoiding magic numbers, 605–606 as database advantage, 234 functions and, 606 include files and, 606–607 need for, 599 object wrappers and, 607 PHP with Apache HTTP Server and, 4 style for, 605–607 version control for, 607 Majordomo MLM, 686 _makeChecksum() function (GameDisplay class), 885 make_content_box() function (PHP), 862–863, 864 _makeDistractors() function (Question class), 904 _makeDistractorsGeometric() function (Question class), 905 _makeDistractorsLinear() function (Question class), 905 makeErrorPage() function (GameDisplay class), 879, 880 make_large_rectangle() function (PHP), 793–794 make_next_prev_box() function (PHP), 863, 864 make_path() function (PHP), 789 make_point() function (PHP), 789 make_ratings_box() function (PHP), 866 make_ratings_receipt_box() function (PHP), 866–867 make_ratings_submission_box() function (PHP), 867 make_small_rectangle() function (PHP), 793 make_subject_string() function (trivia game), 910 _makeTopMatter() function (GameDisplay class), 882–883 manuals MySQL, 263, 290 PEAR, 987 PHP, 85, 105–107, 784, 987–989 many-to-many data database design issues for, 252, 253–254 example, 253 many-to-one data. See one-to-many or many-to-one data mapo_tofu.xml recipe listing, 770–771 matching variables and columns example (OOP), 392–395 mathematical operators (PHP) arithmetic, 192–193 assignment, 194, 611 comparison, 194–195

functions and, 192 incrementing, 193–194, 611 parentheses with, 195 precedence, 195 table summarizing, 206–207, 515 mathematics (PHP) arbitrary precision (BC), 511–515 avoiding magic numbers, 605–606 base conversion, 503–506 basic math functions, 196, 207 exercise calculator example, 200–206 exponents and logarithms, 506–507 mathematical constants, 501–502 mathematical operators, 192–195 numeric types, 72, 73–75, 191 randomness, 196–200 table summarizing, 206–207, 515–516 tests on numbers, 502–503 trigonometric functions, 507–510 troubleshooting math problems, 225–226 max() function (PHP), 196, 347 max_execution_time setting (PHP), 564 maximal PHP style, 614–615, 984 _maybeChangeLevel() function (Game class), 894–895 maybe_handle_new_rating() function (PHP), 866 maybe_print_answer_date() function (PHP), 615 mbox mailbox format, 683 mbx mailbox format, 683 mcrypt_cbc() function (PHP), 547–548 mcrypt_cfb() function (PHP), 547–548 mcrypt_create_iv() function (PHP), 548 mcrypt_ecb() function (PHP), 547–548 mcrypt_get_key_size() function (PHP), 548 mcrypt_ofb() function (PHP), 547–548 MD5 algorithm, 435–436, 823, 824 medium PHP style, 615–617 MEDIUMBLOB type (MySQL), 291 MEDIUMINT type (MySQL), 290 MEDIUMTEXT type (MySQL), 291 member functions (methods) defined, 369 DOM XML, 741–742 member variable has no value in, 404 PEAR DB, 678–679 PHP support for, 371 private, 378–379 protected, 378, 379–380 simulating overloading, 384 member variables accessing in PHP, 372 defined, 369 no value in member function, 404 PHP support for, 371 memory management C language, 969 Java, 720 Oracle, 644

Index ✦ M

merging arrays (PHP), 412 metadata functions (MySQL), 285 metaphone() function (PHP), 438 method_exists() function (PHP), 388, 390 methods. See member functions mhash function library, 550 Microsoft Access databases, PHP support for, 241 Microsoft Active Server Pages. See ASP Microsoft Internet Information Server. See IIS Microsoft Outlook Express, 684 Microsoft SQL Server. See SQL Server Microsoft Windows. See Windows microtime() function (PHP), 452, 567 Midgard Web site, 995 MIME (Multipurpose Internet Mail Extensions), 694–695 min() function (PHP), 196, 347 minimal PHP style, 613–614, 985 minus sign (-) as PHP arithmetic operator, 192 mkdir() function (PHP), 449 mktime() function (PHP), 453 MLMs (mailing list managers), 685–686 module PHP CGI versus, 36 Perl versus, 976 modulus operator (PHP), 192, 193 moving around. See navigation Mozilla mail/news, 684 mSQL (MySQL precursor), 5–6, 241 MTAs (Mail Transfer Agents), 682–683 mt_getrandmax() function (PHP), 197 mt_rand() function (PHP), 196–197 mt_srand() function (PHP), 197–199 MUAs (Mail User Agents), 684 multidimensional arrays (PHP) defined, 158 exercise calculator example, 183–188 overview, 163–164 retrieving string values from, 163–164 multiline (C-style) comments (PHP), 66 multiple connections to MySQL, 285–287 Multipurpose Internet Mail Extensions (MIME), 694–695 mutt MUA, 684 mutually recursive functions (PHP), 117 mycrypt function library (Unix), 547–548, 549 MyISAM tables, 262. See also tables (MySQL) myisamchk recovery utility, 277 myOptions() function (JavaScript), 711 MySQL adding a new user, 267 advantages, 6–17, 259 applications list online, 289 backups, 272–274 client commands, 265 compatibility, cross-platform, 11 connecting to, 279–280, 285–287 costs, 6–8 creating databases with PHP, 289–291

data types, 289–291 defined, 4 downloading, 262, 263, 264 dumping data into, 923–927 ease of use, 9 feature development fast for, 15 focus of this book and, 243–244 history, 5–6 installing, 260–264 licensing, 7–8, 259–260 manual, 263, 290 multiple connections, 285–287 mysqli versus mysql extension, 261 open source listing, 13 overview, 4 permissions, 265–269 PHP support for, 242 PHPMyAdmin GUI for, 269–272 pronunciation of, 4 recovery, 276–278 replication, 274–276 root password, 264 speed, 12 stability, 12 user administration, 265–269 user communities, 17 version 3 versus version 4, 260–262 mysql command (MySQL), 265 mysql extension (MySQL), 261 mysql_affected_rows() function (PHP/MySQL), 281, 285, 292, 360–361 mysql_change_user() function (PHP/MySQL), 292 mysqlcheck recovery utility, 277, 278 mysql_close() function (PHP/MySQL), 292 mysql_connect() function (PHP/MySQL), 279–280, 292, 672 mysql_create_ db() function (PHP/MySQL), 288–289, 292 mysql_data_seek() function (PHP/MySQL), 284, 292 mysql_drop_ db() function (PHP/MySQL), 288–289, 292 mysqldump utility for backups, 272–274 dumping all databases, 273 options, 273–274 selecting specific tables or databases, 273 mysql_errno() function (PHP/MySQL), 287, 292 mysql_error() function (PHP/MySQL), 351, 356 mysql_fetch_array() function (PHP/MySQL), 282, 283, 292 mysql_fetch_field() function (PHP/MySQL), 292 mysql_fetch_lengths() function (PHP/MySQL), 292 mysql_fetch_object() function (PHP/MySQL), 282, 283, 292 mysql_fetch_row() function (PHP/MySQL), 282–283, 292 mysql_field_flags() function (PHP/MySQL), 292 mysql_field_len() function (PHP/MySQL), 293

1021

1022

Index ✦ M–N

mysql_field_name() function (PHP/MySQL), 292 mysql_field_seek() function (PHP/MySQL), 292 mysql_field_table() function (PHP/MySQL), 292 mysql_field_type() function (PHP/MySQL), 284, 292 mysql_free_result() function (PHP/MySQL), 293

mysqli extension (MySQL), 261, 279 mysqli_affected_rows() function (PHP/MySQL), 282 mysqli_connect() function (PHP/MySQL), 280 mysql_insert_id() function (PHP/MySQL), 284, 293, 309 mysqli_num_rows() function (PHP/MySQL), 282 mysqli_select_db() function (PHP/MySQL), 280 mysql_list_dbs() function (PHP/MySQL), 293 mysql_list_fields() function (PHP/MySQL), 293 mysql_list_tables() function (PHP/MySQL), 293 mysql_num_fields() function (PHP/MySQL), 293 mysql_num_rows() function (PHP/MySQL), 282, 293, 360–361 mysql_pconnect() function (PHP/MySQL), 293, 339 mysql_query() function (PHP/MySQL), 281, 288–289, 293, 357 mysql_result() function (PHP/MySQL), 282, 283–284, 293, 361 mysql_select_ db() function (PHP/MySQL), 280, 293, 672 mysql_tablename() function (PHP/MySQL), 293 Mystery Guide Web site. See also converting static HTML sites architecture, 915 audience characteristics, 914 before and after screenshots, 916–917 book page template, 932–940 caching, 942 Community Rating code, 942 database definition file, 920–922 database schema, 918–922 data-massaging, 922–923 dumping data into the database, 922–932 goals for upgrading, 914–915 hardware and software requirements, 915 harvesting data, 928–932 history, 913 inventory for, 914 performance, 870, 941–942 reader ratings on, 869, 870 technical assessment, 915 user interface design, 916–917 my_subtract() function (PHP), 493 my_subtract_ref() function (PHP), 494

N \n. See newline characters nagmail.php cronjob e-mail script, 699–700 Name class, 382 name() method (DomAttr class), 742 NameSub1 class, 383

Index ✦ N–O

NULL type (PHP) defined, 72, 76, 480 using, 76–77 null values (Oracle), 644 numbers (PHP). See mathematics (PHP) numCols() member function (PEAR DB), 679 NUMERIC type (MySQL), 291 numeric types (PHP), 72, 73–75, 191. See also doubles (PHP); integers (PHP) numRows() member function (PEAR DB), 679

O object wrappers, maintainability and, 607 object-oriented databases, 236–237 object-oriented programming. See OOP object-relational databases. See ORDBMS objects. See also instances (OOP) avoiding at first, 984 C language, 969 OOP, 367, 369, 377 PHP, 72, 480 ObjectTester class, 395–398 OCI8 functions (PHP/Oracle) all caps, 645 error reporting, 644 escaping strings, 644 fetching entire data sets, 645 fetching null values, 644 memory management, 644 overview, 643–644 parsing and executing, 644 transactionality, 645–646 oci8_funcs.php file for point editor (Oracle), 648–650 OCIFetch() function (Oracle), 361 OCIResult() function (Oracle), 361 OctDec() function (PHP), 503 ODBC (Open Database Connectivity), 237–238 OFB (output feedback) cipher mode, 547 On to C (Winston, Henry), 985 one-to-many or many-to-one data database design issues for, 252, 253–254 example, 252 primary keys and, 342 one-to-one data database design issues for, 252, 253 example, 252 OOP (object-oriented programming) abstract classes, 381 accessing member variables, 372 accessor functions, 405–406 advanced features, 378–387 automatic calls to parent constructors, 384 calling parent functions, 382–383 chained subclassing, 375–376 class genealogy example, 390–392 constants, 380–381

constructor functions, 372–373 constructors, 369 creating instances, 372 defining classes, 371–372 designing for inheritance, 406–407 destructors, 369 encapsulation, 369 generalized test methods example, 395–398 HTML forms example, 398–404 inheritance, 367–368, 373–374, 406–407 interfaces, 380 introspection functions, 387–390 matching variables and columns example, 392–395 modifying and assigning objects, 377 naming conventions, 405 object defined, 367 overriding functions, 375 overview, 365–370, 407 PHP constructs for, 371–378 PHP support for, 370–371 private and protected members, 378–380 procedural approach versus, 366–367 programming style, 405–407 scoping issues, 377–378 serialization, 385–387 simulating class functions, 381–382 simulating method overloading, 384 terminology, 369–370 troubleshooting, 404–405 types, 367 Web scripting and, 368 Open Database Connectivity (ODBC), 237–238 open source software code forking, 14 further information, 7 licensing, 7–8, 13–14 viability of, 7 volunteer developers for, 14 opening files. See fopen() function (PHP) openlog() function (PHP), 450 operating systems. See also specific operating systems different for development and production, 49 supported by PHP, 11 operators. See also operators (PHP) C language, 967 Java, 720 operators (PHP) assignment, 194, 207, 611 C language similarities, 967 combining concatenation and assignment, 139–140 comparison, 86–87, 88 concatenation, for strings, 139 conciseness and, 611 heredoc syntax for strings, 140 incrementing, 193–194, 206, 611 Continued

1023

1024

Index ✦ O–P

operators (PHP) (continued) Java similarities, 720 logical, 84–85 matching expression types, 64 mathematical, 192–195 ternary conditional, 87–88, 103 optimizers, 567 optout.php form, 325–327 or logical operator (PHP), 84 Oracle cost compared to MySQL, 6 need for, 639–641 OCI8 functions, 643–647 PHP support for, 242 PostgreSQL versus, 639 product batch editor project, 657–666 product point editor project, 647–657 Web architecture and, 641–643 ord() function (PHP), 111, 485 ORDBMS (object-relational databases). See also PostgreSQL advantages, 624 flat-file and relational databases versus, 236–237 ORDER BY construct, 346 OS X. See Macintosh OS X outer joins, 250 outerFunction() function (PHP), 589–590 Outlook Express (Microsoft), 684 output feedback (OFB) cipher mode, 547 output functions (PHP) echo, 80–81 newline characters and, 82 print, 81 printf (C language) and, 81–82 string functions, 150–151 for variables and strings, 81–82 outsourced Web hosting advantages, 35–36 colocation, 39 dedicated server, 39 disadvantages, 36–37 disk space provided, 38 factors creating difficulties for, 36–37 finding a Web hosting service, 38 popularity of, 35 for production site only, 39 throughput issues, 38 unlimited traffic/bandwidth/hits promised, 38 varieties of ISPs, 37 overloading PHP support for, 370 simulating (PHP), 384 overriding functions, 375

P Package Manager (PEAR) automatic package installation, 524 automatic package removal, 524 installing on Linux, 520 installing on Windows, 520–522 overview, 519–520 for packages in scripts, 524–525 semi-automatic package installation, 524 updating, 523 using, 523–525 packages (Java), 720 padding arrays (PHP), 412–413 painting functions (gd toolkit), 785 palette-based images (gd toolkit), 783 parent class automatic calls to parent constructors, 384 calling parent constructors, 382–383 defined, 370 special name parent, 383 parent special name, 383 parentheses [( )] with mathematical operators (PHP), 195 in Perl-compatible regular expressions, 428 parse errors, troubleshooting (PHP), 216–219, 405 parse_exec_fetch() function (Oracle), 649 parse_exec_free() function (Oracle), 649 parsers (XML) definitions of, 743 expat toolkit, 743 PHP DOM parser (gnome-libxml2), 739, 740 PHP SAX parser (libxml2), 739, 743 validating versus nonvalidating, 739 parsing functions Oracle, 644 PHP, 421–424 passing data between Web pages. See also HTML forms exercise calculator example, 134–136 formatting form variables, 125–132 GET method for, 120–124 HTML forms limitations for, 119, 120 overview, 136 PHP variable assignment and, 125–128 POST method for, 124–125 stateless nature of HTTP and, 119 superglobal arrays for, 111, 132–133 passing data to PHP from JavaScript, 714–717 PASSWORD() function (MySQL), 261 password.inc Weblog password file, 809 password_maker.inc random password generator, 698 passwords changing, user authentication and, 839–846 database versus system, 256 encrypting, 256, 536–537, 822–823 forgotten, user authentication and, 836–839

Index ✦ P

No Connection warning and, 353–354 random password generation, 698 root (MySQL), 264 storing outside the Web tree, 256–257 two-layer protection, 257–258 Weblog password files, 809, 810 path for include functions, 116 PATH (Unix), MySQL root directory on, 264 path_display.php for fractal images example, 789–790 path_manipulation.php for fractal images example, 791–794 path_tranform.php for fractal images example, 790–791 pclose() function (PHP), 449 PEAR DB wrapper advantages and disadvantages, 670–673 competitors, 670 connection, 675 Data Source Names (DSNs), 674–675 database independence and, 670–673 database management servers supported, 675 disconnection, 676 example, 677–678 member functions, 678–679 overview, 669 PHP5 and, 672 queries, 676 row retrieval, 676 PEAR MDB wrapper, 670 PEAR package-management system automatic package installation, 524 automatic package removal, 524 list of PEAR packages, 518–519 overview, 517, 519 Package Manager, 519–525 PEAR database, 519 semi-automatic package installation, 524 using packages in scripts, 524–525 PEAR (PHP Extension and Application Repository). See also PEAR DB; PEAR packagemanagement system coding style, 525–528 Foundation Classes (PFC), 525 history, 518 manual, 987 overview, 517–518, 528–529 package-management system, 518–525 PHP Extension Community Library (PECL), 525 Web site, 518, 523 PECL (PHP Extension Community Library), 525 pen-setting functions (gd toolkit), 785 percent sign (%) as modulus operator (PHP), 192, 193 in PHP tags (ASP-style), 55 in printf() and sprintf() format strings, 150

Perdue, Tim (Webmaster), 994 performance. See efficiency or performance period. See dot (.) Perl scripting language guide to this book, 977–978 hashes compared to PHP arrays, 158 PHP differences, 974–977 PHP for Perl programmers, 973–978 PHP similarities, 973–974 PHP variables like, 67 regular expressions compatible with, 427–430 tips, 977 Perl-compatible regular expressions (PHP) common pattern constructs, 428 functions, 429–430 overview, 427–428 permissions (IP-based), 852 permissions (MySQL) adding a new user, 267 adding or editing, 267 dangerous permissions, 268 forcing the database to reload new privilege data, 268 levels of, 255 for local development, 268 MySQL permissions system, 265–269 replication and, 275 revoking, 268 scope of, 267–268 setting, 255–256 for shared-hosting Web site, 269 for standalone Web site, 268–269 troubleshooting, 353–354 user table for, 266 permissions (PHP) file upload security and, 545 overview, 439–440 permissions (PostgreSQL), 628–629 permissions (Unix) directory permissions, 440 document root directory, 43 file permissions, 439–440 further information, 440 persistent database connections, 339 Personal Home Page Tools, 3, 4 pfsockopen() function (PHP), 451 pg_affected_rows() function (PHP), 630 pg_close() function (PHP), 630 pg_connect() function (PHP), 629 pg_fetch_all() function (PHP), 629 pg_fetch_array() function (PHP), 629 pg_fetch_assoc() function (PHP), 629 pg_fetch_object() function (PHP), 629 pg_fetch_result() function (PHP), 629 pg_fetch_row() function (PHP), 629 pg_free_result() function (PHP), 630

1025

1026

Index ✦ P

pg_num_fields() function (PHP), 630 pg_num_rows() function (PHP), 630 pg_pconnect() function (PHP), 629 pg_query() function (PHP), 629

Phorum Web site, 996 PHP Classes Repository Web site, 995 PHP Construction Kit, 4 PHP Extension and Application Repository. See PEAR PHP Extension Community Library (PECL), 525 PHP mode. See also HTML mode escaping from HTML mode into, 53–54, 56–57, 218–219 heredoc syntax for strings, 140, 616–617 include files not in, 58 maximal PHP style, 614–615, 984 medium PHP style, 615–617 minimal PHP style, 613–614, 985 scope of variables and switching modes, 70 troubleshooting mode issues, 218–219 PHP (PHP: Hypertext Preprocessor). See also specific elements advantages, 6–17 for C programmers, 967–971 cgi-bin directory for, 534 codebases, 994–995 compatibility, cross-platform, 11 compatibility with HTML, 53 compiling for distribution, 11 costs, 6–8 creating MySQL databases with, 289–291 databases supported by, 241–242 defined, 3 downloading distributions, 40, 41 downloads list, 987 ease of learning, 980 ease of use, 8 escaping from HTML into, 53–54, 56–57, 218–219 extensions supporting other programs and protocols, 14 feature development fast for, 14–15 history, 4–5 for HTML coders, 979–986 HTML versus, 61–62 HTML-embeddedness of, 9–11 installing, 39–50 integrating Java and, 723–729 internationalization and, 745 for Java programmers, 719–723 as JavaScript backup, 705–707 knowledgebases, 994 licensing, 7–8 mailing lists, 989–993 manual, 85, 105–107, 784, 987–989 module versus CGI, 36 native PHP errors, 576–577 not proprietary, 16

as official Apache HTTP Server module, 4 OOP constructs, 371–378 open source listing, 13–14 operating systems supported, 11 origin of name, 3 outputting JavaScript with, 703–705 overview, 3–4 passing JavaScript data to, 714–717 for Perl programmers, 973–978 permissions, 439–440 popularity of, 15–16 PostgreSQL functions in, 629–630 programming language not tag-based, 11 projects online, 995–996 proprietary products similar to, 3 pseudocode, 982–983 public deployments, 5 real-time 3D and, 32 receiving e-mail with, 686–687 running as server module, 534 sending e-mail with, 687–690 server-side scripting tasks handled by, 32 speed, 12 stability, 12 syntax, 61–67 training courses online, 980–981 user communities, 17 Web hosting choices for, 35–39 Web servers supported, 11 Web site, 41, 987–989 phpBB Web site, 996 phpbible.xml REST client, 767–769 PHPBuilder Web site, 994 phpdoc tool, 602–603 PHPGroupware Web site, 996 PHP-GTK mail client, 687 phpinfo() function (PHP), 555 php.ini file. See also register_globals directive for ASP-style PHP tags, 55 auto-append-file setting, 565 auto-prepend-file setting, 565 disable_functions setting, 564 display_errors setting, 351, 356, 533, 587–588, 589 doc_root setting, 565 e-mail configuration, 688 error_prepend_string setting, 564 error_reporting setting, 564, 588–589 ignore_user_abort setting, 566, 567 for include functions, 58 include_path setting, 565 installing PHP and, 44, 46 log_errors setting, 588, 589 magic_quotes_gpc setting, 565 magic_quotes_runtime setting, 565 magic_quotes_sybase setting, 565

Index ✦ P

max_execution_time setting, 564

overview, 563 safe_mode setting, 563 safe_mode_allowed_env_vars setting, 564 safe_mode_exec_dir setting, 563 safe_mode_protected_env_vars setting, 564 sendmail_from setting, 688 sendmail_path setting, 688 session.auto_start setting, 468 session.cookie_lifetime setting, 468 session.save-handler setting, 468, 566 session.save-path setting, 468 session.use_cookies setting, 468

short-open PHP tags and, 54, 55 short_open_tag setting, 563 SMTP setting, 688 upload_tmp_dir setting, 565 variables_order setting, 564 warn_plus_overloading setting, 564 PHPLIB wrapper, 670 PHPMyAdmin GUI for MySQL database generation using, 289 disabling when not in use, 270 http or cookie-based authorization, 270–271 installing locally only, 270 main database screen, 272 MySQL command-line client versus, 269 security issues, 270–271 SSL encryption for, 270 terminology, 271 Web site, 995 PHP-Nuke Web site, 995 PHPSlash Web site, 995 PHPWiki Web site, 996 pi mathematical constants for, 501–502, 507 trigonometric function for, 507 pi() function (PHP), 507 pi_approx() function (PHP), 513 pi_approx_bc() function (PHP), 514 pictures. See graphics pine MUA, 684 plus sign (+) in Perl-compatible regular expressions, 428 as PHP arithmetic operator, 192 in POSIX-style regular expressions, 425 PNG format issues for browsers, 781 point editor project. See product point editor project (Oracle) point_along_segment() function (PHP), 793 pointer system built into arrays (PHP), 165–166 pointers (C language), 969 point_off_segment() function (PHP), 793 point_x() function (PHP), 789 point_y() function (PHP), 789 polform.php HTML form for XML, 748–749

poll.xml XML file, 751–752 polymorphism, PHP support for, 370 POP servers for e-mail, 684–685 popen() function (PHP), 449 popularity of PHP, 15–16 populate_cities() function (PHP), 308 portability, as database advantage, 234 pos() function (PHP), 174. See also current() function (PHP) POSIX-style regular expressions (PHP) example, 425–426 functions, 426–427 overview, 425 POST method (HTTP) REST and, 760 XML-RPC and, 761 POST method (PHP) advantages and disadvantages, 124 automatic variable assignment with, 125 for form handling, 124–125 GET method versus, 122, 124 GET method with, 124 for nonidempotent usages, 124 postfix MTA, 683 PostgreSQL advantages, 623–624 building database structures, 627–629 cartoons database example, 630–637 command-line utilities, 626–627 creating databases, 627 creating tables, 627–628 edit.php example, 634–636 functions in PHP, 629–630 index.php example, 630–631, 633–634, 636–637 inserting data in tables, 628 inserting records, 628 insert.php example, 631–633 installing, 624–627 listing databases, 627 opening databases, 627 Oracle versus, 639 PHP support for, 242 user privileges, 628–629 Web site, 625 on Windows, 624–625 _postHighScoreString() function (GameDisplay class), 885–886 pound sign (#) for PHP comments, 66–67 pow() function (PHP), 507 PowerGres (Software Research Associates), 625 precedence of comparison operators, 87 further information, 85 of logical operators, 85 of mathematical operators, 195 rules for expressions, 64

1027

1028

Index ✦ P–Q

preg_grep() function (PHP), 429 preg_match() function (PHP), 429, 430 preg_match_all() function (PHP), 429, 430 preg_quote() function (PHP), 429 preg_replace() function (PHP), 429 preg_replace_callback() function (PHP), 429 preg_split() function (PHP), 429

prerequisites. See system requirements Prescod, Paul (REST promoter), 760 prev() function (PHP), 171, 174 prev_content_id() function (PHP), 863–864 previousQuestionCorrect() function (Game class), 892 primary keys (database) creating, 341–342 criteria for, 341 defined, 341 print function (PHP) HTML mode statements versus, 91–92 multidimensional arrays and, 163–164 overview, 81 for variables and strings, 81–82 print_all_array_backwards() function (PHP), 171 print_all_array_reset() function (PHP), 170–171 print_all_foreach() function (PHP), 168 print_all_next() function (PHP), 169–170 print_ancestry() member function (OOP), 390 print_ancestry_aux() member function (OOP), 390–391 print_better_deal function (PHP), 109 print_class_tree() function (PHP), 392 print_class_tree() member function (OOP), 391 print_class_tree_aux() member function (OOP), 391–392 print_day_options() function (PHP), 615 printf function (C language), 81–82 printf() function (PHP) format string for, 150–151 sprintf() function versus, 150 print_first_name_bad() function (PHP), 345–346 print_first_name_better() function (PHP), 346 print_header() function (PHP), 113–114 printing. See also output functions (PHP) array printing functions, 418–419 complex, for query display, 302–303, 305–307 diagnostic statements (PHP), 589–590 string functions for (PHP), 150–151 print_keys_and_values() function (PHP), 171–172 print_links() function, 432–433 print_r() function (PHP), 418, 590 print_value_length() function (PHP), 173 privacy, cookies and, 471 private members, 378–379 privileges. See permissions (MySQL); permissions (PHP); permissions (PostgreSQL); permissions (Unix)

procedural abstraction, 83 procedural programming, 366–367 procedures (database) choosing a database and, 240 defined, 240 views and stored procedures, 303 prod_point.php file for point editor (Oracle), 651–657 product batch editor project (Oracle) batch_upload_new.php spreadsheet upload script, 657, 662–666 get_categories.sql stored procedure, 657–658 header_download.php script, 657, 658–662 overview, 657 product point editor project (Oracle) file of functions (oci8_funcs.php), 648–650 overview, 647–648 point editor code (prod_point.php), 651–657 production different operating system for development, 49 display_errors setting for, 351 outsourcing, while self-hosting development, 39 program-execution functions (PHP), 538 programming versus scripting, 32 programs (PHP). See also specific programs Hello World, 55–56 security against running arbitrarily, 537–538 security against source code access, 533–534 separating code from design, 618–619 stepping through, 595 projects online (PHP), 995–996 propagating session variables (PHP) by registering variables, 460–461 using \$_SESSION superglobal array, 459–460 proprietary software costs compared to PHP/MySQL, 6 limitations of PHP extensions and, 14 PHP advantages over, 16 products similar to PHP, 3 protected members, 378, 379–380 prototypes (C language), 969 pscp file uploader, 807 pseudocode, 982–983 pseudo-random number generators (PHP) making a random selection, 199–200 overview, 196–197, 198 seeding the generator, 197–199 psql commands listing databases, 626 opening databases, 627 public-key encryption, 545–546 PX: PHP Code Exchange Web site, 995

Q qdbconn() custom connect function (PHP/MySQL), 280 qmail MTA, 683

qmail-pop3d POP server, 685

Index ✦ Q–R

qpopper POP server (Qualcomm), 685 Qualcomm Eudora Light, 684 qpopper POP server, 685 queries (MySQL). See also building forms from queries; displaying queries in HTML tables; SELECT statements aggregating results, 346 broken or invalid, 356–359 comma faults, 358 date and time fields for, 347–348 error-checking, 357–358 finding last row inserted, 348–349 making from PHP, 281–282 misspelled names in, 358 optimizing, 609–610 restricting with WHERE clause, 345–346 results with too little or too much data, 359–360 sorting results, 346, 347 troubleshooting, 356–360 unbound variables and, 359 unquoted string arguments in, 358–359 queries (PEAR DB), 676 query() member function (PEAR DB), 679 query_clauses.php file, 959–960 Question class (trivia game), 875, 901–905 question mark (?) for GET strings in URLs, 120 in Perl-compatible regular expressions, 428 in PHP tags, 54 question_class.php file (trivia game), 901–905 queue functions (PHP), 415, 416 quit command (MySQL), 265 quitting. See stopping quotation marks (”) literal, in doubly quoted strings (\”), 78, 355 magic-quotes setting, 355 single quotation marks versus, 78–79, 137 for strings (Perl), 974 for strings (PHP), 68, 78, 137 unescaped, errors from, 219, 354–355 quotations table (MySQL), 858

R \r (carriage-return character), 78 radio buttons in exercise calculator example, 175–179 RADIO form elements, 327–331 rand() function (PHP), 196, 197, 199 random_char() function (PHP), 199–200, 698 randomness making a random selection, 199–200 password generation functions, 698 pseudo-random number generators (PHP), 196–197, 198 random number functions (PHP), 197 seeding the generator, 197–199

random_string() function (PHP), 199 range() function (PHP), 161 rate_boss.php three-part form, 317–321 rated_display.php page, 859–861

rating system. See user-rating system rating_functions.php file, 865–867 ratings table (MySQL), 859 rating_types() function (PHP), 865–866 rating_values table (MySQL), 858

1029

1030

Index ✦ R–S

register_globals directive (continued)

session test script assuming, 464–465 superglobal arrays versus, 133, 473 user-authentication systems and, 821 variable overwriting and, 473–474 registering variables in sessions (PHP) for propagating sessions variables, 460–461 test script, 464–465 register.php registration form, 827–829 registration for user authentication form for, 827–829 new-user confirmation page, 830–831 overview, 823 script for functions, 824–827 regular expressions (Perl), 977 regular expressions (PHP) defined, 421 functions, 426–427, 429–430 link-scraper example, 430–433 need for, 424 Perl differences, 977 Perl-compatible, 427–430 POSIX-style, 425–427 regex abbreviation for, 424 types of, 424 using in functions, 432–433 relate() function (JavaScript), 712 relational databases flat-file and object-relational databases versus, 236–237 overview, 247–248 SQL and, 245 SQL databases as, 247 removeChild() method (DomNode class), 742 rename() function (PHP), 449 rendering problems, troubleshooting (PHP), 210–215 replacement functions for strings (PHP), 146–148 replication choosing a database and, 241 master-slave model for, 274 MySQL, 274–276 MySQL versions and, 274 Oracle and, 642–643 process for, 275–276 REpresentational State Transfer. See REST require() function (PHP). See also include functions (PHP) other include functions versus, 57 scope and, 115 requirements. See system requirements require_once() function (PHP). See also include functions (PHP) other include functions versus, 57 scope and, 116 reset() function (PHP), 170–171, 174

resources (PHP) defined, 72, 480 handling, 480–481 REST (REpresentational State Transfer) further information, 760 overview, 760 phpbible.xml client, 767–769 rest_amazon_client.php client, 765–767 XML-RPC versus, 761–762 rest_amazon_client.php REST client, 765–767 RESTWiki Web site, 760 results.php results listing, 716–717 retirement_calc.php form example, 126–128 retrieving characters from strings (PHP), 139 values from multidimensional arrays (PHP), 163–164 values from simple arrays (PHP), 162 return value of functions defined, 105 side effects versus, 105 reusing functions, 295, 611 reversing arrays (PHP), 411 review.php book page template, 932–940 REVOKE command (MySQL), 268 revoking permissions (MySQL), 268 rewind() function (PHP), 449 right outer joins, 250 right_label() function (PHP), 956 _rightString() function (GameDisplay class), 884 Ritchie, Dennis M. (The C Programming Language), 985 rivalrous resources, Oracle for, 640 rmdir() function (PHP), 449 robots.txt file, 434 robustness commandments of, 607 need for, 599 style for, 607–608 unavailability of service issues, 608 unexpected variable types and, 608 Rootshell Web site, 552 round() function (PHP), 196, 485 round_to_digits() function (trivia game), 899–900 row retrieval (PEAR DB), 676 rsort() function (PHP), 417–418 rtrim() function. See chop() function (PHP) rules() function (GameText class), 888–889 running arbitrary programs, security against, 537–538 run-time bugs, 585. See also debugging

S Sade.com (PHP deployment), 5 _safeGeometricArguments() function (Question

class), 904–905 safe_mode setting (PHP), 563 safe_mode_allowed_env_vars setting (PHP), 564

Index ✦ S

safe_mode_exec_dir setting (PHP), 563 safe_mode_protected_env_vars setting (PHP), 564 same_class_name() member function (OOP), 391 sandwich_frames.html frameset, 714 sandwich_order.html form, 714–716

SAPI (Service Access Point Identifier), 723–724 save() method (DomDocument class), 742 saveXML() method (DomDocument class), 742 SAX (Simple API for XML) case folding, 745–746 event hooks, 743 functions, 746–747 further information, 743 other XML APIs versus, 739–740 overview, 739, 743 PHP parser (libxml2), 739, 743 simple example, 744 target encoding, 745–746 troubleshooting, 755 using, 743–744 SayMyABCs() function (PHP), 111 SayMyABCs3() function (PHP), 112–113 SayMyABCs2() function (PHP), 112 scalability as database advantage, 234 switching databases for, 238 schema changes, limiting with Oracle, 642 scope in OOP (PHP), 377–378 scope of functions (PHP) include() and require() and, 115–116 recursion and, 116–117 single rule for, 115 scope of permissions (MySQL), 267–268 scope of variables (Perl), 976 scope of variables (PHP) assignment and, 69 defined, 69 functions and, 70, 110–114 global, 69, 111–112 local, 111–112 overview, 69–70 Perl differences, 976 switching modes and, 70 unbound variables and, 222 scp file uploader, 807 scripting. See also client-side scripting; server-side scripting client-side (overview), 22–26 client-side versus server-side, 31 programming versus, 32 server-side (overview), 26–32 scripting languages. See also JavaScript; Perl scripting language; PHP (PHP: Hypertext Preprocessor) for Java, 722 for server-side scripting, 27

script-kiddies, 533 searching. See finding secret_function() function (PHP), 215 Secure Sockets Layer. See SSL security. See also encryption; passwords; all permissions entries attacks possible, 532–539 backing up databases, 258 dangerous permissions (MySQL), 268 database advantages for, 235 dedicated server issues, 39 e-mail safety, 538–539 for file uploads, 542–545 GET method flaws for, 122 importance of, 531 minimizing damage, 531 networks and, 531, 532, 535, 548 overview, 531, 552–553 phpinfo() function dangers, 555 PHPMyAdmin GUI issues, 270–271 against reading arbitrary files, 535–537 register_globals directive and, 540–542, 821 rules of thumb for, 531, 552–553 against running arbitrary programs, 537–538 silent mode for, 256–257 against site defacement, 532–533 against source code access, 533–534 system administrators and, 539 user authentication issues, 820–823 against viruses and other e-critters, 538–539 Web sites for information about, 552 security attacks accessing source code, 533–534 e-mail safety, 538–539 reading arbitrary files, 535–537 running arbitrary programs, 537–538 site defacement, 532–533 social engineering, 537 viruses and other e-critters, 538–539 Security-focus.com Web site, 552 SELECT client command (MySQL), 265 SELECT field form elements, 332–334 SELECT INTO feature, 239 SELECT statements joins, 247–250 min and max with, 347 overview, 247–251 permissions for, 255 speeded by indexes, 340–341 subselects, 238, 251 syntax, 247 WHERE clause, 345–346 selecting database to work on, 280 substrings (PHP), 144–145 self-defined functions. See user-defined functions (PHP)

1031

1032

Index ✦ S

client-side scripting versus, 31 data flow schema, 27 defined, 3 example, 28–31 overview, 33 PHP code on the server, 28–29, 31 programming versus scripting, 32 real-time 3D and, 32 scripting engines, 27 scripting languages, 27 server to client communication using, 26 uses for, 32 Service Access Point Identifier (SAPI), 723–724 session functions (PHP), 465–468 \$_SESSION superglobal array (PHP) propagating session variables using, 459–460 test script using, 462–464 session.auto_start setting (PHP), 468 session.cookie_lifetime setting (PHP), 468 session_decode() function (PHP), 468 session_destroy() function (PHP), 466 session_encode() function (PHP), 467 session_get_cookie_params() function (PHP), 468 session_id() function (PHP), 467 session_is_registered() function (PHP), 466 session_module_name() function (PHP), 467 session_name() function (PHP), 467 session_regenerate_id() function (PHP), 467 session_register() function (PHP), 461, 466 sessions alternatives, 456–458 configuration variables, 468–469 cookies versus, 457–458 defined, 455 functions (PHP), 465–468 making PHP aware of, 459 overview, 478 in PHP, 458–462 propagating session variables, 459–461 registering variables in, 460–461 stateless nature of HTTP and, 455–456 storing the session data, 461–462 test script using register_globals, 464–465 test script using \$_SESSION, 462–464 troubleshooting, 478 uses for tracking, 456 session.save-handler setting (PHP), 468, 566 session_save_path() function (PHP), 467 session.save-path setting (PHP), 468 session_set_cookie_params() function (PHP), 468 session_start() function (PHP), 459, 460, 461, 465 session_unregister() function (PHP), 466 session_unset() function (PHP), 466 session.use_cookies setting (PHP), 468 session_write_close() function (PHP), 466

Index ✦ S

SET type (MySQL), 291 set_cookie() function (PHP)

arguments, 470 deleting cookies, 472 described, 469 examples, 471–472 HTTP header sent by call to, 470, 475 reading cookies and, 472–473 refusal of cookies and, 475 reverse-order interpretation and, 475 set_error_handler() function (PHP), 578 setName() member function (OOP), 395 set_session_value() function (trivia game), 899 settype() function (PHP), 482 _setupQuestionIds() function (Game class), 893 SGML (Standard Generalized Markup Language) SGML-style (short-open) PHP tags, 54–55, 733 XML as form of, 731 short-circuit of logical operators (PHP), 85 short-open (SGML-style) PHP tags, 54–55, 733 short_open_tag setting (PHP), 563 SHOW COLUMNS FROM command (MySQL), 265 SHOW TABLES command (MySQL), 265 shuffling arrays (PHP), 411–412 side effects of functions, 105 signing files digitally, 550–551 signing up to mailing lists (PHP), 989 silent mode for security, 256–257 at sign indicating, 280 similarity functions for strings (PHP), 438 simpleparser.php XML parser, 744 simplex_import_dom() function (SimpleXML), 748 simplex_load_file() function (SimpleXML), 748 simplex_load_string() function (SimpleXML), 748 SimpleXML API functions, 748 other XML APIs versus, 739–740 overview, 740, 747 using, 747–748 simplexml.php SimpleXML API example, 747–748 Sin() function (PHP), 507 single quotation marks (’) apostrophes in strings and, 355 double quotation marks versus, 78–79, 137 literal, in singly quoted strings (\’), 77, 355 magic-quotes setting, 355 for strings (Perl), 974 for strings (PHP), 77–78, 137 single-key encryption, 546–548 single-line comments (PHP), 66–67 site defacement, security against, 532–533 site development ISPs, 37 sizeof() function (PHP), 164 skills_profile.php form, 332–334

slash (/) in Perl-compatible regular expressions, 427–428 as PHP arithmetic operator, 192 for PHP comments, 66–67 _sleep() function Game class, 895, 896 PHP, 385–387 slicing arrays (PHP), 413 slicing strings (PHP), 144–145 SMALLINT type (MySQL), 290 SMTP server for e-mail, 682–683 SMTP setting (PHP), 688 SOAP (Simple Object Access Protocol) mapo_tofu.xml recipe for project, 770–771 overview, 762–763 server and client project, 770–773 XML-RPC similarities, 762 soap_recipe_client.php SOAP client, 772–773 soap_recipe_server.php SOAP server, 771 social engineering, 537 socket, defined, 450 socket functions (PHP), 450–451 Software Research Associates’ PowerGres, 625 Solid databases, PHP support for, 242 sort() function (PHP), 417–418 sorting array sorting functions (PHP), 417–418 query results, 346 using min and max instead, 347 soundex() function (PHP), 438 source code access, security against, 533–534 Source Forge Web site, 687, 996 speed. See efficiency or performance spiders. See Web spiders spike() function (PHP), 791–792, 794, 795 splicing arrays (PHP), 412–413 split() function (PHP), 427 spliti() function (PHP), 427 sprintf() function (PHP), 150–151 SQL Bible (Kriegel, Alex and Trukhnov, Boris), 245 SQL For Dummies (Taylor, Allen G.), 245 SQL Server (Microsoft) cost compared to MySQL, 6 PHP support for, 241 SQL tutorial basic logical structure, 246 data manipulation statements, 246–252 database design, 253–255 DELETE statements, 252 further information, 245 INSERT statements, 251 legible style, 247 meaning of acronym, 246 overview, 258 privileges and security, 255–258 Continued

1033

1034

Index ✦ S

SQL tutorial (continued) relational databases and, 245 SELECT statements, 247–251 standards, 246 UPDATE statements, 251 SQLite, 242, 983 square brackets ([ ]) in POSIX-style regular expressions, 425 for retrieving characters in strings (deprecated), 139 square roots mathematical constants for, 501–502 while loop example, 98–99 SquirrelMail Web site, 687, 996 srand() function (PHP), 197–199 SSL (Secure Sockets Layer) further information, 270, 551 overview, 551 for PHPMyAdmin directory encryption, 270 stability of Apache HTTP Server, 12 of PHP and MySQL, 12 stack functions (PHP), 415–416 Standard Generalized Markup Language. See SGML startElement() function (SAX), 744 startElement() method (SOAP), 772 stat() function (PHP), 449 stateless protocol defined, 119 HTTP as, 119, 455–456 sessions and, 455–456 statements (PHP). See also expressions (PHP) blocks, 65–66 defined, 63 expressions as building blocks, 63 reasons for writing, 65 terminated by semicolon, 63 static HTML. See also converting static HTML sites advantages, 21 as basic Web page, 19 example, 19–20 HTML request and response for, 21 ideological rigor and, 22 limitations, 22 technologies addressing limitations of, 22 static variables in functions (PHP), 112–113 stepping through programs, 595 Stepwise.com Web site, 45 STG validator, 739 stopping MySQL client session, 265 MySQL on Windows, 263 storage. See disk space stored procedures (database) defined, 303 Oracle, 640–641, 646–647 views and, 303

strcasecmp() function (PHP), 143, 144 strchr() function (PHP), 143, 144 strcmp() function (PHP)

comparison operators versus, 88 overview, 143, 144 strcspn() function (PHP), 436–437 stream_set_blocking() function (PHP), 451 stream_set_write_buffer() function (PHP), 449 strftime() function (PHP), 452, 453 string arguments, errors form unquoted (MySQL), 358–359 string functions (PHP) case changing functions, 148–149 cleanup functions, 145–146 comparison functions, 143, 144 escaping functions, 149–150 finding characters and substrings, 141–142 hashing using MD5 algorithm, 435–436 HTML functions, 434–435 inspecting strings, 141 overview, 438 printing and output functions, 150–151 searching strings, 143–144 similarity functions, 438 string replacement functions, 146–148 substring selection functions, 144–145 tokenizing and parsing functions, 421–424 treating strings as character collections, 436–437 variety of, 140 string_cipher() function (PHP), 497–498 strings (PHP). See also string functions (PHP) advanced functions, 434–438 character arguments and, 138 checking for user-authentication system, 821–822 combining concatenation and assignment, 139–140 comparing with strcmp() function, 88 comparison operators with, 87, 88 concatenation operator, 139 curly braces for variable interpolation, 138 defined, 72, 77, 137, 480 dicing, 144–145 doubly quoted, 68, 78, 137 escape-sequence replacements, 78 exercise calculator example, 151–156 functions, 140–151, 421–424, 434–438 hashing using MD5 algorithm, 435–436 heredoc syntax, 140, 616–617 HTML functions, 434–435 immutability, 142 indexes, 139 length not limited, 80 math expressions as, 68 newlines in (\n), 78, 80 output functions, 81–82 overview, 137–138, 156 Perl similarities, 974

Index ✦ S

retrieving from multidimensional arrays, 163–164 retrieving individual characters, 139 similarity functions, 438 singly versus doubly quoted, 78–79, 137 singly-quoted, 77–78, 137 slicing, 144–145 tokenizing and parsing functions, 421–424 treating as character collections, 436–437 unterminated, parse error from, 219 variable not showing up in print string, 221 variables in, 78, 79–80 strip_db() function (Oracle), 650 stripslashes() function (PHP), 150, 322, 355–356 strip_tags() function (PHP), 435 stristr() function (PHP), 143, 144 strlen() function (PHP), 141, 144 strpos() function (PHP) overview, 141–142, 144 strstr() function and, 145 substr function and, 145 str_repeat() function (PHP), 147 str_replace() function (PHP), 146–147, 148 strrev() function (PHP), 147 strrpos() function (PHP), 142, 144 strspn() function (PHP), 436, 437 strstr() function (PHP) overview, 143, 144 strpos() function and, 145 substr function and, 145 strtok() function (PHP), 421–423 strtolower() function (PHP), 148–149 strtoupper() function (PHP), 149 struct type (C language), 969 strval() function (PHP), 483 style for conciseness, 599, 610–613 for efficiency, 599, 608–610 heredoc syntax for strings, 140, 613–617 HTML mode versus PHP mode, 613–617 for maintainability, 599, 605–607 maximal PHP style, 614–615, 984 medium PHP style, 615–617 minimal PHP style, 613–614, 985 OOP in PHP, 405–407 overview, 620 PEAR coding style, 525–528 for readability, 599, 600–605 for robustness, 599, 607–608 separating code from design, 618–619 for SQL, legible, 247 uses for, 599 style.inc Weblog stylesheet, 806–807 stylesheets. See CSS (Cascading Style Sheets) subclasses. See child classes submitButtonString() member function (OOP), 400

subqueries or subselects choosing a database and, 238 overview, 251 subscribing to mailing lists (PHP), 989 substitution cipher example, 495–499 substr function (PHP) overview, 148 for slicing and dicing, 144–145 strpos() function and, 145 strstr() function and, 145 types and, 72 substring functions. See string functions (PHP) substr_replace() function (PHP), 147, 148 Sun Java Server Pages. See JSP superclass. See parent class superglobal arrays (PHP) automatic global variables versus, 132–133 overview, 132–133 propagating session variables using, 459–460 as visible within function definitions, 111 Suraski, Zeev (PHP developer), 4 swapping databases. See switching databases switch construct (PHP) endswitch construct with, 101 if structure versus, 88, 93 overview, 92–93, 103 PEAR coding style for, 527 syntax, 92–93, 103 switching databases database abstraction and, 242–243 scalability and, 238 Sybase databases, PHP support for, 242 symlink() function (PHP), 449 syntax. See also syntax (PHP) C language, 967 Java, 719 Perl, 973 syntax (PHP). See also specific statements and constructs blocks of statements, 65–66 calling functions, 104 case sensitivity, 62–63 as C-like, 62, 967 comments, 66–67 expressions, 63–65 forgiving nature of PHP, 61 function definitions, 107–108 heredoc, for strings, 140, 616–617 highlighting, 986 HTML syntax versus, 61–62 Java similarities, 719 overview, 82 Perl similarities, 973 statements, 63 whitespace insensitivity, 62

1035

1036

Index ✦ S–T

syslog() function (PHP), 450, 590–592 system administrators, 539 system functions (PHP) calendar conversion functions, 453–454 date and time functions, 451–453 network functions, 450–451 overview, 454 system requirements for PHP installation, 40–41 for PHP on Unix, 40, 41 for PHP on Windows, 40

T tab character (\t), 78 tables (HTML), database tables versus, 295–296. See also displaying queries in HTML tables tables (MySQL) BDB, 262 changing structure of, 255 choosing field types for, 345 creating, 254 date and time fields, 347–348 deleting, 254 designing, 344–345 finding last row inserted, 348–349 for HTML graphics data set, 776–777 HTML tables versus, 295–296 InnoDB, 262 MyISAM, 262 MySQL versions and, 262 transaction-safe, 262 user table for permissions, 266 for user-rating system, 858, 859 tables (PostgreSQL) creating, 627–628 inserting data, 628 inserting records, 628 tags (PHP) ASP-style, 55 canonical, 54 escaping from HTML into PHP, 53–54, 56–57 Hello World example, 55–56 HTML script, 55 in included files, 58 short-open (SGML-style), 54–55, 733 variable scope and, 70 tags (XML). See elements (XML) tail log monitoring tool (Apache), 586–587 Tan() function (PHP), 507 target encoding (SAX), 745–746 Taylor, Allen G. (SQL For Dummies), 245 Taylor, Andrew (SQL inventor), 246 TCP/IP server for e-mail, 682 tcpserver TCP/IP server, 682 Teak e-mail client, 687 team members needed for Oracle, 642

templates (PHP) book page example (Mystery Guide Web site), 932–940 page consistency and, 618–619 for simple Weblog, 802, 803–804 for Web page navigation, 122–124 ternary conditional operator (PHP), 87–88, 103 test() member function (OOP), 396–397 testing the Java extension for PHP, 725–726 text editors choosing, 986 for PHP development, 49–50 readability and, 600–601 WYSIWYG editors versus, 986 TEXT form element, 322–324 text functions (gd toolkit), 786 TEXT type (MySQL), 291 TEXTAREA form element, 322–324 TextBoxBoldHeader class, 375–376 TextBoxHeader class, 374 TextBox.php class, 372, 373 ThinkPHP Web site, 993 threading, choosing a database and, 239 throwing an exception, 572–573 tightly coupled programs, 758 time() function (PHP), 451 TIME type (MySQL), 291 Timeout Apache configuration setting, 562 time-outs, troubleshooting (PHP), 227 timestamp functions with (PHP), 452–453 TIMESTAMP type (MySQL), 291 TINYBLOB type (MySQL), 291 TINYINT type (MySQL), 290 TINYTEXT type (MySQL), 291 titlehelp.html e-mail form, 691–692 titlehelp.php e-mail form handler, 692–693 toArray() function (JavaScript), 714–715 tokenizing strings defined, 421 functions for (PHP), 421–424 tokens (PHP), 63 top_hat() function (PHP), 791, 792, 795 toString() member function (OOP), 394, 398–399, 401–402, 403 touch() function (PHP), 449 tour_brochure() function (PHP), 490–491 tour_guide() function (PHP), 490 tour_guide_2() function (PHP), 492 transactional databases. See also Oracle atomic paradigm versus, 240 choosing a database and, 239–240 defined, 239 transactionality defined, 261 MySQL, 261 Oracle, 645–646

Index ✦ T

transform_path() function (PHP), 790–791, 794 triggers choosing a database and, 240 Oracle and, 641 trigonometric functions (PHP) displaying results, 508–510 overview, 507 table summarizing, 507–508 trigonometry overview, 510 for trig.php intersection area calculator, 947–950 trig.php intersection area calculator, 946, 948–950 trim() function (PHP), 145–146, 148 trivia game certainty_utils.php file, 875, 898–901 classes defined for, 875 code files overview, 875 concepts, 871 creating the database, 906–910 dbvars.php file, 875, 910 design considerations, 910–911 entry_form.php file, 875, 908–909 exception handling, 878, 911 the game, 872–875 game_class.php file, 889–896 game_display_class.php file, 878–887 game_parameters.php file, 896–898 game_text_class.php file, 888–889 index.php file, 875, 876–878 persistence of data, 910–911 playing the game yourself, 875 question_class.php file, 901–905 rules of the game, 874–875 sample screens, 872–874 separating code from display, 910 table definitions, 906–908 troubleshooting. See also debugging; error messages; logging argument number mismatches, 109–110, 225 avoiding errors, IDE help for, 594–595 blank image, 796 blank page, 210–211 broken image, 796–797 broken or invalid queries, 356–360 browser displays PHP script, 209–210, 214–215 browser prompts you to save file, 210 cookies, 474–475 debugging queries in PHP code, 361–362 document contains no data, 211–212 DOM parser, 755 e-mail, 701 error reporting and logging for (PHP), 587–593 failed opening [file] for inclusion, 216 failures to load page, 215–216 fatal error during connection, 351–352 file permissions, 219–220 function problems, 224–225

HTTP error 403, 220 IIS error information, 587 incomplete page, 212–214 installation-related problems, 209–210 Java, 728–729 math problems, 225–226 member variable has no value in member function, 404 missing includes, 220 mode issues, 218–219 no connection, 351–353 numerical variable unexpectedly zero, 221 object-oriented programming, 404–405 output unexpected, 58 overwritten variables, 223–224 page cannot be found, 215 parse errors (PHP), 216–219, 405 PHP/MySQL functions, 360–361 privileges, 353–354 query results with too little or too much data, 359–360 rendering problems, 210–215 SAX parser, 755 sending HTTP headers (PHP), 477, 786 serialization, 387 Server or host not found/Page cannot be displayed, 210 sessions, 478 SQL syntax errors, 356–359 from symptoms to causes (table), 227–230 time-outs, 227 unbound variables, 221–222 unescaped quotes, 219, 353–354 unintended page, 212–214 variable not showing up in print string, 221 XML, 755 troutworks Web site, 942, 996 truecolor images (gd toolkit), 783 Trukhnov, Boris (SQL Bible), 245 truncate_quotation() function (PHP), 864 try/catch construct (PHP), 113, 572 20000101.txt Weblog dated entry, 804–805 type testing functions (PHP), 481 types. See also types (PHP) C language, 968 Java, 721 MySQL, 289–291, 345 OOP, 367 Perl, 974 types (MySQL) choosing field types for tables, 345 general rule for, 289 manual information for, 290 table summarizing, 290–291

1037

1038

Index ✦ T–U

types (PHP). See also specific types arithmetic operators and, 192–193 automatic conversion of, 71, 191, 481–482 C language differences, 968 C language types versus, 72–73 conversion behavior, 482 conversion examples, 483–484 conversion functions, 482–483, 485–486 declaration not needed for variables, 67, 71 explicit conversions, 482–484 integer overflow, 486 Java types versus, 721 matching in expressions, 64 numeric, 191 overview, 71–72, 82, 479–480, 487 Perl similarities, 974 printf() and sprintf() specification of, 151 simple, 72–80 type testing functions, 481 unexpected, robustness and, 608

U uasort() function (PHP), 417–418 ucfirst() function (PHP), 149 ucwords() function (PHP), 149

UDDI (Universal Description, Discovery, and Integration), 764 uksort() function (PHP), 417–418 umask() function (PHP), 449 unassigned variables (PHP), 68–69 unassigning variables (PHP), 69 unavailability of service issues, 608 unbound variables (MySQL), 359 unbounded loops (PHP). See also loops (PHP) bounded loops versus, 94 while loop example, 98–99 underscore character (_) camelcaps versus, 604 _checksumChecks() function (GameDisplay class), 885 _construct() function, 372–373, 879, 887, 888, 891 _currentQuestionString() function (GameDisplay class), 883 _distractorString() function (GameDisplay class), 883–884 _gameStateString() function (GameDisplay class), 887 _getQuestionIdsAtLevel() function (Game class), 893–894 _highScoreEligible() function (GameDisplay class), 884–885 _highScoreString() function (GameDisplay class), 886–887 _installQuestion() function (Game class), 892–893

_makeChecksum() function (GameDisplay class),

885 _makeDistractors() function (Question class),

904 _makeDistractorsGeometric() function (Question class), 905 _makeDistractorsLinear() function (Question

class), 905 _makeTopMatter() function (GameDisplay class),

882–883 _maybeChangeLevel() function (Game class),

894–895 _postHighScoreString() function (GameDisplay

class), 885–886 _rightString() function (GameDisplay class),

884 _safeGeometricArguments() function (Question

class), 904–905 _setupQuestionIds() function (Game class), 893 _sleep() function, 385–387, 895, 896 _updateScores() function (Game class), 894 _wakeup() member function (PHP), 386–387 unescape_quotes() function (Oracle), 648 UNIQUE indexes, 343–344

UNIREG terminal interface builder, 5 Universal Description, Discovery, and Integration (UDDI), 764 Universal Resource Indicators. See URLs Universal Resource Locators. See URLs Unix. See also Linux compile-time options, 556–561 disabling mysql extension, 261 e-mail configuration for PHP, 688 installing MySQL on, 263–264 installing PHP with Apache on, 42–44 placing MySQL root directory on PATH, 264 prerequisites for installing PHP, 41 single-key encryption functions, 547–548, 549 text editors, 50 unlink() function (PHP), 449 unquote() function (Oracle), 650 unserialize() function (PHP), 385 unset() function (PHP) deleting elements from arrays, 164 restoring variable to unassigned state, 69 unzipping Apache source distribution, 42 PHP binary archive, 45, 46 PHP source distribution, 42–43 UPDATE statements condition needed for, 252 overview, 251 permissions for, 255 slowed by indexes, 340–341 syntax, 251 _updateScores() function (Game class), 894

Index ✦ U–V

879, 880 updateWithAnswer() function (Question class), 902,

user_is_loggedin() function (PHP), 831, 832 user_login() function (PHP), 832–833 user_logout() function (PHP), 833

usernames, database versus system, 256 user-rating system aggregating results, 867–869 collecting votes, 859–867 Community Rating code, 942 database connection, 861–862 domain, 858 extensions and alternatives, 869–870 initial design, 857–859 linking ratings with content, 859 performance, 869 possible ratings, 858 quotation content presentation functions, 862–864 quotations table, 858 rated_display.php page, 859–861 ratings table, 859 rating_values table, 858 user_register() function (PHP), 824–825 usort() function (PHP), 417–418 UUNet access providers, 37

V validating parsers for DTDs (XML), 739 validity (XML), 735, 739, 755 value() method (DomAttr class), 742 values of assignment expressions (PHP), 65 monitoring for variables, 595 NAN values (PHP), 226 prefilled, for forms, 126–128 retrieving from multidimensional arrays (PHP), 163–164 retrieving from simple arrays (PHP), 162 of unassigned variables (PHP), 68 of variables (PHP), 67 VARCHAR type (MySQL), 291 var_dump() function (PHP), 418–419 variables. See also variables (PHP) Java, 720–721 MySQL, unbound, 359 Perl, 974, 975, 977 variables (PHP) array variables with forms, 129–131 assigning, 67–68 automatic assignment with GET or POST, 125 case sensitivity, 62–63, 125 checking assignment, 68–69 for checking first-time submission of forms, 128–129 combining concatenation and assignment, 139–140 declaring, or not, 67 dollar sign (\$) for, 9, 67 Continued

1039

1040

Index ✦ V–W

variables (PHP) (continued) in doubly quoted strings, 78, 79–80, 137 as function arguments, 109 as function names, 495 global versus local, 111–112 hidden, as session alternative, 457 in included files, 58 Java variables versus, 720–721 monitoring values, 595 NAME attribute, 125 naming, 67, 125, 603–604 naming conventions, 223 not showing up in print string, 221 numerical variable unexpectedly zero, 221 output functions, 81–82 overwriting, register_globals directive and, 473–474 overwritten, troubleshooting, 223–224 Perl differences, 975 Perl similarities, 974, 977 propagating session variables, 459–461 reassigning, 68, 604 registering in sessions, 460–461 scope, 69–70 session configuration variables, 468–469 static, 112–113 in strings, curly braces for interpolating, 138 type declaration not needed for, 67, 71 unassigned, 68–69 unassigning, 69 unbound, troubleshooting, 221–222 unexpected types, robustness and, 608 VALUE attribute, 126 value of, 67 variables_order setting (PHP), 564 vector arrays, 159 Venn diagrams. See data visualization with Venn diagrams venn.php Venn diagram functions, 946, 952–957 venn_visualization() function (PHP), 952–956 verify_pw() function (PHP), 537 version control for maintainability, 607 vertical bars (||) as PHP logical operator, 84 viewing environment variables, 555 views (database), stored procedures and, 303 vim text editor, 50, 986 viruses and other e-critters, 538–539 visual debugging tools overview, 593 Zend Development Environment, 593–596 Visual SlickEdit text editor, 986 visualization_form.php form, 946, 958–961 visualizing data. See data visualization with Venn diagrams

Washington IMAP server, 685 wc_handler_math.php form handler, 204–206 wc_handler_var.php form handler, 135–136 Web architecture, Oracle and, 641–643 Web browsers. See browsers Web hosting colocation, 39 compromise solutions, 39 dedicated server, 39 finding a Web hosting service, 38 outsourcing, 35–38 outsourcing production, self-hosting development, 39 overview, 50–51 self-hosting, 38 Web pages. See also Internet resources; passing data between Web pages; Web sites GET method for navigation, 122–124 string-manipulation functions (PHP), 434–435 Web servers. See also Apache HTTP Server; IIS (Microsoft Internet Information Server); Web hosting server-side tasks, 27 simple HTTP request and response, 21 supported by PHP, 11 Web services advantages for integration, 759–760 current issues, 763–764 data munging and, 757–758 ease of implementation, 760 .NET services, 763 overview, 757–760, 774 REST client project, 765–769 REST standard, 760 SOAP server and client project, 770–773 SOAP standard, 762–763 Web sites incorporating, 764 XML-RPC standard, 761–762 Web Services Description Language (WSDL), 764 Web sites. See also Internet resources; Web pages permissions for shared-hosting site (MySQL), 269 permissions for standalone site (MySQL), 268–269 Web spiders link-scraper example and, 430, 433 writing well-behaved, 434 Web successfulness, 759 Web-crawlers. See Web spiders weblog_db_create.php database creation script, 810–811 weblog.php Weblog template, 803–804

Index ✦ W–X

Winston, Henry (On to C), 985 —with-apache[=DIR] or —with-apache2[=DIR]

compile-time option (Unix), 556–557 —with-apx[=DIR] or —with-apx2[=DIR] compile-

time option (Unix), 557 —with-config-file-path[=DIR] compile-time

option (Unix), 559 —with-[database][=DIR] compile-time option

(Unix), 557–558 —with-dom[=DIR] compile-time option (Unix), 559 —with-exec-dir[=DIR] CGI compile-time option

(Unix), 561 —with-java[=DIR] compile-time option (Unix), 558 —with-mcrypt[=DIR] compile-time option (Unix), 558 —with-xmlrpc compile-time option (Unix), 558

Wolpert, Ed (Cygwin FAQ author), 625 Word Wide Web Consortium (W3), 740 Word Wide Web successfulness, 759 workout calculator. See exercise calculator example workout_calc_var.html form, 134–135 World of Windows Networking Web site, 40 writepoll.php script for XML, 749–751 writing files, PHP functions for, 445–446 WSDL (Web Services Description Language), 764 W3 (Word Wide Web Consortium), 740 WYSIWYG editors, 986

X xemacs text editor, 50

XHTML, short-open PHP tags and, 54 xinetd TCP/IP server, 682

XML (eXtensible Markup Language). See also specific APIs Amazon RESTservice client, 765–767 application example, 748–755 choosing an API for, 739–740 declaration, 733 defined, 731 display promises and pitfalls, 734 Document Object Model (DOM) for, 739, 740–742 document type definitions (DTDs), 735–739 elements (tags), 733 mapo_tofu.xml recipe listing, 770–771 overview, 731–733, 756 parsers, 739, 740, 743 requirements for well-formedness, 733 separating content from display with, 734 short-open PHP tags and, 54, 733 Simple API for XML (SAX) for, 739, 743–747 simple example, 732–733 SimpleXML API for, 740, 747–748 troubleshooting, 755 uses for, 734–735 validity, 735, 739, 755 xml_error_string() function (SAX), 746

1041

1042

Index ✦ X–Z

xml_get_error_code() function (SAX), 746 xml_parse() function (SAX), 746 xml_parser_create() function (SAX), 746 xml_parser_free() function (SAX), 746

XML-RPC standard, 761–762 xml_set_character_data_handler() function

(SAX), 747 xml_set_default_handler() function (SAX), 747 xml_set_element_handler() function (SAX), 746 xor logical operator (PHP), 84

Y YEAR type (MySQL), 291

Yin, Mimi (Web site designer), 916

Z Zend Accelerator, 993 Zend Development Environment, 593–596 Zend Encoder precompiler, 11, 993 Zend scripting engine, 27, 993 Zend Studio IDE, 48–49, 50, 993 Zend.com, 4, 993 zero (0) as default start for index numbering, 161 division-by-zero warning, 225 numerical variable unexpectedly zero, 221 as printf() and sprintf() padding character, 151 zmailer MTA, 683

wiley php 5 mysql bible part three

wiley php 5 mysql bible part three