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

Tài liệu Blogging and the Damage Done pptx

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

FEBRUARY 2005
VOLUME IV - ISSUE 2
FEBRUARY 2005
VOLUME IV - ISSUE 2
www.phparch.com
Plus: Security Corner, Reviews, News and much more

LEARNING PHP WAS NEVER THIS MUCH FUN
Come learn PHP in Paradise with us
(and spend less than many other conferences)
Ilia Alshanetsky - Accelerating PHP Applications, Marcus Boerger - Implementing PHP 5 OOP Extensions,
John Coggeshall - Programming Smarty, Wez Furlong - PDO: PHP Data Objects, Daniel Kushner - Introduction to
OOP in PHP 5
, Derick Rethans - Playing Safe: PHP and Encryption, George Schlossnagle - Web Services in PHP 5,
Dan Scott - DB2 Universal Database, Chris Shiflett - PHP Security: Coding for Safety, Lukas Smith - How About
Some PEAR For You?
, Jason Sweat - Test-driven Development with PHP, Andrei Zmievski PHP-GTK2
The Magazine For PHP Professionals
php|
Tropics
Moon Palace Resort, Cancun, Mexico.
May 11-15 2005
At php|tropics, take the exam and
Get Zend Certified
and we'll pay your fees!
For more information and to sign up: />Early-bird discount in effect for a limited time!
II NN DD EE XX
February 2005

PHP Architect


www.phparch.com
4
6 Editorial
Blogging and the Damage Done
7 What’s New!
49
Test Pattern
The Myth of Reusable
by Marcus Baker
55 Review
The ZEND PHP Certification
Experience
by Peter B. MacIntyre
68 Security Corner
PHP Security Consortium
by Chris Shiflett
72 exit(0);
Welcoming PHP to the World
by Marco Tabini
10 PHP Under Fire
by Christian Wenz
20 HTML_QuickForm and Smarty
by David Perrin
29 Enterprise Development with the
iConnect Architecture
by Alex Pagnoni
40 The PRADO Framework
by Qiang Xue
58 Secure Communications with
PHP and SSH

by Sara Golemon
TABLE OF CONTENTS
php|architect
TM
Departments
Features

EEDDIITTOORRIIAALL
H
ow can you tell if a technology has reached critical mass?
Easy: you look at how much damage it’s causing. Pretty
much every human invention is neutral in itself; any ben-
efits (or drawbacks) come from the way it’s used: atomic
energy can be used to power a city or destroy it; cars make it trav-
el over distances that were unthinkable just a hundred years ago
possible, and are happily destroying our planet with their pollut-
ing emissions.
Blogs have finally reached the “do and die” level of usage. They
started as glorified online diaries. Comments mutated them into
electronic sounding boards. RSS turned them into a self-publishing
tool. The corporate world has rapidly misused them into propa-
ganda weapons.
Running your own blog, as many of our readers and authors do,
is, in many cases, a liberating experience. Personally, I like the idea
of throwing my ideas out there in a free-form format and let other
people take them apart, comment on them and, possibly, even use
them.
Many people, it seems to me, have pretty much the same atti-
tude with regards to how they run their blogs. Where they go
wrong, in my opinion, is in the fact that they continue to think of

blogs as personal diaries, which is often incompatible with the way
their readers see them.
For my part, as much as I love writing on my blog, I often find
myself being overly cautious about what I write in it—because, no
matter what I think, people see it not as “Marco’s blog,” but as
“php|architect’s blog.” This severely limits, in my mind, the range
of topics I can cover and how I can cover them. In fact, this prob-
lem has come up more than once when people have criticized me
either for dissing our competition or for failing to disclose ties with
companies that were mentioned in my posts one way or another.
In both the instances I recall, the comments were misplaced—I
didn’t dis the competitors, but simply expressed a personal prefer-
ence, and the ties between us and another company had nothing
to do with my posts.
Still, I respect the fact that, to many people, my blog is a way to
peek into the less-public face of php|architect, which is just fine
but requires a bit more thoughts than “I’ll write about what I had
for breakfast.” Some people—and many companies—have yet to
figure out what the limits of blogging are. Thus, we see employ-
ees of corporations posting proprietary information and getting
fired for it (and justly so), and employees posting completely
harmless information and getting fired for it anyway (in a decided-
ly unfair manner).
What I find really funny is the fact that so much fuss is being
made about blogs when they are, in fact, nothing more than
the tip of the iceberg. Clearly, the problem is somehow con-
nected to the fact that a weblog reads like a friendly chat but
February 2005

PHP Architect


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

Authors
Marcus Baker, Sara Golemon,
Peter MacIntyre, Chris Shiflett,
Alex Pagnoni, David Perrin,
Christian Wenz, Qiang Xue
php|architect (ISSN 1709-7169) is published twelve times a year by
Marco Tabini & Associates, Inc., P.O. Box 54526, 1771 Avenue Road,
Toronto, ON M5M 4N5, Canada.
Although all possible care has been placed in assuring the accuracy of
the contents of this magazine, including all associated source code, list-
ings and figures, the publisher assumes no responsibilities with regards

of use of the information contained herein or in all associated material.
Contact Information:
General mailbox:

Editorial:
Subscriptions:
Sales & advertising:
Technical support:
Copyright © 2003-2004 Marco Tabini &
Associates, Inc. — All Rights Reserved
BBllooggggiinngg aanndd tthhee
DDaammaaggee DDoonnee
EE DD II TT OO RR II AA LL RR AA NN TT SS
TM
Continued on Page 9
NNEEWW SSTTUUFFFF
February 2005

PHP Architect

www.phparch.com
7
What’s New!
php|architect launches php|
tropics
2005
Ever wonder what it's like to learn PHP in paradise? Well, this year we've decided to give
you a chance to find out!
We're proud to announce php|tropics 2005, a new conference that will take place between
May 11-15 at the Moon Palace Resort in Cancun, Mexico. The Moon Palace is an all-

inclusive (yes, we said all inclusive!) resort with over 100 acres of ground and 3,000 ft. of
private beach, as well as excellent state-of-the-art meeting facilities.
As always, we've planned an in-depth set of tracks for you, combined with a generous
amount of downtime for your enjoyment (and your family's, if you can take them along
with you).
We even have a very special early-bird fee in effect for a limited time only.
For more information, go to
/>.
Maguma Workbench 2.2
Maguma has announced the release of Maguma Workbench 2.2
On 20 January 2005, Maguma published the newest version of Maguma Workbench. Maguma
Workbench 2.2 has new features, more stability and a new pricing concept. During the same period
Maguma will also publish the Maguma Workbench SDK, for more independence to create new mod-
ules for your Workbench. For this reason Maguma has created a competition for developers, to create
new plugins.
The new features, like the PHP Function list, drag´n´drop and the hotkey F12 (hide/restore tool win-
dows) brings you more efficiency. Patches have also been applied to the PHP Code Parser, Class
Wizard, Script Parameter Implementation and more (see Changelog for more details at
hhttttpp::////ssuuppppoorrtt mmaagguummaa ccoomm//??aarrttiiccllee==cchhaannggeelloogg222200
)
With this release of Workbench we are also making a reality of “Make it your Workbench” which
means now the core price of Workbench is only 69 Euro and it’s up to the user to choose which modules/features they want to add
to the core product. The core provides the basic features such as Syntax highlighting, Class browsing, and script execution, while
the extra modules provide the added features such as local filesystem browsing, debugging, regular expression developer, and
much more. So each customer can buy only the function and modules that they need and will use.
For more information visit:
hhttttpp::////wwwwww mmaagguummaa ccoomm//
The Zend PHP Certification Practice Test Book is now available!
We're happy to announce that, after many months of hard work, the Zend PHP
Certification Practice Test Book, written by John Coggeshall and Marco Tabini, is now

available for sale from our website and most book sellers worldwide!
The book provides 200 questions designed as a learning and practice tool for the
Zend PHP Certification exam. Each question has been written and edited by four
members of the Zend Education Board the very same group who prepared the
exam. The questions, which cover every topic in the exam, come with a detailed
answer that explains not only the correct choice, but also the question's intention,
pitfalls and the best strategy for tackling similar topics during the exam.
For more information, visit
hhttttpp::////wwwwww pphhppaarrcchh ccoomm//cceerrtt//mmoocckk__tteessttiinngg pphhpp
NN EE WW SS TT UU FF FF
NNEEWW SSTTUUFFFF
February 2005

PHP Architect

