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

Tài liệu Php | architect docx

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.69 MB, 73 trang )


Certification Central

5 Editorial
To XML, or Not to XML!
6 What’s New!
57 Product Review
webEdition
by Peter B. MacIntyre
62 Product Review
DHTML Menu Studio
by Peter B. MacIntyre
67 Security Corner
Ideology
70 e x i t ( 0 ) ;
A Look at PHP in Government
by Andi Gutmans and Marco Tabini
9 Object-oriented vs. Relational Part II
Managing Distractions and Reverse-
Engineering Abstractions
by Rick Morris
17 Developing a PHP - XML Generator
by Man-ping Grace Chau
32 PHP 5 & XML
by Ilia Alshanetsky
42 Hiding Your Sins
Practical Caching for the PHP Developer
by Allen Smithee
50 Secure Your System with a Port
Security Guard
by Ron Goff


3
November 2004

PHP Architect

www.phparch.com
TABLE OF CONTENTS
II NN DD EE XX
php|architect
Features
Departments
TM
*By signing this order form, you agree that we will charge your account in Canadian
dollars for the “CAD” amounts indicated above. Because of fluctuations in the
exchange rates, the actual amount charged in your currency on your credit card
statement may vary slightly.
Choose a Subscription type:
CCaannaaddaa//UUSSAA $$ 9977..9999 CCAADD (($$6699..9999 UUSS**))
IInntteerrnnaattiioonnaall AAiirr $$113399..9999 CCAADD (($$9999..9999 UUSS**))
CCoommbboo eeddiittiioonn aadddd--oon
n $$ 1144..0000 CCAADD (($$1100..0000 UUSS))
((pprriinntt ++ PPDDFF eeddiittiioonn))
Your charge will appear under the name "Marco Tabini & Associates, Inc." Please
allow up to 4 to 6 weeks for your subscription to be established and your first issue
to be mailed to you.
*US Pricing is approximate and for illustration purposes only.
php|architect Subscription Dept.
P.O. Box 54526
1771 Avenue Road
Toronto, ON M5M 4N5

Canada
Name: ____________________________________________
Address: _________________________________________
City: _____________________________________________
State/Province: ____________________________________
ZIP/Postal Code: ___________________________________
Country: ___________________________________________
Payment type:
VISA Mastercard American Express
Credit Card Number:________________________________
Expiration Date: _____________________________________
E-mail address: ______________________________________
Phone Number: ____________________________________
Visit: http://www
.phparch.com/print
for
more information or to subscribe online.
Signature: Date:
To subscribe via snail mail - please detach/copy this form, fill it
out and mail to the address above or fax to +1-416-630-5057
php|architect
The Magazine For PHP Professionals
YYoouu’’llll nneevveerr kknnooww wwhhaatt wwee’’llll ccoommee uupp wwiitthh nneexxtt
S
ubscribe to the print
edition and get a copy of
Lumen's LightBulb — a
$499 value
absolutely FREE


!
In collaboration with:
Upgrade to the
Print edition
and save!
For existing
subscribers
Login to your account
for more details.
EXCLUSIVE!
EXCLUSIVE!
† Lightbulb Lumination offer is valid until 12/31/2004 on the purchase of a 12-month print subscription.
November 2004

PHP Architect

www.phparch.com
EE DD II TT OO RR II AA LL RR AA NN TT SS
php|architect
Volume III - Issue 11
November, 2004
Publisher
Marco Tabini
Editorial Team
Arbi Arzoumani
Peter MacIntyre
Eddie Peloke
Graphics & Layout
Arbi Arzoumani
Managing Editor

Emanuela Corso
Director of Marketing
J. Scott Johnson

Account Executive
Shelley Johnston

Authors
Ilia Alshanetsky, Ron Goff, Man-ping Grace
Chau, Peter MacIntyre, Rick Morris,
Chris Shiflett, Allen Smithee
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,
listings 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-2004 Marco Tabini &
Associates, Inc. — All Rights Reserved
I
have a confession to make. I’m an XML-phobe. I know, in today’s soci-
ety of political correctness and respect for other cultures, that’s nothing

short of inexcusable, but what can I say? I’m getting old and, therefore,
cranky.
When I first heard of XML a while back, I couldn’t help but thinking of
it as the answer to a question nobody asked. This feeling was, in fact, aug-
mented by the continuous misuse of this outrageously verbose in all sorts
of places where it really didn’t belong. Have a configuration file? Let’s
make it XML. Need to store data? Why use a database—we have XML!
At the time, I was part of a team whose job was interfacing a Microsoft-
based web system to a legacy mainframe system, which, at the time, was
no walk in the park, as everything had to take place through a carefully-
choreographed exchange of text files. I remember that, at some point, the
irony of it all struck me: here was a perfect scenario in which being able
to use XML would have been, at last, beneficial (although manipulating
text files with ASP was about as pleasant as stapling your lips together)
and, of course, there was no way I could have used it, because it would
have required too much work on the mainframe side. On the other hand,
I had to use XML for pretty much half of the configuration files on the
Windows machine. Lovely.
As time has gone by, the XML craze has somewhat faded to a more rea-
sonable level: we now use it for its intended purpose—the structure com-
munication of data between two or more heterogeneous systems—more
often than not. It has become the basis of XHTML, whose importance is,
in my opinion, not in the beauty of a “well-designed” web page, but in
the fact that any robot should be able to parse XHTML, thus paving the
way for better search engines, more focused online advertising, and so on.
Still, despite (or, more probably, because) XML was designed to be a
human-readable format, manipulating an XML document “by hand” is
not fun—regardless of how good your particular platform is at handling
strings and arrays. What it takes is a strong set of tools designed specifical-
ly to parse, modify and produce XML documents and are capable of inter-

facing with the underlying platform in a way that hides the minutiae of
the language from the developers.
PHP 4 had what could be considered a germinal XML infrastructure, but
with PHP 5 we now have a robust toolset (despite a few kinks here and
there) that can be used to perform all sorts of XML manipulations—and
which will be indispensable to the introduction of PHP in an enterprise
environment that requires interoperation between a variety of different
systems.
I had a taste of just how important this is to our readers during
php|works, when I sneaked into Ilia Alshanetsky’s session on PHP 5 and
XML… and had to leave because I couldn’t get a seat. Once the confer-
ence was over, therefore, I had to ask Ilia if he wanted to write a compa-
rable article for the magazine; the result is this month’s main piece.
As usual, Ilia came through in style with an article that explores every
single facet of the functionality available in PHP 5 (with a quick look at
what was available in PHP 4), with plenty of practical examples and real-
world suggestions.
I hope you will find it as useful as I did—and that it will help you in your
projects.
Until next month, happy readings!
EDITORIAL
TM
T
o
XML
, or
N
ot to
XML!
November 2004


PHP Architect

www.phparch.com
6
What’s New!
NN EE WW SS TT UU FF FF
Zend announces the PHP 5 Coding Contest Winners
Zend has released the names of the winners of the PHP 5 Coding Contest!!
“ It really wasn’t that easy to choose between the top applications; there are quite
a few that ended up in the top 20 or so that could just have easily been in the
top 6. Without your input, we’d still be arguing over them!
A special mention goes to MyObjects
*
, a project that provides its own persistent
object library and tools for generating classes directly from a MySQL database. A
minor coding style issue was all that prevented the project from being one of the
top prizewinners. The voters liked it too, and it ended up coming in 7th place.
Keep an eye out for the author, Erdinc Yilmazel of Turkey - we’d put money on
his winning next time, if there’s a next time!
Another special mention goes to Hive
**
, which came in 41st because nobody in
the public domain voted for it. We disagreed - it ranked 3rd in the judges list -
so we’ve scrambled around to find a judges prize for the author, Robert
Janeczek. Ironically, Robert describes Hive as ‘a low-level version of the PRADO
project’...
Our judges and the public agreed over PRADO
***
, which won outright. All we

