Tải bản đầy đủ (.pdf) (68 trang)

Tài liệu The iterator pattern pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (3.75 MB, 68 trang )

Cookies and milk. Peanut butter and jam. Nothing goes well together like PHP and the
Web
and this year you get both when you come join us at php|works and web|works 2005—two great confer-
ences dedicated to the wonderful world of PHP and advanced Web development. What’s best, you get access to
both great conferences for one low price!
/>Early-bird in effect until August 1
st
, 2005
Hurry! Space is limited. Prices start at just $349 US!
Rasmus Lerdorf–Identifying and Preventing XSS Attacks, John Coggeshall–PHP Enterprise Architecture,
Wez Furlong
–PHP Streams: Lucky Dip, George Schlossnagle–Regex Unlimited, Ilia Alshanetsky–Managing PHP Performance,
Derick Rethans–How PHP Ticks, Chris Shiflett–Hands-on PHP (BYOL)
,
Marcus Böerger–Happy SPLing, Dan Scott–LIMIT Yourself
to MySQL No More
,
Daniel Udey–Separating Content and Design,

Lukas Smith–Database Abstraction,

Paul Reinheimer–REST,

Robert Reinhardt–Multilingual Flash,

Ron Harwood–Web Games with PHP

F
F
E


E
A
A
T
T
U
U
R
R
E
E
S
S
14 The Interator Pattern
Making Manipulating Object Collections Easy
by Jason E. Sweat
25 PHP Library
for Permissions Management
A Generic Permissions Management PHP Library
by Simone Grassi and Bernhard Gaul
35 Change Your Life with Version Control
An Introduction to Subversion
by Clay Loveless
44 Creating a Simple Image Gallery
by Martin Psinas
07.2005
Download this month’s code at:
h
h
t

t
t
t
p
p
:
:
/
/
/
/
w
w
w
w
w
w
.
.
p
p
h
h
p
p
a
a
r
r
c

c
h
h
.
.
c
c
o
o
m
m
/
/
c
c
o
o
d
d
e
e
/
/
D
D
E
E
P
P
A

A
R
R
T
T
M
M
E
E
N
N
T
T
S
S
6 EDITORIAL
pear upgrade Home_Residence
7 WHAT’S NEW
10 TIPS
& TRICKS
Input Filtering: Part 1
Why Filter?
by Ben Ramsey
54 TEST PATTERN
Not Just Nouns
by Marcus Baker
58 PRODUCT REVIEW
FPDF: PDF Generation Library
by Peter B. MacIntyre
63 SECURITY CORNER

Theory
by Chris Shiflett
67 Exit(0);
Forget Viagra, Get a Regex!
by Marco Tabini

E
E
D
D
I
I
T
T
O
O
R
R
I
I
A
A
L
L
ast month, my wife, daughter, and I moved out of our (what we’d come to
refer to as ghetto) apartment, and into our first house.
I hate moving. I hate packing every little thing I own into boxes, and disassem-
bling the furniture. I hate trying to wedge the n-hundred pound sofa-bed out the
all-too-narrow doors, and trying to move the refrigerator without breaking any of
the ceramic tiles that make up the kitchen floor (“oops”).

Then, after many hours of what seemed like endless stair-climbing, box taping,
keep-or-toss decision making, and one too many not-as-fun-as-it-sounds Tetris-
like games of van and truck packing (“Can we get the rest in this trip? What if we
move this box, and put the chairs in the other truck? I think we need one of those
tall skinny pieces.”), the process is reversed, and we’re left with the joyous tasks
of unloading, more stair climbing, stacking, new-paint scrape-avoidance, more
narrow-door squeezing, trying to remember how to re-assemble the customer-
assembled furniture, and a basement full of boxes that were poorly labeled (in
haste).
To top it all off, my genius (and by “genius,” I mean moronic) telephone com-
pany somehow couldn’t figure how to reconnect our phone, properly, no matter
how many times we “call[ed] back in three hours.” As a result, we spent a full
week offline—it took me days to catch up on email.
Fortunately, I have wonderful friends and family—some of whom traveled over
1000 km to help us get the house ready (and visit us, of course)—who worked
for nothing more than pizza, cold beer a sincere “thank you.”
As much as I hate all things related to moving, and am glad it’s over, there’s a
great joy that accompanies moving into our first house—our own first house.
I see a parallel between upgrading our home, and upgrading my development
and production environments. PHP 5.1 is on the horizon, and while I truly hate
the stress that upgrading a production environment brings (no matter how well
tested), I’m always—ok, usually—left with a similar joy of a successful upgrade,
better performance, and new features. As always, we’re developing in exciting
times!
This month, we have a special treat for you: a chapter from our soon-to-be-
released php|architect’s Guide to Design Patterns, by Jason Sweat. In it, he’ll show
you the ins and outs of Iterators in PHP, whether self-constructed, or built on a
foundation like PHP 5’s Standard PHP Library (SPL). The piece is literally full of
code, and it’s sure to whet your appetite for more design pattern goodness.
Security corner is back, rounding out our full lineup of columns, and Peter has

reviewed the newest version of FPDF, a library that, if you haven’t used, you’ve
probably heard of.
Happy reading! Now, I must go back to painting, landscaping, plastering,
wiring, cleaning, organizing and unpacking.
July 2005

PHP Architect

www.phparch.com
php|architect
Volume IV - Issue 7
July, 2005
Publisher
Marco Tabini
Editorial Team
Arbi Arzoumani
Peter MacIntyre
Eddie Peloke
Graphics & Layout
Aleksandar Ilievski
Managing Editor
Emanuela Corso
News Editor
Leslie Hill

Authors
Marcus Baker, Bernhard Gaul,
Simone Grassi, Clay Loveless,
Peter B. MacIntyre, Martin Psinas,
Ben Ramsey, Chris Shiflett,

Jason E. Sweat
php|architect (ISSN 1709-7169) is published twelve times a year by
Marco Tabini & Associates, Inc., P.O. Box 54526, 1771 Avenue Road,
Toronto, ON M5M 4N5, Canada.
Although all possible care has been placed in assuring the accuracy of
the contents of this magazine, including all associated source code, list-
ings and figures, the publisher assumes no responsibilities with regards
of use of the information contained herein or in all associated material.
Contact Information:
General mailbox:
Editorial:
Subscriptions:
Sales & advertising:
Technical support:
Copyright © 2003-2005 Marco Tabini &
Associates, Inc. — All Rights Reserved
TM
p
p
e
e
a
a
r
r
u
u
p
p
g

g
r
r
a
a
d
d
e
e
H
H
o
o
m
m
e
e
_
_
R
R
e
e
s
s
i
i
d
d
e

e
n
n
c
c
e
e
L
July 2005

PHP Architect

www.phparch.com
7
What’s
NEW
? >
PHP 5.1 Beta 2
Php.net announces the release of PHP
5.1 beta2.
"PHP 5.1 Beta 2 is now available! A
lot of work has been put into this
upcoming release and we believe it
is ready for public testing.
Some of the key improvements of PHP
5.1 include:
• PDO (PHP Data Objects) - A
new native database abstraction
layer providing performance,
ease-of-use, and flexibility.

• Significantly improved lan-
guage performance mainly due
to the new Zend Engine II exe-
cution architecture.
• The PCRE extension has
been updated to PCRE 5.0.
• Many more improvements
including lots of new functional-
ity & many bug fixes, especially
in regards to SOAP, streams and
SPL.
• See the bundled NEWS file
for a more complete list of
changes.
Everyone is encouraged to start
playing with this beta, although it is
not yet recommended for mission-
critical production use."
Check out all the latest info at
php.net
.
phpBB 2.0.16
phpBB.com has released the latest version of their open source bulletin board package.
What's new? Phpbb.com lists the changes as:
• Fixed critical issue with highlighting
• Url descriptions able to be wrapped over more than one line again
• Fixed bug with eAccelerator in admin_ug_auth.php
• Check new_forum_id for existence in modcp.php
• Prevent uploading avatars with no dimensions
• Fixed bug in usercp_register.php, forcing avatar file removal without updat-

ing avatar informations within the database
• Fixed bug in admin re-authentication redirect for servers not having
index.php as one of their default files set
Visit phpbb.com
for all the latest info.
FUDforum 2.6.14RC2
Fudforum.org announces their latest
release:
"The 2nd release candidate for 2.6.14
is now out, aside from a number of
bug fixes few important developments
were done as well.
• FUDforum can now make use
of PDO Database driver for PHP
5.0/5.1 with support for
MySQL,PostgreSQL and SQLite
backends.
• FUDforum can now be
installed on systems running
PHP 5.1, the few BC changes
introduced by this release are
now being accommodated.
• The temporary table usage is
now optional, which means
forum install no longer requires
this permission to be
available."
To grab the latest release or for more
info, visit fudforum.org
.

SOLAR 0.5.0
Solar.php announces the latest release
of their "simple object library and
application repository" version 0.5.0.
paul-m-jones.com announces some of
the highlights as:
• Unit tests for Solar_Base, _Cache,
_Error, and _Locale
• End-user documentation (not just
API docs) for those same classes, plus
the overarching Solar class itself
For all the highlights, visit
solarphp.com
.
AjaxAC 0.4.1
Do you have a project which requires the use of AJAX? Check out the latest release of
AjaxAC a "PHP framework which can be used to develop, create, and generate AJAX
applications". According the announcement, version 0.4.1 includes:
"The ArithmeJax sample application was created. The JavaScript escape() was
replaced with encodeURIComponent(). The hook name generator was changed to
include __ in front of the hookname due to an IE6 compatibility error. The redundant
AjaxAC class was removed and this functionality was moved to the AjaxACApplication
class. All examples were updated to reflect the removal of the main AjaxAC class."
Grab the latest release from />phpReports 0.4.1
phpReports report generator has
announced the latest release, version
0.4.1. According to the announce-
ment, this release includes:
"The setPageSize(size) and
getPageSize() methods were added to

the PHPReportMaker object. Now you
can specify the page size using code
like "$oRpt = new PHPReportMaker();
$oRpt->setPageSize(30);". This
method overrides the XML value."
Visit rce
forge.net/ for more information or to
download.
W
W
h
h
a
a
t
t


s
s
N
N
e
e
w
w
?
?
>
>

July 2005

PHP Architect