www.phparch.com
8
PostgreSQL 8.0
The folks at PostgreSQL have announced the release of PostgreSQL 8.0.
This is the first PostgreSQL release to natively run on Microsoft Windows as a
server. It can run as a Windows service. This release supports NT-based Windows releases
like Win2000, XP, Win2003. Older releases like Windows 95, 98, and ME are not supported because these operating systems do not
have the infrastructure to support PostgreSQL. A separate installer project has been created to ease installation on Windows:
hhttttpp::////ppggffoouunnddrryy oorrgg//pprroojjeeccttss//ppggiinnssttaalllleerr
.
For more information visit:
hhttttpp::////wwwwww ppoossttggrreessqqll oorrgg
Check out some of the hottest new releases from PEAR.
File 1.1.0RC4
Provides easy access to read/write to files along with some common routines to deal with paths. Also pr vides interface for handling

CSV files.
File_Passwd 1.1.2
Provides methods to manipulate and authenticate against standard Unix, SMB server, AuthUser (.htpasswd), AuthDigest (.htdigest),
CVS pserver and custom formatted password files.
Text_Wiki 0.25.0
Abstracts parsing and rendering rules for Wiki markup in structured plain text.
Net_IDNA 0.5.0
This package helps you to encode and decode punycode strings easily.
Net_UserAgent_Mobile 0.21.0
Net_UserAgent_Mobile parses HTTP_USER_AGENT strings of (mainly Japanese) mobile HTTP user agents. It’ll be useful in page dis-
patching by user agents. This package was ported from Perl’s HTTP::MobileAgent.
curl and libcurl 7.13.0
curl.haxx.se has announced the latest release of curl and libcurl 7.13.0. Some of the changes
include:
• added
——ffttpp aaccccoouunntt
and
CCUURRLLOOPPTT__FFTTPP__AACCCCOOUUNNTT
• added
CCUURRLLOOPPTT__SSOOUURRCCEE__UURRLL
and
CCUURRLLOOPPTT__SSOOUURRCCEE__QQUUOOTTEE
• obsoleted
CCUURRLLOOPPTT__SSOOUURRCCEE__HHOOSSTT
,
CCUURRLLOOPPTT__SSOOUURRCCEE__PPAATTHH
,
CCUURRLLOOPPTT__SSOOUURRCCEE__PPOORRTT
and
CCUURRLLOOPPTT__PPAASSVV__HHOOSSTT

• added
——33pp uurrll
,
——33pp uusseerr
and
——33pp qquuoottee
This release also contains many bug fixes.
For more information or to download, visit
ccuurrll hhaaxxxx ssee
.
Netdoc 1.25
The people at visiomode.com have announced the release of Netdoc 1.25
Netdoc is a content management system that focuses tightly on content creation and edit-
ing. Netdoc 1.25 comes with a complete user privilege system. Websites can be made global readable, only readable to some, or
even global writable. These privileges can be applied also to any part of the website, and defining them takes generally only a cou-
ple of rules.
Netdoc is made with PHP and it stores the data into a MySQL database and uses Apache as a web server. Netdoc is installed on the
server and it creates dynamic pages with friendly URLs. The site is updated through the web interface directly on that same server
and thus there is no pushing of content or FTP transfer taking place at any time.
For more information visit:
hhttttpp::////wwwwww vviissiioommooddee ccoomm
NNEEWW SSTTUUFFFF
February 2005

PHP Architect

www.phparch.com
9
Looking for a new PHP Extension? Check out some of the lastest offerings from PECL.
pecl_http 0.2.0

Currently implemented features:
• Building absolute URIs
• RCF compliant HTTP redirects
• Caching by “Last-Modified” and/or ETag (with ‘on the fly’ option)
• Sending data/files/streams with (multiple) ranges support
• Negotiating user preferred language/charset
• Convenient request functions to HEAD/GET/POST if libcurl is available
colorer 0.1
Colorer take5 is a syntax highlighting and text parsing library, that provides services of text parsing in host editor systems in real-time
and transforming results into colored text. For details, see />While colorer is primarily designed for use with text editors, it can be also used for non-interactive syntax highlighting, for example, in
web applications. This PHP extension provides basic functions for syntax highlighting.
maxdb 1.0
MaxDB PHP is an extension which provides access to the MySQL MaxDB databases. It is compatible with MySQL’s mysqli extension.
vld 0.8.0
The Vulcan Logic Disassembler hooks into the Zend Engine and dumps all the opcodes (execution units) of a script.
is, for all intents and purposes, cast in the Internet stone—as the Romans used to say, verba volant, scripta
manent. What is written in a blog “sticks” and has the potential of embarrassing a company by short-circuit-
ing its carefully choreographed PR spin machine.
Is this really so bad, though? Consider this: information that goes on a blog stays on a blog. Yes, it can be
crawled by a spider, but, eventually, any information that’s deleted at the source will drop off search engines.
A posting being propagated by outside sources, such as other blogs, is a bit more problematic, but eventual-
ly even those blogs will let it go. Now consider this: Google owns a collection of some ten or more years’
worth of Usenet news. Ten years! Anything any one of us has ever posted on Usenet—as well as hundreds of
public mailing lists—has stuck around for all this time (and is likely to stick around for a lot longer).
The persistence of Usenet data, to me, is much more troublesome than blogs. There are plenty of posts I’d
rather I never made (go ahead search them all and post them on your blog!), but for the most part the thing
that bothers me is that I never made a posting with the idea that I was creating a permanent record of my
mischief. On top of that, Usenet has been around for a lot longer than blogs—so there’s plenty of silliness
going around for everyone.
In the end, the corporate world seems to be developing its usual odi et amo relationship with blogs: on one

hand, they’re a great tool for public relations, while on the other they are a source of infinite frustration. It’s
the age-old problem of public relations: wanting as much third-party publicity as possible, which is often con-
sidered as more reliable than company-sponsored fluff, but only if the corporation is in complete control of it.
In my neck of the woods, that’s called having your pie and eating it, too, although I suspect someone else
may use a slightly cruder term connected to the food by-products of male cattle. But only on their weblog.
Editorial Continued from Page 6
BBllooggggiinngg aanndd tthhee DDaammaaggee DDoonnee

PHP & MySQL” almost sounds like a tautology,
but this is a bit unfair in respect to the other data-
bases available. SQLite is a very strong contender,
especially if there are many read operations and little in
the way of write operations. PostgreSQL gets excellent
reviews, but still struggles with the market share.
Microsoft SQL Server (“MSSQL”) is usually only avail-
able in a heterogeneous network, but a renowned IT
magazine benchmarked various web server setups
(Apache, IIS, PHP, ASP.NET, MySQL, MSSQL) a couple
of years ago, with Apache on Linux and MSSQL on
Windows being the winning combination.
A DBMS that has been mostly neglected by both
developers and the media is the Firebird database. It all
began on September 4, 1984, when former DEC
employee Jim Starkey sat down and started to imple-
ment his own database server. This was later pursued at
Borland, and resulting InterBase turned out to be a
quite successful product that was well-received by the
market (even though Borland tried to rename itself with
very little success).
The next important step in the development of the

software turned out to be July 25, 2000. The same day
the fatal Concorde crash near Paris happened, Borland
(then probably Inprise) took the source code of their
InterBase database system and turned it into open
source. This launched a new project, FirebirdSQL, that
developed the database server further based on
Borland’s code. The code was issued under the
InterBase Public License v1.0, also known as IPL
(
hhttttpp::////wwwwww bboorrllaanndd ccoomm//ddeevvssuuppppoorrtt//iinntteerrbbaassee//ooppeennssoouurrcc
ee//IIPPLL hhttmmll
), which is a variant of the Mozilla Public
License.
Speaking of Mozilla, when the Mozilla project started
working on his standalone browser, they first code-
named it Phoenix. However, since there already existed
a motherboard manufacturer with that name, the
browser was rechristened “Mozilla Firebird.” This
caused some confusion, at least according to the
“Firebird-the-database” faction. After some discussions,
the Mozilla project changed the name of its browser to
the one we now all know: Firefox (which is not a fox,
by the way, but a panda—despite the logo). The
Firebird database, however, kept its name.
REQUIREMENTS
PHP 4.x , 5.x + InterBase extension
OS Linux, Max, Windows
Other Software Firebird
Code Directory phpfire
February 2005


PHP Architect

www.phparch.com
FFEEAATTUURREE
10
PHP Under Fire
by Christian Wenz
When praising the vast database support that PHP pro-
vides, the products that are mentioned most often are
the likes of MySQL, SQLite, PostgreSQL and MSSQL,
but there are several others. One database that has
been rather neglected for a long time is Firebird. It’s
time for a closer look.
FF EE AA TT UU RR EE
FFEEAATTUURREE
PHP Under Fire
February 2005

PHP Architect

www.phparch.com
11
The current version of Firebird, as of writing this arti-
cle, is 1.5.2. The codebase of this release, however, is
already called Firebird 2, the next large milestone. The
reason for this is that the original codebase turned into
open source by Borland was written in C; the major
goals for Firebird 2 are a general code-cleaning and, of
course, porting the product to C++. The developers

