Programming PHP

Errata for Programming PHP

Submit your own errata for this product.


The errata list is a list of errors and their corrections that were found after the product was released. If the error was corrected in a later version or reprint the date of the correction will be displayed in the column titled "Date Corrected".

The following errata were submitted by our customers and approved as valid errors by the author or editor.

Color Key: Serious Technical Mistake Minor Technical Mistake Language or formatting error Typo Question Note Update



Version Location Description Submitted By Date Submitted Date Corrected
Printed, PDF, ePub, Mobi, Safari Books Online
Page 8
Example 1-1. hello_world.php

The coding for Hello World includes redundant code. The first bit: <html> <head> <title>Look Out World</title> </head> <body> <?php echo "Hello, world!"; ?> Shouldn't be there as it is followed by the same thing that is properly closed with the </body> and </html> tags. The above code would resolve to nothing when the site is loaded.

Note from the Author or Editor:
correct as suggested, redundant code, the entire sample 1-1 should be thus: <html> <head> <title>Look Out World</title> </head> <body> <?php echo "Hello, world!"; ?> </body> </html>

Anonymous  Mar 18, 2013  Nov 08, 2013
PDF
Page 11
1st paragraph

The first paragraph mentions using code in a file called library.sql. Page xxi mentions a link to the book's page at O'Reilly "where we list errata, examples, and any additional information." However, when I go there. I cannot find a link to download the example code. Where is it?

Note from the Author or Editor:
http://examples.oreilly.com/0636920012443/

Janet Shea  Apr 28, 2013  Nov 08, 2013
PDF
Page 22
Last paragraph

The text says: Integer literals can be written in decimal, octal, or hexadecimal. Note: Integer literals can also be written in binary format.

Note from the Author or Editor:
Correct as suggested: was : Integer literals can be written in decimal, octal, or hexadecimal. Change to: Integer literals can be written in decimal, octal, binary, or hexadecimal.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
Printed
Page 23
3rd paragraph

0b01100000 // decimal 1 The decimal value of the binary literal is 96 and not 1;

Note from the Author or Editor:
correct as suggested 0b01100000 // decimal 1 should be 0b01100000 // decimal 96

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 25
2nd paragraph

if ($a == $b) { echo "a and b are equal" } is missing a semicolon.

Note from the Author or Editor:
Correct as suggested. Change code to the following: if ($a == $b) { echo "a and b are equal" ; }

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 29
1st paragraph

$callback = function myCallbackFunction() { echo "callback achieved"; } This syntax is wrong. The function cannot have a name and it must be anonymous. The statement should also be terminated with a semicolon. Correct: $callback = function () { echo "callback achieved"; };

Note from the Author or Editor:
Correct as suggested, code example should now be: $callback = function () { echo "callback achieved"; }; call_user_func ( $callback );

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 31
1st paragraph in the section "Local scope"

The words "That is, it is visible only to code in that function (INCLUDING nested function definitions);" should be "That is, it is visible only to code in that function (EXCEPTING nested function definitions);"

Note from the Author or Editor:
Correct as changed...

Anonymous  Oct 11, 2013  Nov 08, 2013
PDF
Page 35
4-th row in the table from bottom

this row in the table "Table 2-3. PHP operators" seems to be wrong 5 L = Assignment It states that the assignment operator has left precedence, but it should be right instead. Consider the next example: $a = 2; $b = 3; $c = $b = $a; echo $a . $b . $c; this example produces the string "222". So the exact order of execution is: 1. assign to the variable $b the value of $a 2. assign to the variable $c the value produced by the $b = $a operation. That is why all the variables have the value of 2. And if the precedence was left, as table states, $c should be 3.

Note from the Author or Editor:
That is right, it should be R, the row below it should also be R. so the new entries for those rows should read: 5 R = Assignment R +=,-=, (...) Assignment with operation

Anonymous  Oct 12, 2013  Nov 08, 2013
PDF
Page 38
casting examples

"9 Lives." - 1; // 8 (float) should actually be: "9 Lives." - 1; // 8 (integer)

Note from the Author or Editor:
Almost correct as suggested .. change the line from : "9 Lives." - 1; // 8 (float) to: "9. Lives" - 1; // 8 (float) [the period in the example was in the wrong place.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 40
Table 2-7