need to do now is get a laptop to Qiang Xue, the author of the winning applica-
tion, and then we can sit around in the office drinking too much caffeine and
playing hangman with a clear conscience. “
For more information, and to try the winning software for yourself, visit
/>* [MyObjects ]
/>** [Hive]
/>*** [PRADO]
/>MySQL Version 4.1 Certified as
Production Ready
MySQL.com has announced that version
4.1 of its database management system
is now production-ready for large-scale
enterprise deployment:
“ MySQL AB, developer of the world’s
most popular open source database,
today announced the general avail-
ability of MySQL® 4.1. Certified by
the company as production-ready for
large-scale enterprise deployment,
this significant upgrade to the
MySQL database server features
advanced querying capabilities
through subqueries, faster and more
secure client-server communication,
new installation and configuration
tools, and support for international
character sets and geographic data.
MySQL 4.1 can be downloaded now
at


PHPX 3.5.4 Released
A quick note from
pphhppvvoollccaannoo..ccoomm
announces the latest version of PHPX:
“ After much too long in waiting, 3.5.4
can be downloaded. There are a lot
of new features, including a guest-
book and shoutbox, user groups
have been added and stuff that I
dont feel like putting here too!
PHPX is a constantly evolving and
changing Content Management
System (CMS). PHPX is highly cus-
tomizable and high powered all in
one system. PHPX provides content
management combined with the
power of a portal by including in the
core package modules such as FAQ,
polls, and forums. PHPX uses
dynamic-template-design, what this
means is that you have the power to
control what your site will look like.
Themes are included, but not
required. You can create the page
however you want, and PHPX will
just insert code where you want it.
No more 3 columns if you don’t want
it! Written in the powerful server
language, PHP, and utilizing the
amazingly fast and secure database

MySQL, PHPX is a great solution for
all size website communities, at the
best price possible...free! “
Zend Encoder for MAC OSX Now Available
Zend has announced the release of Zend Encoder for Mac OS X.
“ The Zend Encoder is the recognized industry standard in PHP intellectual property
protection. The Zend Encoder allows an unlimited number of PHP applications to
be distributed, while ensuring your investment and source code are protected
from copyright infringement.
Independent Software Vendors (ISV’s) and Professional Service Providers (PSP’s)
rely on the Zend Encoder to deliver their exclusive and commercial PHP applica-
tions to customers without revealing their valuable intellectual property. By pro-
tecting their PHP applications, these and other enterprises expand distribution
and increase revenue.
The Zend Encoder compiles and converts plain-text PHP scripts into a platform-
independent binary format known as a ‘Zend Intermediate Code’ file. These
encoded binary files are the ones that are distributed instead of the human-read-
able PHP files. The performance of the encoded PHP application is completely
unaffected!
The Zend Optimizer, a free download, is the run-time environment that enables
end-users to transparently execute these files as if they were regular PHP scripts.
The Zend Optimizer not only provides an additional level of increased security
against reverse engineering, it also improves performance speed. “
For more information visit:
www.zend.com
November 2004

PHP Architect

www.phparch.com

7
NNEEWW SSTTUUFFFF
Apache HTTP Server 1.3.33 Released
From Apache.org:
“ The Apache Software Foundation and The Apache HTTP Server Project are pleased to announce the release of version 1.3.33 of
the Apache HTTP Server (“Apache”). This Announcement notes the significant changes in 1.3.33 as compared to 1.3.31 (1.3.32
was not formally released). The Announcement is also available in German and Japanese .
This version of Apache is principally a bug and security fix release. A partial summary of the bug fixes is given at the end of this
document. A full listing of changes can be found in the CHANGES file. Of particular note is that 1.3.33 addresses and fixes 2
potential security issues: CAN-2004-0940
*
Fix potential buffer overflow with escaped characters in SSI tag string. And CAN-
2004-0492
**
Reject responses from a remote server if sent an invalid (negative) Content-Length.
We consider Apache 1.3.33 to be the best version of Apache 1.3 available and we strongly recommend that users of older ver-
sions, especially of the 1.1.x and 1.2.x family, upgrade as soon as possible. No further releases will be made in the 1.2.x family.

Apache 1.3.33 is available for download from
/>*
/>**
/>PostNuke Security Alert
Postnuke.com has posted a new security alert regarding a Hack into the the ZIP archive of PostNuke .750
“ We discovered last night that
was the target of a malicious attack and files in the ZIP archive
of PostNuke .750 were changed. Immediately upon discovering this all links to the downloads section were removed and on
Tuesday the 26th at 8:30 GMT the original download package was restored.
Our investigations so far have revealed the attack was initiated on Sunday, 24.Oct, at 23:50 (11:50 PM) GMT. The attacker used
an exploit in the download management software pafiledb to change the download address of PostNuke-0.750.zip to point to a
compromised archive. We must stress this is a security compromise of paFileDB and has nothing to do with the PostNuke appli-

cation.
Note, if you downloaded the tar.gz archive you are not affected so you do nothing, only those who downloaded the zip version
were affected and must take immediate action as detailed below.
The changes made by the hackers were in two places. First, during the installation routine all data submitted (this includes the
server, the database credentials, the admin name and password) is sent to a different server. Second, in one file there was code
allowing a malicious user to execute any shell command on the web server.
As noted before, immediate action is required from everyone who downloaded the .zip package between Sunday (24.Oct) at
23:50 GMT until Tuesday (26.Oct) at 8:30 GMT. “
For more information visit:
news.postnuke.com
Take Advantage of Marco’s Wonky Math and Save Up to $80
Our fall/winter 2004 subscription campaign is in full effect—and this year we have some great offers for all our sub-
scribers, regardless of whether you’re becoming a member of our family for the first time or if you’re been looking
forward for your copy of php|a since the very beginning.
Signing up for a php|a subscription (or adding another 12 months to your existing one) right now
means some great offers, which include:
• A $80 discount on the Zend Certification Guide
• A free 64MB USB Memory Key, complete with the php|architect logo
For more information, visit our website at
/>Errata
In last month’s Tips & Tricks column, John mentioned that a reader had pointed out a small flaw in his random-line access algo-
rithm. In true php|architect fashion, we misspelled his name—quoting him as Chris Cowell, while his real name is Chris Dowell. Sorry,
Chris!
November 2004

PHP Architect

www.phparch.com
8
NNEEWW SSTTUUFFFF

Looking for a new PHP Extension? Check out some of the lastest offerings from PECL.
WinBinder 0.27.093
WinBinder is an extension that allows PHP programmers to build native Windows applications. It wraps a limited but important subset
of the Windows API in a lightweight, easy-to-use library so that program creation is quick and straightforward.
Parsekit 1.0
This package provides a userspace interpretation of the opcodes generated by the Zend engine compiler built into PHP.
This extension is meant for development and debug purposes only and contains some code which is potentially non-threadsafe.
Imlib2 0.1
imlib2 is a very fast image manipulation library, but without the support for as many image formats as other libraries such as
imagemagick.
You will need the imlib2 library from
in order to compile this extension.
This extension is experimental. It's been tested on a number of Linux installs, but nothing else. Please report any bugs to the main-
tainer!
Translit 0.1
This extension allows you to transliterate text in non-Latin characters (such as Chinese, Cyrillic, Greek etc) to Latin characters. Besides
the transliteration, the extension also contains filters to convert to upper- and lower-case words in Latin, Cyrillic and Greek, and per-
form special forms of transliteration, such as converting ligatures such as the Norwegian "ÃE" to "ae," as well as normalizing punctua-
tion and spacing.
Check out some of the hottest new releases from PEAR.
PHPUnit 2.1.2
PHPUnit is a regression testing framework used by the developer who implements unit tests in PHP.
DB_odbtp 1.0.2
DB_odbtp is a PEAR DB driver that uses the ODBTP extension to connect to a database.
It can be used to remotely access any Win32-ODBC accessible database from any platform.
Mail_mbox 0.3.0
This extension can split messages inside an Mbox, return the number of messages, return, update or remove a specific message, or
add a message to it.
I18Nv2 0.9.1
This package provides basic support to localize your application, like locale based formatting of dates, numbers and currencies.