hope—among other things—for a serious speedup of
the software.
The feature list of Firebird 1.5 is already quite impres-
sive, including ACID compliance (including full transac-
tion control), stored procedures (written in PSQL), trig-
gers, UDFs, generators, full SQL-92 Entry Level 1 sup-
port and most of SQL-99—some other databases took
a lot of time to achieve this. The database is available
on all major platforms, including Linux, Mac OS X and
Windows. Since Firebird supports an OS-independent
data format, changing the platform is rather easy.
Installation
Firebird is available from its SourceForge project site at
hhttttpp::////ffiirreebbiirrdd ssoouurrcceeffoorrggee nneett//
. The download section
features both the source code and binary releases:
RPMs for Linux, packages for Mac OS X and both ZIP
archives and self-contained installers for the Windows
platform. There are two flavours available: the “Classic”
version of Firebird works on a file basis, which makes it
very easy to deploy but really hard when parallel
processes try to access the same database file (and
maybe even try to perform write operations on it). But
Firebird also comes in a second flavour, called “Super
Server,” which implements a server process that oper-
ates between the client applications and the database
file, caring about things like request processing and
threading. For FreeBSD, Mac OS X and Solaris, current-
ly only the classic versions are available; in fact, Mac
users are stuck with the older version 1.51 (that’s cor-

rect—the current version is indeed 1.5.2, with one
more dot). There is also an embedded server available,
making it possible to bundle Firebird with other appli-
cations (similarly to how SQLite now comes with PHP
5).
Windows and Mac users have it quite easy to install
Firebird: they can download convenient installers that
take care of copying the files to the system (see Figures
1 and 2). For Windows, a ZIP package is also available,
so the users can take care of copying the files them-
selves. Note that the Mac installation hung consistent-
ly on one of my test machines—if something like this
happens, you will have to go back even further to a pre-
vious version.
Under Linux, you can either install the RPM file or do
some more work yourself. For the latter, the TGZ
archive contains the shell script
iinnssttaallll sshh
, which takes
care of the installation and copies firebird into
//oopptt//ffiirreebbiirrdd//
(see Figure 3). Among these files is a
shell script, called
uunniinnssttaallll sshh,,
that does exactly what
it sounds like.
After the installation process, the database has a mas-
Figure 1
Figure 2
Figure 3

ter user. It is called
ssyyssddbbaa
(or
SSYYSSDDBBAA
, as Firebird does
not care too much about upper or lower case when it
comes to usernames) and has the default password
mmaasstteerrkkeeyy
. If you’re using the Linux installer, you can
enter your own password for this user; on other sys-
tems, you should change
ssyyssddbbaa
’s password immedi-
ately after installation for obvious security reasons. In
the
bbiinn
directory of Firebird, you find the
ggsseecc
tool,
which can be used to both change passwords and add
or delete users. However, for real convenience, you can
use a web-based tool—we’ll look into that later on.
There are several client libraries for Firebird, including
an ODBC driver and, of course, a PHP extension.
However, trying the URL
hhttttpp::////pphhpp nneett//ffiirreebbiirrdd
turns
up nothing. The reason for this is a historical one: since
Firebird was previously called InterBase and PHP has
always had great database support, the extension car-

ries interbase in its name and the associated manual
page can be reached at
hhttttpp::////pphhpp nneett//iibbaassee
.
Installation under Windows is easy: the extensions
directory (called
eexxtteennssiioonnss
in PHP 4 and
eexxtt
in PHP 5)
contains the file
pphhpp__iinntteerrbbaassee ddllll
that hooks you up
with the client libraries of Interbase, so the only thing
you have to do is to modify
pphhpp iinnii
:
extension=php_interbase.dll
If you are compiling by yourself, be sure to use the
compilation switch
——wwiitthh iinntteerrbbaassee
. You can also pro-
vide the directory to the libraries:
——wwiitthh
iinntteerrbbaassee==//vvaarr//ffiirreebbiirrdd//lliibb
. Afterwards, the obliga-
tory call to
pphhppiinnffoo(())
or
pphhpp mm

(see Figure 4) shows the
installed extension.
Administration
The first steps when administering the newly installed
database is, of course, to change the credentials for the
master user—and create a new one that takes care of
the sample application we are about to develop. This
can be done using a console: the
bbiinn
directory of the
Firebird installation contains the
ggsseecc
tool, which can
be used for this task. However, since we are using PHP
anyway, this is a good opportunity to use a web-based
interface written in PHP. The tool is called ibWebAdmin
(“ib” standing for Interbase), and available for free at
hhttttpp::////iibbwweebbaaddmmiinn ssoouurrcceeffoorrggee nneett//
(see Figure 5). Before
actually using this software, you first have to configure
it. After unpacking the archive and copying it onto the
web server, the file
iinncc//ccoonnffiigguurraattiioonn iinncc pphhpp
requires
some special attention. There, you have to provide
some information about the Firebird installation. Most
important are the following values:
•• BBIINNPPAATTHH
—Directory to the Firebird binaries
•• SSEECCUURRIITTYY__DDBB

—Location of the Firebird data-
base that contains user names and other
security-related information (usually called
sseeccuurriittyy ffddbb
)
•• TTMMPPPPAATTHH
—Temporary path, where the web
server requires read and write access into
Windows users have the additional requirement to use
forward slashes only in their filenames. Here are some
sample values for a default installation under Windows.
Linux users can more or less use the values already pres-
ent in the
ccoonnffiigguurraattiioonn iinncc pphhpp
file without making
any change.
define(‘BINPATH’,
‘C:/Progra~1/Firebird/Firebird_1_5/bin/’);
define(‘SECURITY_DB’,
‘C:/Progra~1/Firebird/Firebird_1_5/security.fdb’);
define(‘TMPPATH’, ‘/tmp/’);
Also, the PHP configuration requires some special set-
tings. For instance, ibWebAdmin is still using the
$$HHTTTTPP__**__VVAARRSS
arrays to access form and session data; as
a consequence, you must not set
rreeggiisstteerr__lloonngg__aarrrraayyss
in
pphhpp iinnii
to

OOffff
, although this is the standard setting
in
pphhpp iinnii rreeccoommmmeennddeedd
. After this is done, however, the
software works quite well. You can then first login to an
existing database or create a new one. The best way is
to first connect to
sseeccuurriittyy ffddbb
and then add a new
user. Finally, create a new database file (in our samples:
//ttmmpp//ffiirreebblloogg ggddbb
, your mileage may vary), providing
the new user credentials. Then, create a file
(
ccoonnnneecctt iinncc pphhpp
) where you provide the username,
associated password and the hostname. The latter is a
concatenation of the server name, a colon and the (full)
path to the database file. This file will be included in all
scripts, enabling it to provide the database parameters
application-wide.
<?php
$host = ‘localhost:/tmp/fireblog.gdb’;
$user = ‘phpa’;
$pass = ‘aphp’;
?>
But back to ibWebAdmin. There, you can quite easily
set up your tables using a neat WYSIWYG interface.
Under the SQL tab, you can also directly enter the SQL

code that creates the tables.
The sample application will be a really simple weblog
with a comment feature. For this, we need two tables.
One contains the blog entries. As mentioned earlier, it’s
a very simple blog, so this table only has a few fields:
title of the entry, text of the entry, creation date of the
entry. For the latter field, we set a default value of
‘‘nnooww’’
. In Firebird, this automatically uses the current
date and time as default value whenever a new record
is inserted.
February 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
12
PHP Under Fire
FFEEAATTUURREE
PHP Under Fire
February 2005

PHP Architect

www.phparch.com
13
DROP table entries;
CREATE table entries (
id INTEGER NOT NULL PRIMARY KEY,

title VARCHAR(100),
content VARCHAR(2000),
creation DATE DEFAULT ‘now’
);
As you see, we also have a primary key: the
iidd
field.
There is nothing like
AAUUTTOO__IINNCCRREEMMEENNTT
or
IIDDEENNTTIITTYY
in
Firebird, but something even better: Generators. A sim-
ilar concept exists in PostgreSQL and Oracle. These
generators can later be used to create a suitable value
for
iidd
, even using a trigger or manually, as you will see
in a later listing. Here is the code to create a generator
that will then be used for the
eennttrriieess
table:
DROP GENERATOR entries_gen;
CREATE GENERATOR entries_gen;
Users can add comments to weblog
entries. These entries will also be
saved in the database, but in anoth-
er table. This one is rather similar in
concept to the
eennttrriieess

table, but
also contains a foreign key—as well
as its own generator:
DROP table comments;
CREATE table comments (
id INTEGER NOT NULL PRIMARY KEY,
entries_id INTEGER,
content VARCHAR(2000),
creation DATE DEFAULT ‘now’
);
DROP GENERATOR comments_gen;
CREATE GENERATOR comments_gen;
Now you are set—it’s time to move
on to some PHP coding!
Basic SQL Operations
The first step in working with PHP
and Firebird is to connect to the data
source. This is done using the
iibbaassee__ccoonnnneecctt(())
function. As param-
eters, you provide the host, user-
name and password—so all the data
that is already available via the
ccoonn
nneecctt iinncc pphhpp
file. The return value of
iibbaassee__ccoonnnneecctt(())
is either a handle to
the connection or
FFaallssee