The text says "String that is entirely numeric String that is not entirely numeric Numeric". This is not correct. The examples are going to be compared in lexicographical order. Example: $str1 = '1533a'; $str2 = '154'; if ($str1 > $str2) { echo 'numeric'; } else { echo 'lexicographical '; }

Note from the Author or Editor:
Correct, as suggested, 3rd last line in table 2-7: String that is entirely numeric String that is not entirely numeric Numeric changes to: String that is entirely numeric String that is not entirely numeric Lexicographic

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 40
Table 2-7

The text says "String that is not entirely numeric Number Lexicographic". This is not correct. The comparison is this case is numeric. Example: $str1 = '1533a'; $str2 = 154; if ($str1 > $str2) { echo 'numeric'; } else { echo 'lexicographical '; }

Note from the Author or Editor:
Correct, as suggested, 2nd last line in table 2-7: String that is not entirely numeric Number Lexicographic changes to: String that is not entirely numeric Number Numeric

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 42
'Right shift' paragraph

The text says: Shifting a binary number to the right inserts a 0 as the leftmost bit of the number and moves all other bits to the right one place. Note: This is not correct because if the number is negative that a 1 is going to be inserted as the leftmost bit of the number.

Note from the Author or Editor:
This is correct for positive numbers, so let's update the sentence to the following: Shifting a positive binary number to the right inserts a 0 as the leftmost bit of the number and moves all other bits to the right one place. Shifting a negative binary number to the right inserts a 1 as the leftmost bit of the number and moves all other bits to the right one place.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 43
last line

'synonymous operands' should be 'synonymous operators'.

Note from the Author or Editor:
'synonymous operands' should be 'synonymous operators'.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 44
2nd paragraph

The text says "Casting an array to a numeric type gives 1,...". The exception is that if the array is empty the numeric value is going to be 0 instead of 1.

Note from the Author or Editor:
Correct as suggested ... changing the sentence from: Casting an array to a numeric type gives 1, and casting an array to a string gives "Array" (seeing this in your output is a sure sign that you’ve printed a variable that contains an array). to this: Casting an array to a numeric type gives 1 (if the array is empty it gives 0), and casting an array to a string gives "Array" (seeing this in your output is a sure sign that you’ve printed a variable that contains an array).

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 54
3rd paragraph

for ($i = 0, $j = 0; $i <= 10; $i++, $j *= 2) { $total += $j; } When $j is initialized as 0 then $total will also have a value of 0 in the end. This is probably not the intention and $j should be initialized to the value 1.

Note from the Author or Editor:
Correct, $j should be initialized to other than 0... code should now read: $total = 0; for($i = 0, $j = 1; $i <= 10; $i ++, $j *= 2) { $total += $j; }

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
Printed, PDF
Page 68
Keywords section

You say: "...you cannot give a **variable**, function, class, or constant the same name as a keyword" But actually you can name a variable $else or $empty. Tested with PHP 5.4.19

Note from the Author or Editor:
Page 21 text is: ...you cannot give a variable, function, class, or constant the same name as a keyword. corrected to: you cannot give a function, class, or constant the same name as a keyword.

Ruben Santacruz  Sep 06, 2013  Nov 08, 2013
PDF
Page 72
1st paragraph

The text says "(including instances of classes that extend or implement that class)". It is not correct to say that a class can be implemented - interfaces can be implemented.

Note from the Author or Editor:
The text that reads "(including instances of classes that extend or implement that class)" should instead read "(including instances of classes that extend that class)".

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
Printed, PDF
Page 76
Booleans section, values that evaluate to false

You say that an object with no values or functions evaluates to false. But that was only true in PHP 4. This book is supposed to cover PHP 5. Source: php.net documentation When converting to boolean, the following values are considered FALSE: the boolean FALSE itself the integer 0 (zero) the float 0.0 (zero) the empty string, and the string "0" an array with zero elements an object with zero member variables (PHP 4 only) the special type NULL (including unset variables) SimpleXML objects created from empty tags Every other value is considered TRUE (including any resource).

Note from the Author or Editor:
Page 25, chapter 2. 2nd last bullet is: An object with no values or functions It should be removed. As this book aims to cover version 5.3 and above.