www.phparch.com
8
Check out some of the hottest new releases from PEAR.
XML_RPC 1.3.1
A PEAR-ified version of Useful Inc's XML-RPC for PHP. It has support for HTTP/HTTPS transport, proxies and authentication.
This release is security related, and solves the recently discovered, and widespread remote-code-execution vulnerabili-
ty. All users are strongly encouraged to upgrade immediately.
Translation2 2.0.0beta7
This class provides an easy way to retrieve all the strings for a multilingual site from a data source (i.e. db).
The following containers are provided, more will follow:
• PEAR::DB
• PEAR::MDB
• PEAR::MDB2
• gettext
• XML
• PEAR::DB_DataObject (experimental)
It is designed to reduce the number of queries to the db, caching the results when possible.
An Admin class is provided to easily manage translations (add/remove a language, add/remove a string).
Currently, the following decorators are provided:
• CacheLiteFunction (for file-based caching)
• CacheMemory (for memory-based caching)
• DefaultText (to replace empty strings with their keys)
• ErrorText (to replace empty strings with a custom error text)
• Iconv (to switch from/to different encodings)
• Lang (resort to fallback languages for empty strings)
• SpecialChars (replace html entities with their hex codes)

• UTF-8 (to convert UTF-8 strings to ISO-8859-1)
Mail 1.1.5
PEAR's Mail:: package defines the interface for implementing mailers under the PEAR hierarchy, and provides supporting
functions useful in multiple mailer backends. Currently supported are native PHP mail() function, sendmail and SMTP. This
package also provides a RFC 822 Email address list validation utility class.
HTML_QuickForm_advmultiselect 0.4.0
The HTML_QuickForm_advmultiselect package adds an element to the HTML_QuickForm package that is two select boxes
next to each other emulating a multi•select.
DB_ldap 1.1.1
The PEAR::DB_ldap class provides a DB compliant interface to LDAP servers.
php|architect Releases New Design Patterns Book
We're proud to announce the release of php|architect's Guide to PHP Design Patterns,
the latest release in our Nanobook series.
You have probably heard a lot about Design Patterns a technique that helps you design
rock-solid solutions to practical problems that programmers everywhere encounter in their
day-to-day work. Even though there has been a lot of buzz, however, no-one has yet come
up with a comprehensive resource on design patterns for PHP developers—until today.
Author Jason E. Sweat's book php|architect's Guide to PHP Design Patterns is the
first, comprehensive guide to design patterns designed specifically for the PHP developer.
This book includes coverage of 16 design patterns with a specific eye to their applications in
PHP when building complex web applications, both in PHP 4 and PHP 5 (where appropriate,
sample code for both versions of the language is provided).
For more information,
/>.
W
W
h
h
a
a

t
t


s
s
N
N
e
e
w
w
?
?
>
>
July 2005

PHP Architect

www.phparch.com
9
Looking for a new PHP Extension? Check out some of the lastest offerings from PECL.
ibm_db2 1.0.2
This extension supports IBM DB2 Universal Database, IBM Cloudscape, and Apache Derby databases.
yaz 1.0.3
This extension implements a Z39.50 client for PHP using the YAZ toolkit.
pecl_http 0.9.0
• Building absolute URIs
• RFC compliant HTTP redirects

• RFC compliant HTTP date handling
• Parsing of HTTP headers and messages
• Caching by "Last-Modified" and/or ETag
(with 'on the fly' option for ETag generation from buffered output)
• Sending data/files/streams with (multiple) ranges support
• Negotiating user preferred language/charset
• Convenient request functions built upon libcurl
• HTTP auth hooks (Basic)
• PHP5 classes: HttpUtil, HttpResponse, HttpRequest, HttpRequestPool, HttpMessage
runkit 0.3.0
Replace, rename, and remove user defined functions and classes. Define customized superglobal variables for general pur-
pose use. Execute code in restricted environment (sandboxing).
F
ilter input. What does that
mean? Well, in short, it means
what it says, but there’s some-
thing deeper hidden behind these
words, something sinister. Yes,
these words mean user input can-
not be trusted. For that matter, no
input, regardless of its source—
forms, RSS feeds, cookies, etc.—is
trustworthy. In fact, the level of dis-
trust in input must be so high that
you no longer accept anything
from these sources at face value.
Always verify the input data to
ensure it’s the expected, genuine
article.
But why is this so hard to do? Is it

because we innately want to trust
people and other sources? Heavens,
no! It’s hard because programmers
are naturally lazy.
Filtering input means writing
more code, writing smarter code.
For those who wish to finish a proj-
ect quickly, this is daunting, and so
they quickly scribble down some
code—if, in fact, code can be scrib-
bled—and deploy a release hoping
to catch the problems in later bug-
fix (sometimes called security)
releases. This can, however, cause
great problems in the meantime,
not the least of which could consist
of SQL injection or cross-site script-
ing (XSS)… or just plain bad data.
Ensuring against bad data
through filtering input is what we’ll
focus on over the next three install-
ments of Tips & Tricks. So, come
along with me, and before we’re
finished, you’ll be cynical and dis-
trustful with the best of them—no
longer able to trust input of any
kind—and, thus, security-con-
scious.
July 2005


PHP Architect

www.phparch.com
10
T
T
I
I
P
P
S
S
&
&
T
T
R
R
I
I
C
C
K
K
S
S
Input Filtering, Part 1:
Why Filter?
by Ben Ramsey
This year has seen an increased focus on PHP security, and this is good for

the language, developers, and business community. One phrase that comes
to mind when discussing secure coding practices is Chris Shiflett’s mantra
of “filter input, escape output.” While we know what this means in a gen-
eral sense, practical examples elude us, so for the next three months, Tips
& Tricks will give practical suggestions for input filtering, chock full of code
examples.
Why Filter Input?
Input is bad. In fact, it’s evil. Just get
that through your head, and you’ll
be off to a great start.
Input is evil because its source
cannot be trusted and the type of
data expected is not always the
type received, and all the client-side
validation scripts in the world can’t
stop input coming from another
source completely invalidated.
What do I mean by “another
source?” I mean: another form on
another Web site that makes use of
your form (often referred to as a
spoofed form) for some insidious
means—or someone or some script
posting by any number of alterna-
tive means.
Let’s take, for example, the form
in Listing 1, which is located at the
imaginary URL
h
h

t
t
t
t
p
p
:
:
/
/
/
/
e
e
x
x
a
a
m
m
p
p
l
l
e
e
.
.
n
n

e
e
t
t
/
/
f
f
o
o
r
r
m
m
.
.
h
h
t
t
m
m
l
l
.
(We’ll continue to come back to this
form during the next few months;
don’t worry—the code will be
included in each column.) Now,
this is a form we’ve all seen; it asks

for a name and contact informa-
tion—no doubt, you’ve used a sim-
ilar form in the past, and there’s
nothing wrong with this form, but
there are a few assumptions often
made about it.
One assumption is that the
m
m
a
a
x
x
l
l
e
e
n
n
g
g
t
t
h
h
attribute of the fields pre-
vents a user from entering more
text than allowed. This is wrong.
While a Web browser can correctly
prevent a user from doing so

through this particular form, there’s
nothing to stop the re-creation of
this form on another server and
using it to submit a much longer
string of data.
Another assumption is that the
user may pick states only from
among the options listed in the
s
s
t
t
a
a
t
t
e
e
drop-down field. Again, this is
wrong and for the same reasons.
The Web browser might prevent
said user from entering other values
when using this form, but if recreat-
ed, the sky’s the limit.
We’re starting to see a pattern
emerge. A Web form/application is
safe only when used properly. This
is obvious. But if used improperly,
then processing scripts can receive
any and all kinds of input.

Still, let’s look at two more
assumptions about this form—just
for the heck of it.
This form has a set number of
fields. Does that mean these are the
only fields that can be submitted?
No! Also, can we assume that the
processing script
([process_form.php] in this case)
can only receive submissions from
this form? The answer, again, is no.
The form in Listing 2 illustrates
why these assumptions are wrong.
This form lives on another server—
for example, at
h
h
t
t
t
t
p
p
:
:
/
/
/
/
e

e
v
v
i
i
l
l
.
.
e
e
x
x
a
a
m
m
-
-
p
p
l
l
e
e
.
.
n
n
e

e
t
t
/
/
f
f
o
o
r
r
m
m
-
-
s
s
p
p
o
o
o
o
f
f
.
.
h
h
t

t
m
m
l
l
.
The first thing to notice about this
form is that there are no
m
m
a
a
x
x
l
l
e
e
n
n
g
g
t
t
h
h
attributes. Well, for one, these are
hidden fields that don’t use the
m
m

a
a
x
x
l
l
e
e
n
n
g
g
t
t
h
h
attribute, but that’s not
important. The fields don’t have to
be hidden, and, either way, a devi-
ous miscreant may enter as much
data as he pleases. Secondly, the
s
s
t
t
a
a
t
t
e

e
field now has a value of “The
Shire.” Wait a minute… that wasn’t
in our option list, but it doesn’t
matter because it’ll post just fine.
Thirdly, this form includes a new
field: the
j
j
u
u
n
n
k
k
field. This doesn’t do
much now, but consider a server
July 2005

PHP Architect

www.phparch.com
T
T
I
I
P
P
S
S

&
&
T
T
R
R
I
I
C
C
K
K
S
S
11
1 <!— A form located at: —>
2 <form method=”POST” action=”process_form.php”>
3 Name: <input type=”text” name=”name” maxlength=”50” />
4 <br />
5 Street: <input type=”text” name=”street” maxlength=”100” />
6 <br />
7 City: <input type=”text” name=”city” maxlength=”50” />
8 <br />
9 State:
10 <select name=”state”>
11 <option>Pick a state </option>
12 <option>Alabama</option>
13 <option>Alaska</option>
14 <option>Arizona</option>
15