if some-
thing did not work out as planned.
The following code snippet just
checks this information and displays
an associated message:
<?php
include ‘connect.inc.php’;
if (false !== ($db = ibase_connect($host, $user,
$pass))) {
echo ‘Connection established!’;
} else {
echo ‘Something went wrong ’;
}
?>
If this generates no error, it is time to actually send SQL
statements to the database. This is done using the
iibbaassee__qquueerryy(())
function. This one expects two parame-
ters: the database handle and the SQL statement to be
sent. The first script will be a PHP page that allows the
maintainer of the weblog to enter data into the
eennttrriieess
table. This is the form:
<form method=”post”
action=”<?php echo $_SERVER[‘PHP_SELF’]; ?>”>
Title: <input type=”text” name=”title” /><br />
Comment: <textarea name=”content” cols=”40”
rows=”5”></textarea><br />
Figure 4
Figure 5

February 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
14
PHP Under Fire
<input type=”submit” value=”Enter blog entry” />
</form>
Upon submitting the form, an SQL statement is assem-
bled and then sent to the database. See a modified
excerpt from the code:
$sql = sprintf(“INSERT INTO entries (id, title, con-
tent)
VALUES (GEN_ID(entries_gen, 1), ‘%s’, ‘%s’);”,
$_POST[‘title’],
$_POST[‘content’]
);
ibase_query($db, $sql);
The expression
GGEENN__IIDD((eennttrriieess__ggeenn,, 11))
retrieves the
current value of the provided generator and increases it
to the next value. The complete listing is available in
the code archive for this article under the name
iinnsseerrtt
bbaadd pphhpp
. It’s probably obvious why the file carries that
name: assembling an SQL query like that opens up your

application to SQL injection attacks and must be avoid-
ed at any cost. You should, instead, use parameterized
queries. Instead of “pasting” values into the SQL state-
ment, you use placeholders and later provide values for
those placeholders. The InterBase/Firebird extension
then glues the values to the placeholders and takes care
of any potentially dangerous special characters.
In order to implement this, you first have to prepare
an SQL statement using
iibbaassee__pprreeppaarree(())
, providing the
database handle and the parameterized SQL statement
(each parameter being marked by the question mark
character). The return value of
iibbaassee__pprreeppaarree(())
can
then be used with
iibbaassee__eexxeeccuuttee(())
. This function
expects the statement object (returned by
iibbaassee__pprreeppaarree(())
) and then a list of the values of all
placeholders. Here is a shortened code snippet that
demonstrates the usage of these two functions:
$sql = “INSERT INTO entries (id, title, content)
VALUES (
GEN_ID(entries_gen, 1), ?, ?);”;
$query = ibase_prepare($db, $sql);
ibase_execute($query, $_POST[‘title’], $_POST[‘con-
tent’]);

This is both safer and also more efficient than concate-
nating strings into SQL. Listing 1 (
iinnsseerrtt pphhpp
) contains
the full code for the HTML form that allows entering
new weblog entries. Of course, you should build addi-
tional security into this page, such as a password-pro-
tection mechanism.
Reading Out Information
Up to now, we have only sent information towards the
database but did not care too much about the return
values. This will change in this section. The return val-
ues of
iibbaassee__qquueerryy(())
and
iibbaassee__eexxeeccuuttee(())
identify the
result set of these queries. Once you have these, the
“standard” naming convention that most PHP exten-
sions use applies to Firebird as well:
<<ddaattaabbaasseennaammee>>__ffeettcchh__aassssoocc(())
fetches the current row
of the resultset into an associative array, while
<<ddaattaa
bbaasseennaammee>>__ffeettcchh__oobbjjeecctt(())
creates an object where field
names are turned into object properties. A simple
wwhhiillee
loop, in connection with one of those functions, iter-
ates over the whole result set so that you can send the

information gathered to the browser. Do note that, by
default, field values are saved in uppercase even if they
were typed in lowercase in the
CCRREEAATTEE TTAABBLLEE
SQL state-
ment.
The following (again, simplified) code snippet reads
1 <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “
2 <html>
3 <head>
4 <title>Firebird &amp; PHP</title>
5 </head>
6 <body>
7 <?php
8 include ‘connect.inc.php’;
9
10 if (isset($_POST[‘title’]) && isset($_POST[‘content’])) {
11 if (false !== ($db = ibase_connect($host, $user, $pass))) {
12 $sql = “INSERT INTO entries (id, title, content) VALUES (
13 GEN_ID(entries_gen, 1), ?, ?);”;
14 $query = ibase_prepare($db, $sql);
15 if (false !== ($result = ibase_execute($query, $_POST[‘title’], $_POST[‘content’]))) {
16 echo ‘<p>Saved entry.</p>’;
17 } else {
18 echo ‘Something went wrong while trying to save the entry ’;
19 }
20 } else {
21 echo ‘Something went wrong ’;
22 }
23 }