Ruben Santacruz  Sep 06, 2013  Nov 08, 2013
PDF
Page 81
print() paragraph

The example is: if (print("test")) { print("It worked!"); } It worked! It should be: if (print("test")) { print("It worked!"); } testIt worked! The text 'test' from the condition evaluation is also printed.

Note from the Author or Editor:
The example code reading if (print("test")) { print("It worked!"); } It worked! should instead read: if (print("test\n")) { print("It worked!"); } test It worked!

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 89
Last paragraph

The text says: Only encode partial URLs (the bit after http://www.example.com/hello) and add the protocol and domain name later. Note: The partial url should be the bit after http://www.example.com/.

Note from the Author or Editor:
The text that reads "Only encode partial URLs (the bit after http://www.example.com/hello) and add the protocol and domain later." should instead read: "Only encode partial URLs (the bit after http://www.example.com/) and add the protocol and domain later. The partial URL was inadvertently included in the protocol and domain portion.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 92
'Exact Comparisons' section

The text says: The == operator casts nonstring operands to strings, so it reports that 3 and "3" are equal. Note: This is not correct. The string operand is cast to nonstring and not the other way around. That's why '32a' == '32'.

Note from the Author or Editor:
The sentence "The == operator casts nonstring operands to strings, so it reports that 3 and "3" are equal." needs to be changed to read: "The == operator casts string operands to numbers, so it reports that 3 and "3" are equal. Due to the rules for casting strings to numbers, it would also report that 3 and "3b" are equal, as only the portion of the string up to a non-number character is used when casting it."

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 116
'Splitting' section

The text says: An empty pattern matches at every boundary between characters in the string. This lets you split a string into an array of characters: $array = preg_split('//', $string); Note: This actually returns two more characters - one in the beginning and one in the end - preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY); will help.

Note from the Author or Editor:
The text "An empty pattern matches at every boundary between characters in the string." should be changed to read instead: "An empty pattern matches at every boundary between characters in the string, and at the start and end of the string". The sample code also returns two empty strings; one at the beginning of the results and one at the end, that are the empty character from the boundaries between the start of the string and its first character and the end of the string and its last character.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 131
Last example on page

The definition of the the function that's assigned to the $callback variable doesn't compile. Should be an anonymous function (remove the 'printRow' text).

Note from the Author or Editor:
Corrected code is as follows with some added echos for debugging purposes (output proof) and building the table elements around the array_walk call - also the callback function reference is changed to $printRow.: $printRow = function ($value, $key) { print("<tr><td>{$key}</td><td>{$value}</td></tr>\n"); }; $person = array('name' => "Fred", 'age' => 35, 'wife' => "Wilma"); echo "<table border=1>" ; array_walk($person, $printRow); echo "</table>" ;

Joel Barnum  Mar 06, 2014 
PDF
Page 133
1st Paragraph (code)

The code to test array_reduce dosen't work because of a bad definition of the function, function name "addItUp" must be removed.