It also attempts to provide an OS-independent way to
sseettllooccaallee(())
and aims to provide language and country names translated into
many languages. It provides these classes:
• I18Nv2-OS-independent (Linux/Win32)
sseettllooccaallee(())
, other utilities
• I18Nv2_Locale-locale based formatter
• I18Nv2_Negotiator-HTTP negotiation of preferred language and charset
• I18Nv2_Country-multilingual list of country names
• I18Nv2_Language-multilingual list of language names
• I18Nv2_Charset-list of common and not so common charsets and aliases
• I18Nv2_AreaCode-list of international area codes (phone)
Stream_Var 1.0
Stream_Var can be registered as a stream with
ssttrreeaamm__rreeggiisstteerr__wwrraappppeerr(())
and allows stream-based access to variables in any
scope. Arrays are treated as directories, so it's possible to replace temporary directories and files in your application with variables.
Distractions Abound
Apparently, a few of our loyal readers have been won-
dering just when Part II of this series would come out,
or whether it had vanished into the
//ddeevv//nnuullll
bitbuck-
et. Please bear with me; since writing that first article I
have gone through three South Florida hurricanes and
the birth of my second child (a boy!). So, suffice it to
say that there have been a few distractions in my life.
But, in the best tradition of making lemons into lemon-
ade, let’s think about what distractions can teach us.

Foremost, I would have to say that they highlight the
need to think clearly and accomplish as much as possi-
ble in the shortest possible time (and if my parents had
known when I was 16 that I would grow up to write a
line like that, they would truly believe in miracles).
With that in mind, let’s think about how databases
help us manage distractions. I have a very small synop-
sis of what the relational model of data affords us: the
ability to name things in order to control them. That may
seem a tad simplistic, but think about it: relational data-
bases give us the ability to apply a distinct and clear
name with a value attached to everything—and, most
importantly, they don’t require any other mechanism
than a simple declaration of the named element and its
attributes in order to retrieve the associated value. In
other words, you don’t need to think about “the infor-
mation in column #2 of row #34,” or “the
eeyyee__ccoolloorr
field is in column #4 of this table.” Instead, the mecha-
nism for accessing your data simply is the statement of
what you are looking for. “Get all
eeyyee__ccoolloorr
values for
employees born before 1968” can be directly translat-
ed into
SSEELLEECCTT eeyyee__ccoolloorr FFRROOMM eemmppllooyyeeee WWHHEERREE eemmppllooyy--
eeee..bbiirrtthhddaayy >>== ‘‘11996688--0011--0011’’;;
. The fact that most data-
base systems also allow you to ask for the data on row
#34 and the value in column #2 should be regarded as

a nuisance rather than a feature, if you truly follow the
principles of relational database design.
Distractions also teach us that abstraction helps us
manage the organization of our lives. If we had to think
about every single step we took, we would be pretty
frustrated by the end of the day, but our bodies allow
us to abstract that into a general concept called “walk-
ing.” Thus, rather than thinking about moving our feet
up and down in the exact steps we will have to take in
order to get to the refrigerator, we just decide to walk
to the refrigerator, and let the abstraction take over
(believe me, with a wife, a 4-year-old and a newborn, I
have been doing a lot of walking to the refrigerator
lately). In the same way, both relational database sys-
tems and object-oriented programming allow us to cre-
ate abstractions that save us time in the future. They
just do so in different ways.
What’s wrong with this picture?
As we discussed in Part I, one of the biggest distractions
in modern programming is the “object-relational
November 2004

PHP Architect

www.phparch.com
9
FF EE AA TT UU RR EE
Object-oriented
vs. Relational
Part II

by Rick Morris
PHP: 4.x+
OS: Any
Other software: PostgreSQL version 7.4+
Code Directory: relational
REQUIREMENTS
To many object-oriented developers, there is a sense that
the relational model for data management is at odds with
the concepts of object-oriented development. Are these
views justified? Are they practical? In part II of this two-
part series, we build a simple example of an object-orient-
ed application that derives business logic from the data-
base without object/relational mapping.
Managing
Distractions and
Reverse-Engineering
Abstractions
impedance mismatch.” For example, let’s look at a
basic SQL query and online form that a PHP developer’s
apprentice might create. Our developer has been wise
in taking advantage of abstraction, so she uses the PEAR
HHTTMMLL__QQuuiicckkffoorrmm
class to generate the form for a simple
user signup script (see Listing 1). It is, undoubtedly, a
nice choice—and kudos to our aspiring guru for taking
the time to read, instead of just hacking a quick-n-dirty
HTML form with interspersed PHP. We will, for the
moment, assume that
$$ddbb
is an instance of a database

abstraction class with nice methods like
ccrreeaattee__eennttrryy(())
and
llaasstt__eerrrroorr(())
.
This example might look nice, clean and readable—
really a pleasure to look at if you are tired of the
spaghetti code littering many web-based applications.
So what’s wrong with it? Well, just think about what
has to be done if you have to modify the database: your
developer will have to modify every script that interacts
with the table and other DB structures that have been
changed. Amazingly, this is the expected—and accept-
ed—state of affairs for most application programming
out there, especially in the area of web-based software.
The benefits of the relational model are often seen to
be at odds with the capabilities of Object-oriented
Programming. While the relational model is based on
set-oriented thinking, which presents a unified logical
method of accessing and modifying all kinds of data,
object-oriented programming provides a metaphorical
approach to data and essentially uses custom functions
to bundle behaviors with it. While at first it seems logi-
cal that one would just develop objects in parallel with
the tables in one’s logical database design, we saw that
this leads to a fundamental problem: you inevitably end
up duplicating effort, as you slavishly model one envi-
ronment to follow the other.
Really, the best parallel to objects and behaviors in
the relational world could be datatypes and operators.

Think about it. The real objection is that datatypes are
seen as “scalar” and “primitives,” but there is actually
nothing in the relational model itself that prevents
datatypes/domains from being complex, composite, or
even customized by the user, along with customized
operators. This begs the question, however, since most
database systems don’t have a truly comprehensive
way to deal with custom datatypes. However, we can at
least take a step in that direction with the use of
domains.
A Note on Terminology:
Since this is an attempt at a serious look at what can be
accomplished by programming in accordance with the
relational model, we will use relational terminology.
Rather than “datatype”, we will refer to “domain” and,
rather than “table,” we will use the term “relation”.
There is a good reason for this: we should be able to
treat custom domains the same way as baseline scalar
datatypes like
IInntt
and, in fact, a domain is simply the
“set of all possible values” for a certain term (think
about your high school algebra). Also, a table is a rela-
tion, but so is a view (in fact, so is the result set from
any query or stored procedure). The point here is that
there is a decided advantage to our programming
front-end if we don’t make distinctions between
datatypes and custom domains, or between tables and
views. Your application front-end has no
real need to know the underlying design

of your database, but simply what is pre-
sented to it by the developer. Also, since
we are discussing an object-oriented
framework for PHP as it interacts with
relational databases, every classname will
have the prefix
RReell
. This is especially nec-
essary since PHP—even version 5—does
not have namespaces.
What would happen, though, if we did
associate every datatype in our DBMS
(along with custom domains and com-
posite types), to a class in our program-
ming framework? Of course, there would
still have to be some work done to tie in
the application framework with the data-
base, but it would not have to be associ-
ated with specific business logic, focusing
instead on more generic, abstract con-
cerns—the perfect case of code reuse, if
you will.
Now, what would happen if you
designed other classes “by composition
November 2004

PHP Architect

www.phparch.com
10

