So, we end up with: • Users, groups and roles • Permissions • Objects and object categoriesUsers can be part of one or more groups, and eachgroup can have a parent group, to allowing the
Trang 2ences 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!
http://www.phparch.com/works
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
Trang 414 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
10 TIPS & TRICKS
Input Filtering: Part 1
Trang 6ast 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
php|architect
Volume IV - Issue 7 July, 2005
Publisher
Marco Tabini
Editorial Team
Arbi Arzoumani Peter MacIntyre Eddie Peloke
Graphics & Layout
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: info@phparch.com
Editorial: editors@phparch.com
Subscriptions: subs@phparch.com
Sales & advertising: sales@phparch.com
Technical support: support@phparch.com
Copyright © 2003-2005 Marco Tabini & Associates, Inc — All Rights Reserved
TM
p pe ea ar r u up pg gr ra ad de e
H Ho om me e_ _R Re es si id de en nc ce e
L
Trang 7"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.comhas 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 ing avatar informations within the database
updat-• Fixed bug in admin re-authentication redirect for servers not having index.php as one of their default files set
Visit phpbb.comfor all the latest info.
FUDforum 2.6.14RC2
Fudforum.organnounces 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 http://ajax.zervaas.com.au/
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 http://phpreports.source forge.net/for more information or to download.
Trang 8Check 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:
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.
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, http://www.phparch.com/shop_product.php?itemid=96.
Trang 9• 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 pose use Execute code in restricted environment (sandboxing).
Trang 10pur-Filter 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 itbecause we innately want to trustpeople and other sources? Heavens,no! It’s hard because programmersare naturally lazy
Filtering input means writingmore code, writing smarter code
For those who wish to finish a ect quickly, this is daunting, and sothey quickly scribble down somecode—if, in fact, code can be scrib-bled—and deploy a release hoping
proj-to catch the problems in later
bug-fix (sometimes called security)
releases This can, however, causegreat problems in the meantime,not the least of which could consist
of SQL injection or cross-site ing (XSS)… or just plain bad data.Ensuring against bad datathrough filtering input is what we’llfocus on over the next three install-ments of Tips & Tricks So, comealong with me, and before we’refinished, you’ll be cynical and dis-trustful with the best of them—nolonger able to trust input of anykind—and, thus, security-con-scious
script-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.
Trang 11Why 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 theimaginary URL
h t : / x m l e / o m h ml (We’ll continue to come back to thisform during the next few months;
don’t worry—the code will beincluded in each column.) Now,this is a form we’ve all seen; it asksfor a name and contact informa-tion—no doubt, you’ve used a sim-ilar form in the past, and there’snothing wrong with this form, butthere are a few assumptions oftenmade about it
One assumption is that the
m x e g h attribute of the fields pre-h
vents a user from entering moretext than allowed This is wrong.While a Web browser can correctlyprevent a user from doing sothrough this particular form, there’snothing to stop the re-creation ofthis form on another server andusing it to submit a much longerstring of data
Another assumption is that theuser may pick states only fromamong the options listed in the
s a ee drop-down field Again, this iswrong and for the same reasons.The Web browser might preventsaid user from entering other values
when using this form, but if
recreat-ed, the sky’s the limit
We’re starting to see a patternemerge A Web form/application issafe only when used properly This
is obvious But if used improperly,then processing scripts can receiveany and all kinds of input
Still, let’s look at two moreassumptions about this form—justfor the heck of it
This form has a set number offields Does that mean these are theonly fields that can be submitted?No! Also, can we assume that theprocessing script([process_form.php] in this case)can only receive submissions fromthis form? The answer, again, is no.The form in Listing 2 illustrateswhy these assumptions are wrong.This form lives on another server—for example, at h t : / v l e a -
devi-s a ee field now has a value of “TheShire.” Wait a minute… that wasn’t
in our option list, but it doesn’tmatter because it’ll post just fine.Thirdly, this form includes a newfield: the j nk field This doesn’t domuch now, but consider a server
TTIIPPSS && TTRRIICCKKSS
1 <!— A form located at: http://example.net/form.html —>
2 <form method=”POST” action=”process_form.php”>
3 Name: <input type=”text” name=”name” maxlength=”50” />
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” />
6 $req -> setMethod ( HTTP_REQUEST_METHOD_POST );
7 $req -> addHeader ( ‘Referer’ , ‘http://example.net/form.html’ );
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?
Trang 12where rr g s e _ l b ls is enabled
and variables aren’t initialized—
think about what it can do
The R f r r Question
Invariably, the question now arises:
But what about the R f r rr? 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 f r rr 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 f r r header in
requests The R f r r, when includ-r
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 f r rr 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 f r rr 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 f r r to blockr
requests from other sites:
if
(strcmp($_SERVER[‘HTTP_REFER-ER’],
‘http://example.net/form.html’)
== 0) {
// It came from the right
place, so let’s process it }
Now, this snippet of code will erly thwart a form such as the one
prop-in Listprop-ing 2 from postprop-ing to
p o e s f r hp, so long as theclient includes a R f r rr headerthat doesn’t match, but mischie-vous users aren’t in the business of
being foiled by clients Let’s
consid-er anothconsid-er means of posting andtake a look at Listing 3
The code in Listing 3 is similar tothat found in Listing 2 in that itposts to p o e s f r hp from adifferent location and bypasses allthe local constraints placed on it(e.g m x e g hh and any client-sidescripting) However, Listing 3 is dif-ferent because it doesn’t rely on a
Web browser and, thus, can modifyany part of the request In this case,
P A : H T _ e u st generates avalid P ST request, while adding a
R f r rr header Thus, the scriptsuccessfully posts to
p o e s f r hp because it sends
a valid R f r rr header with a valuethat p o e s f r hp expects
Now You’re Getting It
And so, we must filter the input It’sthat simple We cannot be sure theinput comes from the proper loca-tion, nor are we sure it is exactlywhat we want In fact, we’re prettysure it’s not
Feeling distrustful yet? Good.Great, even Do not trust inputfrom users, from anywhere This iswhy it’s important to ensure thatinput received is input expected
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 ;
Trang 13The 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 ff r t l, as in the l R f 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 T,T
$ P ST, and $ C O IE We’ll not look
in $ R Q E TT, 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 Q E T ‘ a e ]] could refer to
$ G T ‘ a e ], ] $ P S [ n m ’], or
even $ C O I [ n m ’], so we want
to be sure it’s coming from the
cor-rect location, which is P ST in this
case
Luckily for us, PHP has already
done the work of capturing the
input In p o e s f r hp, the
val-ues passed by the input from—
f r t l (or from wherever it wasl
submitted)—are in $ P ST But the
data in $ P ST, 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 thatmindset includes being wary ofinput
Now, to keep track of our good
data, we’ll store everything that’sconsidered clean (as in: it conforms
to expectations) to the aptly named
$ l an array, which will somewhatmimic everything that’s in $ P ST—
without all the evil tendencies
One approach that I often see is asanitizing function that gets applied
to the $ P ST array, as seen inListing 4 While this type ofapproach removes harmful charac-ters, it does not provide a whitelistsolution Instead, it blacklists poten-tially harmful characters (controlcharacters) and escapes the input(with h m e t t e ( ), which is not
a part of the filtering process We’re
only concerned with filtering the
input at this point, so we want theraw data—filtered, but raw
Escaping will take place during theoutput stage, which isn’t coveredhere
A whitelist approach defines thevalid range of characters/numbers,the acceptable values (of a s l c
field, for example), and the allowedfields For now, let’s take a look atdefining the allowed fields toensure we receive and processnothing more than expected
Listing 5 gives a whitelist examplefor defining the allowed fields First,
we use the $ h t _ i tt array todefine the allowed fields Then, werun the $ P ST array through the
f l e ( function using
$ h t _ i tt as a model What’sreturned to the $ l an array is theexpected input Anything unex-pected is left back in $ P ST where
it safely remains excluded from therest of the script
This is a very simple approach
that does not include any furtherinput checking—for now Though, Ihope it is evident how thisapproach adds a level of flexibility
to the filtering process For ple, imagine a $ o t w i e l st,
Wrap Up
By now, you should be fully vinced that all input is evil and whyit’s important to filter all incomingdata When it comes to input, thereare no guarantees as to the origin ofthe data or the type received.Whether working with GET, POST,cookies, RSS feeds, and the like,always filter input—regardless
con-Tune in next month when we’llwrestle more input to ensure inputreceived is input expected
TTIIPPSS && TTRRIICCKKSS
To Discuss this article:
http://forums.phparch.com/238
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 ra amsey@ @php p .net tor read his blog at h ht ttp:// /benra amse ey y.com/ /.
Input Filtering, Part 1: Why Filter?
Trang 14Object-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 n ow object in a graphical user interface framework
could collect any number of control objects — a M nu,
a S i er, and a B t on, 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 r y type andy
rich set of array manipulation functions (Indeed, giventhe combination of the native array type in the lan-guage and a host of flexible functions designed to workwith this native type, you need a pretty compelling rea-son not to use arrays as your means of manipulatingcollections of objects.)
REQUIREMENTS
Code Directory iterator
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.
Pattern
by Jason E Sweatauthor of
php|architect’s Guide to PHP Patterns
Trang 15FEEAATTUURREE
Here’s native array iteration in PHP:
$test = array(‘one’, ‘two’, ‘three’);
echo $output; // produces ‘onetwothree’
The r s t )function restarts iteration to the beginning
of the array; c r e t )returns the value of the current
element; and n x ( advances to the next element in
the array and returns the new c r e t ) value When
you advance past the end of the array, n x ( returns
f l ee 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 containthe details of how to manipulate a specific collection,including which items to show (filtering) and in whatorder (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 ter work in PHP 4 as well, albeit with a healthy amount
chap-of reference operators added) The object, L n a le,represents media such as movies and albums and isintended to be part of a web site or service to let usersreview or lend portions of their media collection toother users (For this example, do not concern yourselfwith persistence and the like.)
Let’s start with the code in Listing 1 as the basis forthe class and write some tests
To implement the requirements of this initial test, ate a class with a few public attributes and some meth-ods to toggle the values of these attributes, such as that
cre-in Listcre-ing 2
L n a le is a good, generic start Let’s extend it totrack items like DVDs or CDs
Figure 1
Trang 16M d a extends a L n a le 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 d a has three publica
instance variables, M d a : a e, e M d a : e rr, and
M d a : y e The constructor takes two arguments ande
stores the first in $ a e and the second in e $ e rr 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 b a y Like a reg-y
ular library, L b a yy should be able to add, remove and
count the items in the collection Eventually, L b a 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 b a y:y
class LibraryTestCase extends UnitTestCase {
Now add some interesting features to the test:
class LibraryTestCase extends UnitTestCase {
An easy way to implement a d ) is to piggyback on
PHP’s flexible array functions: you can add items to an
array instance variable and use c u t ) to return the
number of items in the collection
L b a yy 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 d a and a L b a y classes usedy
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 );
6 public function checkout ( $borrower ) {
7 $this -> status = ‘borrowed’ ;
8 $this -> borrower = $borrower ;
9 }
10
11 public function checkin () {
12 $this -> status = ‘library’ ;
7 public function construct ( $name , $year , $type = ’dvd’ ) {
8 $this -> name = $name ;
9 $this -> type = $type ;
10 $this -> year = (int) $year ;
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
Trang 17FEEAATTUURREE
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 r t )to go tothe beginning of a collection, n x ( to move to the
next item in sequence as you iterate, c r e t t m ) toretrieve the current item from the collection as you iter-ate, and i D n ( to indicate when you have iteratedover the entire collection
In the next section, we are going to create the
L b a y o I e a or 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 b a y is to write a new test case for the newy
concrete Iterator Since each test method will be
manipulating a L b a yy filled with M d aa instances, youcan employ the U i T s C s : s t p ) method topopulate a variable with a L b a yy in a known state foreach test (For the purposes of this article, treat
U i T s C se as a generic unit testing suite The ated code does, however, serve to illustrate how
associ-L b a yy should perform.)
Start by adding the L b a y : e I e a o () method
as a FactoryMethod for instances of the
$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 function construct ( $collection ) {
7 $this -> collection = $collection ;
9 while ( $item = $it -> next ()) {
10 $output = $item -> name ;
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 );
Trang 18The g t t r t r ) method passes the L b a yy’s $ o
-l c i nn 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 operoper-ates
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 s G t o I e a o ( method to match
the Iterator design pattern The i D n ( method
should only be true if you’ve iterated over the entire
collection If the iterator’s just been created, i D n (
should obviously return f l ee to indicate it’s okay to
As usual with Test Driven Development (TDD),
imple-ment the simplest possible code that satisfies your test
So, what should happen during the first iteration.
c r e t t m ) should return the first M d a objecta
added in the I e a o T s C s : s t p ) method and
i D n ( 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’);
It’s critical that L b a y o I e a or receives the $ o
-l c i nn in the constructor (see the minimal tation of L b a y above) and returns the y c r e t )item
implemen-of that array from the c r e t t 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 x (
method should change what item is returned by the
c r e t t m )method This test captures that
4 function getIterator ( $type = false ) {
5 switch ( strtolower ( $type )) {
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 ;
19 while ( $item = $it -> next ()) {
20 $output = $item -> name ;
Trang 19The third iteration looks much like the others, except
the i D n ( method must return t ue You also want
n x ( 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
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 Thisrequires a new accessor method in L b a yy to fetch anobject by key
class Library { //
function get($key) {
if (array_key_exists($key, $this->collection)) { return $this->collection[$key];
} } }
Also, you’d pass $ h s (the library itself) to the con-s
structor instead of $ h s > o l c i nn (the array taining the Media collection) in the
con-L b a y : e I e a o ( method
The “external” iterator would then just track a
point-er intpoint-ernally to know which element of the L b a y col-y
lection it’s currently referencing, and would use the erence to the L b a y passed in the constructor to cally
ref-the g t )method to retrieve the current object
The implementation seen in Listing 6 assumes thatyour collection array is indexed starting with 0 and iscompletely 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 x ( , c r e t t m ), and i D n (
into just n x ( by having the latter either advance andreturn the current item from the collection or returnfalse if the entire collection has been processed
Listing 7 shows one way to write a test for this tion of the API
varia-Notice the simplified control structure for looping
n x ( returns an object or f l e, allowing you to per-e
form the assignment inside the w i ee loop conditional.The next few examples explore variations of the
Iterator pattern using the smaller interface As a
con-venience, change the L b a y : e I e a o ( method
to a parameterized FactoryMethod so you can get either
the four-method iterator or the two-method iterator(n x ( and r s t )from that single method)
class Library { //
function getIterator($type=false) { switch (strtolower($type)) { case ‘media’:
} }
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 ();
Trang 20Here, L b a y : e I e a o ( now accepts a
parame-ter to select what kind of iparame-terator to return The default
is L b a y o I e a or (so the existing tests still pass
Passing the string m d a to the method creates anda
Oops! The dreaded test failure! What caused this?
Somehow, the first iteration was skipped—that’s a bug
To fix the error, return c r e t )for the first call of the
n x ( method
The code in Listing 8 corrects our logic error and vides a streamlined w i ee loop iterator
pro-Filtering Iterator
With Iterators, you can do more than just present each
item of the collection, you can also select which itemsare presented Let’s modify the L b a y : e I e a o (
to allow two additional iterator types (Listing 9)
The L b a y v i a l I e a or class should only ate over items that have a status of “library” (recall thatthe c e k u ( method changes the status to “bor-rowed”)
iter-The test in Listing 10 creates a new M d a instancea
and stores it in the variable $ vd The first highlighted
a s r E u l ) assertion verifies that the new item ispresent when iterating with L b a y v i a l I e a or.Next, the test uses the c e k u ( method and verifies
that the new item is missing from the display
The code to implement filtering (Listing 11) is verysimilar to the L b a y t r t r : e t ), except filtering
is done prior to returning the item If the current itemdoes not match the filter criteria, the code returns
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 ;
7 function construct ( $collection ) {
8 $this -> collection = $collection ;
18 $sort_funct ( null , null , $this -> collection );
19 $this -> sorted_keys = $this -> collection -> keys ();
20 usort ( $this -> sorted_keys , $sort_funct );
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 ;
Trang 21Sorting 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 MM d aa in the
col-lection by release date
For a test (Listing 12), add some M d aa instances with
dates older that those of the items added in the s t 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 $ a e values in ae
string, a string is formed from both the $ a ee and $ e r
properties, which is then appended to an $ u p t array.t
The implementation of L b a y e e s d t r t rr is
nearly identical to L b a y t r t rr, 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 o t )statement sorts the $ o l c i nn array prior
to iteration You can avoid copying all of the other codefor the class by simply inheriting from the
L b a y t r t rr class itself
Is it possible to use an external iterator to accomplishthis same sorted iteration? Yes, but you must pull a fewtricks 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 haveaccess to the collection so it can fetch members forcomparison However, because the generated function
is used in a u o t ), you don’t have the option of ing the collection as an additional parameter Instead,you can use the trick shown in the code block above tostore a reference to the collection inside the functionprior to calling it with u o t )
pass-What you’re sorting is the list of keys for the tion When u o t )is complete, the keys will be sorted
collec-in order by the year attribute of each object collec-in the lection
col-In the n x ( method, an object in the collection is
accessed via the g t ) method, but indirectly through
the $ o t d k ys mapping If you recall the externalversion of the GoF-style iterator, arrays with gaps orstrings in the keys could be problematic This same trickcould be used for a simple external iterator to alleviatethe 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 PHPLibrary” (SPL) iterator
The w i e loop structure used so far is very compacte
and usable, but PHP coders may be more comfortablewith the f r a hh structure for array iteration Wouldn’t
it be nice to use a collection directly in a f r a hh loop?That’s exactly what the SPL iterator is for
(Even though this article has been written entirely for
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 ;
20 new StandardLibraryIterator ( $this -> collection );
21 $this -> iterator -> rewind ();
22 }
23 }
24 ?>
Listing 17
“I terator couples the object-oriented programming principals
of encapsulation and polymorphism ”
Trang 22PHP 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 hhttp://wwww sitepoint.com/ aarticle/php5-ss ttan
d
dardd libraryy.)
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 FF r a h b e i r ry, and
r w n ( k y )returns the current index of your
collec-tion r w n ( is like r s t ): iteration begins at the
start of your collection See Listing 15
Here we just implement the required functions
work-ing on our $ o l c i nn attribute (If you don’t
imple-ment all five functions and you add the i p e e t
I e a or 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 l m r h c o e c a l L b a yy
The only difference between this case and the test for
S l t r t r e t a ee is the class of the $ h s > i
attribute created in the s t p ) method That makes
sense: the two classes must behave identically
Listing 17 contains P l m r h c o e c a l L b a y.y
L b a y is extended to get the collection manipula-y
tion methods The SPL methods are added, too, all
del-egating to the $ t r t r attribute, which is created inr
r w n ( Below is the code for the
S a d r L b a y t r t r.r
The code in Listing 18 should look familiar:
essential-ly, it’s a copy of the five SPL functions from the
F r a h b e i r ry 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 r a hh control structure to loop
The new i e a o T p ( 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 e a o T p (
method again, the code is actually implementing the
1 <?php
2 class StandardLibraryIterator {
3 protected $valid ;
4 protected $collection ;
5 function construct ( $collection ) {
6 $this -> collection = $collection ;
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 ;
10 function iteratorType ( $type = false ) {
11 switch( strtolower ( $type )) {
22 $type = $this -> iterator_type ;
23 $this -> iterator = new $type ( $this -> collection );
24 $this -> iterator -> rewind ();
25 }
26 }
27 ?>
Listing 20
Trang 23State pattern, rather than the Strategy pattern.)
You can easily implement RR l a e L b a y t r t r byr
extending S a d r L b a y t r t r and overriding ther
constructor to add the sorting of the incoming
array And with that you have a working
P l m r h c o e c a l L b a yy
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 r a hh control
structure is indeed cool The only unfortunate issue
with the SPL implementation is the significant potential
for namespace clashing with “I e a or” How much
PHP 4 object-oriented code has some sort of an
I e a or class as a base class for the libraries’ iterators?
Of those, how many define the five required methods
in the same capacity? Perhaps i p e e t FF r a h b e
would have been a less intrusive name If you choose touse the SPL, you should investigate the other support-
ed iterators, like R c r i e r a I e a or and ous other flavors
numer-F
FEEAATTUURREE
Available Right At Your Desk
All our classes take placeentirely through the Internetand feature a real, live instructor that interacts with each student through voice or real-time messaging
What You Get
Your Own Web SandboxOur No-hassle Refund PolicySmaller Classes = Better Learning
Sign-up and Save!
For a limited time, you canget over $300 US in savings
just by signing up for our training program!
New classes start every three weeks!
http://www.phparch.com/cert
To Discuss this article:
http://forums.phparch.com/233
Jason has been an IT professional for over ten years He is currently an application 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
devel-j
The Iterator Pattern
Trang 25FEEAATTUURREE
Whether 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 managepermissions for many different types of projects Themain elements are users and permissions As far as usersare concerned, you usually need to manage groups androles Permissions are created as a flat list whereby eachapplication using the library shall be able to have itsown, independent permissions list Those permissionsmust 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, thatallows grouping objects by type So, we end up with:
• Users, groups and roles
• Permissions
• Objects and object categoriesUsers can be part of one or more groups, and eachgroup 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.
for Permission Management
by Simone Grassi and Bernhard Gaul
REQUIREMENTS
Other Software Apache, MySQL, Flash plug-in
Code Directory permissions
Trang 28ation of group hierarchies Later, we will see why we
need roles and how they associate permissions to
objects
In an application that requires permissions, you will
usually have many different objects to which these
per-missions may be applies Each object will probably have
a unique key (database primary keys) within its
catego-ry If we use object categories it will allow us to apply
permissions to single objects by specifying the object
category as well as the unique id of the object The
per-missions database will use the same unique id of the
object that is used in the application database Our
library assumes that these unique identifiers are
inte-gers
Permissions to Users and Groups
A user can be assigned permissions, directly If, for
example, a RR AD permission is assigned to a user,
direct-ly, he will be granted this permission in any case, on all
objects of any possible object category Groups, on the
other hand, are useful in different ways: first to allow
the creation of hierarchies, using subgroups; second, if
a set of permissions is assigned to a group then every
user associated with the group will be granted those
permissions It will be enough to change the
permis-sions assigned to the group to change those associated
with the individual users
How do you associate permissions with users and
groups? There are three different possible ways:
• Directly: the assigned permission is valid on
all objects of all categories
• Relative to a category of objects: the sion applies to all objects that are part of thiscategory of objects
permis-• Relative to a single object: valid only for thespecific object within a specific categoryThe objective is to satisfy the requirements of differ-ent scenarios As an example, let’s imagine we have anapplication that manages users’ access to documentswithin different folders In this scenario, there are atleast two categories of objects: documents and folders.Assignment of a permission, directly to a user or group
of users, is useful, for example, to allow the tor to have write permissions on all folders and docu-ments (that is on all objects of all categories of objects).Assigning permissions to a single category of objectsallows, for instance, assigning read and write permis-sions to a single user on all folders, creating a sort offolder administrator Finally, assigning permissions on asingle object allows gives specific access—like read orwrite—on a single folder (e.g a specific user may onlyaccess a specified folder with write permission)
administra-Permissions can be assigned to groups in the sameway as to users—that is directly to the group, relative to
a specific category of objects, or to a single object Thisallows the creation of permission profiles, and usersassociated with a given group will inherit this profile(there could be, for instance, a group of folder admin-istrators or document administrators)
Figure 1
Trang 29Why Groups are Not Enough?
We have seen that we can assign permission to both
users and groups (in a general way, to all objects, only
on a category of objects or on a single object) For
many projects, though, this will not be enough What
is needed is the possibility to assign a set of permissions
to a user or group, on a specific object or category of
objects To account for this need, we introduced the
concept of roles
Take a simple example: within a sample application
where users use and manage folders and documents,
there could be the need for a publisher role, defined as
a user allowed to “publish” documents—adding
docu-ments to folders A publisher would need to have
access permission on all folders to create new
docu-ments within them This role could be assigned to all
folders, in which case the role is assigned to the user
relative to a category of objects (the folder category)
Or, a user could be defined as publisher for just a single
folder In this case, the role is assigned to the user only
on the specific object (the folder that is part of the
cat-egory folders) As you can see from Figure 1, the
differ-ence between groups and roles is how those entities are
related to users A user is part or not part of a group,
but a role is assigned to a user relative to an object
cat-egory (or relative to a single object)
Note that Figure 1 does not show the “object” This
entity is undefined, as every application will have their
own entities that will act as objects We provided 3
fields, though, to associate object categories with
objects: oo j c _ d t b ee, o j c _ d f e d a e ande
o j c _ d d s r p i n f e d a e For each object cat-e
egory, o j c _ d t b ee is the name of the table that
stores the objects that are part of this category The
o j c _ d f e d a ee field stores the name of the field
that is the primary key of the object table Finally, the
o j c _ d d s r p i n f e d a ee field stores a tion (or title) of the object The use of those fieldsallows the developer to retrieve information about asingle object, directly from the table created by theapplication that uses the permission library
descrip-The Library
Like many other libraries, our permissions tion is a single class and can be used by “client”-soft-ware through a single API All data is stored in a data-base (we used MySQL), and PEAR::DB_DataObject isused as DB Abstract Layer which makes it easy to movethe library to other databases Configuration is simple,and a few parameters are enough to enable DataObject
implementa-to communicate with the DB
An Example Application: Folders and Documents
The code included with php|architect allows you to seethe library in action The example implementationshows permissions management in a small application.All we need to manage are folders and documents Wehave users, and each of them has different needs Toaccommodate these needs, we will use the differentcapabilities of the library The first thing that
e a p e p p (see the zip file that accompanies this arti-p
cle) needs to do is instantiate the class:
$auth = &new authorization_manager($username);
Passing the username is sufficient; it allows the class toretrieve permissions information about that user Still,you can see the API in action:
docu-w i ee, an array is prepared, it contains the d c m n _ d,d
d c m n _ a e and information about permissions Ase
you can see, to determine if the current user has R A
permission, we just call a t o i e ) The first ter is the requested permission, and the second param-eter is the object category (O J C _ Y E D C M NT) Theobject id, in this situation, is the d c m n _ d.d
parame-The API would return t ue if the current user has thispermission, false otherwise In the example, you cansee two tables: in the first, a list of folders; in the sec-ond, a list of documents from the current folder Thepermissions are represented by R AA (read-write-add ele-ments) for folders and RW (read-write) for documents.When the letter x is present, it means the current userx
does not have this permission
able to manage permissions
for many different
types of projects ”
Trang 30Changing the user, by using the drop-down menu,
you can see how different permissions are assigned to
different users See the database entries to fully
under-stand how this is implemented, with groups, roles, and
direct permissions
Let’s see, user by user, how permissions are assigned
The ss p r s rr user has direct permission to R AD,
W I EE and A D E E E TS on everything
The d v l p rr user has permissions on documentsinside source folders This is implemented by assigningthe publisher role to this user
The f l e a m nn user has all permissions on all ers This is made possible by assigning the publisherrole to the user, but not to a specific object It isassigned to the f l e s object category This gives thes
fold-user permissions on all folders Note that this fold-user has
8 <form method=post action=”example.php” name=”perm_library”>
9 <a href=”example.php”>List of Folders</a><br/><br/>
10 <?
11 $users = array( 0 => ’superadmin’ , ’folderadmin’ ,
12 ‘publisher’ , ’reader’ , ’developer’ );
13 print ‘Select user:<select name=username ‘
14 ’ onChange=”javascript:window.document.forms[0].’
15 ’submit();”>’ ;
16 for ( $i = ; $i < count ( $users ); $i ++)
17 print “<option” (! strcmp ( $users [ $i ], $username )?
18 ‘ selected>’ : ’>’ ) $users [ $i ] ’</option>’ ;
26 // View the list of folders
27 $fold_db = &new DataObject_Folders ();
33 if ( array_key_exists ( ‘folder_id’ , $_REQUEST ))
34 $actual_folder_id = $_REQUEST [ ‘folder_id’ ];
35 while ( $fold_db -> fetch ())
36 {
37 $folders [ $i ][ ‘folder_name’ ] = $fold_db -> folder_name ;
38 $folders [ $i ][ ‘folder_id’ ] = $fold_db -> folder_id ;
39 $folders [ $i ][ READ ] = $auth -> authorize (
40 READ , OBJECT_TYPE_FOLDER , $fold_db -> folder_id );
41 $folders [ $i ][ WRITE ] = $auth -> authorize (
42 WRITE , OBJECT_TYPE_FOLDER , $fold_db -> folder_id );
43 $folders [ $i ][ ADD_ELEMENT ] = $auth -> authorize (
44 ADD_ELEMENT , OBJECT_TYPE_FOLDER , $fold_db -> folder_id );
50 $doc_db = &new DataObject_Documents ();
51 $doc_db -> father_folder_id = $_REQUEST [ ‘folder_id’ ];
52 $doc_db -> find ();
53 $i = 0
54 while ( $doc_db -> fetch ())
55 {
56 $docs [ $i ][ ‘document_name’ ] = $doc_db -> document_name ;
57 $docs [ $i ][ ‘document_id’ ] = $doc_db -> document_id ;
58 $docs [ $i ][ READ ] = $auth -> authorize (
59 READ , OBJECT_TYPE_DOCUMENT , $doc_db -> document_id );
60 $docs [ $i ][ WRITE ] = $auth -> authorize (
61 WRITE , OBJECT_TYPE_DOCUMENT , $doc_db -> document_id );
62 $docs [ $i ][ ADD_ELEMENT ] = $auth -> authorize (
121 if ( $auth -> authorize ( READ ,
122 OBJECT_TYPE_DOCUMENT , $docs [ $i ][ ‘document_id’ ]))
123 print ‘R’ ;
124 else
125 print ‘x’ ;
126 if ( $auth -> authorize ( WRITE ,
127 OBJECT_TYPE_DOCUMENT , $docs [ $i ][ ‘document_id’ ]))
Trang 31no permission on individual documents Even if a user
has permission to an object category, he does not
auto-matically receive the same permission on objects
with-in this category
The pp b i h rr user is a bit different from the f l e
-a m nn He has the role of publisher on all folders, but
this role gives only R AD and A D E E E TT permissions
So, the publisher can add elements and access all
fold-ers, but cannot modify the folder itself (lmoving the
folder elsewhere, for example)
The v e er user has R AD permission on all This
per-mission is granted through group membership V e e
is part of the G O P V E E SS group, which is given R A
permission on both object categories (folders and
doc-uments)
Figure 2 shows the list of users s p r d in is
select-ed, and the relative permissions, directly assigned tothis user are shown Figure 3 shows a more complexuse of permissions, as used in a real application TheFlash GUI shows the object category information Foreach of them, you can see which permissions areassigned to users, through roles, groups or directly InFigure 3 C R _ C I T is the selected object category NoT
users or groups have relations with C R _ C I TT Onlythe A e d MM i AA m n s r t r RR le has been assigned
to (at least) one user, relative to C R _ C I TT
We have seen how to assign permission in many ferent ways, directly to users, using roles, and throughgroups This scheme grants flexibility and can be adapt-
dif-ed to many applications with good initial planning Thedeveloper must determine which permissions will beneeded within his application, differenciating betweenobject categories, groups, and roles Again, it’s impor-tant to define the correct list of permissions After thisscheme is created it’s straightforward to add a t o -
i e ) calls in your code to let your code reflect the
planned permission scheme
Authorize: Our Application User Interface
The current user needs to be identified to the librarywhen the application begins execution After this,requests for the permissions of the current user can bemade via a single method, called a t o i e ) Everykind of authentication can be used to identify the user,the user table is very general, and can be shared withyour preferred authentication library The authorizemethod can be called in three different modes:
A t o i e P R I S O _ E I E): This specifies onlythe requested permission Authorize returns true onlywhen the current user has this permission, but notwhen it is only relative to an object or on an object cat-egory The user must own the permission outright (foreach object type) This is typically used to create
“super” users
A t o i e P R I S O _ E I E O J C _ Y E) :Determine if the current user has been granted the P R
M S I N D F NE permission on a specific category ofobjects (called O J C _ Y EE) For example, a user could
NO OT TE E::The Flash client is provided
as compiled file only, but some tation details, such as the applicationmodel for validating input fields using reg-ular expressions, can be found onBernhard’s homepage athttp://www.bgxcomponents.com
Trang 32implemen-have WW I EE permission on all documents (given that we
have a category of objects that includes all types of
documents)—this will grant W I EE permission on all
documents, but not on other categories of objects, like
folders, assuming we defined folders as a different
cat-egory of objects
A t o i e P R I S O _ E I E O J C _ Y E O J C _
D): You can determine if a given user has access to a
sin-gle, specific object To do this, you must specify both
the object category (O J C _ Y EE) and the unique id of
the object (O J C _ D) The D O J C _ D is unique only inD
the set of objects included in the O J C _ Y EE category
of objects
Common GUI for a common Library
So far, we’ve only talked about building a good library
that provides for the needs of many different
applica-tions, but what about administering the data? A
com-mon GUI, pre-built and easy to deploy, would be very
helpful Again, the objective is to provide a ready-made
package you can plug into your own application We
decided to provide this in form of a single, compiled
Flash file that communicates with the server via XML
Reasons to use Flash
For simple forms (e.g an ordering form, or even
shop-ping cart solutions) stateless HTML based GUIs that are
(re-)constructed and downloaded with every data
exchange are fine
For more complex applications like our permissions
editor, however, a solution that can maintain state on
the client and could also take care of some of the more
complex GUI components needed, like editable tree
structures, would be a distinct advantage
Flash provides rich, platform independent client
capabilities within a lightweight vector-based, easily
downloadable and well distributed runtime
environ-ment While Flash has always been very well known for
its graphic and animation capabilities, for our
permis-sions application it was more Flash’s extensive scripting
capabilities that were key In particular, Flash allows:
• data to be organized in such a way that onlysmall chunks need to be loaded as the userrequests them
• the use of complex data objects such asuser-permission trees on the client
• client-side state retention
• the creation of complex form based GUIs
• binding data to a large set of readily able GUI components like lists, combos, andtrees that can also be customized
avail-• the tracking of changes, client side, and mission of only data that has changed (e.g when saving)
sub-Flash has evolved into a true rich internet applicationarchitecture, meaning parts of the business logic canreside on the client while exchanging data only withthe server
Client-Server Communication
The API used to communicate between the Flash clientand the server application is generic so that the Flashclient could be swapped for any other client that cansend and retrieve data via HTTP and understands XML.How is this done? On the client side, we have creat-
ed a PHP page to which predefined Q e y t i g andg
F rm parameters can be sent to request certain types ofdata (e.g users filtered by a search parameter) in XMLformat The page can also receive data to be saved tothe database
For our Flash file, we have provided an external tings file which you can use to specify the exact URL forthe different calls By default we assume that the Flashfile resides in the same directory as the x l c e t r p p
set-page that processes the calls, but you could change theURL to whatever suits you The X L A I d c filec
describes the calls that can be made to the server Youcan try them out by simply entering the URLs into theaddress field of your browser
This document also describes the structure of theXML that is returned for each call The client is expect-
ed to populate an appropriate GUI with the submitteddata, and handle changes To submit changes to theserver, an XML string has to be sent as a form parame-ter to a PHP page that will handle the save request.Within this XML document are sections for changed,new and deleted data When notifying of new orchanged data, the whole object (e.g a user or groupdefinition) is sent, but in the case of a deletion, we sendonly the ID of the object in question This way you get
a very lightweight communication model for dataexchange, requiring only the minimum data to be sent
at a time
dynamic web pages - german php.node
news scripts tutorials downloads books installation hints
www.dynamicwebpages.de
sex could not be better |
Trang 33Client Customizations
With the ss t i g ml file from which Flash reads the
URL definitions for the commands, you can also control
the appearance of the client (to some extent) Primarily,
you can cjamge all of the labels that appear in the GUI,
allowing you to change the language from English to
whatever you need There are also some CSS-like style
definitions for the graphical appearance that you could
change, and finally regular expression validations for
various field types For example, you might want to
change the input requirement for passwords from
“^[a-zA-Z0-9]+$” to something else
Conclusion
The presented library should suit many applications,
allowing an immediate and easy implementation via
the permissions API Authentication types are not
pre-defined and can be created as needed A flexible and
easily deployable Flash GUI is provided (in the code
archive) to administer the permissions library database,
using a generic XML “gateway” that could be used to
create other front ends if needed
F
FEEAATTUURREE
PHP Library for Permissions Management
To Discuss this article:
http://forums.phparch.com/231
Simone is about to start a PhD at Trinity College in Dublin on Model-Driven Architectures next Obtober Bernhard is a multimedia developer and general user interface specialist based in Dublin.
EDITOR’S NOTE: The code provided by the
authors, for this article, is very extensive, and the submission contains binary files (the Flash client, for example) As such, we have decided to refrain from printing the entire code, and have instead included it only in the code archive (zip file) that accompanies this article.
Trang 34SITEWORX control panel
/mo SMALL BIZ $ 21 95
NODEWORX Reseller Access
All of our servers run our in-house developed PHP/MySQL
server control panel: INTERWORX-CP
INTERWORX-CP features include:
- Rigorous spam / virus filtering
- Detailed website usage stats (including realtime metrics)
- Superb file management; WYSIWYG HTML editor
INTERWORX-CP is also available for your dedicated server Just visit
http://interworx.info for more information and to place your order.
WHY NEXCESS.NET? WE ARE PHP/MYSQL DEVELOPERS
LIKE YOU AND UNDERSTAND YOUR SUPPORT NEEDS!
ORDER TODAY AND GET 10% OFF ANY WEB HOSTING PACKAGE
VISIT HTTP://NEXCESS.NET/PHPARCH FOR DETAILS
D e d i c a t e d & M a n a g e d D e d i c a t e d s e r v e r s o l u t i o n s a l s o a v a i l a b l e
/mo N EX R ESELL 2 $ 59 95
7500 MB Storage
100 GB Transfer Unlimited MySQL Databases Host Unlimited Domains PHP5 / MySQL 4.1.X NODEWORX Reseller Access
NEW! PHP 5 & MYSQL 4.1.X
PHP4 & MySQL 3.x/4.0.x options also available
We'll install any PHP extension you need! Just ask :)
MONEY BACK GUARANTEE
FREE DOMAIN NAME
WITH ANY ANNUAL SIGNUP
4.1.x
3.x/4.0.x