Note from the Author or Editor:
Corrected code should be, with some added echos for debugging if needed: $addItUp = function ($runningTotal, $currentValue) { //echo $runningTotal . " " . $currentValue . "<br/>" ; $runningTotal += $currentValue * $currentValue; return $runningTotal; }; $numbers = array(2, 3, 5, 7); $total = array_reduce($numbers, $addItUp); echo "<br/> TOTAL: " . $total; also the next example should be update to this: $addItUp = function ($runningTotal, $currentValue) { //echo $runningTotal . " " . $currentValue . "<br/>" ; $runningTotal += $currentValue * $currentValue; return $runningTotal; }; $numbers = array(2, 3, 5, 7); $total = array_reduce($numbers, $addItUp, 11); echo "<br/> TOTAL: " . $total; with the callback function name changed to $addItUp in both instances.

Ricardo Ferreira  Jan 27, 2014 
PDF
Page 134
Example 5-2

function hasRequired() does not work correctly because the $_POST array has the keys even with empty fields sent - the browser sends an empty string.

Note from the Author or Editor:
Replace existing code example 5-2 with the following (just added the array_filter after the Post[submit] if test, and passed in the trimmed filter to hasRequired: <?php function hasRequired($array, $requiredFields) { $array = $keys = array_keys ( $array ); foreach ( $requiredFields as $fieldName ) { if (! in_array ( $fieldName, $keys )) { return false; } } return true; } if ($_POST ['submitted']) { $testArray = array_filter($_POST); echo "<p>You "; echo hasRequired ( $testArray, array ( 'name', 'email_address' ) ) ? "did" : "did not"; echo " have all the required fields.</p>"; } ?> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST"> <p> Name: <input type="text" name="name" /><br /> Email address: <input type="text" name="email_address" /><br /> Age (optional): <input type="text" name="age" /> </p> <p align="center"> <input type="submit" value="submit" name="submitted" /> </p> </form>

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
ePub
Page 153
SupernaturalPerson class definition

The SupernaturalPerson class references a protected method of the Person class without extending the Person class. See code below. class Person { public $age; public function __construct() { $this->age = 0; } public function incrementAge() { $this->age += 1; $this->ageChanged(); } protected function decrementAge() { $this->age &#8722;= 1; $this->ageChanged(); } private function ageChanged() { echo "Age changed to {$this->age}"; } } class SupernaturalPerson { public function incrementAge() { // ages in reverse $this->decrementAge(); } }

Note from the Author or Editor:
The code: class SupernaturalPerson { public function incrementAge() { // ages in reverse $this->decrementAge(); } } needs to be changed to: class SupernaturalPerson extends Person { public function incrementAge() { // ages in reverse $this->decrementAge(); } } The SupernaturalPerson class is intended to inherit form the Person class, and the code example does not work as described unless it does.

sjbenner  Apr 30, 2013  Nov 08, 2013
PDF
Page 157
trait definition (Logger)

public log($logString) is missing its 'function' keyword.

Note from the Author or Editor:
The code that reads: trait Logger { public log($logString) { should instead read: trait Logger { public function log($logString) { The function declaration for log() was missing the function keyword which is a syntax error.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 158
trait definitions (First, Second)

public doFirst() and public doSecond() are missing the 'function' keyword.

Note from the Author or Editor:
The code that reads: public addUser(User $user) should instead read: public function addUser(User $user) The code that reads: public doFirst() should instead read: public function doFirst() Finally, the code that reads: public doSecond() should instead read: public function doSecond() On the following page (p.159), the code that reads: public doAll() should instead read: public function doAll() In all four cases the missing function keyword causes a syntax error.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 171
example 6-4

function session_is_registered() is deprecated in php 5.3 and removed in php 5.4.

Note from the Author or Editor:
The code reading: if (!session_is_registered('l')) { should instead read: if (!isset($_SESSION['l'])) { The session_is_registered() function is deprecated as of PHP 5.3 and removed as of PHP 5.4.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
PDF
Page 171
Example 6-4

The statement session_register('l'); should actually be session_register('logger'); because the variable is named 'logger' and not 'l'.

Note from the Author or Editor:
The sample code that reads: if (!session_is_registered('l')) { $logger = new Log("/tmp/persistent_log"); session_register('l'); $logger->write("Created $now"); } should instead read: if (!isset($_SESSION['logger'])) { $logger = new Log("/tmp/persistent_log"); $_SESSION['logger'] = $logger; $logger->write("Created $now"); } Both the session_is_registered() and session_register() functions are deprecated in PHP 5.3 and removed in PHP 5.4. In addition, the code was registering the variable as 'l', while assuming it was registered as 'logger'.

Dilyan Dokov  Mar 24, 2013  Nov 08, 2013
Safari Books Online
177 - 189
All code in the listed page range 177 - 189

In all of the code in the section Processing Forms, the $_GET variable is not handled correctly. It is never checked to see if it is set with the isset function. This check should be the first thing at the top of all the code listings.

Note from the Author or Editor:
Although we do not mention it all that well ... our example code is not always as efficient as it should be. This was done to show the points of the code that we were trying to make rather than be bogged down with too much extra code.

James Butler  Jul 17, 2013  Nov 08, 2013
Safari Books Online
181
Code listing temp2.php

The code in the book and in the downloaded code will give the undefined index on line 7 because the first time the code runs the $_GET['fahrenheit'] variable does not exist. Instead of the line: $fahr = $_GET['fahrenheit']; The code should have been this: if(isset($_GET['fahrenheit'])) { $fahr = $_GET['fahrenheit']; } else { $fahr = null; }

Note from the Author or Editor:
Agreed: Change the code example 7-4 to the following: <html> <head> <title>Temperature Conversion</title> </head> <body> <?php if (isset ( $_GET ['fahrenheit'] )) { $fahrenheit = $_GET ['fahrenheit']; } else { $fahrenheit = null; } if (is_null ( $fahrenheit )) { ?> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="GET"> Fahrenheit temperature: <input type="text" name="fahrenheit" /><br /> <input type="submit" value="Convert to Celsius!" /> </form> <?php } else { $celsius = ($fahrenheit - 32) * 5 / 9; printf ( "%.2fF is %.2fC", $fahrenheit, $celsius ); } ?> </body> </html>

James Butler  Jul 17, 2013  Nov 08, 2013
PDF
Page 185
Example 7-8, function makeCheckboxes

function makeCheckboxes in the book and the one in the sample code are different. The former does not seem to work, but the latter does. //function makeCheckboxes in the book: function makeCheckboxes($name, $query, $options) { foreach ($options as $value => $label) { $checked = in_array($value, $query) ? "checked" : ''; echo "<input type=\"checkbox\" name=\"{$name}\" value=\"{$value}\" {$checked} />"; echo "{$label}<br />\n"; } } //function makeCheckboxes in the example code: function makeCheckboxes($name, $query, $options) { foreach ($options as $value => $label) { printf('%s <input type="checkbox" name="%s[]" value="%s" ', $label, $name, $value); if (in_array($value, $query)) { echo "checked "; } echo "/><br />\n"; } }

Note from the Author or Editor:
For sample 7-8 (pg 185, 186), just make the following change to the call to the makeCheckboxes function: <?php makeCheckboxes('attributes[]', $attrs, $personalityAttributes); ?><br /> adding [ ] to the attributes (first parameter being sent to the function.

Anonymous  Aug 19, 2013  Nov 08, 2013
Printed
Page 198
Example 7-13

As the PHP manual states, to use cookie-based sessions, session_start() must be called before outputing anything to the browser. However, the html head and body are started before session_start() is called in this example.

Note from the Author or Editor:
Sorry, I have found this in the documentation... you are correct in the case of cookie based sessions. Note: To use cookie-based sessions, session_start() must be called before outputing anything to the browser. The code should be corrected to the following for cookie based sessions: <?php session_start() ?> <html> <head><title>Preferences Set</title></head> <body> <?php $colors = array( // remainder of code ... etc...

Patrick Cronin  Dec 05, 2013 
Printed
Page 217
example 8.6

reading the file content with $comments = fread() gives an error when the file is empty. Replacing by $comments = file_get_contents() works, and matches the code highlights on page 219 below the 1st paragraph.

Note from the Author or Editor:
Correct as identified ... the sample code should match that noted on page 219. Therefore the line of code on page 217 in example 8-6 (line 9) should be: $comments = file_get_contents($filename) ; note that even the code shown on 219 has an extra closing brace that should not be there.

Patrick Beaudan  Nov 10, 2013 
PDF
Page 300
after 2nd paragraph

The code if (check_auth($_POST['username'], $_POST['password'])) { $_SESSION['auth'] = TRUE; session_regenerate_id(); } will not delete the old session id. http://php.net/manual/en/function.session-regenerate-id.php If the old session id remains, it can be used by an attacker. The code below deletes the old session id. if (check_auth($_POST['username'], $_POST['password'])) { $_SESSION['auth'] = TRUE; session_regenerate_id(TRUE); }

Note from the Author or Editor:
The code: if (check_auth($_POST['username'], $_POST['password'])) { $_SESSION['auth'] = TRUE; session_regenerate_id(); } should be changed to: if (check_auth($_POST['username'], $_POST['password'])) { $_SESSION['auth'] = TRUE; session_regenerate_id(TRUE); } Starting with PHP 5.1, the session_regenerate_id() function does not delete the existing session file unless you specify to.

Fumito MIZUNO  Jul 12, 2013  Nov 08, 2013