Programming PHP, Second Edition by Kevin Tatroe, Rasmus Lerdorf, Peter MacIntyre The unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification This page was updated June 18, 2008. UNCONFIRMED errors and comments from readers: {25} Table 2-2; I'm reading the edition 11/04 of the book. The "escape sequences" \{ \} \[ \] actually does not exist, for example just displays (PHP 5.2): \{\}\[\] There is only one exception reported by the manual www.php.net: "Again, if you try to escape any other character, the backslash will be printed too! Before PHP 5.1.1, backslash in \{$var} hasn't been printed." Since I'm running PHP 5.2, I can't verify this sentence. (26) 4th and 5th lines from the bottom; Replace 0.314*101 with 0.314*10^1 (or make ^1 a superscript 1) Replace 17.0*10-3 with 17.0*10^(-3) (or make ^(-3) a superscript -3) {33} first line; The operator ".=" is used, but it is not described until p48 [33] All; Missing pages 33-48. {39} example at the bottom of the page; The second line from the bottom has "9 Lives." - 1 // 8 (float) The type here is in fact an integer, as the following output shows: Script started on Sun 09 Sep 2007 03:54:35 PM CDT $ php --version PHP 5.1.4 (cli) (built: Jul 14 2006 11:04:03) Copyright (c) 1997-2006 The PHP Group Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies $ php integer double $ exit Script done on Sun 09 Sep 2007 03:56:09 PM CDT The example presumably demonstrates the rule stated a few lines prior: "If the string contains a period (.) or upper- or lowercase e, evaluating it numberically produces a floating-point number." Taken literally, this implies that "9. Lives" - 1 should evaluate to a floating-point number, but it seems this is not the case. Perhaps the text should read "If the number at the start of the string contains a period ...", etc. {41} paragraph below table 2-5; Text reads: AS illustrated in Table 2-6, incrementing "z" or "Z" wraps it back to "a" or "Z" and.... should be: AS illustrated in Table 2-6, incrementing "z" or "z" wraps it back to "aa" or "AA" and.... (tested in PHP5 environment) (42-44) entire page; The definition list of the comparison operators doesn't make sense (formatting problem?) For example: the definition tag for the equality operator reads: "equality (=) operator= (equals sign):== (equal to) operatorEquality (==)" Why not just: "equality (=)"? If this layout is intentional, there is no explanation for why it is thus. (When we get to the section "Logical operators" on p.45, the tags change to what one would intuitively expect ("Logical AND (&&, and)") {53} Last code fragment; $j was not defined in the code fragment, leading to errors when you run it. (64) Line 8; Replace "reflexive" with "inverses". {70} Example 3-6; $count was never defined in the code fragment. Correction: function count_list(){ if(func_num_args() == 0){ return false; } else { $count = 0; for ($i = 0; $i < func_num_args();$ i++){ $count += func_get_arg($i); } return $count; } } {79} chart on bottom; Most of the Specifiers should be lower-case letters. Also, there is a difference between "e" and "f" as listed below. (From PHP.net -> http://ca3.php.net/manual/en/function.sprintf.php) b - the argument is treated as an integer, and presented as a binary number. c - the argument is treated as an integer, and presented as the character with that ASCII value. d - the argument is treated as an integer, and presented as a (signed) decimal number. e - the argument is treated as scientific notation (e.g. 1.2e+2). The precision specifier stands for the number of digits after the decimal point since PHP 5.2.1. In earlier versions, it was taken as number of significant digits (one less). f - the argument is treated as a float, and presented as a floating-point number (locale aware). F - the argument is treated as a float, and presented as a floating-point number (non-locale aware). Available since PHP 4.3.10 and PHP 5.0.3. o - the argument is treated as an integer, and presented as an octal number. s - the argument is treated [as] and presented as a string. u - the argument is treated as an integer, and presented as an unsigned decimal number. x - the argument is treated as an integer and presented as a hexadecimal number (with lowercase letters). X - the argument is treated as an integer and presented as a hexadecimal number (with uppercase letters). The examples on page 80 all seem to work, although using unspecified variables ($day, $month, $year) is somewhat confusing. Am also hard-pressed to find what a "double" and a "double with precision" are - are these terms explained anywere in the book? {81} Middle of page; The calls of print_r on true, false, and NULL have comments indicating that \n is printed. This is not correct. No \n is printed for any of the calls. So print_r(true) results in the output of a single 1, nothing more, and print_r(false) and print_r(NULL) produce no output at all. (83) line 6; The word "charset" should be "charlist". {83} second code example; Because there are no leading or trailing tabs in $record, the effect of calling trim with a charlist is exactly the same as calling trim without a charlist. So the example fails to illustrate the point that it is intended to show. (85) 3/4 down the page; In the example on flipping the translation table in order to convert from text-with-entites back to the original text, the output is wrong: Einst Ürzende Neubauten should read Einstürzende Neubauten (86) "Extracting meta tags" section; The first sentence of this section is misleading and should be changed: "If you have the HTML for a web page in a string, the get_meta_tags() function returns an array of the meta tags in that page." should read something like "If you have the URL of a web page in a string, ...", etc. As originally written, it sounds as though one is supposed to put the HTML markup for the page in the string. [87] example at the bottom of the page; The output shown in the last two lines of the page is incorrect. One actually gets "It's never going to work," she cried, as she hit the backslash () key. That is, one gets the original value of $string except with the backslash in the parentheses removed. A casual reader might thing that after calling addslashes on $string, the contents of $string actually changes to what is output by the line echo addslashes($string); If this were indeed the case, then the quoted output for echo stripslashes($string); would in fact be correct, since stripslashes would then simply be undoing what addslashes did to string. But this is not how these functions work. They do not alter the value of their arguments in place. In this example, the value of $string remains unchanged. To correct this example, one could simply replace the line echo addslashes($string); with the two lines $string = addslashes($string); echo $string; leaving everything else the same. (95) 2nd sample code section; The program code and sample output are intermixed: The third line is print_r($a);Array There should be a line break before "Array". {100} First paragraph.; The last sentence of the paragraph states "[^\]] matches any character that is not a closing bracket". This is true only if one is using Perl-compatible regular expressions. When using POSIX-style regular expressions, the first "]" in "[^\]]" is treated as the closing bracket of the character class, and so "[^\]]" matches any two-character sequence in which the first character is not "\" and the second character is "]". {101} Subpatterns; I tried the example ereg('([0-9]+)', 'You have 42 magic beans', $captured); The function does return true as written in the book. The problem is with the var $captured. If you perform var_dump you have the following: array(2) { [0]=> string(2) "42" [1]=> string(2) "42" } Shouldn't index 0 (zero) contain the whole string? "The zeroth element of the array is set to the entire string being matched against." Since POSIX-style does use of the Unix locale system I tried it also on Windows and get the same results for $captured var. {106} Bottom of the page; On the bottom of the page (and in the header of the next page) we can see 2 patters: 1) '/([[:alpha:]]+)\s+\1/' 2) '/([[:alpha:]]+)\s+\1)/x' I guess the problem is in the statement: "These two patterns are the same, but one is much easier to read". They are not the same. As instructed in the book the 2nd one will strip whitespaces before matching. If so, it will not find repeated words. Example: $pattern1 = '/([[:alpha:]]+)\s+\1/'; $pattern2 = '/([[:alpha:]]+\s+\1)/x'; $str = 'Look for a word word again.'; if(preg_match($pattern1, $str)) echo 'true'; else echo 'false'; You'll have different results for $pattern1 and $pattern2 [112] last sentence on the page; The last sentence states "The cut never changes the outcome of the match; it simply makes it fail faster." This may be true of the pattern in this example, but it is not true in general. For example, /(?>\d+)5foo/ does not match the string '12345foo', but /(\d+)5foo/ does. (118) first line; The closing regular expression is missing: "/$re" should be "/$re/". [132] top; The function calls made should be add_up(0,2) add_up(4,3) add_up(13,5) add_up(38,7) (132-3) Example 5-2; This example seems out of place. The discussion immediately before and after the example is all about the 'in_array' function, but the example does not use this function at all! (It does use the 'empty' function, which hasn't been discussed up to this point.) (133) Second code example; The second line of the second code block reads: $k = array_search($person, 'Wilma'); The order of the arguments is incorrect. The search term should come first, the array to search should come second. The corrected code is: $k = array_search('Wilma', $person); The order is *correctly* referenced on page 391. [135-6] Example 5-3; Like Example 5-2, this example uses $submitted where it needs to use $_POST['submitted']. Similarly for $sort_type. A simple fix would be to call "extract($_POST)" before either of these two variables is used. {142} Last paragraph; Output from Example 5-4: there is one too many 'Exiting' output message. The last is one 'Exiting' output message line should be removed. After 'Entering first (...)' there should only be the exiting messages from first() and third(). [146] The line just before the "tip" icon that starts "// outputs:"; The output is wrong. It should read "Barney and Fred are best friends." (147) Second sentence of the second paragraph.; A missing comma makes this sentence easy to mis-read. The sentence currently reads "For instance, if you call $rasmus->birthday() inside the birthday() method, $this holds the same value as $rasmus." It sounds here as though $rasmus->birthday() is being called inside the birthday() method, that is, that somehow $rasmus->birthday() is being called recursively. I'm sure this is not the intended meaning. A comma just before "inside" (possibly with the word "then" added) would clarify the meaning: "For instance, if you call $rasmus->birthday(), then inside the birthday() method, $this holds the same value as $rasmus." In addition, the comma after "method" should perhaps be eliminated. (152) code example just before the "Destructors" heading; It is very confusing that this example uses PHP4-style contructors ("function Person(...) {...}" and "function Employee(...) {...}" when only PHP5-style contructors ("__contruct") are mentioned in the text. (153) 1st paragraph; PHP's destructor method is called __destruct(), not __destructor(). See http://www.php.net/language.oop5.decon . [156] Example 6-2, function get_inherited_methods.; When a class has no parent class, presumably it has no inherited methods. But as defined, this function ("get_inherited_methods") incorrectly returns ALL of the class's methods in such a case. (157) Example 6-2, function get_child_classes; The line if (substr($class, 0, 2) == '_ _') { probably contains a typo, since the substr can never by longer than two characters and thus the condition can never be true since '_ _' contains three characters. Presumably the compared-to string should be '__' (no space). [157] Example 6-2, function get_child_classes; This may be a configuration-dependent problem, but I found that many of the built-in classes returned by get_declared_classes couldn't be instantiated by the call $child = new $class and attempting to do so threw an exception (for example, "DOMAttr::__construct() expects at least 1 parameter, 0 given"). In any case, I had to wrap this line in a try-catch block to get this example to work. (161) Example 6-3.; The first function is the constructor and should therefore be called: function __construct($filename) { not function Log($filename) { (161) Example 6-3.; The first line of the declaration of the fifth function in class Log reads "function _ _wakeup() {". It should read "function __wakeup() {" (no space between the two underscores). Similarly for the sleep function. [178] 3rd line of code after "// create HTML for identically named checkboxes; printf('%s " [195] Example 7-15; The code of example 7-15 does not work. It should contain $_COOKIE['bgcolor'], but it doesn't. Here is a working example: Color Selector
[204] last paragraph; LAST CODE EXAMPLE ON THE PAGE: Wrong: $row = $result->fetchrow(DB_FETCHMODE_ASSOC); should be: $row = $result->fetchrow(DB_FETCHMODE_OBJECT); {205} bottom; $movies = array (...); shoud say $books = array (...); (206) Bottom of page; Last line says: "$db->insertMultiple($compiled, $books);" Last line should have said: "$responses = $db->executeMultiple($compiled, $books);" (207) 2nd-to-last paragraph: the sample code with sample output; This example is supposed to demonstrate the "getCol" method which was just introduced in the preceding paragraph. But "getAll" is written instead. In other words, the line $titles = $db->getAll("Select title FROM books ORDER BY pub_year ASC"); should read $titles = $db->getCol("Select title FROM books ORDER BY pub_year ASC"); (Using "getAll" would make "$titles" an array of arrays and "$title" an array. This would make the output something like Array Array Array ). (207) last line of text; "movies" should be "books" "movie" should be "book" (219) End of example code, just before tag; Missing end tag. [220] in example 8-6; Need to define $cat_id Insert this line after "require_once('db_login.php');" $cat_id = $_REQUEST['cat_id']; {275} bottom of function BookList; In 3rd line from end of function BookList, $x receives the result of the function join(). The call to function join passes in an empty string as the first parameter and an array of lines of a file as the second parameter (the result of the call to the file() function). However, the join reference on page 444 says that join() should expect an array as its first parameter and string as its second. I think that either the call to join on 275 or the reference info on 444 is reversed. I just looked up join and implode on php.net. It says the parameters can be in either order, so I guess this isn't really a mistake. However, to save people the confusion, it would be great if you could make a note of this is the join documentation on 444 and the implode documentation on 438, or just change the example on 275 to be consistent with your own documentation. (276) Function: cdata; The if/else in the function "cdata" uses "===", should this be "=="? {277} 1st paragraph (1st code sample); When I run the sample code below: $parser = new domdocument(); $rootNode = $parser->load('books.xml'); processNodes($rootNode); function processNodes($node) { $children = $node->children; foreach ($children as $child) { if ($child->nodeType == XML_TEXT_NODE) { echo $child->noteValue; } elseif ($child->nodeType == XML_ELEMENT_NODE) { processNodes($child); } } } I get the following PHP Warning error: Invalid argument supplied for foreach() in \websites\webapps\learnPHP\ProgPHP2\Ch11- XML\ParseXML-DOM2.php on line 10 Any suggestions? [277] top; The DOM XML example is completely broken and does not run. Not even the syntax is right: echo $child->noteValue; should be: echo $child->nodeValue; [277] Code in DOM section; Broken, old syntax, typos, you name it.... Corrections are commented on $parser = new DomDocument(); $rootNode = $parser->load('BookList.xml'); processNodes($parser); // $parser, NOT $rootNode which only holds load() successTRUE/FALSE function processNodes($node) { $children = $node->childNodes; // childNodes, NOT children foreach ($children as $child) { if ($child->nodeType == XML_TEXT_NODE) { echo $child->nodeValue; // nodeValue, NOT noteValue } else if ($child->nodeType == XML_ELEMENT_NODE) { processNodes($child); } } } [277]8th line from the bottom; foreach ($document->library->book as $book) should be foreach ($document->book as $book) {280} top; Example 11-12: is not necessary because the XML document (example 11-11) does not contain any elements. [299] eval example doesn't work; Here is a working eval example: Here is the entry to my computer!