FFEEAATTUURREE
Object-oriented vs. Relational Part II
1 <?php
2
3 /* file: obj_rel.php */
4
5 require_once “HTML/QuickForm.php”;
6
7 $form = new HTML_QuickForm(‘user_signup’, ‘get’);
8 $form->addElement(‘header’, ‘’, ‘New User Sign-up’);
9 $form->addElement(‘text’, ‘username’, ‘Username’);
10 $form->addElement(‘password’, ‘password’, ‘Password’);
11 $form->addElement(‘text’, ‘firstname’, ‘First Name’);
12 $form->addElement(‘text’, ‘lastname’, ‘Last Name’);
13 $form->addElement(‘text’, ‘email’, ‘Email Address’);
14 $form->addElement(‘reset’, ‘btnClear’, ‘Clear’);
15 $form->addElement(‘submit’,
‘btnSubmit’, ‘Submit’);
16
17 $form->addRule(‘username’, ‘Your username is required’, ‘required’);
18 $form->addRule(‘password’, ‘Your password is required’, ‘required’);
19 $form->addRule(‘email’, ‘Your email address is required’, ‘required’);
20
21 if ($form->validate()) {
22
23 if($db->create_entry(‘new_user’, $_POST))
24 {
25 echo “Your validation email has been sent”;
26 }
27 else

28 {
29 echo $db->last_error();
30 }
31 }
32 else
33 {
34 $form->display();
35 }
36 ?>
Listing 1
rather than inheritance” to automatically “know” what
to do when presented with a specific table, query, or
other database construct, given that you already have a
class that parallels each datatype? Are these just rhetor-
ical questions? Not really.
If you think this through a little, you’ll find that the
concept we presented in the last article hints exactly at
this type of solution. In other words, rather than the
peculiarly brittle approach of creating a parallel class for
every table, we instead opt to model orthogonal con-
cerns, leaving us much freer to change one aspect of
the system without changing another. Now, if we want
to change the way our application deals with autonum-
bered primary key columns, for example, we just have
to change it in one place, instead of many. Adding val-
idation capabilities to our front-end is not such a frus-
trating experience anymore.
If you use domains, you have even more control. For
example, if you decide that wherever the “zipcode”
domain is used as a column definition, you want the

application to present it in the Courier font, it is a one-
time change (I’m sure you can imagine far more useful
ways of applying this approach to your own application
problems).
Of course, in order to do this sort of thing, you not
only need a class for every domain, but you also need
a way to “reverse engineer” every relation that you are
dealing with, in order to get the metadata for column
definitions, datatypes used, primary keys, and so on.
“What a huge task,” you might be thinking.
Fortunately, most of this work has already been done
for you; if you use either MySQL or PostgreSQL, you
will easily realize that phpMyAdmin and phpPgAdmin
have code that accomplishes all of the above—and
more. In fact, there is one such application for the
FireBird SQL engine as well (IBWebAdmin), and even
one for Oracle (phpOracleAdmin). You can think of this
reverse engineering to be similar to the concept of
“reflection” as used in programming languages to
reverse-engineer functions, classes, and objects in order
for a program to “understand itself” and modify its
behavior according to rules set by the programmer.
November 2004

PHP Architect

www.phparch.com
11
FFEEAATTUURREE
Object-oriented vs. Relational Part II