16 </select><br />
17 Postal Code: <input type=”text” name=”postal”
18 maxlength=”5” /><br />
19 Phone: <input type=”text” name=”phone” maxlength=”25” />
20 <br />
21 E-mail: <input type=”text” name=”email” maxlength=”255” />
22 <br />
23 <input type=”submit” value=”Submit” />
24 </form>
Listing 1
1 <form method=”POST”
2 action=” />3 <input type=”hidden” name=”name” value=”Frodo Baggins” />
4 <input type=”hidden” name=”state” value=”The Shire” />
5 <input type=”hidden” name=”postal”
6 value=”It is my precious!” />
7 <input type=”hidden” name=”junk”
8 value=”Junk data being passed” />
9 <input type=”submit” value=”Submit” />
10 </form>
Listing 2
1 <?php
2 // Using PEAR::HTTP_Request
3 require_once ‘HTTP/Request.php’;
4 $req =& new HTTP_Request(
5 ‘ />6 $req->setMethod(HTTP_REQUEST_METHOD_POST);
7 $req->addHeader(‘Referer’, ‘ />8 $req->addPostData(‘name’, ‘Gandalf the Grey’);
9 $req->addPostData(‘state’, ‘Middle-earth’);
10 $req->addPostData(‘email’, ‘Olorin I was in my youth’);
11 $response = $req->sendRequest();
12 ?>

Listing 2
Input Filtering, Part 1: Why Filter?
where
r
r
e
e
g
g
i
i
s
s
t
t
e
e
r
r
_
_
g
g
l
l
o
o
b
b
a

a
l
l
s
s
is enabled
and variables aren’t initialized—
think about what it can do.
The
R
R
e
e
f
f
e
e
r
r
e
e
r
r
Question
Invariably, the question now arises:
But what about the
R
R
e
e

f
f
e
e
r
r
e
e
r
r
? Yes,
what about it? I can check it, right?
Sure, go ahead, but it’ll bite you in
the end.
It is a common misconception
that every request includes a
R
R
e
e
f
f
e
e
r
r
e
e
r
r

header and that the value
of this header always represents the
origin of the request. In truth and
practice, the origin of the request is
always the client. The client can be
a Web browser or it can be a script
that resides on a server, some-
where. It may or may not choose to
include a
R
R
e
e
f
f
e
e
r
r
e
e
r
r
header in
requests. The
R
R
e
e
f

f
e
e
r
r
e
e
r
r
, when includ-
ed, may or may not indicate the
previously requested parent
resource. In fact, some proxy
servers have been known to modify
or drop the
R
R
e
e
f
f
e
e
r
r
e
e
r
r
header alto-

gether, thus blocking entire offices
and even ISPs from viewing Web
sites programmed to check for it.
All this amounts to the fact that
R
R
e
e
f
f
e
e
r
r
e
e
r
r
is highly unreliable as a
means of protecting Web applica-
tions from outside posting.
Furthermore, it is not as important
to ensure input comes from a spe-
cific place as it is that the input
received conforms to expectations.
Nevertheless, we’ll take a look at
how scripts use
R
R
e

e
f
f
e
e
r
r
e
e
r
r
to block
requests from other sites:
if (strcmp($_SERVER[‘HTTP_REFER-
ER’],
‘ />== 0) {
// It came from the right
place, so let’s process it
}
Now, this snippet of code will prop-
erly thwart a form such as the one
in Listing 2 from posting to
p
p
r
r
o
o
c
c

e
e
s
s
s
s
_
_
f
f
o
o
r
r
m
m
.
.
p
p
h
h
p
p
, so long as the
client includes a
R
R
e
e

f
f
e
e
r
r
e
e
r
r
header
that doesn’t match, but mischie-
vous users aren’t in the business of
being foiled by clients. Let’s consid-
er another means of posting and
take a look at Listing 3.
The code in Listing 3 is similar to
that found in Listing 2 in that it
posts to
p
p
r
r
o
o
c
c
e
e
s

s
s
s
_
_
f
f
o
o
r
r
m
m
.
.
p
p
h
h
p
p
from a
different location and bypasses all
the local constraints placed on it
(e.g.
m
m
a
a
x

x
l
l
e
e
n
n
g
g
t
t
h
h
and any client-side
scripting). However, Listing 3 is dif-
ferent because it doesn’t rely on a
Web browser and, thus, can modify
any part of the request. In this case,
P
P
E
E
A
A
R
R
:
:
:
:

H
H
T
T
T
T
P
P
_
_
R
R
e
e
q
q
u
u
e
e
s
s
t
t
generates a
valid
P
P
O
O

S
S
T
T
request, while adding a
R
R
e
e
f
f
e
e
r
r
e
e
r
r
header. Thus, the script
successfully posts to
p
p
r
r
o
o
c
c
e

e
s
s
s
s
_
_
f
f
o
o
r
r
m
m
.
.
p
p
h
h
p
p
because it sends
a valid
R
R
e
e
f

f
e
e
r
r
e
e
r
r
header with a value
that
p
p
r
r
o
o
c
c
e
e
s
s
s
s
_
_
f
f
o

o
r
r
m
m
.
.
p
p
h
h
p
p
expects.
Now You’re Getting It
And so, we must filter the input. It’s
that simple. We cannot be sure the
input comes from the proper loca-
tion, nor are we sure it is exactly
what we want. In fact, we’re pretty
sure it’s not.
Feeling distrustful yet? Good.
Great, even. Do not trust input
from users, from anywhere. This is
why it’s important to ensure that
input received is input expected.
July 2005

PHP Architect


www.phparch.com
12
T
T
I
I
P
P
S
S
&
&
T
T
R
R
I
I
C
C
K
K
S
S
1 <?php
2 function filter (&$input, $allowed) {
3 $validated = array();
4 foreach ($input as $key => $value) {
5 if (in_array($key, $allowed)) {
6 $validated[$key] = $value;

7 }
8 }
9 return $validated;
10 }
11
12 $white_list = array(
13 ‘name’,
14 ‘street’,
15 ‘city’,
16 ‘state’,
17 ‘postal’,
18 ‘phone’,
19 ‘email’
20 );
21
22 $clean = filter($_POST, $white_list);
23 ?>
Listing 5
1 <?php
2 function sanitize (&$value, $key) {
3 if (!ctype_print($value)) {
4 $value = preg_replace(‘/[[:cntrl:]]/’, ‘’, $value);
5 }
6 $value = htmlentities($value);
7 }
8
9 $clean = $_POST;
10 array_walk($clean, ‘sanitize’);
11 ?>
Listing 4

Input Filtering, Part 1: Why Filter?
“No input, regardless of its source is trustworthy.”
The approach we’ll take to filter
input is often called a “whitelist”
approach (as opposed to a “black-
list” approach). Instead of using a
blacklist to tell our script what kind
of input we won’t allow (e.g. input
coming from somewhere other
than
f
f
o
o
r
r
m
m
.
.
h
h
t
t
m
m
l
l
, as in the
R

R
e
e
f
f
e
e
r
r
e
e
r
r
example), we’ll use a whitelist to
tell it exactly what to allow.
This is actually a much simpler
approach because, now, we don’t
have to think of the myriad kinds of
data an attacker might try to sub-
mit to our script. Instead, we need
only know what we want to receive
and ensure that the received input
matches up.
Capturing and Taming Input
Now, let’s talk about capturing
some of this evil input.
There are a few places we’ll con-
sider looking for input:
$
$

_
_
G
G
E
E
T
T
,
$
$
_
_
P
P
O
O
S
S
T
T
, and
$
$
_
_
C
C
O
O

O
O
K
K
I
I
E
E
. We’ll not look
in
$
$
_
_
R
R
E
E
Q
Q
U
U
E
E
S
S
T
T
, though it does con-
tain the values from each of these

superglobal arrays. In short, we
want to know the exact scope of
the input, so we’ll use the specific
superglobal for the location we
expect to find it. For example,
$
$
_
_
R
R
E
E
Q
Q
U
U
E
E
S
S
T
T
[
[


n
n
a

a
m
m
e
e


]
]
could refer to
$
$
_
_
G
G
E
E
T
T
[
[


n
n
a
a
m
m

e
e


]
]
,
$
$
_
_
P
P
O
O
S
S
T
T
[
[


n
n
a
a
m
m
e

e


]
]
, or
even
$
$
_
_
C
C
O
O
O
O
K
K
I
I
E
E
[
[


n
n
a

a
m
m
e
e


]
]
, so we want
to be sure it’s coming from the cor-
rect location, which is
P
P
O
O
S
S
T
T
in this
case.
Luckily for us, PHP has already
done the work of capturing the
input. In
p
p
r
r
o

o
c
c
e
e
s
s
s
s
_
_
f
f
o
o
r
r
m
m
.
.
p
p
h
h
p
p
, the val-
ues passed by the input from—
f

f
o
o
r
r
m
m
.
.
h
h
t
t
m
m
l
l
(or from wherever it was
submitted)—are in
$
$
_
_
P
P
O
O
S
S
T

T
. But the
data in
$
$
_
_
P
P
O
O
S
S
T
T
, you’ll remember, is
still evil data. We must first filter it.
There’s more than one way,
however, to filter form input, and I
won’t pretend that my suggestions
are any more than what they are:
suggestions. They are not the right
way, but they are a way, and these
tips are sure to help control input
and provide a foundation on
which to build. What’s important is
to write code with a security-con-
scious mindset, and part of that
mindset includes being wary of
input.

Now, to keep track of our good
data, we’ll store everything that’s
considered clean (as in: it conforms
to expectations) to the aptly named
$
$
c
c
l
l
e
e
a
a
n
n
array, which will somewhat
mimic everything that’s in
$
$
_
_
P
P
O
O
S
S
T
T


without all the evil tendencies.
One approach that I often see is a
sanitizing function that gets applied
to the
$
$
_
_
P
P
O
O
S
S
T
T
array, as seen in
Listing 4. While this type of
approach removes harmful charac-
ters, it does not provide a whitelist
solution. Instead, it blacklists poten-
tially harmful characters (control
characters) and escapes the input
(with
h
h
t
t
m

m
l
l
e
e
n
n
t
t
i
i
t
t
i
i
e
e
s
s
(
(
)
)
), which is not
a part of the filtering process. We’re
only concerned with filtering the
input at this point, so we want the
raw data—filtered, but raw.
Escaping will take place during the
output stage, which isn’t covered

here.
A whitelist approach defines the
valid range of characters/numbers,
the acceptable values (of a
s
s
e
e
l
l
e
e
c
c
t
t
field, for example), and the allowed
fields. For now, let’s take a look at
defining the allowed fields to
ensure we receive and process
nothing more than expected.
Listing 5 gives a whitelist example
for defining the allowed fields. First,
we use the
$
$
w
w
h
h

i
i
t
t
e
e
_
_
l
l
i
i
s
s
t
t
array to
define the allowed fields. Then, we
run the
$
$
_
_
P
P
O
O
S
S
T

T
array through the
f
f
i
i
l
l
t
t
e
e
r
r
(
(
)
)
function using
$
$
w
w
h
h
i
i
t
t
e

e
_
_
l
l
i
i
s
s
t
t
as a model. What’s
returned to the
$
$
c
c
l
l
e
e
a
a
n
n
array is the
expected input. Anything unex-
pected is left back in
$
$

_
_
P
P
O
O
S
S
T
T
where
it safely remains excluded from the
rest of the script.
This is a very simple approach
that does not include any further
input checking—for now. Though, I
hope it is evident how this
approach adds a level of flexibility
to the filtering process. For exam-
ple, imagine a
$
$
p
p
o
o
s
s
t
t

_
_
w
w
h
h
i
i
t
t
e
e
_
_
l
l
i
i
s
s
t
t
,
$
$
g
g
e
e
t

t
_
_
w
w
h
h
i
i
t
t
e
e
_
_
l
l
i
i
s
s
t
t
, or even
$
$
r
r
s
s

s
s
_
_
w
w
h
h
i
i
t
t
e
e
_
_
l
l
i
i
s
s
t
t
. Now, it becomes
clear that this simple example can
expand to filter anything:
$post_clean = filter($_POST,
$post_white_list);
$get_clean = filter($_GET,

$get_white_list);
$rss_clean = filter($rss,
$rss_white_list);
In next month’s column, I’ll revisit
this same code and discuss strate-
gies for defining the data type for
each field.
Wrap Up
By now, you should be fully con-
vinced that all input is evil and why
it’s important to filter all incoming
data. When it comes to input, there
are no guarantees as to the origin of
the data or the type received.
Whether working with GET, POST,
cookies, RSS feeds, and the like,
always filter input—regardless.
Tune in next month when we’ll
wrestle more input to ensure input
received is input expected.
July 2005

PHP Architect

www.phparch.com
T
T
I
I
P

P
S
S
&
&
T
T
R
R
I
I
C
C
K
K
S
S
13
About the Author ?>
To Discuss this article:
/>Ben Ramsey is a Technology Manager for Hands On Network in Atlanta, Georgia. He is an author, Principal member of
the PHP Security Consortium, and Zend Certified Engineer. Ben lives just north of Atlanta with his wife Liz and dog Ashley.
You may contact him at
r
r
a
a
m
m
s

s
e
e
y
y
@
@
p
p
h
h
p
p
.
.
n
n
e
e
t
t
or read his blog at
h
h
t
t
t
t
p
p

:
:
/
/
/
/
b
b
e
e
n
n
r
r
a
a
m
m
s
s
e
e
y
y
.
.
c
c
o
o

m
m
/
/
.
Input Filtering, Part 1: Why Filter?
O
bject-Oriented Programming encapsulates
application logic in classes. Classes, in turn, are
instantiated as objects, and each individual
object has a distinct identity and state.
Individual objects are a useful way to organize your
code, but often you want to work with a group of
objects, or a collection. A set of result rows from a SQL
query is a collection.
A collection need not be homogeneous either. A
W
W
i
i
n
n
d
d
o
o
w
w
object in a graphical user interface framework
could collect any number of control objects — a

M
M
e
e
n
n
u
u
,
a
S
S
l
l
i
i
d
d
e
e
r
r
, and a
B
B
u
u
t
t
t

t
o
o
n
n
, among others.
Moreover, the implementation of a collection can
vary: a PHP array is a collection, but so is a hash table,
a linked list, a stack, and a queue.
The Problem: How can one easily manipulate any col-
lection of objects?
The Solution: Use the Iterator pattern to provide uni-
form access to the contents of a collection.
You may not realize it, but you use the Iterator pat-
tern every day—it’s embodied in PHP’s
a
a
r
r
r
r
a
a
y
y
type and
rich set of array manipulation functions. (Indeed, given
the combination of the native array type in the lan-
guage and a host of flexible functions designed to work
with this native type, you need a pretty compelling rea-

son not to use arrays as your means of manipulating
collections of objects.)
REQUIREMENTS
PHP
5
OS
Any
Code Directory
iterator
July 2005

PHP Architect

www.phparch.com
14
You have probably heard a lot about Design Patterns a
technique that helps you design rock-solid solutions to
practical problems that programmers everywhere
encounter in their day-to-day work. Even though there
has been a lot of buzz, however, no-one has yet come up
with a comprehensive resource on design patterns for PHP
developers until today. In this excerpt from Jason E.
Sweat's book php|architect's Guide to PHP Design
Patterns, you'll learn about the Iterator pattern, whether
custom-built, or with PHP 5's new Standard PHP Library.
The Iterator
Pattern
by Jason E. Sweat
author of
php|architect’s Guide to PHP Patterns

F
F
E
E
A
A
T
T
U
U
R
R
E
E
July 2005

PHP Architect

www.phparch.com
15
Here’s native array iteration in PHP:
$test = array(‘one’, ‘two’, ‘three’);
$output = ‘’;
reset($test);
do {
$output .= current($test);
} while (next($test));
echo $output; // produces ‘onetwothree’
The
r

r
e
e
s
s
e
e
t
t
(
(
)
)
function restarts iteration to the beginning
of the array;
c
c
u
u
r
r
r
r
e
e
n
n
t
t
(

(
)
)
returns the value of the current
element; and
n
n
e
e
x
x
t
t
(
(
)
)
advances to the next element in
the array and returns the new
c
c
u
u
r
r
r
r
e
e
n

n
t
t
(
(
)
)
value. When
you advance past the end of the array,
n
n
e
e
x
x
t
t
(
(
)
)
returns
f
f
a
a
l
l
s
s

e
e
. Using these iteration methods, the internal
implementation of a PHP array is irrelevant to you.
Iterator couples the object-oriented programming
principals of encapsulation and polymorphism. Using
Iterator, you can manipulate the objects in a collection
without explicitly knowing how the collection is imple-
mented or what the collection contains (what kinds of
objects). Iterator provides a similar interface to different
concrete iteration implementations, which do contain
the details of how to manipulate a specific collection,
including which items to show (filtering) and in what
order (sorting).
Let’s create a simple object to manipulate in a collec-
tion. (Though this example is in PHP 5, Iterators are not
unique to PHP 5 and most of the examples in this chap-
ter work in PHP 4 as well, albeit with a healthy amount
of reference operators added). The object,
L
L
e
e
n
n
d
d
a
a
b

b
l
l
e
e
,
represents media such as movies and albums and is
intended to be part of a web site or service to let users
review or lend portions of their media collection to
other users. (For this example, do not concern yourself
with persistence and the like.)
Let’s start with the code in Listing 1 as the basis for
the class and write some tests.
To implement the requirements of this initial test, cre-
ate a class with a few public attributes and some meth-
ods to toggle the values of these attributes, such as that
in Listing 2.
L
L
e
e
n
n
d
d
a
a
b
b
l

l
e
e
is a good, generic start. Let’s extend it to
track items like DVDs or CDs.
Figure 1
M
M
e
e
d
d
i
i
a
a
extends
L
L
e
e
n
n
d
d
a
a
b
b
l

l
e
e
and tracks details about spe-
cific media, including the name of the item, the year it
was released, and what type of item it is. See Listing 3.
To keep things simple,
M
M
e
e
d
d
i
i
a
a
has three public
instance variables,
M
M
e
e
d
d
i
i
a
a
:

:
:
:
n
n
a
a
m
m
e
e
,
M
M
e
e
d
d
i
i
a
a
:
:
:
:
y
y
e
e

a
a
r
r
, and
M
M
e
e
d
d
i
i
a
a
:
:
:
:
t
t
y
y
p
p
e
e
. The constructor takes two arguments and
stores the first in
$

$
n
n
a
a
m
m
e
e
and the second in
$
$
y
y
e
e
a
a
r
r
. The
constructor also allows an optional third parameter to
specify type (which defaults to “dvd”).
Given individual objects to manipulate, you can now
create a container to hold them: a
L
L
i
i
b

b
r
r
a
a
r
r
y
y
. Like a reg-
ular library,
L
L
i
i
b
b
r
r
a
a
r
r
y
y
should be able to add, remove and
count the items in the collection. Eventually,
L
L
i

i
b
b
r
r
a
a
r
r
y
y
should also permit access to individual items (objects)
in the collection (which is shown momentarily in the
Sample Code section of this chapter).
For right now, let’s build a test case for
L
L
i
i
b
b
r
r
a
a
r
r
y
y
:

class LibraryTestCase extends UnitTestCase {
function TestCount() {
$lib = new Library;
$this->assertEqual(0, $lib->count());
}
}
It’s easy enough to write a class that satisfies this test:
class Library {
function count() {
return 0;
}
}
Now add some interesting features to the test:
class LibraryTestCase extends UnitTestCase {
function TestCount() { /* */ }
function TestAdd() {
$lib = new Library;
$lib->add(‘one’);
$this->assertEqual(1, $lib->count());
}
}
An easy way to implement
a
a
d
d
d
d
(
(

)
)
is to piggyback on
PHP’s flexible array functions: you can add items to an
array instance variable and use
c
c
o
o
u
u
n
n
t
t
(
(
)
)
to return the
number of items in the collection.
class Library {
protected $collection = array();
function count() {
return count($this->collection);
}
function add($item) {
$this->collection[] = $item;
}
}

L
L
i
i
b
b
r
r
a
a
r
r
y
y
is now a collection, but it provides no way to
retrieve or manipulate the individual members of the
collection.
Let’s move on to the purpose of the article, imple-
mentation of the Iterator design pattern.
The following UML class diagram shows the GoF
Iterator pattern with the
M
M
e
e
d
d
i
i
a

a
and
L
L
i
i
b
b
r
r
a
a
r
r
y
y
classes used
July 2005

PHP Architect

www.phparch.com
F
F
E
E
A
A
T
T

U
U
R
R
E
E
16
The Iterator Pattern
1 <?php
2 // PHP5
3 class LendableTestCase extends UnitTestCase {
4 function TestCheckout() {
5 $item = new Lendable;
6 $this->assertFalse($item->borrower);
7 $item->checkout(‘John’);
8 $this->assertEqual(‘borrowed’, $item->status);
9 $this->assertEqual(‘John’, $item->borrower);
10 }
11 function TestCheckin() {
12 $item = new Lendable;
13 $item->checkout(‘John’);
14 $item->checkin();
15 $this->assertEqual(‘library’, $item->status);
16 $this->assertFalse($item->borrower);
17 }
18 }
19 ?>
Listing 1
1 <?php
2 class Lendable {

3 public $status = ‘library’;
4 public $borrower = ‘’;
5
6 public function checkout($borrower) {
7 $this->status = ‘borrowed’;
8 $this->borrower = $borrower;
9 }
10
11 public function checkin() {
12 $this->status = ‘library’;
13 $this->borrower = ‘’;
14 }
15 }
16 ?>
Listing 2
1 <?php
2 class Media extends Lendable {
3 public $name;
4 public $type;
5 public $year;
6
7 public function __construct($name, $year, $type=’dvd’) {
8 $this->name = $name;
9 $this->type = $type;
10 $this->year = (int)$year;
11 }
12 }
13 ?>
Listing 3
1 <?php

2 class IteratorTestCase extends UnitTestCase {
3 function setup() { /* */ }
4 function TestGetGofIterator() {
5 $this->assertIsA($it = $this->lib->getIterator(),
‘LibraryGofIterator’);
6 $this->assertFalse($it->isdone());
7 $this->assertIsA($first = $it->currentItem(), ‘Media’);
8 $this->assertEqual(‘name1’, $first->name);
9 $this->assertFalse($it->isdone());
10
11 $this->assertTrue($it->next());
12 $this->assertIsA($second = $it->currentItem(), ‘Media’);
13 $this->assertEqual(‘name2’, $second->name);
14 $this->assertFalse($it->isdone());
15
16 $this->assertTrue($it->next());
17 $this->assertIsA($third = $it->currentItem(), ‘Media’);
18 $this->assertEqual(‘name3’, $third->name);
19 $this->assertFalse($it->next());
20 $this->assertTrue($it->isdone());
21 }
22 }
23 ?>
Listing 4
F
F
E
E
A
A

T
T
U
U
R
R
E
E
July 2005

PHP Architect

www.phparch.com
17
to make the example concrete. (GoF is the Gang of
Four— Erich Gamma, Richard Helm, Ralph Johnson,
and John Vlissides, writers of the famous, and definitive
Design Patterns, Elements of Reusable Object-Oriented
Software).
Your collection class must provide a FactoryMethod to
create an instance of your Iterator.
Iterator classes define an interface of
f
f
i
i
r
r
s
s

t
t
(
(
)
)
to go to
the beginning of a collection,
n
n
e
e
x
x
t
t
(
(
)
)
to move to the
next item in sequence as you iterate,
c
c
u
u
r
r
r
r

e
e
n
n
t
t
I
I
t
t
e
e
m
m
(
(
)
)
to
retrieve the current item from the collection as you iter-
ate, and
i
i
s
s
D
D
o
o
n

n
e
e
(
(
)
)
to indicate when you have iterated
over the entire collection.
In the next section, we are going to create the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
G
G
o
o
f
f

I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
class as an example of a direct
implementation of the GoF Iterator design pattern—see
Figure 1.
Sample Code
The first step in implementing the GoF Iterator pattern
within
L
L
i
i
b
b
r
r

a
a
r
r
y
y
is to write a new test case for the new
concrete Iterator. Since each test method will be
manipulating a
L
L
i
i
b
b
r
r
a
a
r
r
y
y
filled with
M
M
e
e
d
d

i
i
a
a
instances, you
can employ the
U
U
n
n
i
i
t
t
T
T
e
e
s
s
t
t
C
C
a
a
s
s
e
e

:
:
:
:
s
s
e
e
t
t
U
U
p
p
(
(
)
)
method to
populate a variable with a
L
L
i
i
b
b
r
r
a
a

r
r
y
y
in a known state for
each test. (For the purposes of this article, treat
U
U
n
n
i
i
t
t
T
T
e
e
s
s
t
t
C
C
a
a
s
s
e
e

as a generic unit testing suite. The associ-
ated code does, however, serve to illustrate how
L
L
i
i
b
b
r
r
a
a
r
r
y
y
should perform.)
Start by adding the
L
L
i
i
b
b
r
r
a
a
r
r

y
y
:
:
:
:
g
g
e
e
t
t
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
(
(

)
)
method
as a FactoryMethod for instances of the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
G
G
o
o
f
f
I
I
t
t
e
e

r
r
a
a
t
t
o
o
r
r
class.
class IteratorTestCase extends UnitTestCase {
protected $lib;
function setup() {
$this->lib = new Library;
$this->lib->add(new Media(‘name1’, 2000));
$this->lib->add(new Media(‘name2’, 2002));
$this->lib->add(new Media(‘name3’, 2001));
}
function TestGetGofIterator() {
$this->assertIsA($it = $this->lib->getIterator()
,’LibraryGofIterator’);
}
}
Here’s the implementation.
class Library {
1 <?php
2 class LibraryGofIterator {
3 protected $collection;
4 function __construct($collection) {

5 $this->collection = $collection;
6 }
7 function first() {
8 reset($this->collection);
9 }
10 function next() {
11 return (false !== next($this->collection));
12 }
13 function isDone() {
14 return (false === current($this->collection));
15 }
16 function currentItem() {
17 return current($this->collection);
18 }
19 }
20 ?>
Listing 5
1 <?php
2 class LibraryGofExternalIterator {
3 protected $key = 0;
4 protected $collection;
5
6 function __construct($collection) {
7 $this->collection = $collection;
8 }
9 function first() {
10 $this->key=0;
11 }
12 function next() {
13 return (++$this->key < $this->collection->count());

14 }
15 function isDone() {
16 return ($this->key >= $this->collection->count());
17 }
18 function currentItem() {
19 return $this->collection->get($this->key);
20 }
21 }
22 ?>
Listing 6
1 <?php
2 class IteratorTestCase extends UnitTestCase {
3 //
4 function TestMediaIteratorUsage() {
5 $this->assertIsA(
6 $it = $this->lib->getIterator(‘media’)
7 ,’LibraryIterator’);
8 $output = ‘’;
9 while ($item = $it->next()) {
10 $output .= $item->name;
11 }
12 $this->assertEqual(‘name1name2name3’, $output);
13 }
14 }
15 ?>
Listing 7
1 <?php
2 class LibraryIterator {
3 protected $collection;
4 protected $first=true;

5 function __construct($collection) {
6 $this->collection = $collection;
7 }
8 function next() {
9 if ($this->first) {
10 $this->first = false;
11 return current($this->collection);
12 }
13 return next($this->collection);
14 }
15 }
16 ?>
Listing 8
“Use the Iterator pattern to
provide uniform access to the
contents of a collection.

July 2005

PHP Architect

www.phparch.com
F
F
E
E
A
A
T
T

U
U
R
R
E
E
18
//
function getIterator() {
return new LibraryGofIterator($this->collec-
tion);
}
}
The
g
g
e
e
t
t
I
I
t
t
e
e
r
r
a
a

t
t
o
o
r
r
(
(
)
)
method passes the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
’s
$
$
c
c

o
o
l
l
-
-
l
l
e
e
c
c
t
t
i
i
o
o
n
n
to the constructor of the new concrete iterator.
This technique has two important implications: each
iterator is independent, so multiple iterators can oper-
ate at the same time. Additionally, the iterator operates
on the collection as it existed at the time the iterator
was requested. If another item is added to the collec-
tion at any time later, you must request another itera-
tor to display it (at least in this implementation).
Continue enhancing the test suite by adding asser-
tions to the

T
T
e
e
s
s
t
t
G
G
e
e
t
t
G
G
o
o
f
f
I
I
t
t
e
e
r
r
a
a

t
t
o
o
r
r
(
(
)
)
method to match
the Iterator design pattern. The
i
i
s
s
D
D
o
o
n
n
e
e
(
(
)
)
method
should only be true if you’ve iterated over the entire

collection. If the iterator’s just been created,
i
i
s
s
D
D
o
o
n
n
e
e
(
(
)
)
should obviously return
f
f
a
a
l
l
s
s
e
e
to indicate it’s okay to
iterate.

class IteratorTestCase extends UnitTestCase {
function setup() { /* */ }
function TestGetGofIterator() {
$this->assertIsA($it = $this->lib->getIterator()
,’LibraryGofIterator’);
$this->assertFalse($it->isdone());
}
}
As usual with Test Driven Development (TDD), imple-
ment the simplest possible code that satisfies your test
case:
class LibraryGofIterator {
function isDone() {
return false;
}
}
So, what should happen during the first iteration.
c
c
u
u
r
r
r
r
e
e
n
n
t

t
I
I
t
t
e
e
m
m
(
(
)
)
should return the first
M
M
e
e
d
d
i
i
a
a
object
added in the
I
I
t
t

e
e
r
r
a
a
t
t
o
o
r
r
T
T
e
e
s
s
t
t
C
C
a
a
s
s
e
e
:
:

:
:
s
s
e
e
t
t
U
U
p
p
(
(
)
)
method and
i
i
s
s
D
D
o
o
n
n
e
e
(

(
)
)
should continue to be false, since two addi-
tional items remain to be iterated over.
class IteratorTestCase extends UnitTestCase {
function setup() { /* */ }
function TestGetGofIterator() {
$this->assertIsA($it = $this->lib->getIterator()
,’LibraryGofIterator’);
$this->assertFalse($it->isdone());
$this->assertIsA($first = $it->currentItem(),
‘Media’);
$this->assertEqual(‘name1’, $first->name);
$this->assertFalse($it->isdone());
}
}
It’s critical that
L
L
i
i
b
b
r
r
a
a
r
r

y
y
G
G
o
o
f
f
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
receives the
$
$
c
c
o

o
l
l
-
-
l
l
e
e
c
c
t
t
i
i
o
o
n
n
in the constructor (see the minimal implemen-
tation of
L
L
i
i
b
b
r
r
a

a
r
r
y
y
above) and returns the
c
c
u
u
r
r
r
r
e
e
n
n
t
t
(
(
)
)
item
of that array from the
c
c
u
u

r
r
r
r
e
e
n
n
t
t
I
I
t
t
e
e
m
m
(
(
)
)
method.
class LibraryGofIterator {
protected $collection;
function __construct($collection) {
$this->collection = $collection;
}
function currentItem() {
return current($this->collection);

}
function isDone() {
return false;
}
}
What should happen in the next iteration? The
n
n
e
e
x
x
t
t
(
(
)
)
method should change what item is returned by the
c
c
u
u
r
r
r
r
e
e
n

n
t
t
I
I
t
t
e
e
m
m
(
(
)
)
method. This test captures that expect-
ed behavior:
class IteratorTestCase extends UnitTestCase {
function setup() { /* */ }
function TestGetGofIterator() {
$this->assertIsA($it = $this->lib-
>getIterator(), ‘LibraryGofIterator’);
$this->assertFalse($it->isdone());
$this->assertIsA($first = $it->currentItem(),
‘Media’);
$this->assertEqual(‘name1’, $first->name);
$this->assertFalse($it->isdone());
$this->assertTrue($it->next());
$this->assertIsA($second = $it->currentItem(),
The Iterator Pattern

1 <?php
2 class Library {
3 //
4 function getIterator($type=false) {
5 switch (strtolower($type)) {
6 case ‘media’:
7 $iterator_class = ‘LibraryIterator’;
8 break;
9 case ‘available’:
10 $iterator_class = ‘LibraryAvailableIterator’;
11 break;
12 case ‘released’:
13 $iterator_class = ‘LibraryReleasedIterator’;
14 break;
15 default:
16 $iterator_class = ‘LibraryGofIterator’;
17 }
18 return new $iterator_class($this->collection);
19 }
20 }
21 ?>
Listing 9
1 <?php
2 class IteratorTestCase extends UnitTestCase {
3 //
4 function TestAvailableIteratorUsage() {
5 $this->lib->add($dvd = new Media(‘test’, 1999));
6 $this->lib->add(new Media(‘name4’, 1999));
7 $this->assertIsA(
8 $it = $this->lib->getIterator(‘available’)

9 ,’LibraryAvailableIterator’);
10 $output = ‘’;
11 while ($item = $it->next()) {
12 $output .= $item->name;
13 }
14 $this->assertEqual(‘name1name2name3testname4’, $output);
15
16 $dvd->checkOut(‘Jason’);
17 $it = $this->lib->getIterator(‘available’);
18 $output = ‘’;
19 while ($item = $it->next()) {
20 $output .= $item->name;
21 }
22 $this->assertEqual(‘name1name2name3name4’, $output);
23 }
24 }
25 ?>
Listing 10
‘Media’);
$this->assertEqual(‘name2’, $second->name);
$this->assertFalse($it->isdone());
}
}
Piggybacking again on PHP’s array functions, use
n
n
e
e
x
x

t
t
(
(
)
)
on the array.
class LibraryGofIterator {
protected $collection;
function __construct($collection) {
$this->collection = $collection;
}
function currentItem() {
return current($this->collection);
}
function next() {
return next($this->collection);
}
function isDone() {
return false;
}
}
The third iteration looks much like the others, except
the
i
i
s
s
D
D

o
o
n
n
e
e
(
(
)
)
method must return
t
t
r
r
u
u
e
e
. You also want
n
n
e
e
x
x
t
t
(
(

)
)
to indicate success of moving to the next itera-
tion.
With small modifications to the [next()] and
[isDone()] methods, all of the tests pass. (See Listings 4
and 5).
There’s just one problem with the Iterator test case: it
doesn’t reflect how iterators are typically used. Yes, it
tests all of the features of the Iterator pattern, but appli-
cation code uses the Iterator in a much simpler way. So,
the next step is to write a test to run more realistic
code.
class IteratorTestCase extends UnitTestCase {
protected $lib;
function setup() { /* */ }
function TestGetGofIterator() { /* */ }
function TestGofIteratorUsage() {
$output = ‘’;
for ($it=$this->lib->getIterator(); !$it-
>isDone(); $it->next()){
$output .= $it->currentItem()->name;
}
$this->assertEqual(‘name1name2name3’, $output);
}
}
So far, the implementation of Iterator copies an array
(the collection) and uses PHP’s internal pointer to track
the iteration. You can also implement the Iterator by
keeping track of the collection index by yourself. This

requires a new accessor method in
L
L
i
i
b
b
r
r
a
a
r
r
y
y
to fetch an
object by key.
class Library {
//
function get($key) {
if (array_key_exists($key, $this->collection)) {
return $this->collection[$key];
}
}
}
Also, you’d pass
$
$
t
t

h
h
i
i
s
s
(the library itself) to the con-
structor instead of
$
$
t
t
h
h
i
i
s
s
-
-
>
>
c
c
o
o
l
l
l
l

e
e
c
c
t
t
i
i
o
o
n
n
(the array con-
taining the Media collection) in the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
:
:

:
:
g
g
e
e
t
t
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
(
(
)
)
method.
The “external” iterator would then just track a point-

er internally to know which element of the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
col-
lection it’s currently referencing, and would use the ref-
erence to the
L
L
i
i
b
b
r
r
a
a
r
r

y
y
passed in the constructor to call
the
g
g
e
e
t
t
(
(
)
)
method to retrieve the current object.
The implementation seen in Listing 6 assumes that
your collection array is indexed starting with 0 and is
completely sequential.
A Variant Iterator API
While the foregoing code is a complete implementa-
tion of the Iterator pattern as described by GoF, you
may find the four-method API a bit cumbersome. If so,
you can collapse
n
n
e
e
x
x
t

t
(
(
)
)
,
c
c
u
u
r
r
r
r
e
e
n
n
t
t
I
I
t
t
e
e
m
m
(
(

)
)
, and
i
i
s
s
D
D
o
o
n
n
e
e
(
(
)
)
into just
n
n
e
e
x
x
t
t
(
(

)
)
by having the latter either advance and
return the current item from the collection or return
false if the entire collection has been processed.
Listing 7 shows one way to write a test for this varia-
tion of the API.
Notice the simplified control structure for looping.
n
n
e
e
x
x
t
t
(
(
)
)
returns an object or
f
f
a
a
l
l
s
s
e

e
, allowing you to per-
form the assignment inside the
w
w
h
h
i
i
l
l
e
e
loop conditional.
The next few examples explore variations of the
Iterator pattern using the smaller interface. As a con-
venience, change the
L
L
i
i
b
b
r
r
a
a
r
r
y

y
:
:
:
:
g
g
e
e
t
t
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
(
(
)

)
method
to a parameterized FactoryMethod so you can get either
the four-method iterator or the two-method iterator
(
n
n
e
e
x
x
t
t
(
(
)
)
and
r
r
e
e
s
s
e
e
t
t
(
(

)
)
from that single method).
class Library {
//
function getIterator($type=false) {
switch (strtolower($type)) {
case ‘media’:
$iterator_class = ‘LibraryIterator’;
break;
default:
$iterator_class = ‘LibraryGofIterator’;
}
return new $iterator_class($this->collection);
}
}
F
F
E
E
A
A
T
T
U
U
R
R
E
E

July 2005

PHP Architect

www.phparch.com
19
The Iterator Pattern
1 <?php
2 class LibraryAvailableIterator {
3 protected $collection = array();
4 protected $first=true;
5 function __construct($collection) {
6 $this->collection = $collection;
7 }
8 function next() {
9 if ($this->first) {
10 $this->first = false;
11 $ret = current($this->collection);
12 } else {
13 $ret = next($this->collection);
14 }
15 if ($ret && ‘library’ != $ret->status) {
16 return $this->next();
17 }
18 return $ret;
19 }
20 }
21 ?>
Listing 11
Here,

L
L
i
i
b
b
r
r
a
a
r
r
y
y
:
:
:
:
g
g
e
e
t
t
I
I
t
t
e
e

r
r
a
a
t
t
o
o
r
r
(
(
)
)
now accepts a parame-
ter to select what kind of iterator to return. The default
is
L
L
i
i
b
b
r
r
a
a
r
r
y

y
G
G
o
o
f
f
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
(so the existing tests still pass.
Passing the string
m
m
e
e
d

d
i
i
a
a
to the method creates and
returns a
L
L
i
i
b
b
r
r
a
a
r
r
y
y
I
I
t
t
e
e
r
r
a

a
t
t
o
o
r
r
instead.
This is some code to implement [LibraryIterator]:
class LibraryIterator {
protected $collection;
function __construct($collection) {
$this->collection = $collection;
}
function next() {
return next($this->collection);
}
}
Oops! The dreaded test failure! What caused this?
Somehow, the first iteration was skipped—that’s a bug.
To fix the error, return
c
c
u
u
r
r
r
r
e

e
n
n
t
t
(
(
)
)
for the first call of the
n
n
e
e
x
x
t
t
(
(
)
)
method.
The code in Listing 8 corrects our logic error and pro-
vides a streamlined
w
w
h
h
i

i
l
l
e
e
loop iterator.
Filtering Iterator
With Iterators, you can do more than just present each
item of the collection, you can also select which items
are presented. Let’s modify the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
:
:
:
:
g
g

e
e
t
t
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
(
(
)
)
to allow two additional iterator types (Listing 9).
The
L
L
i
i

b
b
r
r
a
a
r
r
y
y
A
A
v
v
a
a
i
i
l
l
a
a
b
b
l
l
e
e
I
I

t
t
e
e
r
r
a
a
t
t
o
o
r
r
class should only iter-
ate over items that have a status of “library” (recall that
the
c
c
h
h
e
e
c
c
k
k
O
O
u

u
t
t
(
(
)
)
method changes the status to “bor-
rowed”).
The test in Listing 10 creates a new
M
M
e
e
d
d
i
i
a
a
instance
and stores it in the variable
$
$
d
d
v
v
d
d

. The first highlighted
a
a
s
s
s
s
e
e
r
r
t
t
E
E
q
q
u
u
a
a
l
l
(
(
)
)
assertion verifies that the new item is
present when iterating with
L

L
i
i
b
b
r
r
a
a
r
r
y
y
A
A
v
v
a
a
i
i
l
l
a
a
b
b
l
l
e

e
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
.
Next, the test uses the
c
c
h
h
e
e
c
c
k
k
O

O
u
u
t
t
(
(
)
)
method and verifies
that the new item is missing from the display.
The code to implement filtering (Listing 11) is very
similar to the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
I
I
t

t
e
e
r
r
a
a
t
t
o
o
r
r
:
:
:
:
n
n
e
e
x
x
t
t
(
(
)
)
, except filtering

is done prior to returning the item. If the current item
does not match the filter criteria, the code returns
$
$
t
t
h
h
i
i
s
s
-
-
>
>
n
n
e
e
x
x
t
t
(
(
)
)
instead.
July 2005


PHP Architect

www.phparch.com
F
F
E
E
A
A
T
T
U
U
R
R
E
E
20
The Iterator Pattern
1 <?php
2 class IteratorTestCase extends UnitTestCase {
3 //
4 function TestReleasedIteratorUsage() {
5 $this->lib->add(new Media(‘second’, 1999));
6 $this->lib->add(new Media(‘first’, 1989));
7 $this->assertIsA(
8 $it = $this->lib->getIterator(‘released’)
9 ,’LibraryReleasedIterator’);
10 $output = array();

11 while ($item = $it->next()) {
12 $output[] = $item->name .’-’. $item->year;
13 }
14 $this->assertEqual(
15 ‘first-1989 second-1999 name1-2000 name3-2001 name2-2002’
16 ,implode(‘ ‘,$output));
17 }
18 }
19 ?>
Listing 12
1 <?php
2 class LibraryReleasedExternalIterator {
3 protected $collection;
4 protected $sorted_keys;
5 protected $key=-1;
6
7 function __construct($collection) {
8 $this->collection = $collection;
9 $sort_funct = create_function(
10 ‘$a,$b,$c=false’,
11 ‘static $collection;
12 if ($c) {
13 $collection = $c;
14 return;
15 }
16 return ($collection->get($a)->year -
17 $collection->get($b)->year);’);
18 $sort_funct(null,null,$this->collection);
19 $this->sorted_keys = $this->collection->keys();
20 usort($this->sorted_keys, $sort_funct);

21 }
22
23 function next() {
24 if (++$this->key >= $this->collection->count()) {
25 return false;
26 } else {
27 return $this->collection->get($this->sorted_keys[$this-
>key]);
28 }
29 }
30 }
31 ?>
Listing 13
1 <?php
2 class SplIteratorTestCase extends UnitTestCase {
3 protected $lib;
4
5 function setup() {
6 $this->lib = new ForeachableLibrary;
7 $this->lib->add(new Media(‘name1’, 2000));
8 $this->lib->add(new Media(‘name2’, 2002));
9 $this->lib->add(new Media(‘name3’, 2001));
10 }
11
12 function TestForeach() {
13 $output = ‘’;
14 foreach($this->lib as $item) {
15 $output .= $item->name;
16 }
17 $this->assertEqual(‘name1name2name3’, $output);

18 }
19 }
20 ?>
Listing 14
1 <?php
2 class ForeachableLibrary
3 extends Library
4 implements Iterator {
5 protected $valid;
6 function current() {
7 return current($this->collection);
8 }
9 function next() {
10 $this->valid = (false !== next($this->collection));
11 }
12 function key() {
13 return key($this->collection);
14 }
15 function valid() {
16 return $this->valid;
17 }
18 function rewind() {
19 $this->valid = (false !== reset($this->collection));
20 }
21 }
22 ?>
Listing 15
Sorting Iterator
An iterator can do more than show all or a portion of
the collection. An iterator can also show the collection

in a specific order.
Let’s create an iterator that sorts the
M
M
e
e
d
d
i
i
a
a
in the col-
lection by release date.
For a test (Listing 12), add some
M
M
e
e
d
d
i
i
a
a
instances with
dates older that those of the items added in the
s
s
e

e
t
t
U
U
p
p
(
(
)
)
method. If the iterator works, these older items should
be sorted to the beginning of the iteration.
This test uses the items in each iteration slightly dif-
ferently: instead of just appending the
$
$
n
n
a
a
m
m
e
e
values in a
string, a string is formed from both the
$
$
n

n
a
a
m
m
e
e
and
$
$
y
y
e
e
a
a
r
r
properties, which is then appended to an
$
$
o
o
u
u
t
t
p
p
u

u
t
t
array.
The implementation of
L
L
i
i
b
b
r
r
a
a
r
r
y
y
R
R
e
e
l
l
e
e
a
a
s

s
e
e
d
d
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
is
nearly identical to
L
L
i
i
b
b
r

r
a
a
r
r
y
y
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
, except for one
additional line in the constuctor.
class LibraryReleasedIterator extends LibraryIterator
{
function __construct($collection) {
usort($collection, create_function(‘$a,$b’,
‘return ($a->year - $b->year);’));

$this->collection = $collection;
}
}
The
u
u
s
s
o
o
r
r
t
t
(
(
)
)
statement sorts the
$
$
c
c
o
o
l
l
l
l
e

e
c
c
t
t
i
i
o
o
n
n
array prior
to iteration. You can avoid copying all of the other code
for the class by simply inheriting from the
L
L
i
i
b
b
r
r
a
a
r
r
y
y
I
I

t
t
e
e
r
r
a
a
t
t
o
o
r
r
class itself.
Is it possible to use an external iterator to accomplish
this same sorted iteration? Yes, but you must pull a few
tricks to accomplish it. See Listing 13.
Key here is the creation of a utility function for per-
forming the sort. The sorting function needs to have
access to the collection so it can fetch members for
comparison. However, because the generated function
is used in a
u
u
s
s
o
o
r

r
t
t
(
(
)
)
, you don’t have the option of pass-
ing the collection as an additional parameter. Instead,
you can use the trick shown in the code block above to
store a reference to the collection inside the function
prior to calling it with
u
u
s
s
o
o
r
r
t
t
(
(
)
)
.
What you’re sorting is the list of keys for the collec-
tion. When
u

u
s
s
o
o
r
r
t
t
(
(
)
)
is complete, the keys will be sorted
in order by the year attribute of each object in the col-
lection.
In the
n
n
e
e
x
x
t
t
(
(
)
)
method, an object in the collection is

accessed via the
g
g
e
e
t
t
(
(
)
)
method, but indirectly through
the
$
$
s
s
o
o
r
r
t
t
e
e
d
d
_
_
k

k
e
e
y
y
s
s
mapping. If you recall the external
version of the GoF-style iterator, arrays with gaps or
strings in the keys could be problematic. This same trick
could be used for a simple external iterator to alleviate
the problem of gaps in the sequence of keys.
SPL Iterator
No article on the Iterator design pattern and PHP would
be complete without discussing the “Standard PHP
Library” (SPL) iterator.
The
w
w
h
h
i
i
l
l
e
e
loop structure used so far is very compact
and usable, but PHP coders may be more comfortable
with the

f
f
o
o
r
r
e
e
a
a
c
c
h
h
structure for array iteration. Wouldn’t
it be nice to use a collection directly in a
f
f
o
o
r
r
e
e
a
a
c
c
h
h

loop?
That’s exactly what the SPL iterator is for.
(Even though this article has been written entirely for
F
F
E
E
A
A
T
T
U
U
R
R
E
E
July 2005

PHP Architect

www.phparch.com
21
The Iterator Pattern
1 <?php
2 class PolySplIteratorTestCase extends UnitTestCase {
3 protected $lib;
4 function setup() {
5 $this->lib = new PolymorphicForeachableLibrary;
6 $this->lib->add(new Media(‘name1’, 2000));

7 $this->lib->add(new Media(‘name2’, 2002));
8 $this->lib->add(new Media(‘name3’, 2001));
9 }
10 function TestForeach() {
11 $output = ‘’;
12 foreach($this->lib as $item) {
13 $output .= $item->name;
14 }
15 $this->assertEqual(‘name1name2name3’, $output);
16 }
17 }
18 ?>
Listing 16
1 <?php
2 class PolymorphicForeachableLibrary
3 extends Library
4 implements Iterator {
5 protected $iterator;
6 function current() {
7 return $this->iterator->current();
8 }
9 function next() {
10 return $this->iterator->next();
11 }
12 function key() {
13 return $this->iterator->key();
14 }
15 function valid() {
16 return $this->iterator->valid();
17 }

18 function rewind() {
19 $this->iterator =
20 new StandardLibraryIterator($this->collection);
21 $this->iterator->rewind();
22 }
23 }
24 ?>
Listing 17
“Iterator couples the object-oriented programming principals
of encapsulation and polymorphism.

PHP 5, the following SPL code is the only code that
works solely in PHP 5, and then only if you’ve compiled
PHP 5 with SPL enabled. Harry Fuecks wrote a nice arti-
cle introducing the SPL and covering the SPL iterator;
see
h
h
t
t
t
t
p
p
:
:
/
/
/
/

w
w
w
w
w
w
.
.
s
s
i
i
t
t
e
e
p
p
o
o
i
i
n
n
t
t
.
.
c
c

o
o
m
m
/
/
a
a
r
r
t
t
i
i
c
c
l
l
e
e
/
/
p
p
h
h
p
p
5
5

-
-
s
s
t
t
a
a
n
n
d
d
a
a
r
r
d
d
-
-
l
l
i
i
b
b
r
r
a
a

r
r
y
y
.)
Using SPL is essentially a completely different way to
implement iteration, so let’s start over with a new unit
test case and a new class, the
F
F
o
o
r
r
e
e
a
a
c
c
h
h
a
a
b
b
l
l
e
e

L
L
i
i
b
b
r
r
a
a
r
r
y
y
, and
Listing 14.
F
F
o
o
r
r
e
e
a
a
c
c
h
h

a
a
b
b
l
l
e
e
L
L
i
i
b
b
r
r
a
a
r
r
y
y
is the collection that implements
the SPL
I
I
t
t
e
e

r
r
a
a
t
t
o
o
r
r
interface.
You have to implement five functions to create an SPL
iterator:
c
c
u
u
r
r
r
r
e
e
n
n
t
t
(
(
)

)
,
n
n
e
e
x
x
t
t
(
(
)
)
,
k
k
e
e
y
y
(
(
)
)
,
v
v
a
a

l
l
i
i
d
d
(
(
)
)
, and
r
r
e
e
w
w
i
i
n
n
d
d
(
(
)
)
.
k
k

e
e
y
y
(
(
)
)
returns the current index of your collec-
tion.
r
r
e
e
w
w
i
i
n
n
d
d
(
(
)
)
is like
r
r
e

e
s
s
e
e
t
t
(
(
)
)
: iteration begins at the
start of your collection. See Listing 15.
Here we just implement the required functions work-
ing on our
$
$
c
c
o
o
l
l
l
l
e
e
c
c
t

t
i
i
o
o
n
n
attribute. (If you don’t imple-
ment all five functions and you add the
i
i
m
m
p
p
l
l
e
e
m
m
e
e
n
n
t
t
s
s
I

I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
to your class definition, PHP will generate a
fatal error.) The tests pass, and everything is happy.
There’s just one problem: the implementation is lim-
ited to one style of iteration—sorting or filtering is
impossible.
Can anything be done to rectify this? Yes! You can
apply the Strategy pattern and delegate the SPL itera-
tor’s five functions to another object.
Listing 16 is a test for
P
P
o
o
l
l

y
y
m
m
o
o
r
r
p
p
h
h
i
i
c
c
F
F
o
o
r
r
e
e
a
a
c
c
h
h

a
a
b
b
l
l
e
e
L
L
i
i
b
b
r
r
a
a
r
r
y
y
.
The only difference between this case and the test for
S
S
p
p
l
l

I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
T
T
e
e
s
s
t
t
C
C
a
a
s
s

e
e
is the class of the
$
$
t
t
h
h
i
i
s
s
-
-
>
>
l
l
i
i
b
b
attribute created in the
s
s
e
e
t
t

U
U
p
p
(
(
)
)
method. That makes
sense: the two classes must behave identically.
Listing 17 contains
P
P
o
o
l
l
y
y
m
m
o
o
r
r
p
p
h
h
i

i
c
c
F
F
o
o
r
r
e
e
a
a
c
c
h
h
a
a
b
b
l
l
e
e
L
L
i
i
b

b
r
r
a
a
r
r
y
y
.
L
L
i
i
b
b
r
r
a
a
r
r
y
y
is extended to get the collection manipula-
tion methods. The SPL methods are added, too, all del-
egating to the
$
$
i

i
t
t
e
e
r
r
a
a
t
t
o
o
r
r
attribute, which is created in
r
r
e
e
w
w
i
i
n
n
d
d
(
(

)
)
. Below is the code for the
S
S
t
t
a
a
n
n
d
d
a
a
r
r
d
d
L
L
i
i
b
b
r
r
a
a
r

r
y
y
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
.
The code in Listing 18 should look familiar: essential-
ly, it’s a copy of the five SPL functions from the
F
F
o
o
r
r
e
e

a
a
c
c
h
h
a
a
b
b
l
l
e
e
L
L
i
i
b
b
r
r
a
a
r
r
y
y
class. The tests pass.
OK, the code is more complex now, but how does it

support additional iterator types? Let’s add a test for a
“released” version of the iterator to see how additional
iterator types work in this design.
The test case in Listing 19 should look familiar, too, as
it’s very similar to the previous “release” iterator, but
using the
f
f
o
o
r
r
e
e
a
a
c
c
h
h
control structure to loop.
The new
i
i
t
t
e
e
r
r

a
a
t
t
o
o
r
r
T
T
y
y
p
p
e
e
(
(
)
)
method (Listing 20) lets you
switch which style of iterator you want to use. (Since
the iterator type isn’t chosen during the instantiation of
the object and because you can choose a different iter-
ator type on-the-fly by calling the
i
i
t
t
e

e
r
r
a
a
t
t
o
o
r
r
T
T
y
y
p
p
e
e
(
(
)
)
method again, the code is actually implementing the
July 2005

PHP Architect

www.phparch.com
F

F
E
E
A
A
T
T
U
U
R
R
E
E
22
1 <?php
2 class StandardLibraryIterator {
3 protected $valid;
4 protected $collection;
5 function __construct($collection) {
6 $this->collection = $collection;
7 }
8 function current() {
9 return current($this->collection);
10 }
11 function next() {
12 $this->valid = (false !== next($this->collection));
13 }
14 function key() {
15 return key($this->collection);
16 }

17 function valid() {
18 return $this->valid;
19 }
20 function rewind() {
21 $this->valid = (false !== reset($this->collection));
22 }
23 }
24 ?>
Listing 18
1 <?php
2 class PolySplIteratorTestCase extends UnitTestCase {
3 //
4 function TestReleasedForeach() {
5 $this->lib->add(new Media(‘second’, 1999));
6 $this->lib->add(new Media(‘first’, 1989));
7 $output = array();
8 $this->lib->iteratorType(‘Released’);
9 foreach($this->lib as $item) {
10 $output[] = $item->name .’-’. $item->year;
11 }
12 $this->assertEqual(
13 ‘first-1989 second-1999 name1-2000 name3-2001 name2-2002’
14 ,implode(‘ ‘,$output));
15 }
16 }
17 ?>
Listing 19
1 <?php
2 class PolymorphicForeachableLibrary
3 extends Library

4 implements Iterator {
5 protected $iterator_type;
6 protected $iterator;
7 function __construct() {
8 $this->iteratorType();
9 }
10 function iteratorType($type=false) {
11 switch(strtolower($type)) {
12 case ‘released’:
13 $this->iterator_type = ‘ReleasedLibraryIterator’;
14 break;
15 default:
16 $this->iterator_type = ‘StandardLibraryIterator’;
17 }
18 $this->rewind();
19 }
20 //
21 function rewind() {
22 $type = $this->iterator_type;
23 $this->iterator = new $type($this->collection);
24 $this->iterator->rewind();
25 }
26 }
27 ?>
Listing 20
The Iterator Pattern
State pattern, rather than the Strategy pattern.)
class ReleasedLibraryIterator
extends StandardLibraryIterator {
function __construct($collection) {

usort($collection,
create_function(‘$a,$b’,
return ($a->year - $b->year);’));
$this->collection = $collection;
}
}
You can easily implement
R
R
e
e
l
l
e
e
a
a
s
s
e
e
d
d
L
L
i
i
b
b
r

r
a
a
r
r
y
y
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
by
extending
S
S
t
t
a

a
n
n
d
d
a
a
r
r
d
d
L
L
i
i
b
b
r
r
a
a
r
r
y
y
I
I
t
t
e

e
r
r
a
a
t
t
o
o
r
r
and overriding the
constructor to add the sorting of the incoming
array. And with that you have a working
P
P
o
o
l
l
y
y
m
m
o
o
r
r
p
p

h
h
i
i
c
c
F
F
o
o
r
r
e
e
a
a
c
c
h
h
a
a
b
b
l
l
e
e
L
L

i
i
b
b
r
r
a
a
r
r
y
y
.
Issues
Iterators are a nice way to standardize working with col-
lections of objects in your applications. The examples
here have been based on arrays, but the ability to work
on non-array based collections with an identical inter-
face is powerful.
The ability to use collections in the
f
f
o
o
r
r
e
e
a
a

c
c
h
h
control
structure is indeed cool. The only unfortunate issue
with the SPL implementation is the significant potential
for namespace clashing with “
I
I
t
t
e
e
r
r
a
a
t
t
o
o
r
r
”. How much
PHP 4 object-oriented code has some sort of an
I
I
t
t

e
e
r
r
a
a
t
t
o
o
r
r
class as a base class for the libraries’ iterators?
Of those, how many define the five required methods
in the same capacity? Perhaps
i
i
m
m
p
p
l
l
e
e
m
m
e
e
n

n
t
t
s
s
F
F
o
o
r
r
e
e
a
a
c
c
h
h
a
a
b
b
l
l
e
e
would have been a less intrusive name. If you choose to
use the SPL, you should investigate the other support-
ed iterators, like

R
R
e
e
c
c
u
u
r
r
s
s
i
i
v
v
e
e
A
A
r
r
r
r
a
a
y
y
I
I

t
t
e
e
r
r
a
a
t
t
o
o
r
r
and numer-
ous other flavors.
F
F
E
E
A
A
T
T
U
U
R
R
E
E

July 2005

PHP Architect

www.phparch.com
23
Available Right At Your Desk
All our classes take place
entirely through the Internet
and feature a real, live instructor
that interacts with each student
through voice or real-time
messaging.
What You Get
Your Own Web Sandbox
Our No-hassle Refund Policy
Smaller Classes = Better Learning
Curriculum
The training program closely
follows the certification guide—
as it was built by some of its
very same authors.
Sign-up and Save!
For a limited time, you can
get over $300 US in savings
just by signing up for our
training program!
New classes start every three weeks!
/>About the Author ?>
To Discuss this article:

/>Jason has been an IT professional for over ten years. He is currently an application devel-
oper and intranet webmaster for a Fortune 100 company. He has written several tutori-
als and articles for the Zend website, and has recently contributed to the Wrox “PHP
Graphics” handbook. He is also the author of “php|architect’s Guide to PHP Patterns. He
resides in Iowa with his wife and two children. Jason can be contacted at
j
j
s
s
w
w
e
e
a
a
t
t
_
_
p
p
h
h
p
p
@
@
y
y
a

a
h
h
o
o
o
o
.
.
c
c
o
o
m
m

The Iterator Pattern

F
F
E
E
A
A
T
T
U
U
R
R

E
E
July 2005

PHP Architect

www.phparch.com
25
W
hether you need certain functionality for a big
software house or single developer, you want
to find good libraries that you can use, direct-
ly, via Application Programming Interfaces (APIs) with-
out having to modify the code. This is possible by using
Object Oriented development and Pattern Design,
which are both commonly used to create re-usable
code for common tasks.
What Do We Need to Manage?
The first objective of our library is to be able to manage
permissions for many different types of projects. The
main elements are users and permissions. As far as users
are concerned, you usually need to manage groups and
roles. Permissions are created as a flat list whereby each
application using the library shall be able to have its
own, independent permissions list. Those permissions
must then be applied to objects (e.g. read or write per-
mission on a specific document). To do this effectively,
an entity category of objects was introduced, that
allows grouping objects by type. So, we end up with:
• Users, groups and roles

• Permissions
• Objects and object categories
Users can be part of one or more groups, and each
group can have a parent group, to allowing the cre-
A generic library to manage permissions is what you
would want for many projects. It should have a generic
interface to populate the permissions database and man-
age permission needs so that they can be easily personal-
ized. To achieve this, we created a PHP library generic
enough to satisfy the needs of most projects and also pro-
vided a Flash user interface to manage permissions that is
ready for deployment with any web project.
F
F
E
E
A
A
T
T
U
U
R
R
E
E
PHP Library
for Permission Management
by Simone Grassi and Bernhard Gaul
REQUIREMENTS

PHP 4.x
OS Tested in Linux
Other Software
Apache, MySQL,
Flash plug-in
Code Directory permissions

×