24 ?>
25 <form method=”post” action=”<?php echo $_SERVER[‘PHP_SELF’]; ?>”>
26 Title: <input type=”text” name=”title” /><br />
27 Comment: <textarea name=”content” cols=”40” rows=”5”></textarea><br />
28 <input type=”submit” value=”Enter blog entry” />
29 </form>
30 </body>
31 </html>
Listing 1
all the available information from the database, in
reverse chronological order, and prints it out to the
browser:
if (false !== ($result1 = ibase_query($db,
‘SELECT * FROM entries ORDER BY creation DESC’)))
{
$selectcomments = ibase_prepare($db,
‘SELECT * FROM comments WHERE entries_id = ?
ORDER BY creation DESC’);
while ($row1 = ibase_fetch_object($result1)) {
printf(‘<p><b><big>%s</big>
(%s)</b></p><p>%s</p>’,
htmlspecialchars($row1->TITLE),
htmlspecialchars($row1->CRE-
ATION),
htmlspecialchars($row1->CON-
TENT)
);
}
In the same script, all comments
associated to a blog entry are read

out. This is a point where prepared
statements really come in handy and
help with the performance:
$selectcomments = ibase_prepare($db,
‘SELECT * FROM comments WHERE
entries_id = ?
ORDER BY creation DESC’
);
In every iteration through the result
set, the placeholder receives the cur-
rent value of the
iidd
field; then,
iibbaassee__eexxeeccuuttee(())
is called. The state-
ment is therefore only compiled
FFEEAATTUURREE
February 2005

PHP Architect

www.phparch.com
PHP Under Fire
15
1 <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “
2 <html>
3 <head>
4 <title>Firebird &amp; PHP</title>
5 </head>
6 <body>

7 <?php
8 include ‘connect.inc.php’;
9
10 if (false !== ($db = ibase_connect($host, $user, $pass))) {
11 if (false !== ($result1 = ibase_query($db, ‘SELECT * FROM entries ORDER BY creation DESC’))) {
12 $selectcomments = ibase_prepare($db, ‘SELECT * FROM comments WHERE entries_id = ? ORDER BY creation DESC’);
13 while ($row1 = ibase_fetch_object($result1)) {
14 printf(‘<p><b><big>%s</big> (%s)</b></p><p>%s</p>’,
15 htmlspecialchars($row1->TITLE),
16 htmlspecialchars($row1->CREATION),
17 htmlspecialchars($row1->CONTENT)
18 );
19 print ‘<blockquote>’;
20 $result2 = ibase_execute($selectcomments,
$row1->ID);
21 while ($row2 = ibase_fetch_object($result2)) {
22 printf(‘<p><small>%s</small></p>’, $row2->CONTENT);
23 }
24 print ‘</blockquote>’;
25 print ‘<form method=”POST” action=”insert-comments.php”>’;
26 print ‘<input type=”hidden” name=”id” value=”’ . $row1->ID . ‘“ />’;
27 print ‘<input type=”text” name=”content” />’;
28 print ‘<input type=”submit” value=”Add comment” />’;
29 print ‘</form>’;
30 print ‘<hr />’;
31 }
32 } else {
33 print ‘Something went wrong while trying to read the weblog ’;
34 }
35 } else {

36 print ‘Something went wrong ’;
37 }
38 ?>
39 </body>
40 </html>
Listing 2
Figure 6
once and gets a different parameter each time:
while ($row1 = ibase_fetch_object($result1)) {
$result2 = ibase_execute($selectcomments, $row1-
>ID);
while ($row2 = ibase_fetch_object($result2)) {
printf(‘<p><small>%s</small></p>’, $row2->CON-
TENT);
}
After each blog entry and the associated set of com-
ments, a small form is printed out where a new com-
ment may be added:
print ‘<form method=”POST” action=”insert-
comments.php”>’;
print ‘<input type=”hidden” name=”id” value=”’ .
$row1->ID . ‘“ />’;
print ‘<input type=”text” name=”content” />’;
print ‘<input type=”submit” value=”Add comment” />’;
print ‘</form>’;
The complete code for this script,
sseelleecctt pphhpp
, can be
found in Listing 2. Figure 6 shows its output.
Transactions

Firebird also offers decent support for ACID transac-
tions. We could need this in the file
iinnsseerrtt
ccoommmmeennttss pphhpp
, where the comment forms from the pre-
vious sections post their data to. There, we first have to
check if an entry with the provided ID exists in the
eennttrriieess
table. If so, we can add the comment data to
the
ccoommmmeennttss
table. However, what happens if a parallel
process deletes the blog entry between the
SSEELLEECCTT FFRROOMM
eennttrriieess
statement and the
IINNSSEERRTT IINNTTOO ccoommmmeennttss
state-
ment? In this case, transactions come in handy. In order
to implement them, you first have to call
iibbaassee__ttrraannss(())
, providing the database handle. The
return value of this function call is then a transaction
handle. You can use this
handle for subsequent calls to
iibbaassee__qquueerryy(())
or
iibbaassee__pprreeppaarree(())
instead of the database handle.
However, at the end of the script all transactions will be

rolled back (new behavior under PHP 5) unless they are
explicitly committed to the database using
iibbaassee__ccoomm
mmiitt(())
. Therefore, you should always call this function to
end your transactions. In order to rollback, you use the
function called
iibbaassee__rroollllbbaacckk(())
.
The
iinnsseerrtt ccoommmmeennttss pphhpp
script from Listing 3 imple-
ments the aforementioned concept. First, it checks if
there is a blog entry with the provided ID by trying to
SSEELLEECCTT
data and then checking if anything was
returned. If that succeeds, the provided content is writ-
ten into the data source. Finally,
iibbaassee__ccoommmmiitt(())
sub-
mits the statements within the transaction to the data
source.
Advanced Features
Firebird offers several other features for advanced users.
Among them is the support for triggers. Imagine that
you delete one blog entry from the database. What
happens to all its comments? They have to be deleted
as well. For this, a trigger comes in very handy. The fol-
lowing snippet, available in the code archive as a file
(

ttrriiggggeerr ssqqll
), gets rid of the useless comments when-
ever a blog entry gets removed:
DROP TRIGGER delete_entry;
February 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
16
PHP Under Fire
1 <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “
2 <html>
3 <head>
4 <title>Firebird &amp; PHP</title>
5 </head>
6 <body>
7 <?php
8 include ‘connect.inc.php’;
9
10 if (isset($_POST[‘content’]) && isset($_POST[‘id’])) {
11 if (false !== ($db = ibase_connect($host, $user, $pass))) {
12 $t = ibase_trans();
13 $sql1 = “SELECT * FROM entries WHERE id = ?;”;
14 $query1 = ibase_prepare($t, $sql1);
15 if (false !== ($result1 = ibase_execute($query1, $_POST[‘id’])) &&
16 false !== ($row1 = ibase_fetch_object($result1))) {
17 $sql2 = “INSERT INTO comments (id, entries_id, content) VALUES (
18 GEN_ID(comments_gen, 1), ?, ?);”;

19 $query2 = ibase_prepare($t, $sql2);
20 if (false !== ($result2 = ibase_execute($query2, $_POST[‘id’], $_POST[‘content’]))) {
21 ibase_commit($t);
22 echo ‘<p>Saved entry.</p>’;
23 } else {
24 echo ‘Something went wrong while trying to save the comment ’;
25 }
26 } else {
27 echo ‘Something went wrong while trying to save the comment ’;
28 }
29 } else {
30 echo ‘Something went wrong ’;
31 }
32 }
33 ?>
34 <p><a href=”select.php”>Back to weblog</a></p>
35 </body>
36 </html>
Listing 3
SET TERM !!;
CREATE TRIGGER delete_entry FOR entries AFTER DELETE
AS BEGIN
DELETE FROM comments
WHERE entries_id=OLD.id;
END!!
SET TERM; !!
You can directly send this SQL code to the database
using
iibbaassee__qquueerryy(())
, or you use the

iissqqll
command line
tool:
./isql -u phpa -p aphp /tmp/fireblog.gdb <
trigger.sql
From this point on, deleting one entry takes care of all
comments.
Another nice feature of Firebird is the support for
Stored Procedures and UDFs, User Defined Functions.
Both are a way to include your own code within the
database and then execute it. However, this is outside
of the scope of this article—you do not need any spe-
cial PHP features to use this functionality.
However there are some additional PHP functions
that can be used with Firebird data sources. For
instance, you can create your own user management
and do not have to rely on ibWebAdmin:
•• iibbaassee__aadddd__uusseerr(())
—adds a user to the securi-
ty database (provided in the first parameter),
using the username and password of a user
that may add users (parameters #2 and #3)
and the user name and password of the new
user (#4 and #5).
•• iibbaassee__ddeelleettee__uusseerr(())
—deletes a user
(parameter #4) from the security database
(parameter #1), using the privileges of the
user/password combination provided in
parameters #2 and #3

•• iibbaassee__mmooddiiffyy__uusseerr(())
—changes user infor-
mation, using the same function signature as
iibbaassee__aadddd__uusseerr(())
The behavior of these functions, however, has changed
in PHP 5 in combination with the introduction of the
SuperServer edition of Firebird. Now, you have to use
the service manager to connect to the security data-
base and change user information:
include ‘connect.inc.php’;
$server = ibase_service_attach($host, $user, $pass);
ibase_add_user( ); //or ibase_delete_user()
//or ibase_modify_user()
ibase_service_detach($server);
However, obviously, using a GUI tool is much more
convenient.
BLOBs
Among the data types supported by Firebird are also
BLOBs—Binary Large OBjects. They can be used to
store binary data—even large amounts of it—in the
database. You first have to create a database that con-
tains a field with data type BLOB:
DROP TABLE blobdata;
CREATE TABLE blobdata(filename VARCHAR(255), data
BLOB);
Afterwards, the following steps write binary data into
the table:
include ‘connect.inc.php’;
$db = ibase_connect($host, $user, $pass);
$blob = ibase_blob_create($db);

ibase_blob_add($blob, $data);
$id = ibase_blob_close($blob);
$sql = ‘INSERT INTO blobdata(filename, data) VALUES
(?, ?);’;
ibase_query($db, $sql, $filename, $id);
Listing 4 contains a small application (
bblloobb pphhpp
) that
lets the user upload a file and writes it directly into the
database, using PHP’s HTTP upload functionality.
Reading back the binary data from the database is per-
formed using just a few steps as well: simply
SSEELLEECCTT
the
blob column from the table, provide the result as
parameter for
iibbaassee__bblloobb__iinnffoo(())
(to get information
about the BLOB field) and to
iibbaassee__bblloobb__ooppeenn(())
(to
open the BLOB). Then,
iibbaassee__bblloobb__ggeett(())
retrieves the
BLOB data:
include ‘connect.inc.php’;
$db = ibase_connect($host, $user, $pass);
$result = ibase_query(‘SELECT data FROM blobdata’);
$row = ibase_fetch_object($result);
$blobinfo = ibase_blob_info($row->DATA);

$blob = ibase_blob_open($row->DATA);
$blobdata = ibase_blob_get($blob, $blobinfo[0]);
Using Database Abstraction Layers
Several well-known database abstraction layers offer
Firebird support. Most prominently, the upcoming and
long-anticipated PDO (PHP Data Objects
FFEEAATTUURREE
February 2005

PHP Architect

www.phparch.com
PHP Under Fire
17
1 <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”

2 <html>
3 <head>
4 <title>Firebird &amp; PHP</title>
5 </head>
6 <body>
7 <?php
8 if (isset($_FILES[‘upload’]) &&
9 is_uploaded_file($_FILES[‘upload’][‘tmp_name’])) {
10 include ‘connect.inc.php’;
11 $db = ibase_connect($host, $user, $pass);
12 $blob = ibase_blob_create($db);
13 ibase_blob_add($blob,
file_get_contents($_FILES[‘upload’][‘tmp_name’]));
14 $id = ibase_blob_close($blob);

15 $sql = ‘INSERT INTO blobdata(filename, data) VALUES (?,
?);’;
16 ibase_query($db, $sql, $_FILES[‘upload’][‘name’], $id);
17 print ‘<p>Added file to the database.</p>’;
18 }
19 ?>
20 <form method=”post” enctype=”multipart/form-data”>
21 <input type=”file” name=”upload” />
22 <input type=”submit” value=”Upload!” />
23 </form>
24 </body>
25 </html>
Listing 4
Interface) layer
hhttttpp::////ppeeccll pphhpp nneett//ppaacckkaaggee//PPDDOO
includes a provider for Firebird data sources
hhttttpp::////ppeeccll pphhpp nneett//ppaacckkaaggee//PPDDOO__FFIIRREEBBIIRRDD
, but you
should be aware that development has not finished yet.
Users of Unix/Linux can install the required packages
using the PEAR installer:
pear install PDO
pear install PDO_FIREBIRD
In the not too distant future, this will change to the fol-
lowing:
pecl install PDO
pecl install PDO_FIREBIRD
Windows users can refer to the following address at
hhttttpp::////ssnnaappss pphhpp nneett//wwiinn3322//PPEECCLL__55__00
for compiled

PHP 5.0.x versions of the modules or to
hhttttpp::////ssnnaappss pphhpp nneett//wwiinn3322//PPEECCLL__UUNNSSTTAABBLLEE
for 5.1.x
versions. Once you do that (and assuming that every-
thing goes to plan), a unified access to Firebird data
sources using the “future” of PHP’s database access
becomes available (see Figure 7).
As you might have guessed, you will also get lucky
if you search PEAR for suitable packages. Both
PEAR::DB
hhttttpp::////ppeeaarr pphhpp nneett//ppaacckkaaggee//DDBB
and
PEAR::MDB
hhttttpp::////ppeeaarr pphhpp nneett//ppaacckkaaggee//MMDDBB
support
Firebird (and InterBase) with special drivers. Thus, as
you can see, Firebird is a well-respected and also fully-
featured alternative to more mainstream DBMS,
despite its relatively low penetration in the PHP arena.
So do give Firebird a try—and maybe you’ll “fire” one
of your other database systems instead!
FFEEAATTUURREE
PHP Under Fire
About the Author ?>
To Discuss this article:
/>Christian Wenz is author or co-author of over four dozen books, fre-
quently writes for renowned IT magazines and speaks at conferences
around the globe. He is Germany’s very first Zend Certified Professional,
principal at the PHP Security Consortium and maintainer or co-maintain-
er of several PEAR projects.

Award-winning IDE for dynamic languages,
providing a powerful workspace for editing,
debugging and testing your programs. Features
advanced support for Perl, PHP, Python, Tcl and
XSLT, on Linux, Solaris and Windows.
Download your free evalutation at www.ActiveState.com/Komodo30
Figure 7

February 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
20
Like many web developers, I often work with data sub-
mitted from web pages or web service clients into PHP
applications. Recently, while working on a validation
class to ensure quality user input, I happened upon the
PEAR module HTML_QuickForm. As it turned out, a
great deal of the validation I needed to do for the proj-
ect was easily handled by using this module.
Additionally, specialty form validation could be accom-
plished with ease by assigning custom functions to do
validation. What a treat! Sometimes, it is humbling to
have to throw away a few hours of work to take advan-
tage of
something which allows you to do more quickly—with
HTML_QuickForm, I didn’t mind.
As has been the case when beginning to learn other

PHP modules or other programming elements of style,
my first reaction to HTML_QuickForm was enthusiasm
and intrigue, quickly followed by a fear and apprehen-
sion of the learning curve. After working through a cou-
ple of HTML_QuickForm examples from the PEAR web-
site and elsewhere (see references), however, it was sur-
prising to see how little code I needed to take care of
the tasks I work on most every day. In addition, if you
find yourself needing further flexibility and features in
validation or presentation, it isn’t hard to integrate
HTML_QuickForm with your own custom validation
functions and display forms using popular templating
engines like Smarty a nd Flexy.
External PHP Libraries
Libraries of PHP code can enable developers to accom-
plish more with less code. There are a number of well-
written libraries with a variety of uses that are available.
In addition to writing less code, by taking advantage of
code able to save a great deal of
Had it with redundant form validation? Does separating
application and presentation code have you all mixed up?
Check this article for an overview of the Smarty templat-
ing engine, the PEAR HTML_QuickForm form building
module and a complete mini application that cleanly
divides application and presentation as well as handling
comprehensive form validation.
FF EE AA TT UU RR EE
HTML_QuickForm and Smarty
by David Perrin
REQUIREMENTS

PHP
OS Any
Other Software
Code Directory
RESOURCES
URL
hhttttpp::////ssmmaarrttyy pphhpp nneett
URL
hhttttpp::////ppeeaarr pphhpp nneett
URL
hhttttpp::////wwwwww tthheelliinnuuxxccoonnssuullttaannccyy ccoo uukk//ssmmaarrttyy
gguuiiddee hhttmmll
URL
hhttttpp::////wwwwww ddeevvaarrttiicclleess ccoomm//cc//aa//WWeebb DDeessiiggnn
UUssaabbiilliittyy//UUssiinngg HHTTMMLL QQuuiicckkFFoorrmm TToo MMaannaaggee WWeebb
FFoorrmmss PPaarrtt 22//
ii
4.06
MySQL 4, Smarty, PEAR DB
quickform
time. Of course writing applications with libraries isn’t
all peaches and cream—it can be difficult, especially at
first, to learn a new library. Beyond just learning a new
syntax, sometimes you’ve got to dramatically change
your way of thinking about solving problems. It is also
important to consider portability factors should you
need to move your application to other servers when
selecting code libraries.
I’ve found the biggest obstacle when learning a new
tool to be keeping a beginner’s mindset and not get-

ting too frustrated when the code doesn’t immediately
produce the results I expect.
To give you a demonstration of some of
HTML_QuickForm’s capabilities, we’ll create a web reg-
istration application that validates user inputs using
built-in methods. We’ll also take advantage of valida-
tion through regular expressions and custom functions.
The Smarty template engine will help keep our presen-
tation logic separate from the application logic. Our
database requirements are limited to simple selects and
inserts. For demonstration of this mini app, MySQL 4+
suits our needs just fine, but an alternate database serv-
er could easily be substituted. PEAR’s DB module is used
to pass the few simple database queries to a MySQL
database. Should you prefer a different database server,
the application should only require a modification of
the database connection.
First, though, a brief introduction to the tools of
Smarty and HTML_QuickForm.
Why Use a Template Engine?
PHP template engines offer developers an approach to
development that helps draw a division between pres-
entation in HTML and application code in PHP. Ever
find yourself lost in a PHP script composed of mostly
HTML with very little PHP application code? Or find
that lines and lines of
eecchhoo
and
pprriinntt
statements turn

your otherwise clean code into a bit of a kludge?
Many articles have been written on the value of sep-
arating presentation code of a website (e.g.: HTML,
CSS, graphics, and so on) from the application logic.
Templating engines offer a mostly painless way to do
make this separation happen.
Fortunately, there are many well-documented PHP
templating engines out there to choose from. Among
the more popular PHP templating engines are PHP
Savant, patTemplate, Smarty and PEAR’s
HTML_Template_Flexy. Other scripting languages have
templating engines too: Mason, for example, is a pop-
ular example for Perl, while Cheetah appears to be one
of the most selected template engines for Python, and
even Ruby has several.
It seems that, as PHP’s overall popularity has
increased, so has its popularity for use in sophisticated
web applications. The greater the sophistication of an
application, the more difficult that application can be
to maintain when application code is combined with
the HTML. Through a bit of a Forrest Gump-like obser-
vation, even when I’ve got a good plan, the more lines
of code I write, the more complicated that code gets.
Lengthy, complicated code is tough to work with.
Lengthy, complicated code is even tougher to work
with if it is code that you’ve inherited from some other
programmer. Clean code goes a long way toward mak-
ing an application easier to maintain, which, in turn,
can improve your present and future relationships with
those who may be assuming maintenance duties of

your project.
That is really the biggest reason why I’m sold on tem-
plating engines: they allow you to write clear, simple
code. This is done by demanding a level of discipline of
the developer in keeping the presentation code con-
tained within the template file.
Enough Already, How About an Example?
Fair enough. Take a look at Listing 1 for a snippet of
mixed application and presentation code.
First, an SQL statement is built. The SQL statement
looks to select all matching records from a user table
where the email and password columns in the table
matches the
$$__RREEQQUUEESSTT
input. The
$$__RREEQQUUEESSTT
values are
run through the PEAR DB function
qquuootteeSSmmaarrtt(())
. This
function safely formats the input so that it can be used
in building SQL statements.
qquuootteeSSmmaarrtt(())
accepts the
values from
$$__RREEQQUUEESSTT[[‘‘eemmaaiill’’]]
and
$$__RREEQQUUEESSTT[[‘‘ppaassss
wwoorrdd’’]]
and adds and escapes quotes appropriately. The

SQL statement is then run using the
$$ddbb >>GGeettRRooww(())
method, and the results of that query are assigned to
the
$$rrooww
variable as an array. If
$$rrooww
has no values, a
login error message is displayed, otherwise a successful
FFEEAATTUURREE
February 2005

PHP Architect

www.phparch.com
21
HTML_QuickForm and Smarty
// select user and get row
$sql = ‘SELECT * FROM tbl_user ‘
. ‘WHERE email = ‘ . $db->quoteSmart($_REQUEST[‘email’])
. ‘ AND password = ‘
. $db->quoteSmart($_REQUEST[‘password’]);
$row = $db->GetRow($sql);
// display appropriate login message
if (count($row) == 0) {
echo ‘<div class=”message”>Sorry, login failed.</div>’;
} else {
echo ‘<div class=”success”>Login was a success!</div>’;
}
Listing 1

include(‘mySmarty.php’);
$sql = ‘SELECT * FROM tbl_user ‘ . ‘WHERE email = ‘
. $db->quoteSmart($_REQUEST[‘email’])
. ‘ AND password = ‘
. $db->quoteSmart($_REQUEST[‘password’]);
$row = $db->GetRow($sql);
$smarty->assign(‘row’, $row);
$smarty->display(‘template.tpl’);
Listing 2
login message is shown.
Now, in all truthfulness, this is a very readable and
easy to maintain piece of code as it stands. It is possible
that, with the addition of some comments, even a non-
developer would be able to figure what is going on
with these few lines. For an experienced developer,
even if there were a few hundred lines of code like this,
they would likely still be easy to maintain. The case for
using templating engines becomes easier to make
when both the length and sophistication of the code is
greater than this particular example.
Try That with a Smarty Template
With Smarty, we split the original PHP file into two files:
a PHP file (Listing 2) and a template file (Listing 3).
The first line of the PHP snippet hides some gory
details by including the PHP file
mmyySSmmaarrttyy pphhpp
, which
creates an instance of the Smarty class. We’ll get into
the code for configuring Smarty later. The SQL state-
ment and execution of the SQL statement is identical to

the snippet in Listing 1. Following the execution of the
SQL statement through
$$ddbb >>GGeettRRooww(($$ssqqll))
, the
$$rrooww
variable is assigned to the Smarty variable called
rrooww
with
$$ssmmaarrttyy >>aassssiiggnn((‘‘rrooww’’,, $$rrooww))
.
If you are new to working with classes, it may feel
strange to work with different sets of variables. For me,
after becoming more familiar with this syntax, it now
seems more appropriate to have a set of variables
reserved exclusively for the purpose of presentation.
The last line of the PHP calls the Smart display method
(
$$ssmmaarrttyy >>ddiissppllaayy((‘‘tteemmppllaattee ttppll’’))
), where the tem-
plate file
tteemmppllaattee ttppll
is passed as an argument. At
that point, Smarty reads and interprets our template
file.
In Listing 3, a test is performed to determine if the
$$rrooww
variable has a count of zero and the appropriate
message is then displayed.
For those new to Smarty, that gives you a brief feel
for the syntax. The Smarty Crash Course at

hhttttpp::////ssmmaarrttyy pphhpp nneett//ccrraasshhccoouurrssee pphhpp
offers a great
introduction.
Why Smarty?
Documentation, popularity, performance, debugging
console and ease of use have all been reasons why I’ve
been drawn to Smarty. Most all of the benefit I see from
using Smarty could be accomplished by using Flexy or
another template engine.
My first exposure to Smarty came after reading an
article in php|architect in the summer of 2004. Reading
Jason Sweat’s articles on Phrame and Model View
Controller (php|architect, May 2003), I was in search of
a cleaner way to build applications. While initially inter-
ested in the architectural benefits that Phrame and
MVC could bring to web applications, it became appar-
ent that by using Smarty on its own, it would be possi-
ble to realize the benefits I was looking for.
What is HTML_QuickForm?
HTML_QuickForm is a PEAR module for developing
HTML forms. The module has been around for a num-
ber of years. HTML_QuickForm offers tools for form cre-
ation as well as flexible methods for validating form
data.
Not unlike Smarty, there are alternatives to
HTML_QuickForm. The popularity of
HTML_QuickForm, as well as its flexibility, history and
the ability to integrate it with a number of different
template engines were reasons I decided to pursue
HTML_QuickForm.

Sometimes (OK—often) users need some assistance
when filling out a web form. Validation can be handled
on the client side through JavaScript. That validation
should probably be reinforced with server-side valida-
tion to ensure malicious posts or posts from browsers
without JavaScript are properly verified.
HTML_QuickForm can take care of both server-side and
client-side validation, but, in this article, we’ll concen-
trate on the former only.
If you’ve written your own validation functions, per-
haps they accept an input value, a failed prompt, a
minimum length and a maximum length among other
parameters. When you want to validate a value, you
might pass your function those arguments and expect
a value in return. This is similar to the way
HTML_QuickForm allows you to do validation. In fact,
you can take a look at Listing 4 for a quick intro to
HTML_QuickForm.
After including
HHTTMMLL//QQuuiicckkFFoorrmm pphhpp
, an instance of
the HTML_QuickForm object is created and the form
name (and ID), method and action are defined with
$$ffoorrmm == nneeww HHTTMMLL__QQuuiicckkFFoorrmm((‘‘ffrrmmTTeesstt’’,, ‘‘PPOOSSTT’’,,
February 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE

22
HTML_QuickForm and Smarty
{ if $row.count == 0 }
<div class=”message”>Sorry, your login failed.</div>
{ else }
<div class=”success”>Your login was a success!</div>
{ /if }
Listing 3
1 <?php
2
3 require_once ‘HTML/QuickForm.php’;
4 $form = new HTML_QuickForm(‘frmTest’, ‘POST’,
5 $_SERVER[‘REQUEST_URI’]);
6 $form->addElement(‘text’, ‘email’, ‘Email’);
7 $form->addElement(‘text’, ‘name’, ‘Name’);
8
9 $form->addRule(‘email’, ‘That must be a valid email’,
10 ‘email’);
11 $form->addRule(‘name’, ‘Please enter your name’,
12 ‘required’);
13
14 if ($form->validate()) {
15 $form->freeze();
16 echo ‘validated!’;
17 }
18 $form->display();
19
20 ?>
Listing 4
[[$$__SSEERRVVEERR[[‘‘RREEQQUUEESSTT__UURRII’’]]))

.
Next, two text fields name and email are defined
through the
$$ffoorrmm >>aaddddEElleemmeenntt(())
method. The final
element of a submit button element is then added.
Two rules of validation are created using the
$$ffoorrmm
>>aaddddRRuullee(())
method. The
eemmaaiill
field is assigned a rule
that requires a valid email. The rule for the
nnaammee
field,
on the other hand, only requires that a non empty
value be submitted.
A test is then performed to see if the form is valid
through
$$ffoorrmm >>vvaalliiddaattee(())
. If the form is validated suc-
cessfully, the date is “frozen,” which allows no further
editing, and a “validated!” is echoed back to the brows-
er. This mini demo ends with the display of the form
through
$$ffoorrmm >>ddiissppllaayy(())
.
When executed, the code from Listing 4 is rendered
as shown in Figure 1. If that form is submitted and the
validation succeeds, the user would see a screen like

Figure 2. Should validation fail, the user would end up
with a screen like Figure 3.
I found it odd at first to adjust to building forms pro-
grammatically like this, but I really enjoy the benefit of
the built-in validation now. Still, the code in this exam-
ple may look too inflexible for your needs. In the next
example, we’ll go over how to combine the tools of
Smarty and HTML_QuickForm for a mini registration
application.
A very good introduction to the features and ways to
use HTML_QuickForm is on the PEAR website at
hhttttpp::////ppeeaarr pphhpp nneett//mmaannuuaall//eenn//ppaacckkaaggee hhttmmll hhttmmll qquuiicckk
ffoorrmm ttuuttoorriiaall pphhpp
.
Smarty and HTML_QuickForm
HTML_QuickForm allows rendering of
the form to be handled by the default
renderer as done in the example in
Listing 4 or through a template render-
er. The basic HTML_QuickForm gener-
ates a form that is completely function-
al; however, if you are building a proj-
ect with some greater design require-
ments, you might find that default
appearance does not meet the needs of
your project. By defining an alternate
template renderer with
HTML_QuickForm, it is possible to
achieve greater presentation cus-
tomization and control over the form’s

labels and elements as well as valida-
tion messages.
The example project we’re about to
examine combines Smarty and
HTML_QuickForm in a simple registra-
tion application. This application can
be set up with these steps on your own
development machine:
• Install the latest version of the
PEAR::DB and
PEAR::HTML_QuickForm mod-
ules. Instructions for installation
are available at the PEAR website
hhttttpp::////ppeeaarr pphhpp nneett
.
• Install the Smarty template
engine. Smarty and installation
instructions can be found at
hhttttpp::////ssmmaarrttyy pphhpp nneett
.
• Create a new MySQL 4+ data-
base (this example uses the name
ddbb__tteesstt
for it) and run the SQL
code shown in Listing 5. The
commands in that file create
tables for registration (
ttbbll__rreeggiiss
FFEEAATTUURREE
February 2005


PHP Architect

www.phparch.com
23
HTML_QuickForm and Smarty
Figure 1
Figure 2
ttrraattiioonn
) and conferences (
ttbbll__ccoonnffeerreennccee
).
Additionally, a few records are inserted into
ttbbll__ccoonnffeerreennccee
so that we may have some
basic data to work with.
• Create a directory named
rreeggAApppp
within a
web-viewable location.
• Store
iinnddeexx pphhpp
,
rreeggffoorrmm ttppll
and
tthhaannkkyyoouu ttppll
inside the new
rreeggAApppp
directo-
ry.

• In
iinnddeexx pphhpp
, the
$$ttppll >>ccoommppiillee__ddiirr
variable
may need to be modified from
//ttmmpp
to the
full or relative path of a directory which is
writable by the webserver.
//ttmmpp
should be
fine for many non-Windows users.

SSmmaarrttyy ccllaassss pphhpp
may exist on your
machine in a location different than is speci-
fied in the
iinnddeexx pphhpp
file. Depending on how
the Smarty template engine was installed,
this
rreeqquuiirree
may need to be modified to
match your system.
• Modify the
$$ddssnn
variable in the
iinnddeexx pphhpp
file

to a MySQL user that has
SSEELLEECCTT
and
IINNSSEERRTT
privileges on the new database. For demon-
stration purposes, it should be fine to use
the username and password used for creat-
ing the database.
After completing the steps above, if all went well you’ll
be able to point a browser at the newly created direc-
tory and see the web page shown in Figure 4.
How Does It Work?
The first few lines include the PEAR modules and
Smarty class file, which enables the use of their respec-
tive classes and methods.
After requiring the modules, it is possible to set up a
DSN-style connection string and connect to the data-
base. If the attempt to connect to the database results
in an error, the code ends by echoing out that message.
Next, a new Smarty template object is created and
the paths for the Smarty template and template compi-
lation directories are defined. By default, Smarty looks
to place templates in a sub-directory called
tteemmppllaatteess
,
while the compilation of templates is done within a
sub-directory named
tteemmppllaatteess__cc
. The Smarty compila-
tion process interprets template files into PHP files and

places those files within the compilation directory.
In this example, the template files are located in the
current directory. This was done for simplicity, as there
are only two template files. The template compilation
directory was defined as
//ttmmpp
to keep things easy to set
up. It seems to be considered good form to place the
template compilation directory in a location which is
not viewable through the web—but do remember that
it must be writable by the web server. To reduce the
steps for setup in this demonstration, the
template compilation directory of
//ttmmpp
was
selected.
One very cool feature of Smarty is a debugging con-
sole, which you can enable by setting the
ddeebbuuggggiinngg
value to
ttrruuee
. When debugging is turned on, the
Smarty debugging console pops up in a new browser
window. This can be hugely helpful in seeing a big-pic-
ture view of variables that are available for use in the
Smarty template file. If you’re like me and get stuck
sometimes because you can’t see something right
under your nose, this tool can help.
Next, a couple arrays are set up. The data from these
arrays are used in HTML select elements. The first array

is built by selecting data from the database. A request
is made of the database for upcoming conference
records (ID values and conference information). That
data is assigned to the
$$aaCCoonnffeerreennccee
variable through
the
$$ddbb >>GGeettAAssssoocc(())
method.
$$aaPPrreeffiixx
is a two-dimen-
sional array of prefixes. There are a number of ways to
populate select elements, both within
HTML_QuickForm and through Smarty. Building a
select element with results from a database was an
example that seemed important to include.
With some preliminary variable definitions out of the
way, the HTML_QuickForm object is created.
ffrrmmRReegg
is
defined as the name and ID of the form,
PPOOSSTT
is the
method and the action is set through the
$$__SSEERRVVEERR
vari-
able
$$__SSEERRVVEERR[[‘‘RREEQQUUEESSTT__UURRII’’]]
. The next group of lines
are all very similar—form elements are rapidly defined

through the
$$ffoorrmm >>aaddddEElleemmeenntt(())
method. This block
of code adds a header, the two select elements that
February 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
24
HTML_QuickForm and Smarty
CREATE TABLE tbl_registration (
id int(11) NOT NULL auto_increment,
ts timestamp(14) NOT NULL,
registrationdate datetime NOT NULL,
conferenceid int(11) NOT NULL,
prefix varchar(4),
firstname varchar(100) NOT NULL,
lastname varchar(20) NOT NULL,
address1 varchar(50) NOT NULL,
address2 varchar(50),
city varchar(50) NOT NULL,
state varchar(30) NOT NULL,
zip varchar(10) NOT NULL,
phone varchar(15),
email varchar(50) NOT NULL,
PRIMARY KEY (id),
KEY idx_conference_email (conferenceid,email,id)
);

CREATE TABLE tbl_conference (
id int(11) NOT NULL auto_increment,
cost decimal(10,0) NOT NULL,
date date NOT NULL,
location varchar(80) NOT NULL,
title varchar(255) NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO tbl_conference (cost, date, location, title)
VALUES (200, ‘2005-07-11’, ‘Las Vegas’, ‘Vegas baby, Vegas!’);
INSERT INTO tbl_conference (cost, date, location, title)
VALUES (99, ‘2005-07-18’, ‘Boston’, ‘Solving problems through big-
ger government’);
INSERT INTO tbl_conference (cost, date, location, title)
VALUES (500, ‘2005-07-25’, ‘Toronto’, ‘Management Consulting’);
Listing 5
were defined earlier and some text fields.
It is possible to group form elements together by cre-
ating an array of elements as is done for
$$cciittyySSttaatteeZZiipp
. Here
cciittyy
,
ssttaattee
and
zziipp
elements are
added through the
HHTTMMLL__QQuuiicckkFFoorrmm::::ccrreeaatteeEElleemmeenntt(())
method. That array is added to the form object

through the
$$ffoorrmm >>aaddddGGrroouupp(())
method.
A couple of custom validation functions are regis-
tered with
$$ffoorrmm >>rreeggiisstteerrRRuullee(())
.
rreeggiisstteerrRRuullee(())
behaves slightly differently, depending on the type of
rule that is being called. For example, the first
rule is assigned the name
cchheecckkCCiittyySSttaatteeZZiipp
. It
executes a callback function of
vvCCiittyySSttaatteeZZiipp
. The
second rule is assigned the name
cchheecckkPPhhoonnee
and works using the specified regular expression
//dd\\{{33}}\\DD**\\dd{{33}}\\DD**\\dd{{33}}\\DD**\\dd{{44}}\\DD**\\dd**$$//
. If you’re
unfamiliar with regular expressions or have a tough
time with them as I do, the string can
be broken down like this:
/\d{3} # 3 digits
\D*\d{3} # 0 or more non
digits followed
by 3 digits
\D*\d{4} # 0 or more non
digits followed

by 4 digits
\D*\d*$/ # 0 or more non
digits followed
# ending with an
optional number
(eg extension)
I almost always need to seek reference
when creating regular expressions, but
they can allow you to do such great
things with very limited code that it’s
almost always worth the effort. This val-
idation test only passes after receiving a
phone number that matches the for-
mat defined in the regular expression.
221122 555555 11221122
, for example, matches, as
would
((221122)) 555555 11221122 eexxtt 1122
. An
alternative regular expression would be
more welcoming for attendees coming
from outside the United States and
Canada. Take a look at George
Schlossnagle’s regular expressions arti-
cles from the March 2004 and April
2004 editions of php|architect for
deeper information in putting regular
expressions to work in PHP.
Once these specialty validation rules
defined, they are added with the

method
$$ffoorrmm >>aaddddRRuullee(())
.
aaddddRRuullee(())
accepts the name of the field or group
that the rule applies to as well as a
prompt to display if a validation rule
doesn’t pass.
aaddddRRuullee
’s final parameter
is the type of rule which is being applied (e.g. required,
email or a custom rule).
Gaining On It!
All the form elements have been defined and the
groundwork for validation has been completed. The
new renderer object is created by passing the Smarty
template object. Presentation behaviours
are defined for the renderer
with
sseettRReeqquuiirreeddTTeemmppllaattee(())
and
sseettEErrrroorrTTeemmppllaattee(())
.
These methods receive their parameters as Smarty tem-
plate code, which is then used in rendering the form
when required fields or errors are encountered.
The code attempts to validate the form through the
$$ffoorrmm >>vvaalliiddaattee(())
method. If the form data passes val-
idation rules, the form is processed with the

aaddddRReeggiissttrraattiioonn(())
function. That function inserts a reg-
FFEEAATTUURREE
February 2005

PHP Architect

www.phparch.com
25
HTML_QuickForm and Smarty
Figure 3
Figure 4

×