1 <?php
2
3 /* file: RelGui.php */
4
5 require_once(“HTML/QuickForm.php”);
6 require_once(“HTML/Table.php”);
7 require_once(“./relfiles.php”);
8
9 class RelGui
10 {
11
12 var $relation;
13 var $quickform;
14 var $mode;
15 var $dbconn;
16 var $metadata;
17 var $data; //collection of actual data retrieved
18 var $gui;
19
20 function RelGui($relation)
21 {
22 //$this->mode = $mode;
23 $this->relation = $relation;
24 //$this->dbconn = $this->relation->dbconn; //share the
same database connection already established in the $relation
object
25 $this->prepare();
26
27 }
28

29 function set_mode($mode)
30 {
31
32 $valid_modes = array(“list”, “view”, “edit”, “add”,
“insert”, “update”, “search”
);
33 //view, list, edit, etc...
34 if(in_array($mode,$valid_modes))
35 {
36 $this->mode = $mode;
37
38 if($this->mode == ‘list’)
39 {
40 $this->gui = new HTML_Table();
41 }
42 elseif($this->mode)
43 {
44 //if mode is not ‘list’, it is implied that we
are in single-record view/edit mode
45 $this->gui = new HTML_QuickForm(“{$this->rela-
tion->relname}”, ‘POST’);
46 }
47
48 }
49 else
Listing 4
50 {
51 die(“Invalid mode selected;”);
52 }
53

54 }
55
56 function prepare()
57 {
58
59 $this->metadata = $this->relation->get_metadata();
60
61 foreach($this->metadata as $colname => $colinfo)
62 {
63
64 if(in_array($colinfo[“type”],
array(‘integer’,’int4’,’int2’,’int8’ )))
65 {
66 $colinfo[“type”] = ‘int’;
67 }
68
69 $classname = “rel_{$colinfo[“type”]}”;
70
71 echo $classname;
72
73 if(class_exists($classname))
74 {
75
76 //compose column types in here
77 $this->data[$colname] = new $classname;
78
79 }
80 else
81 {
82

83 //default to char domain
84 $this->data[$colname] = new rel_text;
85
86 }
87
88 }
89
90 }
91
92 function render()
93 {
94
95 $this->relation->do_select();
96
97 if($this->mode == ‘list’)
98 {
99
100 //set header row
Listing 4:
Continued...
Continued on page 14
The more advanced ANSI-compliant systems such as
PostgreSQL have a very easy way to query metadata
through SQL (in PostgreSQL you query tables and
views in the
iinnffoorrmmaattiioonn__sscchheemmaa
schema/namespace).
Armed with the tools above to extract metadata, we
can easily construct a very basic system to present an
example of these ideas: first, we create a basic “inter-

face” class called
RReellDDoommaaiinn
, then a class for each
domain/datatype—for now, we’ll limit ourselves to
RReellIInntt
,
RReellFFllooaatt
,
RReellCChhaarr
,
RReellTTeexxtt
(Listing 2 - found in
this month’s code package). Next, we create a class
called
RReellaattiioonn
(Listing 3 - found in this month’s code
package), which will be composed of all domain
objects needed for any specific relation. It also incorpo-
rates whatever methods are needed to extract metada-
ta from the given relation.
Now, this is one aspect of how to combine an object-
oriented application framework with a relational data-
base system. It deals with your database at the micro-
scopic level. What about dealing with your database on
the macroscopic level? What if you could just “throw”
a table name at a certain class or group of classes, and
have the application just read the table metadata,
instantiate the right objects for each datatype in a col-
umn, and automatically build your form? If this sounds
like a too-good-to-be-true theoretical approach, just

think about it a moment: if you have a class for every
datatype, as well as classes to handle all the “mechani-
cal” aspects of connecting to the database, querying,
retrieving data, and so on, then all you need is a class
or set of functions for retrieving table/view metadata
and some methods for tying these classes together into
a logical interface for the database. Finally, we will have
a class called
RReellGGuuii
(Listing 4) to handle the display
and user interaction.
RReellGGuuii
can inherit from some
existing classes, such as PEAR’s
HHTTMMLL__QQuuiicckkFFoorrmm
, and
HHTTMMLL__TTaabbllee
(and many additional helpful PEAR classes,
if you wanted it to). The whole idea here is that your
entire application can pass every database interaction
through a dispatch file that looks essentially like the one
you see in Listing 5, with the classes in the listings men-
tioned above. In addition, the code in Listing 6 ties
them together as required files. Of course, as I men-
tioned earlier, PEAR’s
HHTTMMLL__TTaabbllee
and
HHTTMMLL__QQuuiicckkffoorrmm
are required.
Briefly, here is what is going on in these files:

• When a browser request is made to Listing
5, at a minimum, the GET parameters for
rreellnnaammee
and
mmooddee
need to be passed as part
November 2004

PHP Architect

www.phparch.com
12
FFEEAATTUURREE
Object-oriented vs. Relational Part II
1 <?php
2
3 /* file: relpage.php */
4
5 include (‘./relfiles.php’); //include Domain.php, all
datatypes, and Relation.php
6
7 $dbuser = ‘pgsql’;
8 $password = ‘noregress’;
9 $host = ‘localhost’;
10 $dbname = ‘test1’;
11
12 //$dbconn = pg_connect(“host={$host} user={$dbuser} pass-
word={$password} dbname={$dbname}”);
13 $dbconn = pg_connect(“user={$dbuser} password={$password}
dbname={$dbname}”);

14
15 $relname = $_GET[“relname”];
16
17 $rel = new Relation($relname); //Uses functions from phpPgAdmin
18
19 $rel->set_connection($dbconn);
20
21 if($_GET[“arguments”])
22 {
23 $otherargs = unserialize(stripslashes($_GET[“arguments”]));
24
25 $rel->set_args($otherargs);
26 }
27 $gui = new relGui($rel);
28
29 //print_r($otherargs); //debug output
30
31 $gui->set_mode($_GET[“mode”]); //valid modes are “list”,
“view”, “edit”, “add”, “insert”, “update’, “search”
32
33 echo “<!DOCTYPE HTML PUBLIC \”-//W3C//DTD HTML 4.0
Transitional//EN\”>
34 <html>
35 <head>
36 <meta http-equiv=\”Content-Type\” content=\”text/html\”
37 charset=\”UTF-8\”>
38 <title>{$_GET[“mode”]} {$relname}</title>
39 </head>
40 <body>”;
41

42 $gui->render();
43
44 //uncomment for object dump as HTML comment
45 //echo “<!—”;
46 //var_dump($gui);
47 //echo “—>”;
48
49 echo “</body>
50 </html>”;
51
52 ?>
Listing 5
1 <?php
2
3 /* file: relfiles.php */
4
5 require_once(‘./RelDomain.php’);
6 require_once(‘./Relation.php’);
7 require_once(‘./RelGui.php’);
8 ?>
Listing 6
“T
he benefits of the rela-
tional model are often seen
to be at odds with the capa-
bilities of Object-oriented
Programming.

of the URL. This tells the program what rela-
tion to deal with, and how we want to inter-

act with the relation. Valid modes (for now)
are
lliisstt
,
vviieeww
,
eeddiitt
, and
sseeaarrcchh
. In “list”
mode, the table will be queried, and the
data output as rows.
• When the user clicks an “edit” link on one of
the rows, the page re-draws itself in “edit”
mode, using URL-encoded arguments
passed in the link to provide enough infor-
mation for the
WWHHEERREE
clause in SQL. A form is
then drawn, based on the relation metadata
(column definitions) and the values for each
column in the fetched row. The user can
then edit the row and submit the new val-
ues.
To look a little deeper, the code in Listing 5 first ini-
tializes a new
RReellaattiioonn
object, based on the
rreellnnaammee
parameter, and then passes a database connection

identifier to it. The Relation object prepares the meta-
data for the given table/view. Then, the code initializes
a new
RReellGGuuii
object and passes the
RReellaattiioonn
object to
its constructor. The appropriate mode
is passed as well, so that
rreellGGuuii
can
automatically know how to display the
data. If the mode is
lliisstt
, for example,
then the page looks like Figure 1. If the
mode is
eeddiitt
,
RReellGGuuii
automatically
knows to create an editable form (as
you can see in Figure 2).
Inside Listing 3, you will see that,
after extracting the basic metadata
with
ppgg__mmeettaa__ddaattaa(())
, we loop through
the basic information to first create the
related object for each domain—and

then run some more sophisticated
queries in PostgreSQL to get further
metadata. We take advantage of PHP’s
variable classname calling on lines 68
and 75 of Listing 4 to create our
domain/datatype objects, thus allow-
ing
RReellGGuuii
to derive hints on presenta-
tion, and other aspects of the GUI. Of
course, it is clear that we could do this
without creating the custom
RReellDDoommaaiinn
classes, but then we would lose much
of the ability to add extra behavior to
different column types. To further
illustrate the idea of how we can
affect any area of the system
through this, uncomment
$$tthhiiss--
>>sseettCCssssSSttyyllee((aarrrraayy((‘‘ccoolloorr’’==>>‘‘rreedd’’))))
in the
rreell__iinntt
class stored on line 43 of
Listing 2. Now, any integer type col-
umn will display in red (the new style
will be added to the fourth parameter
of
HHTTMMLL__QQuuiicckkffoorrmm
’s

AAddddEElleemmeenntt
call in
Listing 4). There are many more things
that can be added this way, if you want
to play around with this concept,
including additional HTML attributes,
Javascript event handlers, and so on.
What About MySQL?
You might be wondering how you can
implement these concepts if you are
November 2004

PHP Architect

www.phparch.com
13
FFEEAATTUURREE
Object-oriented vs. Relational Part II
Figure 1
Figure 2
using MySQL. While it is true that MySQL offers far less
functionality, lacking views, constraints, and domains,
than other DBMSs, it is precisely our sort of framework
that can help overcome some of these difficulties. For
example, if you exercise a certain amount of discipline
in table design, you can “fake” domains by naming
columns after PHP classes you have created, and use
the column names as you reverse-engineer your tables.
This way, if you have a column named “zipcode”, you
can assume that it corresponds to your

rreell__zziippccooddee
class in PHP. Also, you could compensate for the lack of
views by creating a class that maintains a lookup table
with a list of names, and associate them with stored
queries, and uses the metadata functions in the
RReellaattiioonn
class to return all the column definitions for
these “views”. Similarly, you could maintain a lookup
list of constraints expressed in PHP which apply to cer-
tain tables, column names, and so forth. The same
could also apply even more to SQLite, or other light-
weight database engines. It’s a win-win situation.
Garbage Collection: A Few Final Notes
Of course, a perfectly valid complaint about this sort of
approach is “what about efficiency?” Don’t all these
extra classes and methods present a serious perform-
ance problem? It’s possible. As a general rule, hard-cod-
ing can lead to increased performance, and that would
apply to how we build our forms and interact with the
database. However, as usual again, this comes at the
price of flexibility and manageability (or “developer
performance”). Which is cheaper, computer perform-
ance or your performance as a programmer? If you
want these advanced capabilities but are worried about
performance consider three things: first, the code pre-
sented here is not optimized; there should be plenty of
ways—especially with PHP5—to get better perform-
ance. Second, there are several good PHP optimization
systems, such as the Zend Optimizer and Zend
Accelerator, as well as the Ioncube Accelerator and the

PPEECCLL::::aappcc
extension, for example, and Third, computer
hardware is really cheap these days. It would probably
cost less than a week’s wages to upgrade a server sig-
nificantly in performance.
Therefore, performance concerns notwithstanding, in
the end we have an interesting situation. We are using
quite a few of the concepts of object-oriented program-
ming: inheritance, encapsulation, aggregation, and
composition, without once infringing on the database’s
handling of business logic. Now I agree that this small
example of coding here is incomplete (it is up to the
reader, for example to implement the
insert/update/search modes), and the data presenta-
tion leaves much to be desired. In order to really create
a seamless whole between the hardcore logic manage-
ment in the database and the interactivity/presentation
of the application layer, one would probably need ten
November 2004

PHP Architect

www.phparch.com
14
FFEEAATTUURREE
Object-oriented vs. Relational Part II
101 $colnum = 0;
102 $rownum = 0;
103 $this->gui->setHeaderContents( $rownum, $colnum,
‘’); //empty space

104 $colnum++;
105 foreach($this->metadata as $colname => $colinfo)
106 {
107
108 $this->gui->setHeaderContents( $rownum, $col-
num, $colname);
109 $colnum++;
110 }
111
112 //create data rows
113
114 $rownum = 1;
115 while($row = $this->relation->fetch_row())
116 {
117 $colnum = 0;
118 $escaped_args = urlencode(serialize($row));
//argumenst to uniquely identify a row
119 $this->gui->setCellContents($rownum, $colnum
,
“<a href=\”{$_SERVER[“PHP_SELF”]}?relname={$this->relation->rel-
name}&mode=edit&arguments={$escaped_args}\”>edit</a>”);
120 $colnum++;
121 foreach($row as $colname => $colval)
122 {
123 $this->gui->setCellContents($rownum, $col-
num, $colval);
124 $colnum++;
125 }
126
127 $rownum++;

128 }
129
130 echo $this->gui->toHTML();
131 }
132 else
133 {
134 //in all other cases there should be only one row
returned
135
136 $this->gui->addElement(‘header’, ‘’, “Edit
{$this->relation->relname}”);
137
138 $row = $this->
relation->fetch_row();
139
140
141 foreach($row as $colname => $colval)
142 {
143
144 $html_attribs = array(“value”=>$colval);
145
146 //additional HTML attribs are set here
147 if(is_array($this->data[$colname]-
>css_attribs))
148 {
149 $html_attribs = array_merge($html_attribs,
$this->data[$colname]->css_attribs);
150 }
151 if(is_array($this->data[$colname]->css_class))
152 {

153 $html_attribs = array_merge($html_attribs,
$this->data[$colname]->css_class);
154 }
155
156 //set max size attribute for textboxes
157 if($this->metadata[$colname][‘len’] > 0)
158
{
159 $html_attribs = array_merge($html_attribs,
array(‘maxlength’ => $this->metadata[$colname][‘len’]));
160 }
161
162 $this->gui->addElement(‘text’, $colname,
$colname, $html_attribs);
163 }
164
165 $this->gui->addElement(‘submit’, ‘btnSubmit’,
‘Submit’);
166
167 $this->gui->display();
168
169 }
170
171 }
172
173
174 }
Listing 4:
Continued from page 11
times as much code as we have here. This article, how-