Execute code

(e.g.: include ('/etc/passwd'); )
"); if ($code) { echo ("

"); echo ("Executing code..."); echo ("
"); eval (stripslashes ($code)); echo ("

"); } // if ?>
{308} top; return str_replace ('...', '...', $contents); should be: return str_replace ('...', '...', $text); [344] Line 3; The line ends with &s_len) but it should end with &s_len, &d) to avoid a segmentation fault. {373} top; "Open the Control Panels folder, and double-click on the ODBC Data Sources icon." Under Windows XP there is no ODBC Data Sources icon in the Control Panel folder. However, there is a 'Administrative Tools' icon. If you open the 'Administrative Tools' folder, you see the ODBC Data Sources icon. [407] Most of the page; What happened to the capitalisation? This list is not very helpful because it omits which letter should or should not be capitalised. {407} first "z" in list of format characters; Replace 'from "1" through' by 'from "0" through'. (420) last entry; Upper/lower case problem, caused by the spelling checker, similar to what was already found with the date() function also occurs with e.g. the 'mode'-parameter of the fopen() function. (420) within spec of "fopen" command; The parameters should ALL be in lower case. e.g in the book "R - Open the file for reading..." should be "r - Open the file for reading..." It's the same case for "W" and "A". I have just spent an hour trying to figure out an error that was the result of this! The same case problem is on page 406-407 in relation to the date command. Half of those parameters should be in lower case, but in the book they are all uppercase. {438} third function on page (implode); In the function definition, the parameters are reversed. Should be: string implode(string separator, array strings) {444} last function on page (join); In the function definition, the parameters are reversed. Should be: string join(string separator, array strings) {471} shell_exec() entry; Is: "Executes command via the shell and returns the last line of output from the command ..." Should be: "... returns the output from the command ..." "the last line" describes the exec() function, not shell_exec() (516) column 1; The php statements include_once, require and require_once are omitted from the index (should refer to pp57-58 {523} Colophon paragraph 1; The animal on the covers is not, in fact, a common cuckoo, as the common cuckoo is not crested. It is probably a roadrunner (Geococcyx californianus).