Instant Access to PHP 5 Advanced Visual QuickPro Guide 2nd Edition Larry Ullman ebook Full Chapters
Instant Access to PHP 5 Advanced Visual QuickPro Guide 2nd Edition Larry Ullman ebook Full Chapters
PHP for the Web Visual QuickStart Guide 4th Edition Larry
Ullman
https://ebookgate.com/product/php-for-the-web-visual-quickstart-
guide-4th-edition-larry-ullman/
ebookgate.com
https://ebookgate.com/product/visual-spatial-thinking-for-advanced-
learners-grades-3-5-1st-edition-emily-hollett/
ebookgate.com
https://ebookgate.com/product/zend-php-5-certification-study-guide-
third-edition-davey-shafik-with-ben-ramsey/
ebookgate.com
https://ebookgate.com/product/php-5-power-programming-1st-edition-
andi-gutmans/
ebookgate.com
Magento PHP Developer s Guide 2nd Edition Allan Macgregor
https://ebookgate.com/product/magento-php-developer-s-guide-2nd-
edition-allan-macgregor/
ebookgate.com
https://ebookgate.com/product/php-mysql-for-advanced-learning-3rd-
edition-hirdesh-bhardwaj/
ebookgate.com
https://ebookgate.com/product/advanced-visual-basic-2010-5th-edition-
kip-r-irvine/
ebookgate.com
https://ebookgate.com/product/beginning-php-and-mysql-5-from-novice-
to-professional-second-edition-w-jason-gilmore/
ebookgate.com
https://ebookgate.com/product/beginning-php-5-and-mysql-from-novice-
to-professional-1st-edition-w-jason-gilmore/
ebookgate.com
VISUAL QUICKPRO GUIDE
PHP 5 ADVANCED
Larry Ullman
Peachpit Press
Visual QuickPro Guide
PHP 5 Advanced
Larry Ullman
Peachpit Press
1249 Eighth Street
Berkeley, CA 94710
510/524-2178
510/524-2221 (fax)
Notice of Rights
All rights reserved. No part of this book may be reproduced or transmitted in any form by any
means, electronic, mechanical, photocopying, recording, or otherwise, without the prior written
permission of the publisher. For information on getting permission for reprints and excerpts,
contact [email protected].
Notice of Liability
The information in this book is distributed on an “As Is” basis, without warranty. While every
precaution has been taken in the preparation of the book, neither the author nor Peachpit Press
shall have any liability to any person or entity with respect to any loss or damage caused or
alleged to be caused directly or indirectly by the instructions contained in this book or by the
computer software and hardware products described in it.
Trademarks
Visual QuickPro Guide is a registered trademark of Peachpit Press, a division of Pearson
Education.
MySQL is a registered trademark of MySQL AB in the United States and in other countries.
Macintosh and Mac OS X are registered trademarks of Apple Inc. Microsoft, Windows, Windows
XP, and Windows Vista are registered trademarks of Microsoft Corp. Screenshots of Web sites in
this book are copyrighted by the original holders.
Many of the designations used by manufacturers and sellers to distinguish their products are
claimed as trademarks. Where those designations appear in this book, and Peachpit was aware
of a trademark claim, the designations appear as requested by the owner of the trademark. All
other product names and services identified throughout this book are used in editorial fashion
only and for the benefit of such companies with no intention of infringement of the trademark.
No such use, or the use of any trade name, is intended to convey endorsement or other affilia-
tion with this book.
987654321
Introduction ix
Chapter 1: Advanced PHP Techniques 1
Chapter 2: Developing Web Applications 43
Chapter 3: Advanced Database Concepts 81
Contents at a Glance
Chapter 4: Security Techniques 123
Chapter 5: E-commerce Techniques 169
Chapter 6: Basic Object-Oriented
Programming 233
Chapter 7: Advanced OOP 263
Chapter 8: Real-World OOP 309
Chapter 9: Networking with PHP 347
Chapter 10: PHP and the Server 373
Chapter 11: PHP’s Command-Line Interface 417
Chapter 12: Using PEAR 443
Chapter 13: Ajax 481
Chapter 14: XML and PHP 529
Index 569
v
Table of Contents
Introduction ix
Chapter 1: Advanced PHP Techniques 1
Multidimensional Arrays . . . . . . . . . . . . . . . . . . . . . . 2
Advanced Function Definitions . . . . . . . . . . . . . . . 18
The Heredoc Syntax . . . . . . . . . . . . . . . . . . . . . . . . . 31
Using printf() and sprintf() . . . . . . . . . . . . . . . . . . . 37
Table of Contents
vi
Table of Contents
Table of Contents
Advanced Theories . . . . . . . . . . . . . . . . . . . . . . . . . 264
Inheriting Classes . . . . . . . . . . . . . . . . . . . . . . . . . . 266
Inheriting Constructors and Destructors . . . . . 271
Overriding Methods . . . . . . . . . . . . . . . . . . . . . . . . 276
Access Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Using the Scope Resolution Operator . . . . . . . . . 289
Creating Static Members . . . . . . . . . . . . . . . . . . . . 294
Abstract Classes and Methods . . . . . . . . . . . . . . . 300
vii
Table of Contents
Index 569
viii
Introduction
i
If you’re looking at this book, then I probably don’t need to tell you how great PHP is.
Presumably, since you’re perusing the pages of an advanced text on the topic, you are
already using PHP for developing dynamic Web sites. Maybe you’ve been doing so for
a couple of years, perhaps just a couple of months. You could have learned PHP on your
own, in a class, or by reading one of the many excellent books on the subject. (I’m
referring not just to my own, of course!) Whatever the case, with some experience
Introduction
under your belt, you probably don’t want another “here’s how to use PHP and isn’t it
swell” book. What you probably want to learn is how to use PHP more efficiently, more
securely, faster, and all-around better than you already are. If so, you’ve found the
right book.
In this humble author’s (or not-so-humble author’s) opinion, advanced PHP is about
learning: how to do different things, how to improve upon the basic things, and about
technologies that intersect with PHP. In short, you know how to make a dynamic Web
site with PHP, but you’d like to know how to make a better Web site, with every possible
meaning of “better.” That’s the approach I’ve taken in writing this book. I’ve not set
out to blow your mind discussing esoteric idiosyncrasies the language has, rewriting
the PHP, MySQL, or Apache source code, or making theoretically interesting but
practically useless code. In short, I present to you several hundred pages of beyond-the-
norm but still absolutely necessary (and often cool) tips and techniques.
ix
Introduction
x
Introduction
Introduction
itself so that, in the end, you will come away
with not just how to do this or that but also
how to apply the overarching mentality to
your own, individual projects.
Unlike with most of my other books, I do
not expect that you’ll necessarily read this
book in sequential order, for the most part.
Some chapters do assume that you’ve read
others, like the object-oriented ones, which
have a progression to them. Some later
chapters also reference examples completed
in earlier ones. If you read the later ones
first, you’ll just need to quickly hop over to
the earlier ones to generate whatever data-
base or scripts the later chapter requires.
Finally, I’ll be using XHTML in my scripts
instead of HTML. I’ll also use some CSS, as
warranted. I do not discuss either of these
subjects in this book (and, to be frank, may
not adhere to them perfectly). If you are not
already familiar with the subjects, you should
look at some online resources or good books
(such as Elizabeth Castro’s excellent Visual
QuickStart Guides) for more information.
xi
Introduction
xii
Introduction
About PHP 5
Although version 5 of PHP has been out
since July 2004 (when the first non-beta
version was released), there are still a large
number of servers running older versions
of PHP, particularly outside of the United
States. This book does assume you’re using
PHP 5, although some examples will work
with older versions of the language.
The most important change in PHP 5,
with respect to this book, is the completely
different object model and syntax. Object-
oriented programming in PHP 4 is a rather
watered-down concept, really not worth
using in comparison to PHP 5’s OOP. The
object-oriented chapters use PHP 5 syntax
exclusively, and that code will not work on
older versions of the language.
Introduction
In addition, PHP 5 added support for the
Improved MySQL extension, designed for
use with MySQL 4.1 or later. With only one
or two exceptions, I use these Improved
MySQL functions instead of the older, “regu-
lar” MySQL functions. If your PHP installa-
tion (or MySQL installation) does not sup-
port these functions, you’ll need to change
the code accordingly.
xiii
Introduction
xiv
Introduction
Introduction
you’ve gone to the correct URL (the book’s
title and edition are plastered everywhere).
Each book I’ve written has its own support
area; if you go to the wrong one, the down-
loadable files won’t match those in the book.
Two bonus chapters, “Image Generation”
and “Creating PDFs,” can be downloaded
for free. Visit www.peachpit.com/title/
0321376013 to learn how to register this
book and access the chapters.
xv
This page intentionally left blank
Advanced
PHP Techniques
1
At the most basic level good programming is determined by whether or not an appli-
cation or script works as intended. This is where the beginning programmer will leave
things, and there is nothing wrong with that. However, the advanced programmer
will work past that point, striving toward improved efficiency, reliability, security,
and portability. This book teaches you how to develop the skills of an advanced PHP
programmer.
1
Chapter 1
Multidimensional Arrays
Because of their power and flexibility, arrays
are widely used in all PHP programming. For
advanced uses, the multidimensional array
often solves problems where other variable
types just won’t do.
For the first of the two examples, I’ll demon-
strate how to sort a multidimensional array.
It’s a common question users have and isn’t
as hard as one might think. For the second
example, I’ll create a database-driven to-do Figure 1.1 One use of multidimensional
list, which can have limitless dimensions arrays will be to create a nested to-do
list.
(Figure 1.1).
2
Advanced PHP Techniques
Multidimensional Arrays
can see how the user-defined sorting sort would be based upon the keys.
function is invoked.
To sort on the second key in the preceding
example, you would want to compare two
strings. That code would be (Figure 1.4
shows the result):
function mysort2 ($x, $y) {
return strcasecmp($x[‘key2’],
➝ $y[‘key2’]);
}
usort ($a, ‘mysort2’);
3
Chapter 1
4
Advanced PHP Techniques
Script 1.1 This script defines a two-dimensional array, which is then sorted based upon the inner array values.
Multidimensional Arrays
24 364 => array ('name' => 'Steve', 'grade' => 85.1),
25 68 => array ('name' => 'Rob', 'grade' => 74.6)
26 );
27
28 // Name sorting function:
29 function name_sort ($x, $y) {
30 return strcasecmp($x['name'], $y['name']);
31 }
32
33 // Grade sorting function:
34 // Sort in DESCENDING order!
35 function grade_sort ($x, $y) {
36 return ($x['grade'] < $y['grade']);
37 }
38
39 // Print the array as is:
40 echo '<h3>Array As Is</h3><pre>' . print_r($students, 1) . '</pre>';
41
42 // Sort by name:
43 uasort ($students, 'name_sort');
44
45 // Print the array now:
46 echo '<h3>Array Sorted By Name</h3><pre>' . print_r($students, 1) . '</pre>';
47
48 // Sort by grade:
49 uasort ($students, 'grade_sort');
50
51 // Print the array now:
52 echo '<h3>Array Sorted By Grade</h3><pre>' . print_r($students, 1) . '</pre>';
53
54 ?>
55 </body>
56 </html>
5
Chapter 1
This example is like the demo in the cause the keys, which store meaningful
introduction to these steps. One signifi- values (see Script 1.1), to be lost.
cant difference is that I want to perform
a descending sort, so that the highest
grades are listed first. This is easily
accomplished: change the comparison
operator from greater than to less than.
5. Print the array as it’s initially defined.
echo ‘<h3>Array As Is</h3><pre>’ .
➝ print_r($students, 1) . ‘</pre>’;
For improved legibility, I’ll use the <pre>
tags and print_r() to quickly reveal the
arrays’ structure and values.
6. Sort the array by name and print the
results.
uasort ($students, ‘name_sort’);
echo ‘<h3>Array Sorted By
➝ Name</h3><pre>’ .
➝ print_r($students, 1) . ‘</pre>’;
Here the uasort() function is used so
that the keys—the student IDs—are not
lost. Figure 1.5 shows the result if just
usort() was used instead.
6
Advanced PHP Techniques
7. Sort the array by grade and print the 8. Complete the page.
results. ?>
uasort ($students, ‘grade_sort’); </body>
echo ‘<h3>Array Sorted By </html>
➝ Grade</h3><pre>’ .
➝ print_r($students, 1) . ‘</pre>’;
9. Save the file as sort.php, place it in your
Web directory, and test in your Web
browser (Figures 1.6 and 1.7).
Multidimensional Arrays
Figure 1.6 The initial array and sorted Figure 1.7 The array sorted by grade, in
by name. descending order (this is the same Web
page as in Figure 1.6, but it couldn’t all
fit in one screenshot).
7
Chapter 1
Database-driven arrays
If you think about it, most database queries
return a multidimensional array (Figure 1.8).
If the query results are immediately sent to
the Web browser one at a time, the multidi-
mensional structure doesn’t add any compli-
cation to your code. However, if you need to
do something more elaborate with the results, Figure 1.8 Selecting multiple columns from multiple
you’ll need a way to comprehend and man- rows in a database results in a multidimensional
age the nested structure. array.
8
Advanced PHP Techniques
Multidimensional Arrays
Table 1.1 This one database table is all that is required to manage a nested to-do list.
9
Chapter 1
10
Advanced PHP Techniques
Figure 1.13 The tasks will normally be added using a For a simple task that’s not a subset of
PHP script, but a test insertion is run just to make another task, only the one column needs
sure everything is on the up and up. to be provided with a value. The SELECT
query confirms that the parent_id,
date_added, and date_completed columns
are automatically given default values
(0000-00-00 00:00:00 is the TIMESTAMP
equivalent of 0).
5. Empty the table.
TRUNCATE tasks;
Multidimensional Arrays
11
Chapter 1
“http://www.w3.org/TR/xhtml1/DTD/ <body>
➝ xhtml1-transitional.dtd”> <?php # Script 1.2 - add_task.php
<html xmlns=”http://www.w3.org/1999/ continues on page 14
➝ xhtml” xml:lang=”en” lang=”en”>
Script 1.2 Tasks are added to the database using this script. Tasks can even be filed under other tasks using the
drop-down menu.
7 </head>
8 <body>
9 <?php # Script 1.2 - add_task.php
10
11 /* This page adds tasks to the tasks table.
12 * The page both displays and handles the form.
13 */
14
15 // Connect to the database:
16 $dbc = @mysqli_connect ('localhost', 'username', 'password', 'test') OR die ('<p>Could not
connect to the database!</p></body></html>');
17
18 // Check if the form has been submitted:
19 if (isset($_POST['submitted']) && !empty($_POST['task'])) {
20
21 // Sanctify the input...
22
23 // The parent_id must be an integer:
24 if (isset($_POST['parent_id'])) {
25 $parent_id = (int) $_POST['parent_id'];
26 } else {
27 $parent_id = 0;
28 }
29
30 // Escape the task:
31 // Assumes Magic Quotes are off!
32 $task = mysqli_real_escape_string($dbc, $_POST['task']);
33
34 // Add the task to the database.
35 $q = "INSERT INTO tasks (parent_id, task) VALUES ($parent_id, '$task')";
36 $r = mysqli_query($dbc, $q);
37
38 // Report on the results:
39 if (mysqli_affected_rows($dbc) == 1) {
12
Advanced PHP Techniques
Multidimensional Arrays
64 while (list($task_id, $parent_id, $task) = mysqli_fetch_array($r, MYSQLI_NUM)) {
65
66 // Add to the select menu:
67 echo "<option value=\"$task_id\">$task</option>\n";
68
69 // Add to the array:
70 $tasks[] = array('task_id' => $task_id, 'parent_id' => $parent_id, 'task' => $task);
71
72 }
73
74 echo '</select></p>
75
76 <input name="submitted" type="hidden" value="true" />
77 <input name="submit" type="submit" value="Add This Task" />
78
79 </form>
80 </fieldset>
81 ';
82
83 // Sort the tasks by parent_id:
84 function parent_sort ($x, $y) {
85 return ($x['parent_id'] > $y['parent_id']);
86 }
87 usort ($tasks, 'parent_sort');
88
89 // Display all the tasks:
90 echo '<h3>Current To-Do List</h3><ul>';
91 foreach ($tasks as $task) {
92 echo "<li>{$task['task']}</li>\n";
93 }
94 echo '</ul>';
95 ?>
96 </body>
97 </html>
13
Chapter 1
14
Advanced PHP Techniques
Multidimensional Arrays
echo ‘<p>The task has been
➝ added!</p>’;
9. Retrieve all the uncompleted tasks.
$q = ‘SELECT task_id, parent_id, task
} else {
➝ FROM tasks WHERE its date_
echo ‘<p>The task could not be
➝ completed=”0000-00-00 00:00:00”
➝ added!</p>’;
➝ ORDER BY date_added ASC’;
}
$r = mysqli_query($dbc, $q);
The query returns three pieces of infor-
mation for every uncompleted task
(once a task has been completed, its
date_completed column would have a
nonzero value). The task_id and the task
itself will be used in the drop-down
menu. The parent_id will be used later
to nest the tasks.
continues on next page
15
Chapter 1
16
Advanced PHP Techniques
Multidimensional Arrays
➝ </li>\n”;
}
echo ‘</ul>’;
This loop will display each task in order
of its parent_id. This is the first step
toward making the list shown in Figure 1.1,
although as you can see in Figure 1.16,
the list isn’t organized as it should be.
This will be solved later in the chapter.
15. Complete the page.
?>
</body>
</html>
Figure 1.19 Adding a task that’s a subset of an 16. Save the file as add_task.php, place it in
existing task. your Web directory, and test in your Web
browser (Figures 1.18 and 1.19).
✔ Tip
■ If you wanted to implement this idea in a
live site, one improvement you could
make would be the ability to add multi-
ple tasks at once. I’ll provide further tips
on fleshing out this example over the
course of the chapter.
17
Chapter 1
◆ Accepting values by reference This function will continue to call itself until
$n is greater than 100, at which point it will
While not often used, sometimes these con- stop executing the function. (That’s obvi-
cepts are indispensable. In discussing and ously a trivial use of this concept; a loop
demonstrating these first two concepts, I’ll would do the same thing.)
continue to build upon the tasks example
Advanced Function Definitions
just begun in the chapter. Recursive functions are necessary when you
have a process that may be followed to an
Recursive functions unknown depth. For example, a script that
searches through a directory may have to
Recursion is the act of a function calling
search through any number of subdirecto-
itself.
ries. Or an array might have an unknown
function somefunction() {
number of dimensions....
// Some code.
With the tasks table created earlier in the
somefunction();
chapter, retrieving and displaying all the
// Possible other code.
tasks is not hard (see Figures 1.17 and 1.18).
} However, the method used in add_task.php
The end result is that your functions can act (Script 1.2) does not properly nest the tasks
both as originally intended and as a loop. like that in Figure 1.1. To accomplish that
The one huge warning when using this tech- desired end, a multidimensional array and a
nique is to make sure your function has an recursive function are required.
“out” clause. For example, the following code
will run ad infinitum:
function add_one ($n) {
$n++;
add_one ($n);
}
add_one (1);
18
Advanced PHP Techniques
“http://www.w3.org/TR/xhtml1/DTD/ <body>
➝ xhtml1-transitional.dtd”> <h3>Current To-Do List</h3>
<html xmlns=”http://www.w3.org/1999/ <?php # Script 1.3 - view_tasks.php
➝ xhtml” xml:lang=”en” lang=”en”>
continues on page 21
Script 1.3 One recursive function and a potentially bottomless multidimensional array will properly display the
nested list of tasks.
19
Chapter 1
50
51
52 // Connect to the database:
53 $dbc = @mysqli_connect ('localhost', 'username', 'password', 'test') OR die ('<p>Could not
connect to the database!</p></body></html>');
54
55 // Retrieve all the uncompleted tasks:
56 $q = 'SELECT task_id, parent_id, task FROM tasks WHERE date_completed="0000-00-00 00:00:00"
ORDER BY parent_id, date_added ASC';
57 $r = mysqli_query($dbc, $q);
58
59 // Initialize the storage array:
60 $tasks = array();
61
62 while (list($task_id, $parent_id, $task) = mysqli_fetch_array($r, MYSQLI_NUM)) {
63
64 // Add to the array:
65 $tasks[$parent_id][$task_id] = $task;
66
67 }
68
69 // For debugging:
70 //echo '<pre>' . print_r($tasks,1) . '</pre>';
71
72 // Send the first array element
73 // to the make_list() function:
74 make_list($tasks[0]);
75
76 ?>
77 </body>
78 </html>
20
Advanced PHP Techniques
21
Chapter 1
22
Advanced PHP Techniques
6. Connect to the database. The $tasks array will store every task.
$dbc = @mysqli_connect (‘localhost’, Figure 1.20 shows the final structure. As
➝ ‘username’, ‘password’, ‘test’) OR described in Step 4, the array’s outer-
➝ die (‘<p>Could not connect to the most key is the parent_id value from
➝ database!</p></body></html>’); the table. The value of this outermost
With the recursive function defined, the array is an array of the tasks with that
parent_id.
rest of the script needs to retrieve all the
tasks, organize them in an array, and then 9. Add a debugging line, if desired.
call the make_list() function. //echo ‘<pre>’ . print_r($tasks,1) .
7. Define and execute the query. ➝ ‘</pre>’;
23
Chapter 1
24
Advanced PHP Techniques
25
Chapter 1
return strcasecmp($x[‘name’],
➝ $y[‘name’]);
Script 1.4 This modified version of the sorting script will reveal how many times each sorting function is invoked,
thanks to a static variable.
Advanced Function Definitions
26
Advanced PHP Techniques
27
Chapter 1
28
Random documents with unrelated
content Scribd suggests to you:
Ah many a mansion shall we visit in our Father’s home,
As we fly beneath his banner, with ages and ages to roam.
A PERPETUAL KING
In a King on a throne and a King there to stay,
You’ve a friendly old monarch who’s ever upright.
There are blessings for you and the men far away,
In a King on a throne and a King there to stay.
His robe is pure white, but the proud make it gay;
Ah, what mercy, what power and amazing foresight
In a King on a throne and a King there to stay—
You’ve a friendly old monarch who’s ever upright!
MY BUTTERFLY[11]
My Butterfly, my wondrous Butterfly,
Forsaking temple great, thou choosest me,
When form and burnished wings arrive—I see
With joy, as ne’er before, thy glory nigh.
We journey through the city, thou and I,
In store and street with joined hearts and free,
While men admire thy trust and amity,
But wonder not in thee, nor question why.
MY SABBATH SERMON
A growing mocker in a maple tree,
Poured forth first notes with youthful glee;
Like an untried poet born to sing,
He’s proving gifts which fame will bring.
PILOT MOUNTAIN
O Jomeokee, thou everlasting guide,
Lifting high thyself, a tower strong
For passing men, and deathless hills around;
For Yadkin and on-flowing Ararat,
Bathing thy feet in humblest gratitude;
Thy lofty head, embraced by cooling clouds,
Gives something forth that’s rich, and unto all—
O Pilot old, thy secret bare to me.
IN FLORIDA
They come from everywhere,
By land, by sea and air,
The old, the young and fair—
And all without a care,
In Florida.
By the Author.
They reached and they tried; they ate and they cried,
Till the four had eaten their fill;
The mother aside still motherhood belied,
And the heart in me struggled still.
And all the hearts right grew more tender and bright,
As the Tanagers grew apace;
And those of insight, said, “The birds have a right
To partake of our friendly grace.”
For glory bright is round it, which has softened many a heart,
A tale of wise and saintly ones, in universal art;
A story mightiest with men now and ever mighty part
It played in the races of old.
We yet believe that angels must have wept and good men sighed,
When Gallilee’s great Son with hateful spite was crucified;
But who would ever dream the fairy spirits were allied
In Heaven’s great scheme of old?
The story sad he told of Christ, the Saviour, and His Cross;
Then joy and laughter sudden ceased, and grieving for their loss,
They shed their tears upon the pebbles and on the velvet moss—
A heaven moved grief of old.
And lo, when they had flown from the enchanted spring and ground,
Just where the tears had fallen on the pebbles lying round,
The Fairy stony crosses by the thousand there were found,
Sweet Nature’s crosses of old.
Note the crosses in this clod of earth.
Photographed in Patrick County, Va.
Envoy
Here’s to Diamond’s health, to the grand-daughter’s grace;
They are under love’s sway, which surpasses the rod;
So united and happy in every place,
With the heart of a child and the gifts of a god.
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
ebookgate.com