ever, provides a basic prototype on how to handle this
sort of thing. Again, PEAR can come to our rescue in
handling more sophisticated presentation and interac-
tion needs, with such classes as the following:
DB_QueryTool
DB_Table
DB_DataObject
DB_DataObject_FormBuilder
SQL_Parser
HTML_Table_Matrix
HTML_Select
HTML_Table_Sortable
Structures_DataGrid
With these classes and the concepts presented in this
article, one could construct a very sophisticated set of
tools, not only for an application framework, but even
for an application development framework. Think about
the possibilities of creating something what would be
like the web-based version of commercial systems like
Access, Paradox, or FileMaker Pro. In one sense, our
tools could be even better, because the forms could
correctly adjust themselves to changes in the database,
which is something even the commercial tools men-
tioned above don’t really handle properly. Where this
sort of approach can really shine, though, is in the cre-
ation of large enterprise applications, where there
might be several development teams, database admin-
istrators, and sysadmins. Imagine being on the phone
with the database administrator saying “sure, go ahead
and make that change, then see what the form looks

like” and wondering what the look on his face looks like
as he hears you speaking!
November 2004

PHP Architect

www.phparch.com
15
FFEEAATTUURREE
Object-oriented vs. Relational Part II
About the Author ?>
To Discuss this article:
/>Rick Morris heads application development for MOS Imaging Systems in
Miami, Florida (
wwwwww..mmooss..uuss
,
wwwwww..nneettccoommppaassss..uuss
). He lives near Fort
Lauderdale, Florida with his wife, 2 children, and the world’s laziest cat.
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!
/>
Introduction
Most XML generators are desktop applications—you
can drag-and-drop beautiful GUI nodes to build a DOM
document. The XML generator introduced here is a
web application. All the richness that you can find in a
desktop application is absent: the form only refreshes
upon submit, a lot more code is needed to make a
dynamic UI, HTML cannot support ‘complex’ data
structures like DOM, the browser cannot maintain
state, and so on. Would a web XML generator imple-
mented in PHP be able to overcome all these con-
straints?
This generator was developed in the Infospheres Lab
at the California Institute of Technology to help users
generate state/transformation files for a crisis manage-
ment system. The states inside the system are described
by XML files. During an event, an agent changes its

state in ways described by XSL files. For more details
about the crisis management system,
you can refer to the Infospheres web site at
wwwwww..iinnffoosspphheerreess..ccaalltteecchh..eedduu
. Making this XML generator
a web application has the advantage of being light-
weight—the client only needs an Internet connection
and a browser to use the service, thus it is platform
independent. The server can also keep track of all the
files generated and save copies. As with all web appli-
cations, efficiency is always the first priority to ensure
performance and reduce server workload.
Let’s understand how it works by looking at a fire
accident scenario. The initial state is ‘at peace’: state
name – normal; dead – 0; injury – 0; police – sleep; fire
station – sleep; and so on. By putting all these values
into the generator (Figure 1), the corresponding XML
file (Figure 2) is generated. A message will be delivered
to the system when a fire breaks out, indicating the ‘fire
agent’ should change its state. The transformation rule
for this transition (e.g.: if the number of injuries stated
in the message is greater than four, the state name
should change to ‘critical’) is specified in the XSL gen-
erator (Figures 3 and 4) to generate the corresponding
XSL file (Figure 5). The flowchart of the entire genera-
tor is shown in Figure 6. As you can see, different XSL
files will be invoked upon different events; for example,
hhaannddlleettiimmeeoouutt..xxssll
will be invoked during timeout.
UI that represents a changing dataset

with complex data structure
Initially, there are only four nodes under the root node
in the XML generator (Figure 7). A new input form is
made when the user modifies this structure (Figures 8
and 9). The user interface is dynamically generated
after every refresh/submit, based on the different
‘states’ (which consist of datasets). In addition, we have
to maintain ‘state’ change, which is based on the pre-
vious ‘state’ and the user’s modifications. You should
immediately think of MVC (Model/View/Controller)
November 2004

PHP Architect

www.phparch.com
17
FF EE AA TT UU RR EE
Developing a PHP - XML Generator
by Man-ping Grace Chau
PHP: 5.x
OS: Any
Other: None
Code Directory: xmlgen
REQUIREMENTS
Developing a UI that manipulates large data sets is difficult. Developing a UI dynamically upon user request is even more
difficult. This article aims to discuss the difficulties in developing a complex UI, demonstrated by the XML/XSL genera-
tor made in the Infospheres Lab at the California Institute of Technology. Examples of how to generate JavaScript dynam-
ically at run time and how to represent a complex DOM tree with simple HTML data structure will also be shown.
Furthermore, the article will discuss the optimization of input validation. Several error checking/correction algorithms will
be demonstrated. This application is developed in PHP5, with extensive use of the new XML library.

November 2004

PHP Architect

www.phparch.com
18
FFEEAATTUURREE
Developing a PHP - XML Generator
Figure 1
Figure 2
Figure 3
Figure 4
Figure 5
Figure 6
Figure 7
“T
his generator was devel-
oped in the Infospheres Lab at
the California Institute of
Technology to help users gen-
erate state/transformation files
for a crisis management sys-
tem.

here: the Model encapsulates the
‘states’; the Controller interprets the
user’s input, modifies the ‘states’ in the
Model and chooses a new View; the
View generates the UI based on the
datasets in the Model (Figure 10). The

main focus here is the datasets:
in order to make an efficient
Model/View/Controller, the dataset
should be easy to manipulate. There
are already many articles about the
MVC design pattern; you can refer to
the book Design Patterns by Erich
Gamma, Richard Helm, Ralph Johnson
and John Vlissides or to Jason Sweat’s
articles that have appeared on the
pages of php|architect for more infor-
mation.
By just looking at the form, it seems
that appending a child is as simple as
adding one more row to the table. It is,
indeed, easy to manipulate a table—
but this is only half of the picture. This
table actually represents a DOM tree
and the rows are the child nodes at dif-
ferent levels (you can see in Figure 11
how the node level is indicated in the
input table). Thus, the dataset should
be a DOM document, with its structure
specified by the user. The problem aris-
es that HTML does not support com-
plex data structures like DOM, and
there is no way to POST a DOM node.
The ‘most complex’ data structure sup-
ported by HTML POST is an array. In
solving this problem, we retrieve the

user’s input in such a way that the it
can be mapped to the DOM document
inside the Model.
Even if you ignore the previous prob-
lem, imagine how complicated it
would be to generate the HTML input
table from a DOM document.
Therefore, let’s look at the problem in
another way: as mentioned, the most
complicated data structure supported
by POST is an array; is it possible that
we can switch the dataset from a DOM
document to an array? This may seem
quite difficult, but PHP makes it less so.
PHP is a scripting language, which
means no compilation is needed. It
supports many more powerful opera-
tions on arrays than most compiled lan-
guages, such as the ability to change
the size of an array at run time and bet-
ter support for associative arrays. An
November 2004

