Errata for Programming PHP

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.

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.

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";
};

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

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.

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.

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.

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: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.

None

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

Printed

Page 170
Text between Example 6.3 and Example 6.4

The text suggests to store the Log class definition in a file called Log.inc. However Example 6.3's title makes it clear that Log's class definition is in Log.php, and Example 6.4's code includes "Log.php." Therefore it seems the text is contradictory on the name of the file containing the Log's class definition. I would assume that they should all be the same, whether .inc or .php?

Note from the Author or Editor:Change "Log.inc" in the first paragraph of p170 to "Log.php".

Patrick Cronin

Dec 04, 2013

Jul 03, 2014

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: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

Jul 03, 2014

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

Jul 03, 2014

Printed

Page 278
Last example in under the Errors heading

The line:
die(xml_error_string($err));
should read
die(xml_error_string($error));

Note from the Author or Editor:Change the first code example (after paragraph 1) on p278 to read:
$error = xml_get_error_code($parser);
In addition, change the final code example on p278 to read:
$error = xml_get_error_code($parser);
if ($error != XML_ERROR_NONE) {
die(xml_error_string($error));
}

Patrick Cronin

Dec 05, 2013

Jul 03, 2014

Printed

Page 278
Second example on the page

The foreach line seeks to iterate over $document->library->children(), but when I try this code on PHP 5.3.26, I get:
Warning: main(): Node no longer exists
Changing $document->library->children() to simply $document->children() at least removes the error, but the example seems to be trivial as books.xml (there is no BookList.xml in the book as noted in a previous erratum) contains no attributes.

Previous to this page, there was no document created titled BookList.xml. However, there was a document titled books.xml, from page 279, that seems most appropriate. I assume the references to BookList.xml should actually be to books.xml.

Note from the Author or Editor:Change instances of "BookList.xml" in code samples (1st, second, and third examples on p284 and first line of p285) on pages 284 and 285 to "books.xml" instead.

Patrick Cronin

Dec 05, 2013

Jul 03, 2014

Printed

Page 285
Just above Example 11-10

Referring to the line reading
$result = $processor->transformToXml($xml);
the book continues with "The /document/ parameter is a DOM object …"
However the parameter given with the $xml variable was never identified as the /document/ parameter. I would suggest changing the sentence to start with: "The $xml parameter is a DOM object…"

Note from the Author or Editor:Change the paragraph on p285
The document parameter is a DOM object representing the XML document.
to instead read:
Each takes the DOM object representing the XML document as a parameter.

Patrick Cronin

Dec 05, 2013

Jul 03, 2014

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);
}