PHP Architect

www.phparch.com
19
FFEEAATTUURREE
Developing a PHP - XML Generator
Figure 8

Figure 9
Figure 10
Figure 12
Figure 11
XML structure like the one in Figures 12
and 13 can be represented by an array
as shown in Figure 14. In storing the
nodes’ values to generate a new file or
form, variables with names like
$$aattttrriibbuuttee__22
, which can easily be
mapped to the array, are used for the
attribute of the second child of the root
node. This is necessary, as the array
cannot store the values and structure at
the same time (you can easily deter-
mine this by looking at the ‘parent
node’ in the array). After a POST, the
values can be retrieved simply as
$$HHTTTTPP__PPOOSSTT__VVAARRSS [[$$vvaarriiaabbllee__nnaammee]]
, in
which the variable names can be
assigned when we loop through the
DOM-structure-array by using the array
keys. This approach solves two prob-
lems at the same time without a com-
plex algorithm: it is much easier to gen-
erate the input table from an array (that
represents the structure) and variables
(that store the node value) (Figure 15—

HTML of input table); both simple vari-
ables and arrays can be POSTed to noti-
fy the server of the changing structure
and node content. The algorithm for
generating the XML file and retrieving
user input will be described in the fol-
lowing sections, when we discuss the
View and Controller. As we will see, this
‘data structure’ also helps improve effi-
ciency.
Arrays in PHP are more useful than in
other languages, since the structure can
be changed during runtime. You can
easily devise a program that utilizes
arrays, like, for example, a computer
purchasing application. Let’s apply the
MVC design pattern again: the Model is
initialized with all the computer models
available; based on the Model, the View
generates an input form to accept pur-
chasing information for each computer.
When the form is submitted, the
Controller interprets the input and noti-
fies the Model about this additional
information. Then, based on the
changed Model, a new View selected
by the Controller generates the valida-
tion form or another more complicated
input form. An array is used here
because it can simplify the

mapping between the purchasing
information/other more complex data
November 2004

PHP Architect

www.phparch.com
20
FFEEAATTUURREE
Developing a PHP - XML Generator
Figure 13
Figure 14
Figure 15
Figure 16
and each computer, as demonstrated in Figures 16
(array with computer models), 17 (array with buyer’s
name), and 18 (array with extra hardware). This map-
ping is not restricted to be a one-to-one relationship;
multiple-to-one is also possible by using nested arrays.
This is only possible if we can change the array size at
run time, because the amount of information is uncer-
tain. This helps a lot in terms of efficiency, because no
searching is needed during mapping and most algo-
rithms that are based on this ‘data structure’ can be fin-
ished in time linear with respect to the number of items
in the arrays. The same approach is applied in making
the XSL generator: the Model is initialized with the
schema of the XML file and the corresponding transfor-
mation rules are stored in arrays as mentioned above.
In dealing with a changing dataset, the MVC design

pattern is the only choice for a web application. On the
other hand, we need to take care of several things
when we use a certain way to store complex data: the
efficiency of manipulating the data, the ease of gener-
ating a user interface from the data, whether HTML is
able to transmit those data, the ease of performing
November 2004

PHP Architect

www.phparch.com
21
FFEEAATTUURREE
Developing a PHP - XML Generator
1 <?php
2 /**
3 * The function to draw the checking table and create file
4 **/
5
6 function xmlCreate($bean) //$bean encapsulated data about the XML file
7 {
8 $this->statement .= $this->table->tableStart(2, 4);
9 $this->statement .= $this->table->rowStart();
10 $this->statement .= $this->table->tableHeader (“Node Level”, 1, 1);
11 $this->statement .= $this->table->tableHeader (“Tag name”, 1, 1);
12 $this->statement .= $this->table->tableHeader (“Defualt value”, 1, 1);
13 $this->statement .= $this->
table->tableHeader (“Attribute”, 1, 1);
14 $this->statement .= $this->table->tableHeader (“Attribute value”, 1, 1);
15 $this->statement .= $this->table->rowEnd(true);

16 $this->file = $bean->getValue($bean->getName());
17 $type = $bean->getValue(“type”);
18 if ($type == 1) //special names for different files
19 {
20 $filename = “files/”.$this->file.”/”.$this->file.”.xml”;
21 }
22 else
23 {
24 $filename = “files/”.$this->
file.”/”.$this->file.”Msg.xml”;
25 }
26 $path = “files/”.$this->file;
27 if (!file_exists($path))
28 {
29 mkdir($path);
30 }
31 $this->xmlBuild($this->info, $bean, “_”, $this->dom);
32 $this->dom->save($filename);
33 $this->statement .= $this->table->tableEnd();
34 $this->statement .= “<br><br><font size=\”3\” face=\”Verdana, Arial, Helvetica, sans-serif\” color=\”#9966FF\”>Agent name: “;
35 $this->statement .= $this->expression->drawName($this->file, $filename);
36 $this->statement
.= “</font>”;
37
38 $string = file_get_contents(“files/agents.dat”);
39 $array = explode(“,”, $string);
40 $exist = false;
41
42 foreach ($array as $key=>$value)
43 {

44 if ($value == $this->file)
45 {
46 $exist = true;
47 }
48 }
49 if (!$exist)
50 {
Listing 1
Figure 18
Continued on page 29
Figure 17
error checking/correction on the data (which we will
look at in next section), and so on. As arrays in PHP are
comparatively a lot more flexible than in other lan-
guages, we should try to make good use of them.
Generating the UI/file
According to the MVC design pattern, the View is
responsible for generating the user interface/file. The
XXmmllBBuuiilldd
class in the XML generator belongs to the
View, which constructs the file based on the XML con-
tents specified by the user in the Model. (Listing 1) It is
very similar to the
BBuuiilldd
class, which constructs the user
interface for retrieving the XML file content. The file is
generated by calling the
xxmmllCCrreeaattee
function, which
invokes the recursive function

xxmmllBBuuiilldd
to build the
‘real’ XML document and draw the checking table. As
you can see, the running time is linear in the number of
nodes, which is as efficient as we can get. Two design
patterns are employed in drawing the checking table:
Bridge and Command.
Class XmlBuild only states the logic
of how to construct the table, while the
implementation of the actual drawing
is delegated to an object instantiated
from class Table. The Bridge pattern is
applied; this decouples the logic and
implementation in such a way that
changing either one will be easy. For
desktop applications, the biggest bene-
fit of employing the Bridge pattern is
portability; different widget implemen-
tations for different platforms, like
Windows, Mac OS and X11, are encap-
sulated in classes that inherit from an
abstract base class
WWiinnddoowwIImmpp
. By just
programming on the abstract base
class, we can specify the construction
logic for the UI on all platforms. When
switching platforms, we only need to
replace the object for implementation
and the logic will stay the same. Based

on the same principle, the Bridge pat-
tern in a web application enables us to
change the implementation of the UI
without modifying the logic, making a
switch from HTML to XHTML, for
example, quite easy (Figure 19). More
importantly, the UI in a web application
changes even more often than in a
desktop application. What most web
applications do is more or less the
same: filling forms, saving or searching
records, and so on. What makes a web
application outstanding is the user
interface—therefore, every developer
should try to make the interface imple-
mentation as flexible as possible.
When the
ddaattaaTTaabbllee
function is called to draw a cell,
$$tthhiiss-->>eexxpprreessssiioonn
is passed as parameter. This is
employing the Command pattern: the action of draw-
ing the content in the table cell is encapsulated in the
object,
$$tthhiiss-->>eexxpprreessssiioonn
in this case (Figure 20).
$$tthhiiss-->>ttaabbllee
is the ‘invoker’ that invokes the drawing
and
$$tthhiiss-->>eexxpprreessssiioonn

is the ‘command’ that knows
how to perform the drawing. The action of drawing
can thus be parameterized before any action takes
place, as in Listing 2, where the node value is specified.
This pattern is helpful in decoupling the objects that
invoke the operations (table) from the objects that
knows how to perform them (expression). In addition,
it is easy to add new invokers or commands by sub-
classing. In the original Command pattern, the invokers
call the ‘execute’ function in the command repeatedly
to perform the action. A restriction arises: only one
method, ‘execute’, can be called by the invoker. The
most straightforward solution is to perform condition-
November 2004

PHP Architect

www.phparch.com
22
FFEEAATTUURREE
Developing a PHP - XML Generator
1 <?php
2 /**
3 * Setup the data of the checking table
4 * (parameterized the action of drawing the checking table before drawing)
5 */
6
7 function setData($result, $mother, $key, $child)
8 {
9 $this->tag = $result[0]; //node tag

10 $this->attr = $result[1]; //node attribute
11 $this->attrv = $result[2]; //node attribute value
12 if ($child)
13 {
14 $this->element = $result[3]; //text node
15 }
16 $this->number = $mother.$key; //node level
17 }
18 ?>
Listing 2
Figure 19
Figure 20
ing in the invoker (perhaps based on the input param-
eters) to decide what function to call on command.
However, this exposes the command object interface
and renders the Command pattern ineffective.
Another approach is to pass in function handlers. It is
easy to create a function handler in PHP because it is
only a string containing the function name, and the
function can be called by
$$oobbjjeecctt-->>$$ffuunnccttiioonn__nnaammee(())
(an example is
ddrraawwLLeevveell
in Listing 3 to print the node
level, called by the
ttaabblleeDDaattaa
function in Listing 4),
which does not involve any ‘complex concept’ like
function pointers in C and C++. In this case, the invok-
er is completely ignorant about the command object.

The main difference between rendering the file and
the UI is that we have to perform extra error checking
when the former is being handled. For example,
November 2004

PHP Architect

www.phparch.com
23
FFEEAATTUURREE
Developing a PHP - XML Generator
1 <?php
2 /**
3 * Draw the level of the node by comparing the last node
with the same level
4 **/
5
6
7 function drawLevel()
8 {
9 $statement = “”;
10 $fields = explode(‘_’, $this->number);
11 $k = count($fields)-2;
12
13 if((isset($this->level[$k]) && ($this->lastLevel >=
$k)))
14 {
15 $fs = explode(‘.’, $this->level[$k]);
16 $last = $fs[count($fs)-1];
17 $last++;

18 for ($j = 0; $j < count($fs)-1; $j++)
19 {
20 $statement .= $fs[$j];
21 $statement .= “.”;
22 }
23 $statement .= $last;
24 $this->level[$k] = $statement;
25 $this->lastLevel = $k;
26 }
27 else
28 {
29 if ($k == 0)
30 {
31 $statement .= “0”;
32 $this->level[0] = $statement;
33 $this->lastLevel = 0;
34 }
35
36 else
37 {
38 $fs = explode(‘.’, $this->level[$k-1]);
39 for ($j = 0; $j < count(
$fs); $j++)
40 {
41 $statement .= $fs[$j];
42 $statement .= “.”;
43 }
44 $statement .= “0”;
45 $this->level[$k] = $statement;
46 $this->lastLevel = $k;

47 }
48 }
49 return $statement;
50 }
51 ?>
Listing 3
1 <?php
2 /**
3 * Draw table content
4 **/
5
6 function tableData ($expObj, $function, $colspan, $rowspan)
7 {
8 $statement = “<TD COLSPAN=$colspan ROWSPAN=$rowspan>”;
9 $statement .= $expObj->$function();
10 $statement .= “</TD>”;
11 $statement .= “\n”;
12 return $statement;
13 }
14 ?>
Listing 4
Figure 21
Figure 22
Figure 23
Figure 24
adding a node without appending it to any parent in a
DOM tree is invalid. In this case, the node is valid when
we merely look at the node content, but when we look
at the tree structure as a whole, the node becomes an
error. This kind of checking is unnecessary if we store

the values in a DOM document, but we store them sep-
arately here. Thus, we need the functions
ggeettCCNNooddee
(Listing 5) and
ggeettMMNNooddee
from Listing 2. These functions
are responsible for error checking and for rendering the
child or parent node using the DOM functions in PHP5.
The DOM functions throw exceptions for invalid
expressions, thus ensuring the correctness of the node
content. In addition,
ggeettCCNNooddee(())
and
ggeettMMNNooddee(())
return
NULL when reading a node without tag names; this
causes all the node’s children to be neglected because
they do not have a parent. With the checking per-
formed by the Controller when appending a number of
children to the tree, the validity of the file can be guar-
anteed.
However, there are cases where checking cannot be
accomplished by just looking at the current value, but
other entries also need to be taken into account. This is
inefficient because some values may be visited multiple
times for checking and the running time may become
exponential. If we apply this method to the XSL gener-
ator, it does not even work—for example, if we try to
identify whether a node is a
vvaalluuee--ooff

node or a text
node by looking at the node value (
vvaalluuee--ooff
node in
Figure 21;
tteexxtt
node in Figure 22). This is error prone
because an expression like
////lleevveell++11
seems to be a
vvaalluuee--ooff
node, but may actually be a text node (using
a strange expression). The most robust solution is to
require the user to specify the types and store them in
another array, which again can be mapped to the orig-
inal set of data easily. This approach can be further
applied to mark whether a field is used, whether the
node is a child or parent, and so on. Although more
resources are needed, this ensures that no node is visit-
ed more than once for error checking. In addition, it
helps simplify the algorithm for building UI/file as all
related information can be found easily without search-
ing (Listing 6).
Input processing
The Controller is responsible for handling the user’s
input according to the MVC design pattern. In order to
design an efficient Controller, we must first understand
what data is transmitted to the server in a PHP web
application.
The GUI in a desktop application usually has event

handling to invoke programs, for example MFC or
Window forms in .NET, and so on. However, in a web
application, there is no way that you can ask a text box
to invoke a function from the server. The only way for
users to communicate with the server is by submitting
the whole form, which means the server will be sent all
November 2004

PHP Architect

www.phparch.com
24
FFEEAATTUURREE
Developing a PHP - XML Generator
1 <?php
2 /**
3 * Identify the default value and save it
4 * Inside a foreach loop with $i, $j counting the level of
the tree
5 **/
6
7 if ($boo[$i][$j] == “default”) //default value
8 {
9 if ($defaultFlag == 1)
10 {
11 echo “no 2 default values please!”;
12 break;
13 }
14 $defaultTag = $tagname;
15 $defaultFlag = 1;

16 $defaultValue = trim($value[$i][$j]);
17 for ($k = 0; $k < count($attribute[$i]); $k++) //set
attribute
18 {
19 $defaultAttribute[$k] = $attribute[$i][$k];
20 $defaultAttributeValue[$k] =
trim($attributeValue[$i
][$k][$j]);
21
22 }
23 if ($type[$i][$j] == “textbox”)
24 {
25 $defaultType = 0;
26 }
27 else
28 {
29 $defaultType = 1;
30 }
31
32 continue;
33 }
34
35 ?>
Listing 6
1 <?php
2 /**
3 * Generate a child node
4 **/
5
6 function & getCNode()

7 {
8
9 if ($this->tag == “”)
10 {
11 return NULL;
12 }
13 else
14 {
15 try
16 {
17 $node = $this->dom->createElement($this->tag);
18 }
19 catch (Exception $exception)
20 {
21 $node = $this->dom-
>createElement(“INVALID_EXPRESSION”);
22 $this->tag = “Invalid Expression! Please
Check!”;
23 }
24 try
25 {
26 if ($this->attr != “”) //invalid attribute
27 {
28 $node->setAttribute
($this->attr, $this->attrv);
29 }
30 }
31 catch (Exception $exception)
32 {
33 $node->setAttribute(“INVALID_EXPRESSION”, $this-

>attrv);
34 $this->attr = “Invalid Expression! Please Check!”;
35 }
36 $text = $this->dom->createTextNode($this->element);
37 $node->appendChild($text);
38 return array($node, array($this->tag, $this->attr,
$this->attrv, $this->element));
39 }
40 }
41 ?>
Listing 5

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×