Vous êtes sur la page 1sur 52

Licensed to:

Joseph Crawford
info@josephcrawford.com
User #63883

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

CONTENTS
February 2009

FEATURES
13

VCL for PHP

Jos Len Serna

20

Rich Internet Applications with Flex and PHP: Part 1

Richard Bates

28

Taking the Desktop Back

Ricky Robinett

33

Optimizing Dojo and Zend Framework Integration

Matthew Weier O'Phinney

41

Grokking the REST Architectural Style

Ben Ramsey

VCL, PHP and a Visual IDE for the win

Creating Desktop RIAs using PHP and Adobe AIR


Built-in support makes Ajax a breeze.

Discover the crucial principles of the REST style.

COLUMNS
4
6
8
10
48
50

Editorial

Elizabeth Tucker Long

New Kid on the Block

ElePHPants!
PEAR Corner

Helgi ormar orbjrnsson

Enterprise PHP

Ivo Jansch

Security Roundup

Arne Blankerts

exit(0);

Marco Tabini

Version Naming
Technical Design

Securing Software & File Uploads


My Way or the UNIX Way

Download this months code at: http://phparch.com/code

WRITE FOR US!

If you want to bring a PHP-related topic to the attention of the professional PHP community,
whether it is personal research, company software, or anything else, why not write an article for
php|architect? If you would like to contribute, contact us, and one of our editors will be happy to
help you hone your idea and turn it into a beautiful article for our magazine. Visit www.phparch.
com/writeforus.php or contact our editorial team at write@phparch.com and get started!

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Enrich your PHP applications with Flex

EDITORIAL

Round Two
by Elizabeth Tucker Long

E-mail me directly: beth@phparch.com


E-mail us in general: info@phparch.com
Post in our forums: http://c7y-bb.phparchitect.com
We appreciate all of the feedback that we get, so be sure to keep it coming.
Dont forget, if you are involved in a PHP or Python user group, we want to
add your group to our directory, so be sure to e-mail beth@phparch.com with
PHP User Group Info in the subject line.
This month, we are focusing on adding a little spice to your PHP development. Take a tour of RIA development with Flex and PHP with Richard Bates
while Matthew Weier OPhinney shows us how a partnership between Zend and
Dojo is making RIA development even easier. Jos Len Serna introduces us
to VCL which brings php into the visual IDE world, and Chris Cornutt makes a
strong case for using CodeIgniter as your framework of choice. If youd like to
branch out into desktop applications, Ricky Robinett walks us through displaying database information in a desktop application using PHP and AIR. Helgi
ormar orbjrnsson discusses PEARs contribution to naming conventions, and
Arne Blankerts provides some simple tips to protect our users from cross-site
scripting attacks. Ben Ramsey sets the record straight on the requirements for
RESTful applications, Ivo Jansch outlines how more time spent in the technical
design phase of a project can save you a huge headache later on, and Marco
finally tries out his iPhone.
I hope you enjoy this months issue!

What's New at Python Magazine


Learn more at: http://pythonmagazine.com
February 2009 Topics:
Mock testing techniques and tools (Grig Gheorghiu)
Creating a collection manager with Elixir (Gatan de Menten)
Multiple Documents on PyObjC (JC Cruz)
Using Python for Pedigree Analysis (John B. Cole, PhD)
Co-designing with web.py: Urban Mediator (Roman Suzi, Joanna
Saad-Sulonen, Andrea Botero)
Simple File Input and Output (Mark Mruss)
Universal Newlines Ate My File: A Cautionary Tale

February 2009
Volume 8 - Issue 2
Publisher
Arbi Arzoumani
Editor-in-Chief
Elizabeth Tucker Long
AuthorLiaison
Elizabeth Naramore
Cathleen MacIsaac
Technical Editors
Steph Fox
Simon Harris
Matthew Turland
Clark Everetts
Graphics & Layout
Arbi Arzoumani
Managing Editor
Arbi Arzoumani
Authors
Richard Bates, Arne Blankerts,
Chris Cornutt, Ivo Jansch, Matthew
Weier O'Phinney, Ben Ramsey, Ricky
Robinett, Jos Len Serna, Marco
Tabini, Helgi ormar orbjrnsson
php|architect (ISSN 1709-7169) is published
twelve times a year by Marco Tabini & Associates,
Inc., 28 Bombay Ave., Toronto, ON M3H1B7,
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.
php|architect, php|a, the php|architect logo,
Marco Tabini & Associates, Inc. and the MTA Logo
are trademarks of Marco Tabini & Associates, Inc.
Contact Information:
General mailbox:
info@phparch.com
Editorial:
editors@phparch.com
Sales & advertising:
sales@phparch.com
Printed in Canada

4 | February 2009 www.phparch.com

Copyright
2003-2009
Marco Tabini & Associates, Inc.
All Rights Reserved

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

elcome to the February edition of php|architect. I just want to say a


quick thanks to everyone who sent us feedback on the new layout and
features in the January issue. If that wasnt you, theres still time to
send us your comments:

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

ElePHPants!

Overlooking the Straits of Gibraltar. Photo


courtesy of Alexandru Stanoi.

Who knew ElePH


Pants were so go
od at pool!
Photo courtesy
of Cal Evans.

the view.
ing and enjoying
Mountain climb
ns.
tha
Re
k
ric
De
of
Photo courtesy

taxi. Photo
Almost home, just waiting for a
courtesy of Ivo Jansch.

Do you have photos of your ElePHPant? We would love to print them. Send us a high-resolution image (or if you
have the high-resolution image posted online, just send us the link) of your ElePHPant. We'll choose several photos
a month to publish. Just can't get enough of these elePHPants? Be sure to check out the ElePHPant World Tour http://www.elephpantworldtour.com
6 | February 2009 www.phparch.com

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

The elePHPants love to travel the world! Here are some photos that they have sent
us from their travels.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

COLUMN

PEAR Corner

Version
Naming
In this column series, Id like to write a openly about PEAR, specifically about its
good and bad sides.

EAR has been around for many, many years, and


thus has accumulated a lot of knowledge on how
to run a large scale project.
PEAR has run into countless hurdles along the way
that had to be solved in one way or another. As a result
of getting over these hurdles, we have produced good
things that affect the whole PHP community and also
things that well...lets face it, didnt help PEAR or PHP
a whole lot.
But, how do we bring that experience from the
knowledge bank of PEAR and give it back to the community, so other projects can learn from us and steer
clear of what we did wrong and embrace what PEAR did
right.
One of the things that really makes PEAR what it is
today are the standards we have been evolving for the
past couple of years. A lot of other projects and even
companies have embraced large chunks of those standards as their de facto standard for PHP userland code.
Just to name a few standards:
Distribution system (channels, packages,
package.xml)
Coding Standards
Version naming
Directory layout
Backwards Compatibility and what that entails
And many others

8 | February 2009 www.phparch.com

If you want to read about the distribution system, you


can grab the November and December issues of this
magazine where I wrote about it in good detail (and
thus will not spend any ink covering it here).

Version Naming
Lets start by talking about the version naming standard and why its important.
Now dont get me wrong, its not like PEAR invented
the need for version naming, be it for PHP projects or
the software world at large, but the fact is that PEAR
was one of the first, if not the first, large-scale PHP
project that had more than one concurrent release at a
time. This fact required a proper standard in the end.
So, almost 5 years ago today, the PEAR group at the
time went ahead and formalized a standard to keep the
version naming more consistent, yet still working with
the version_compare function.
The document they produced can be accessed from
http://pear.php.net/group/docs/20040226-vn.php, but I will
attempt to simplify it a little bit.
First, its important to understand that there is a
difference between version numbers and version state
and how they interact. Lets look at how the basics of
the version numbering system work. Consider x.y.z for a
second, now lets translate that into something human
readable.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

by Helgi ormar orbjrnsson

COLUMN

PEAR Corner

Now lets have a quick look at the states, dev,


alpha, beta, RC or stable (listed in the order of
code maturity). So what you end up with is x.y.zstate
except when you have a stable release. In PEAR,
you might see version namings like so: 0.5.6alpha1,
0.12.0beta3, 1.0.0RC4, 1.2.0 and so on. With this
system in mind, we need to see what each state and
number incrementation really means for you and your
project.
Quite often, I see people do their initial release, and
for some unknown reason, they decide that 0.0.1 is the
best version, swear by it even. In the version naming
standard we have in PEAR, that is not allowed because
when you are releasing the first release you are not
fixing bugs, you are adding new features, so the first
release should always be 0.1.0, at the very least.
Something that happens fairly often as well is that
people do their initial release as 1.0.0 with a stable
state, even though their project doesnt truly have a
stable API, for example, or even a stable product in
general. Perhaps its because they believe they managed to get it very stable, but the fact is, no matter how stable you think your product is for the first
release, always release the first one lower than 1.0.0
stable.
Keep in mind, when you go stable, stay stable! Dont
start messing up the API in a way that people will have
to alter their applications, this tends to be called BC,
or backwards compatibility.

Food for Thought


So, I perhaps didnt cover all that much of the version
naming standard, but I do believe I got my point across
and those interested in learning more can go to the
link I supplied above to get a better idea of how this
all works together beautifully.
A prime example of why its good to have a set standard on the version naming would be when Matthew
Weier OPhinney of Zend Framework fame contacted me
in late 2008 to determine whether or not PEAR had this
kind of a standard. The Zend Framework team was having internal discussions in regards to version naming,
especially for their preview releases, better known by
other folks as alpha releases, where new api changes
are introduced but still not considered stable or that an
api could possibly break before the final release.
In the end, Matthew managed to convince them to
use alpha/beta states on the package level while allowing them to use pr for the website and announcements.
This allows people to utilize version_compare on Zend
Framework for future releases, potentially use a PEAR
channel for distribution, and also, to have appropriate stability states for what the release is suppose to
reflect.
I felt like this was a very good example showing how
using a well-established naming convention benefits
the whole community and makes things a lot clearer for
those familiar with said standards.
Hopefully this is as useful to you as it was to me
and the projects of which I have been a part. It has,
at least, been highly successful to PEAR and numerous
other projects.

Backwards Compatibility
Now what is backwards compatibility? In short, it is
when I, as a application developer, pick lib X to use in
my application and pick release 1.2.0 to start utilizing
the API of lib X. Even though I dont follow the development of lib X, if they follow a proper, no-BC-breaking
approach, then I should be able to upgrade the lib from
1.2.0 to 1.6.0 without having to change a single line
in my code. If a BC break would have occurred between
1.2.0 and 1.6.0, then there is a good chance that my
application would stop working with such an upgrade.
So BC breaks should only happen below stable, preferably only in the alpha state, if possible.
9 | February 2009 www.phparch.com

During the day, Helgi ormar orbjrnsson works for


Ibuildings in London, UK. The rest of his time is taken up
by his passion for all things PEAR. Helgi is a long term
contributor with a wide range of PEAR packages behind him,
and also takes care of the PEAR website. He is currently an
elected member of the governing body, PEAR Group. Helgi
enjoys writing articles, speaking at conferences and working
on PEAR2 and Pyrus.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

x = Major release number


y = Minor, used for feature additions
z = patch level number, used when its purely
only a bug fix release

COLUMN

PHP

by Ivo Jansch

In this issue of the Enterprise PHP


column, Ivo takes a look at some aspects
of the technical design phase of PHP
applications. He covers some important
design decisions that PHP developers
should make, and what elements
make up a technical design for a PHP
application.

havent enjoyed any Radiohead albums since they


released Ok Computer years ago. After that, they
became too creative and too alternative for my
taste. However, I do like their recent single House of
Cards.
Now, before you think youre reading the wrong magazine, Radiohead does not have anything to do with
programming (except perhaps the remarkable fact that
their House of Cards video clip is actually open sourced

at http://code.google.com/creative/radiohead/). But the


House of Cards single is very fitting for this months
article in the Enterprise PHP series.
Today, were going to talk about the technical design
of PHP applications. Last month, we discussed requirements gathering - the what - and today, were going
to look at the how. If we do a technical design before
we start to write code, we make sure that were not
building a house of cards, but instead, a solid wellstructured application that wont break down by just
looking at it.

High-Level Architecture
The technical design of an application has a lot of different aspects. One of the first decisions we have to
make is what high-level architecture we will implement.
Depending on the requirements and the available infrastructure, we might go for a single monolithic set-up
where all the code makes up a single application. This
is what we would call a normal architecture for PHP
applications, and it is probably right for 95% of the applications.

This column benefits greatly from reader input. If you have an interesting project or if
you want to share how you employ PHP in your organization, drop me an email at
enterprisephp@phparch.com. I might contact you for a short interview, or at least I will
use your input when writing this column!
Thank you!
Ivo

10 | February 2009 www.phparch.com

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Technical Design

COLUMN

Version Naming

Service Oriented Architectures


Aside from the MVC model, there are more high-level
architectures that can be applied in PHP applications.
An interesting one to look at is the Service Oriented
Architecture or SOA for short. This architecture is commonly associated with Java and overkill, but in my
opinion, thats not justified. In an SOA, the application
is divided into several different web services that talk
to each other. In the above example of a hotel application, there could be an availability service giving
information about a rooms availability, a pricing service able to deal with pricing schemes, etc. There are
several advantages to a service oriented architecture:

11 | February 2009 www.phparch.com

Each service can be developed independently


from the others. This makes it easier to test
the individual components. Services that arent
ready yet can be stubbed (simulated).
Each service can scale independently. If the
availability service is used a lot more heavily than the pricing service, this service could
scale out to a cluster, while the remaining
services remain on a single box.
Services can each be tested independently.
Unit testing on a service is relatively easy because services have a well-defined API.
PHP is a very suitable language for SOA architectures,
because PHP contains native functionality in the form
of a SoapClient and SoapServer class that can be used
to either consume or to create a web service.
A common component in SOA environments is the
Enterprise Service Bus (ESB), which is more or less a
medium that services use to communicate. For most
PHP applications, an ESB is overkill, as the services
can talk with each other just fine without the need for
a bus. Still, there is an open source PHP ESB product
that might be worth having a look at when implementing a large SOA architecture: Blackbird ESB at
http://www.blackbirdesb.org.
When creating a technical design based on an SOA
architecture, first divide your application requirements
into logical units that would be able to operate fairly
independently. If you can define a clean API for how
a set of features can interact with its surroundings,
its a logical step to place those features in a separate
service. Once youve done this for all features, you have
a service model, and you can start to create the design
for each individual service.
A suggestion for further reading on SOA architectures is the book Understanding Enterprise SOA by Eric
Pulier and Hugh Taylor (http://manning.com/pulier/). The
book is not PHP specific; it explains the ins and outs of
SOA design in a language agnostic way.

Database Design
After weve made a decision on what high-level architecture to implement, we can have a look at the underlying data model. It is up for debate whether or not the
data model should be designed at an early stage in the
design process, but it is my personal experience that

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

The MVC model


A best practice in recent years is to use the MVC model
for such applications. MVC stands for Model, View,
Controller, where the Model contains the business logic
of the application, the View contains the presentation logic (the templates) and the Controller glues the
two together with application logic. It always helps to
have an example, and the clearest example of the MVC
model is a website for booking hotel rooms. The models
in this case would be the room and the reservation,
each containing the implementation of the business
logic, like calculating prices, checking availability, etc.
The view would be the templates that show information about the reservation on screen, and the controller
would implement the pages in a website that lets the
user create a reservation by showing him the view templates and enabling the user to manipulate the underlying model.
This way, the application has a clear structure, and
if you want to change the layout, you only have to
change the view templates. It also promotes reuse. You
can reuse the business logic of the application in multiple different scenarios. This makes programming more
efficient and enhances quality.
When creating the technical design for an MVC application, take the requirements and make a list of all the
models, the views and the controllers you need. Put all
the stuff that deals with how things look in the views.
Put all the things that comprise business logic (logic
that you can envision being more generic than the
application you are building, logic that relates more
to your business than to the website) in models. The
remaining parts (usually the descriptions of how a user
acts with the application) go in the controllers.

COLUMN

12 | February 2009 www.phparch.com

of such a partitioning of the database is that simple


joins across multiple databases arent possible in most
database servers. However, if the separation is strict
enough, those joins across functional parts of the database might not be necessary.

Application Design
The final aspect of the technical design is the design
of the code itself. After the high-level architecture and
the data model, the application design is the third important part of the technical design phase.
Typically, this part of the design consists of class
diagrams, sequence diagrams or data flow diagrams.
Data flow diagrams are useful when the focus of an application is on the data, and you need to identify how
this information flows from one component to the next
and what processing is done on the information. Class
diagrams are always useful, and sequence diagrams are
very useful if there is a complex hierarchy of classes
and you want to visualize what classes and method
calls are involved in a particular feature. All three modeling techniques help visualize the design of an application. The structure of an application is clearer if you
have it in front of you. If you need to change things or
add functionality, the models help in determining what
should be implemented where.

Conclusion
Weve covered just a few scenarios of high-level architecture, database design and application design. The
import take-away, however, is that you pay attention
to these design aspects. Tackling design issues during
the technical design phase saves a lot of time during
the implementation phase. In general, the earlier you
can tackle an issue, the lower the cost of the issue. In
the design phase, while there is no code to maintain,
you are in a good position to tackle architectural issues
such as the scalability of an application.

Ivo Jansch is the CTO of Ibuildings, a PHP services company


based in Europe. He is the author of php|architects Guide
to Enterprise PHP Development, and is an active blogger

and speaker in the PHP community. Ivo also initiated the


ATK Business Framework.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

it works really well to do it as early as possible. Eric


Raymond, one of the early evangelists of open source
software has a saying that goes like this: Smart data
structures and dumb code works a lot better than the
other way around (from his majestic The Cathedral
and The Bazaar article). The way I interpret this saying
is that if your data model is well-designed at an early
stage, the code that makes use of the data model will
be a lot easier and a lot clearer. Whereas if you create
the database in an ad hoc fashion on the fly while you
are writing the code, the code might be more complex
and less manageable, and the data model more difficult
to understand.
There are various techniques for modeling a database. I tend to stick to the classic ERD method for
relational databases with Crows foot notation (see
http://en.wikipedia.org/wiki/Entity-relationship_model), but
any modeling method will do, as long as you apply it
consistently, and as long as your fellow team members
can interpret your models properly.
More important than what notation you use, is the
actual design of the database. Im not going to talk
about stuff like normalization and general modeling,
Im going to assume that this is already part of your
development skills (and if not, there are excellent primers online). Instead Ill discuss a more specific design
decision when it comes to databases. Earlier, I discussed monolithic applications versus service oriented
architectures, and there is a similar design decision to
be made when it comes to the database.
In 95% of the cases, youll develop an application
that has a single database and all is good. But there
are situations where you might consider splitting the
data into multiple databases. In the SOA example, it is
a logical choice to give each service its own database
(on the other hand, its also fine for services to feed
on the same database), but multiple databases can
be a good thing in other applications as well. First, it
helps keep the data models simple (simple is good) and
focused around a certain task. Think of a database with
customer related data (CRM) and a separate database
for keeping track of stocks. The second reason is scalability. If you have multiple small databases, it is easier to scale up only those parts that need it. Instead of
having to scale a massive data model across a database
cluster, it might suffice to scale the heavy transactional
parts while the rest remains in a single database.
Note, by the way, that a significant disadvantage

Version Naming

FEATURE

VCL for PHP

C
L

by Jos Len Serna

hat is VCL for PHP? In short, it is a component


library. Youve probably used other component libraries, like Zend Framework, so what
makes VCL for PHP different? The V in its name, which
stands for Visual. This library was designed from the
beginning to be integrated into a Visual IDE, allowing
developers to write web applications in PHP using RAD
technologies.
When Delphi for Windows 1.0 was released, the status of desktop application development for Windows
was very similar to the status of PHP web application
development today. There are numerous frameworks
and class libraries trying to make PHP web application
development faster and easier, but until recently, there
wasnt a complete solution that allowed you to do it
with a component library in an IDE with visual capabilities. That is why Delphi for PHP and VCL for PHP were
created: to provide a common path in which all existing
and future code could coexist and to create a standard
for PHP components.

Goals of VCL for PHP


VCL for PHP was designed with a very specific purpose,
and the goal was not to write yet another PHP framework:

13 | February 2009 www.phparch.com

Be used in a Visual IDE where components can


be dragged from a palette and dropped into a
design panel
Create a component model to unify the concepts of properties, methods and events
Replicate VCL for Windows library, so using
it would be familiar to existing Delphi for
Windows developers
Reuse as much code as possible from other,
non-VCL libraries
Provide a persistence mechanism (using sessions) to emulate desktop applications

REQUIREMENTS
PHP: 5.2+
Other Software: Zend Framework, PEAR and others
Useful/Related Links:
http://www.qadram.com/vcl4php
http://en.wikipedia.org/wiki/Property_(computer_
science)

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Interested in Visual RAD tools for PHP? This article provides a general overview of
VCL, Visual Component Library, for PHP, what its useful for, and introduces you to
integrating your own components into the Delphi for PHP IDE.

FEATURE

LISTING 1
1.<?php
2.require_once("vcl/vcl.inc.php");
3.//Includes
4.use_unit("forms.inc.php");
5.use_unit("extctrls.inc.php");
6.use_unit("stdctrls.inc.php");
7.
8.//Class definition
9.class Index extends Page
10.{
11. public $Button1 = null;
12. public $Panel1 = null;
13.}
14.
15.global $application;
16.
17.global $Index;
18.
19.//Creates the form
20.$Index=new Index($application);
21.
22.//Read from resource file
23.$Index->loadResource(__FILE__);
24.
25.//Shows the form
26.$Index->show();
27.
28.?>
29.

LISTING 2
1.<?php
2.<object class="Index" name="Index" baseclass="page">
3. <property name="Background"></property>
4. <property name="Caption">Index Page</property>
5. <property name="DocType">dtNone</property>
6. <property name="Height">600</property>
7. <property name="IsMaster">0</property>
8. <property name="Name">Index</property>
9. <property name="Width">800</property>
10. <object class="Panel" name="Panel1" >
11. <property name="Caption">Panel1</property>
12. <property name="Height">192</property>
13. <property name="Left">100</property>
14. <property name="Name">Panel1</property>
15. <property name="Top">72</property>
16. <property name="Width">364</property>
17. <object class="Button" name="Button1" >
18. <property name="Caption">Button1</property>
19. <property name="Height">25</property>
20. <property name="Left">88</property>
21. <property name="Name">Button1</property>
22. <property name="Top">68</property>
23. <property name="Width">75</property>
24. </object>
25. </object>
26.</object>
27.?>
28.

14 | February 2009 www.phparch.com

you ask What about class variables, methods, getters


and setters? and start throwing things at me, please
understand that what we mean by properties here are
class entities that can be accessed in our code directly
by assignment, or used in expressions, but are actually protected by underlying class methods. Those
class methods are normally not invoked explicitly. That
is the syntactic difference between class variables
in PHP and properties in Delphi. More on this under
Component Model later in this article.
VCL for PHP was also designed to allow code reuse
from other libraries. Since it doesnt require a strict
folder structure, and needs only minimal code to implement a wrapper, you can use existing code inside the
IDE with little effort. We have wrapped into the Delphi
for PHP IDE some Zend Framework classes, some PEAR
classes, lots of qooxdoo widgets and ExtJS widgets.
You can wrap almost anything and provide a common
interface through those wrappers, so any developer will
be able to use them easily.

Resource Files
The Delphi for PHP IDE stores and reads component
properties from an .xml.php file. This file is created
by the IDE at design-time, but you are not required to
use the IDE; as it is an XML formatted text file, you
can create it with a text editor. This file is used by
the Page component to create all components and set
the properties to their initial values. This is done in
the loadResource() call, just before the show() call.
Show() is what causes a component to be displayed
in the browser. These files are external resources you
can use as templates, and they provide a separation
between the interface and the code.
In Listing 1, you can see the basic structure of a
Page class with calls to loadResource() and show(). In
Listing 2, you can see the contents of the .xml.php
file. Resource files are not a requirement. You can create your components and assign properties manually, as
shown in Listing 3.

Writing Your Own Components


Components can be built using anything a browser can
understand, like HTML, CSS, Javascript, Flash, Images,
etc. For example, a Button is a component built using
just the <input> HTML tag, but MonthCalendar and
DateTimePicker use DHTML Calendar, a third-party
library that creates calendars with Javascript. These

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Several things must be taken into account to make a


library work in a Visual design tool, as the IDE requires
extra information about the components. This information must be provided by the component developer.
We will see more on this below.
VCL for PHP proposes a component model with all
the features required to integrate components into a
Visual IDE, and a coding convention to specify properties and events. Currently, PHP - unlike languages like
Delphi for Windows or C# - doesnt have a syntax to
express properties, so that must be emulated. Before

VCL for PHP

FEATURE

VCL for PHP

Class Tree
The class library is made up of a
full tree of classes, but all of them
share common ancestors which
implement the core functionality. The root class is called Object,
and all classes in the library
inherit from it. The next major
classes that inherit from Object
are Persistent, Component, and
15 | February 2009 www.phparch.com

Control. Check out Figure 2 to see


a brief class tree.
In this tree, each class provides
specific functionality:
Object: Property System
Persistent: Serialization
and Persistence
Component: Ownership
Control: Parentship and
Visual Capabilities

FIGURE 1

FIGURE 2

Ownership and
Parentship
Its important to understand the
difference between ownership and
parentship, as that will give you
an idea of how components are organized inside a Page. By default,
a Page owns all the components
placed inside, no matter which one
is the parent. After that, the parent for a control is the control into
which it is placed. Lets imagine a
Page, with a Panel, and inside the
Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

components simply wrap the functionality of the library by adding


an interface of properties, methods
and events, but the hard work is
done by the library.
As you can see, creating VCL for
PHP components is not reinventing the wheel like in some other
frameworks; instead, you can just
wrap existing code. Components
can be non-visual and just provide
functionality. The Zend Framework
components for authentication and
ACL, for instance, have no visual
output. Non-visual components
are represented in the designer
as small icons, and you can set
their properties and attach event
handlers as with any other components.
VCL for PHP components are
very simple to write; the first
method you must know about is
dumpContents(). This method is
called when a component needs to
dump all its code to the browser,
and you simply echo all the code
that makes up your component.
This simple approach makes creating wrappers for other libraries very
easy. No complicated tags, attributes, folders, etc. Just dump the
code, and you are done.
Listing 4 shows the code used
by the Upload component in the
dumpContents() method and Figure
1 shows the Upload component in
the visual designer.

FEATURE
Panel, a Button. The Page is the owner of the Panel
and of the Button, but the Page is only the parent of
the Panel, and the Panel is the parent of the Button.
When you call show() for a Page, it iterates through
all the children, telling each of them to show(), and
in turn, each child tells all of its children to show().
These nested calls cause all the controls on a Page to
be shown.

VCL for PHP


On the other hand, PHP does provide magic methods
which can be used to mimic the behaviour of properties. This is what VCL for PHP uses to let you write
methods that will be accessed like properties. As
stated earlier, all VCL for PHP classes inherit from, at
the top level, a class named Object. This class implements the PHP magic methods __get() and __set() to
allow you to create such properties. Look at Listing 6
to see what a property looks like.

Component Model

LISTING 3
1.<?php
2.require_once("vcl/vcl.inc.php");
3.//Includes
4.use_unit("forms.inc.php");
5.use_unit("extctrls.inc.php");
6.use_unit("stdctrls.inc.php");
7.
8.//Class definition
9.class Index extends Page
10.{
11. public $Button1 = null;
12. public $Panel1 = null;
13.}
14.
15.global $application;
16.
17.global $Index;
18.
19.//Creates the form
20.$Index=new Index($application);
21.
22.$Index->Panel1 = new Panel($Index);
23.$Index->Panel1->Parent = $Index;
24.$Index->Panel1->Height = 192;
25.$Index->Panel1->Left = 100;
26.$Index->Panel1->Name = "Panel1";
27.$Index->Panel1->Top = 72;
28.$Index->Panel1->Width = 364;
29.
30.$Index->Button1 = new Button($Index);
31.$Index->Button1->Parent = $Index->Panel1;
32.$Index->Button1->Caption = "Button1";
33.$Index->Button1->Height = 25;
34.$Index->Button1->Left = 88;
35.$Index->Button1->Name = "Button1";
36.$Index->Button1->Top = 68;
37.$Index->Button1->Width = 77;
38.
39.//Shows the form
40.$Index->show();
41.
42.?>

16 | February 2009 www.phparch.com

LISTING 4
1.<?php
2.function dumpContents()
3.{
4. $attributes = $this->getCommonAttributes();
5.
6. $style = $this->getCommonStyles();
7.
8. if ($this->readHidden())
9. {
10. if (($this->ControlState & csDesigning) != csDesigning)
11. {
12. $style.=" visibility:hidden; ";
13. }
14. }
15.
16.
17. if ($style != '') $style = 'style="' . $style . '" ';
18.
19. if ($this->_onshow != null)
20. {
21. $this->callEvent('onshow', array());
22. }
23.
24. echo '<input type="file" value="Up" id="'. $this->_name .
25. '" name="'. $this->_name .'" '. $style .' '.
26. $attributes .'/>';
27.
28.}
29.?>
30.

LISTING 5
1.unit listing5;
2.
3.interface
4.
5.type
6. TMyObject=class
7. private
8. FMyProperty: string;
9. procedure SetMyProperty(const Value: string);
10. published
11. property MyProperty:string read FMyProperty
12. write SetMyProperty;
13. end;
14.
15.implementation
16.
17.{ TMyObject }
18.
19.procedure TMyObject.SetMyProperty(const Value: string);
20.begin
21. FMyProperty := Value;
22.end;
23.
24.end.
25.
26.// to access the property
27.var obj: TMyObject;
28.obj.MyProperty := 'Property Value';
29.Writeln(obj.MyProperty);
30.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

PHP lacks, at this time, properties, in the sense of


providing access methods to fields. A property can be
described as something between a field and a method,
in which the storage is done in the field, but the access
to that field is done using methods, to get and set the
value of that field. By having methods for accessing
a property, you have the opportunity to write code to
react to property changes or to provide some validation
or formatting code when getting the value of a property. In languages like Delphi for Windows or C#, the
language itself provides keyword constructs for that.
Take a look at the Delphi for Windows code sample in
Listing 5.

FEATURE

VCL for PHP

In PHP 5, the visibility of class members can be private, protected or public, but for the IDE, a new scope
must be added, called published. At run-time, a published property is public, but at design-time, only published properties will be shown in the Object Inspector.
This is necessary because not all properties should be
set by the developer at design-time. Since PHP doesnt
have this visibility keyword, VCL for PHP needs some
way to accomplish it.
This is the convention the IDE uses to identify which
properties to show in the Object Inspector: properties whose accessor method names start with read or
write are considered public, and those whose accessor
method names start with get and set are considered
published.

Events
A component can have two types of events, regular
events and Javascript events. Regular events are those
in which the event handler must be a PHP method;
i.e., the code must be written in PHP. For Javascript
events, the event handler must be a function written
in Javascript. The main difference is when and where
the code is executed. For PHP events, the code is executed when the form is submitted to the server. For
Javascript events, the code is executed in the browser,
before anything is posted to the server. For example, a
Button can have two OnClick events; the first one fired
is the Javascript OnClick event, and then after the form
is posted, the PHP OnClick is called.
Events are regular properties - they contain a string
with the name of the method to call - so, to allow
the IDE to know the difference between properties,
events and Javascript events, another convention is
used. Regular events must start with On; for example,
OnClick, and Javascript events must start with jsOn,
for example, jsOnClick.

Calling Events
Events are called by components when all relevant conditions are met. Lets take an easy example, like the
Button OnClick event. In HTML, you know a form button has been clicked if, in the request, there is a form
field that has a name matching the contents of the
name attribute of the <input> tag, with a value set in
the value attribute of the <input> tag. This is exactly
what the Button component looks for. In the init()
17 | February 2009 www.phparch.com

method of the Button class, there is code that fires the


OnClick event, which checks that those conditions are
met to fire a call to the OnClick() event handler using
callEvent().
All event handlers must have two parameters,
$sender and $params, the first one is the object/component that has produced the event, and the second
can be anything the component wants to send, like
mouse coordinates or other information. Events can
also return a value, and it depends on the component
developer to use it or not.
Listing 7 shows a basic example of how to create a
button and attach it to an event to process clicks.

Session Persistence
One of the basic features of VCL for PHP is session
persistence. This features allows you to write web applications that behave like desktop apps. In a desktop
application, you dont worry when your application
starts and finishes, and there is no need to backup
and restore the status of all the controls you have on a
form as the user moves from screen to screen.
With VCL for PHP, you get the same behaviour, because it serializes and unserializes object properties
when required. That way, the state of those components will be always what you expect. For example, if
you change the background color of a Label to red, you
expect that, no matter what happens to the application, no matter which link the user follows, the background color for the Label should always be red, until
you decide to change it. All this is automatic if you
use VCL for PHP components, as it saves in the session
LISTING 6
1.<?php
2.
3.class TMyObject extends Object
4.{
5. protected $_myproperty="";
6.
7. function getMyProperty()
8. {
9. return $this->_myproperty;
10. }
11.
12. function setMyProperty($value)
13. {
14. $this->_myproperty=$value;
15. }
16.
17. function defaultMyProperty()
18. {
19. return "";
20. }
21.}
22.
23.?>
24.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Public and Published

FEATURE
all properties that differ from their default values, and
restores them back again when the script is started.

method from a Javascript event and let the ajax engine


update the browser according to property changes.

Default Values

Data Access

Properties can have default values, which is important


for several reasons. First, the IDEs Object Inspector
shows in bold those property values that differ from
their default value. This allows a developer to easily
see which properties have been changed from default
values and more importantly, for session persistence,
knowing what values are defaults allows us to store just
those properties whose values differ from their defaults. This saves a lot of session space. Finally, when
the IDE saves an .xml.php file, it again saves only the
property values for those properties that differ from
their default values. This saves disk space and speeds
up the .xml.php parsing and loading.

VCL for PHP provides several components to access


data. The standard components are based on the
ADOdb library, which provides an abstraction layer over
the data. If you need faster access and dont require
server abstraction, you can use the native data access
controls for MySQL and Oracle. These controls use the
native PHP functions instead of ADOdb.
Delphi for Windows users will find the data connection model very familiar. You use a Database component, which represents the connection to a server and
the selection of a database. After that, you place Table
or Query components, connect to that database, get all
data from a specific table or use a query to get a subset
or a join of several tables. Then, to connect that Table
or Query (all of them are Dataset descendants) to controls, you use a Datasource.
Using this connection mechanism, components can
access data without worrying about the underlying
structure, and more types of Datasets can be written,
as long they implement all required properties and
methods.

Ajax Integration
With VCL for PHP, you can make use of Ajax, by using
the method ajaxCall(), which generates all the required javascript code to perform a call to the server
using ajax, and then process the returned results to
update the browser.
To make it work, you need to set the UseAjax property of the Page to true, so that processing takes place.
If you need to get debug information for the ajax
requests, you can set UseAjaxDebug to true and youll
get a window with all the information.
In Listing 8, you can see how easy it is to call a PHP

Template Engines
VCL for PHP allows you to make use of templates,
you are not restricted to use .xml.php files, and you
LISTING 8

LISTING 7
1.<?php
2.require_once("vcl/vcl.inc.php");
3.
4.use_unit("forms.inc.php");
5.use_unit("stdctrls.inc.php");
6.
7.class MyPage extends Page
8.{
9. public $Button1=null;
10.
11. function Button1Click($sender, $params)
12. {
13. echo "Button clicked!<hr>";
14. }
15.}
16.
17.$MyPage = new MyPage($application);
18.$MyPage->Name = "MyPage";
19.$MyPage->Button1 = new Button($MyPage);
20.$MyPage->Button1->Name = "Button1";
21.$MyPage->Button1->Parent = $MyPage;
22.$MyPage->Button1->Left= 100;
23.$MyPage->Button1->Top= 100;
24.$MyPage->Button1->OnClick = "Button1Click";
25.$MyPage->init();
26.$MyPage->show();
27.?>

18 | February 2009 www.phparch.com

1.<?php
2.class Index extends Page
3.{
4. public $Label1 = null;
5. public $Button1 = null;
6. function Button1JSClick($sender, $params)
7. {
8. //Dump the call using Ajax to the Button1Click event
9. echo $this->Button1->ajaxCall("Button1Click");
10.?>
11. //Return false to prevent the button submit the form
12. return(false);
13. <?php
14. }
15.
16. function Button1Click($sender, $params)
17. {
18. $this->Button1->Caption = "clicked Ajax " .
19. date("Y-m-d g:i:s a");
20.
21. $this->Label1->Caption = "Hello from Ajax!! " .
22. date("Y-m-d g:i:s a");
23.
24. $this->Label1->Color = "#" .
25. dechex(rand(0, 0xFFFFFF));
26. }
27.}
28.?>
29.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

VCL for PHP

FEATURE

VCL for PHP

HeaderCode
StartForm
EndForm
Check Listing 9 to see what a template looks like, and
where the tags should be inserted. To add VCL for PHP
components, just insert the name of a component as
a smarty tag wherever you want that component to be
shown. Then, just set the TemplateEngine property to
SmartyTemplate and TemplateFilename to the name of
the file in which you stored the template. When the
page is shown, the template will be used to render the
visual aspect and components will be inserted into the
page where you decided.

IDE Integration
To enable your components to be used in a visual IDE,
you need to specify some extra information, called
design-time information. This information allows the
IDE to know how to handle your component, how to
edit properties in the Object Inspector, and where to
place your components on the Tool Palette.
This information is not required when you deploy
your application, so it doesnt add any overhead or
extra size; it is information specific to the IDE. To set
this design-time information and install your components in the IDE, you create a package, a php file with
the extension .package.php. In Listing 10, you can
see a basic package file with calls to the functions that
interact with the IDE.
In a package, you can specify where the IDE can find
the icons that represent your components on the Tool
Palette, the title of your package, the components you
want to install, and the page in which the Tool Palette
will be placed.
To let the Object Inspector know how to handle
some properties, we need to provide specific information in the component package. For example, an array
property should be handled by a specific property
editor in the IDE, which reads the array and provides
a visual interface to edit it. Or a color property,
while the user can type a color name or rgb value, its

19 | February 2009 www.phparch.com

better to provide a dialog to let the user select a color


visually. At the moment, property editors like these
must be written in Delphi for Windows.

Conclusion
VCL for PHP is a new approach to developing PHP web
applications, not only allowing you to use a Visual IDE,
but to apply techniques used when building desktop
applications. This opens up a full range of new possibilities and also opens the door for developers to wrap
and market PHP code according to a new component
standard.

LISTING 9
1.<!DOCTYPE html PUBLIC
2."-//W3C//DTD XHTML 1.0 Transitional//EN"
3."http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4.<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
5.<head>
6.<title>Test Template</title>
7.<meta http-equiv="content-type"
8. content="text/html; charset=utf-8" />
9.{%$HeaderCode%}
10.</head>
11.<body>
12.{%$StartForm%}
13.{%$EndForm%}
14.</body>
15.</html>

LISTING 10
1.<?php
2.require_once("vcl/vcl.inc.php");
3.use_unit("designide.inc.php");
4.
5.setPackageTitle("Put the title of your package here");
6.//Change this setting to the path where the icons for
7.//the components reside
8.setIconPath("./icons");
9.
10.// "PaletteCateg" below should be replaced with the
11.// category in the Tool Palette where the component
12.// should appear
13.
14.//Change yourunit.inc.php to the php file which contains
15.//the component's code
16.registerComponents("PaletteCateg",array("NewComponent"),
17. "yourunit.inc.php");
18.?>

Jos Len Serna is CEO of qadram software S.L. and

the main architect of Delphi for PHP. Delphi for PHP is a


product developed in a partnership between CodeGear
and qadram software S.L. You can contact him at
support@qadram.com.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

can keep working with HTML templates. In fact, the


template engine used by default is Smarty, so if you
already have Smarty templates, you can reuse them
easily. To make an HTML template work in VCL for PHP,
just place three tags in the file, so the library knows
where to put the required code:

FEATURE

Rich Internet Applications


with

Flex & PHP

PART 1

Youve probably noticed that many companies creating rich Internet


applications (RIAs) use the terms Flex and Java almost interchangeably.
Its a commonly held belief that only Java technology can deliver the
features needed to run a serious RIA. But those of us who work with
PHP every day know that it can compete with Java in almost any
market and even best it in a few major areas.
PHP is free, easy to deploy, highly adaptable,
and supported by virtually every Internet
hosting company-even those that charge
only $1.95 per month.
So, why arent more people building their
Adobe Flexbased RIAs with PHP? The biggest
reason is that no major vendor has
supported an implementation
of Adobes Action Message
Format (AMF) integration
with PHP...until now.
Adobe and Zend are both
backing
Zend_Amf,
a Zend Framework
extension that allows
Flex applications to
speak their native
tongue to PHP.
20 | February 2009 www.phparch.com

Fx

Related URLs
PHP: 5.1.4 (for Zend Framework)
Other Software:
Flex Builder v3+ or the Flex Builder plug-in for
Eclipse v3.01+
MySQL Server version 4+
Zend Framework 1.7+
Apache or another PHP-enabled Web server
Useful/Related Links:
Adobe Flex 3 LiveDocs: http://livedocs.adobe.
com/flex/3/
Zend Framework: http://framework.zend.com/
ActionScript 3 CoreLib: http://code.google.
com/p/as3corelib/
Authors Development Blog: http://flexandair.
com/

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

by Richard Bates

FEATURE

Rich Internet Applications with Flex and PHP: Part 1

There are many reasons for choosing Flex as your RIA


development platform. One of the most compelling
arguments is that Flex applications run in Adobe Flash
Player, which is deployed on an astounding 98% of
computers. An equally important statistic is the rate at
which new Flash Player releases are adopted. Adobe estimates that new Flash Player releases reach 90% penetration by their twelfth month of availability. In other
words, almost everyone with a computer can run your
Flex applications without installing anything extra.
Another advantage youll get from Flex is speed and
ease of development. Flexs MXML markup language
makes creating visual components and effects almost
effortless. Couple that with Adobe Flex Builder, which
is based on the immensely popular Eclipse integrated
development environment (IDE), and youve got one of
the most powerful development toolkits available.
This article focuses on one of Flexs powerful features
in particular: AMF. Flash Playerbased applications
like those created in Flex and the Adobe Integrated
Runtime (AIR) can communicate using Adobes binary
AMF format. Using AMF means huge cuts in bandwidth,
with an estimated size as little as 1/6th the size of
the same information represented in a text format like
XML. Moreover, communicating with AMF takes a lot
less code than XML. Youll be using the new Zend_Amf
extension of the Zend Framework to handle the AMF
communication between Flex and PHP.

The Document Manager Application


To explore the Flex/PHP RIA building process, well
be creating an online document-management application. I chose this application because you can set it
FIGURE 1

21 | February 2009 www.phparch.com

up relatively quickly, and your options for extending


it are virtually limitless. Along the way, youll pick up
the skills you need to start building almost any type of
RIA with Flex Builder, Zend_Amf, and PHP. So, lets get
started.

Prior Planning Prevents Poor


Performance
Its a used-up old clich but inexorably true. The first
thing youll need to do is determine what objects youll
be using, their structure, and how to store their underlying data. For this document management application,
the most important object is...the document! Figure 1
depicts the basic Document object youll be using for
this exercise:
Firstly, the document will have an id, which is an integer. It will be an auto-incremented value determined
by MySQL. The user_id property tells you to which
user the document belongs. The name is a descriptive friendly name that the user provides. The url
property holds the location of the file after it has been
uploaded. The description is a longer text field that
is also provided by the user. The type is the extension of the uploaded file, without a period. Finally,
the file_size property denotes the files size in bytes.
There are, of course, many other properties you might
want to keep track of, but for now, these will suffice.
As referenced in the documents user_id property,
you also need an object to represent users. Creating
one now means that you can authenticate users and
show each user only his or her documents. Keep the
User simple, as shown in Figure 2.
The users id, like the documents id, will be an
auto-incremented integer from MySQL. The user will
also have a friendly name, an email address, and a
FIGURE 2

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Why Use Flex?

password. In this sample application, were going to


leave the password in plain text, but Flex can support
MD5 and Secure Hash Algorithm (SHA1) hashing. See
the Related Links section of this article for more information.

Setting up the Database


Now that you know exactly what information you need
to store for your objects, its time to set up the database for persistent storage. First, create a new database, and call it docs. Next, create the documents
table. You can import the Structured Query Language
(SQL) script in Listing 1 to set up the proper fields.
Now, create a users table. Use the SQL script in
Listing 2 to set up the fields and add a default user for
testing.
Note: If you do use this script, note that the test
users email address is test@test.com and the password
is password.

Creating the Project Structure


Now that the database is ready, you can start defining the objects in your code. You must go through
this process twice, once in PHP and again in Adobe
ActionScript 3. Tackle the PHP first, and begin by
creating a proper folder structure. Because your Flex
application will be accessing PHP through your Web
server, you must create the project under your Web
LISTING 1
1.
2.CREATE TABLE IF NOT EXISTS `documents` (
3. `id` int(11) NOT NULL auto_increment,
4. `user_id` int(11) NOT NULL,
5. `name` varchar(255) NOT NULL,
6. `url` varchar(255) NOT NULL,
7. `description` text NOT NULL,
8. `type` varchar(12) NOT NULL,
9. `file_size` int(15) NOT NULL,
10. PRIMARY KEY (`id`)
11.) AUTO_INCREMENT=6;
12.

LISTING 2
1.
2.CREATE TABLE IF NOT EXISTS `users` (
3. `id` int(11) NOT NULL auto_increment,
4. `name` varchar(255) NOT NULL,
5. `email` varchar(255) NOT NULL,
6. `password` varchar(255) NOT NULL,
7. PRIMARY KEY (`id`)
8.) AUTO_INCREMENT=2 ;
9.
10.INSERT INTO
11. `users` (`id`, `name`, `email`, `password`)
12. VALUES
13. (1, 'Tester', 'test@test.com', 'password');
14.

22 | February 2009 www.phparch.com

Rich Internet Applications with Flex and PHP: Part 1


root. In your Web root folder, create a directory called
docs. This folder will be your application directory for
the document managers PHP services. Within the docs
folder, create an include directory; within include,
create a folder called services. Figure 3 depicts this
directory structure.

Adding the Zend Framework


If you dont have the Zend Framework set up and added
to your PHP include path, youll need to download it,
and place the relevant files in the /docs directory. If
you do have the Zend Framework installed, be aware
that Zend_Amf is only included in version 1.7 or later.
If you have an earlier version, youll need to take these
steps, as well.
To get Zend Framework 1.7, visit http://framework.zend.
com/. When youre there, click the large banner that
reads Download Now. Zend_Amf is included in both
the full and minimal versions of Zend Framework, so
choose the one you prefer and save the archive.
When the download is complete, extract the archive
to a convenient location. The result is a folder named
ZendFramework-[version]. Within that folder is a directory named library. If you have an existing installation of an earlier version of Zend Framework, you can
paste this new library folder in place of your old
one. If you do not have a Zend Framework installation,
you can simply copy the needed files into your project
FIGURE 3

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

FEATURE

Rich Internet Applications with Flex and PHP: Part 1

Creating the PHP Classes


Within the /docs/include/services/ directory, create a new PHP file called Document.php. Open the new
file, and define the Document class and its properties,
as shown here:
class Document {
public $id = 0;
public $user_id = 0;
public $name = '';
public $url = '';
public $description = '';
public $type = '';
public $file_size = 0;
}

Next, create another PHP file in the /services directory


called User.php. It should contain
something similar to this:
class User
public
public
public
public
}

{
$id = 0;
$name = '';
$email = '';
$password = '';

FIGURE 4

These files simply define your custom classes and their


properties. When theyre complete, save and close
them. You now need to create the files containing the
PHP methods you want to expose to the Flex application. Create one services file for each of your objects,
Document and User. Begin by creating a new PHP file
called DocumentService.php. Begin the code by importing the custom Document object and declaring the
DocumentService class:
include 'Document.php';
class DocumentService {

The first method to expose is createDocument(),


which will enable the Flex application to create new
Document objects and save them to the database:
/**
* Save a new Document
*
* @param Document $document
*/
function createDocument(Document $document)
{
$id = $document->id;
$user_id = $document->user_id;
$name = $document->name;
$url = $document->url;
$description = $document->description;
$type = $document->type;
$file_size = $document->file_size;
}

This first portion simply assigns values from the


Document object that was passed in to variables. You
could just refer to the properties of the object without
assigning them, but Im doing it this way for greater
clarity. After the variables are populated, you can start
building a database connection and an INSERT statement. Again, for clarity, the database connection will
be explicitly created in each function:

$dbh = mysql_connect('
localhost', 'root', 'password');
$query = "INSERT INTO `docs`.`documents`
(id, user_id, name,
url, description, type,
file_size)
VALUES
(NULL, '$user_id', '$name',
'$url', '$description', '$type',
'$file_size')";
$result = mysql_query($query, $dbh);

Note: Be sure to replace localhost, root, and password with your database information and credentials.
The other method you need to create is
retrieveDocuments(). Use this function to get all
23 | February 2009 www.phparch.com

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

directory (Web Root/docs in this case). You can find


the files you need within the library directory, which
in turn contains the Zend folder. Copy the Zend folder
to your Web Root/docs folder. The resulting folder
structure should look similar to Figure 4.

the users documents from the database, and return


them to the Flex application. See Listing 3.
As you can see, this function selects all the records
with the specified users id from the documents table,
then loops through them, creating a new Document
object for each. These objects are placed into an array
that is finally returned to the client.
FIGURE 5

Rich Internet Applications with Flex and PHP: Part 1


Now that you have a couple of necessary services
for the Document class, create a new PHP file in
the /services directory called UserService.php.
The contents of this file begin much like the
DocumentService file, which can be seen in Listing 4.
The only method you need to declare is loginUser(),
which accepts a User object from the client and tries
to locate it in the database.
The loginUser() function returns a User object
regardless of whether the user is found in the database.
If the User returned is empty, your Flex client will
know the attempt was unsuccessful.
At this point, you should have four files in your
/services directory: User.php, UserService.php,
Document.php, and DocumentService.php. Figure 5
represents the files and folder structure thus far.

The Zend_Amf Endpoint


Until the release of Zend_Amf, the most popular tool for integrating Flex and PHP was AMFPHP
(http://amfphp.org). Those of you who have used
AMFPHP in the past will likely be pleased to know that
Wade Arnold, a driving force in the development of
AMFPHP, is the principal developer of Zend_Amf. As
such, the workflow and structure of Zend_Amf is similar
to AMFPHP. One common requirement between the two
LISTING 4
LISTING 3
1.<?php
2. /**
3. * Retrieve all a user's Documents from the database
4. *
5. * @param int $userid
6. * @return array
7. */
8. function retrieveDocuments($userid)
9. {
10. $dbh = mysql_connect(
11. 'localhost', 'root', 'password');
12. $query = "SELECT * FROM `docs`.`documents`
13. WHERE user_id = '$userid'";
14. $result = mysql_query($query, $dbh);
15. $documentArray = array();
16. while ($row = mysql_fetch_array($result)) {
17. $document = new Document();
18. $document->id = $row['id'];
19. $document->user_id = $row['user_id'];
20. $document->name = $row['name'];
21. $document->url = $row['url'];
22. $document->description
23. = $row['description'];
24. $document->type = $row['type'];
25. $document->file_size
26. = $row['file_size'];
27. array_push($documentArray, $document);
28. }
29. return $documentArray;
30. }
31.}
32.
33.?>

24 | February 2009 www.phparch.com

1.<?php
2.
3.include 'User.php';
4.
5.class UserService {
6.
7.
8. /**
9. * validate a User
10. *
11. * @param User $user
12. * @return User
13. */
14. function loginUser(User $user)
15. {
16. $dbh = mysql_connect('localhost', 'root', 'password');
17. $query = "SELECT * FROM `docs`.`users`
18. WHERE email = '$user->email'
19. AND password = '$user->password'";
20. $result = mysql_query($query, $dbh);
21. $record = mysql_fetch_array($result);
22. $returnUser = new User();
23. if ( $record != false ) {
24. $returnUser->id = $record['id'];
25. $returnUser->name = $record['name'];
26. $returnUser->email = $record['email'];
27. $returnUser->password = $record['password'];
28. return $returnUser;
29. } else {
30. return $returnUser;
31. }
32. }
33.
34.}
35.
36.?>

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

FEATURE

Rich Internet Applications with Flex and PHP: Part 1

require_once 'Zend/Amf/Server.php';
require_once 'include/services/DocumentService.php';
require_once 'include/services/UserService.php';

The first statement makes the Zend_Amf package from


the Zend Framework available to your application.
Next, you require_once the custom classes you created a moment ago. You now need to instantiate a new
Zend_Amf server, and tell the server that you want to
expose the DocumentService class using setclass():

you must echo() the output from the Zend_Amf server.


If you dont, your Flex client will wait for the response
indefinitely:
echo $response;

To test the code and file structure thus far, open a Web
browser and navigate to your gateway.php file (for example: http://localhost/docs/gateway.php). Depending
on your Web server and browser, you will get one of
FIGURE 6

$server = new Zend_Amf_Server();


$server->setClass('DocumentService');

Now, you need to set up whats known as a class map.


The class map specifies which ActionScript classes correspond
to which PHP classes. The ActionScript classes are
named like the PHP classes but with the letters VO
prepended:
$server->setClassMap('DocumentVO', 'Document');

The VO stands for value object and will also be familiar


to those of you who have used AMFPHP. The function
of the value object is similar in Zend_Amf. Remember
to place the ActionScript class name first followed by
the PHP class name. Then, repeat the lines for the User
and UserService classes:
$server->setClass('UserService');
$server->setClassMap('UserVO', 'User');

Because youre just testing with this application, you


may want to turn off production mode. Doing so produces more verbose output to aid in debugging:
$server->setProduction(false);

If you do include this line, switching off production


mode, be sure to set it to true, enabling production
mode before publishing your application in a production environment.
Next, instruct the Zend_Amf server to handle incoming requests:
$response = $server->handle();

Note that in addition to calling $server->handle(),


25 | February 2009 www.phparch.com

FIGURE 7

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

is the gateway, or endpoint, file. Zend_Amf needs this


file to expose your services and handle requests from
Flex. This file is similar to the gateway.php file used
in AMFPHP. In the /docs folder, create a new PHP file
called gateway.php. Then, import some necessary
files:

FEATURE
several results. If your setup is in good working order,
you should either see the text Zend Amf Endpoint
or receive a file download prompt from your browser.
If you dont get either of those outcomes, doublecheck your directory structure, and make sure your
gateway.php file is echoing the output from the Zend_
Amf server instance. If you did get a successful result,
youve finished the Zend_Amf services, and youre ready
to create the last bit of PHP.
Within the /docs folder, create a new PHP file
named upload.php. Predictably, it will contain the
code for uploading files to your server from a Flex client. The code is shown in Listing 5, and is likely to be
a familiar sight.
As you can see from the first few lines, this script expects a file and two fields containing strings by means
of POST. The strings will be the file extension and the
document owners user ID. The script will get the current time as a UNIX timestamp, add an underscore, and
append the user ID and the extension. The script then
attempts to save the file in the directory specified in
the variable $file_path. Be sure to use the full path to
your upload directory. In this case, the upload directory will be within the /docs directory and is be named
uploadedFiles.
If all goes well and the file is saved, the script
returns the generated file name to the client. If
not, it returns a string determined by the error. The
error code muf_error signifies a problem during the
move_uploaded_file() operation, and the error code

Fx

LISTING 5
1.<?php
2.
3.$file_temp = $_FILES['file']['tmp_name'];
4.$file_name = $_FILES['file']['name'];
5.$file_ext = $_POST['exten'];
6.$user = $_POST['userid'];
7.$file_path = '/home/user/public_html/docs/uploadedFiles';
8.$timestamp = time();
9.
10.$uname = $timestamp . '_' . $user . '.' . $file_ext;
11.
12.// checks for duplicate files
13.if ( !file_exists($file_path . '/' . $uname) ) {
14.
15. //c omplete upload
16. $filestatus = move_uploaded_file($file_temp,
17. $file_path . '/' . $uname);
18. if ( !$filestatus) {
19. $message = 'muf_error';
20. } else {
21. $message = $uname;
22. }
23.} else {
24. $message = 'fe_error';
25.}
26.
27.echo $message;
28.
29.?>

26 | February 2009 www.phparch.com

fe_error means the file already exists.

Figure 6 reiterates the proper file and directory structure, accounting for the addition of upload.php and
the uploadedFiles folder.

Flex Time
Now that youve got all the PHP you need and its
speaking AMF, youre ready to leverage it with a Flex
client. To get started, open Flex Builder. Click New >
Flex Project to launch the New Project Wizard. For the
project name, simply type Docs. Also, ensure that Web
Application is selected as the project type. The appropriate settings appear in Figure 7.
Click Finish, and Flex Builder creates your project in
the workspace. When its finished, you should see the
Docs.mxml file in the main editor pane. If not, doubleclick the Docs.mxml file in the left pane of the window. If the file opens in Design view, click the Source
button in the upper-left corner of the main editor pane.
Youll see the MXML code, which begins with a standard
XML tag:
<?xml version="1.0" encoding="utf-8"?>

Fx

This should be followed by the <mx:Application> tag.


The <Application> tag is the root container/root XML
node for your Flex application and all your other components, and you must place ActionScript code within
the opening and closing <mx:Application> tags.
Just as in PHP, you can define custom components in
separate files, but youll need to import them between
these tags.
The opening <mx:Application> tag itself contains a few properties. By default, it contains the default mx namespace
(xmlns:mx=http://www.adobe.com/2006/mxml),
and a layout property. Make sure that the layout
property is set to absolute. Doing so means youre
going to explicitly declare x and y coordinates for your
visual components rather than having Flex arrange
them horizontally or vertically. The <Application>
tag can also optionally contain style declarations similar to Cascading Style Sheet (CSS) documents. To set such declarations, edit your opening

<mx:Application> tag to look like this:

<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
backgroundGradientAlphas="[1.0, 1.0]"
backgroundGradientColors="[#000000, #2E2E2E]">

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Fx

Rich Internet Applications with Flex and PHP: Part 1

FEATURE

Rich Internet Applications with Flex and PHP: Part 1

<mx:RemoteObject
id="roDocumentService"
destination="zend"
source="DocumentService"
endpoint="http://localhost/docs/gateway.php">

This opening tag specifies several attributes:


- id: This ID must be unique within the Flex application, and it will allow you to reference this remote
object elsewhere in the code.
- destination: This is an arbitrary string to identify a
destination.
- source: This is the name of the PHP class you are
accessing through this remote object. This name must
match the class name in your PHP code.
- endpoint: This is the URL to the gateway.php file
you created in the /docs directory under your Web root.
Make sure this URL accurately reflects your Web servers
address.
Next, specify the services you want to access through
the remote object. In other words, the methods you
created in the DocumentService class. Create the
retrieveDocuments() method first:

<mx:method
name="createDocument"
result="onCreateDocumentResult(event)"
fault="handleFault(event)"/>

Just as before, you declare functions to handle the


result (onCreateDocumentResult(), in this case)
and to handle a fault. Again, the events are passed to
the functions that handle them. Now, add the closing
</mx:RemoteObject> tag:
</mx:RemoteObject>

Youre not quite ready to create the functions mentioned in the roDocumentService remote object.
For the time being, youll need to comment out
roDocumentService and its methods by selecting the
text, right-clicking it, then clicking Source > Toggle
Block Comment.
So that you can call your login method for User
objects, declare another remote object and method,
similar to those for the DocumentService:

x
F

<mx:method name="retrieveDocuments"
result="onRetrieveDocumentsResult(event)"
fault="handleFault(event)"/>

The <mx:method> tag also contains some important


attributes:
- name: This is the name of the method in PHP. Be
sure to set the name of the method exactly, as it is
specified in your DocumentService.php file.
- result: When the method returns a result, this
ActionScript function (which we will be creating) will
be called. Notice that you are passing the event itself
to the onRetrieveDocumentsResult() function.
- fault: In the event of a fault, the handleFault()
function will be called. Again, the event will be passed
to the function. Well also be creating this function.

27 | February 2009 www.phparch.com

Also notice that this opening <mx:method> tag


is closed with the shorthand />. Remember, the
<mx:RemoteObject> tag has not yet been closed, and
this method is being placed within the remote object tags. Before you close the <mx:RemoteObject>
tag, insert another <mx:method>, this time for the
createDocument() method:

<mx:RemoteObject
id="roUserService"
destination="zend"
source="UserService"
endpoint="http://localhost/docs/gateway.php">
<mx:method name="loginUser"
result="onRetrieveUserResult(event)"
fault="handleFault(event)"/>
</mx:RemoteObject>

Now the application has the ability to communicate


with PHP services using Zend_Amf. The next step is to
add user interface (UI) controls. Learn more about this
in Part 2 of this article next month.

Richard Bates is a web application developer and

consultant in Athens, Georgia. For the last 8 years, Richard


has worked in this capacity in a wide spectrum of industries,
with clients ranging from telecom and health care to leisure
and real estate. He currently works as a Flex/AIR and PHP
developer with XIG Networks, focusing on e-commerce and
interactive promotional applications.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

These attributes give you an opaque, black-to-gray


background. Every MXML component-not just the
Application-has both functional and style properties
you can manipulate in the opening tag. See the More
Info section of this article for a link to the language
reference.
Under your <mx:Application> tag, you need to set
up some remote objects. Remote objects are created
in MXML using the <mx:RemoteObject> tag. You use
these remote objects to access the services you created in PHP. Begin by creating the opening tag for the
DocumentService:

FEATURE

Taking the
Desktop Back
Lets face it, for web developers, desktop application development can be scary. In
this article, Ill introduce you to the ideas and tools needed to start creating powerful
desktop RIAs using PHP and Adobe AIR.

he first program I ever developed was a Visual


Basic game. Several years later, in high school, I
was introduced to C++ in computer science class
and spent two semesters building desktop applications.
It wasnt until college that I was introduced to and
began developing in PHP. At this point, I made the
decision to leave desktop development behind me. Or
so I thought...

The Desktop Doesn't Have to Be Scary!


Things have changed a lot since I developed my first
Visual Basic game. Web sites are now turning into Rich
Internet Applications (RIAs), which means theyre
starting to act more like an application than a traditional website. In February of 2008, Adobe officially
released AIR. AIR is a runtime environment that makes
it easy to deploy RIAs to the desktop.
Although communication between AIR and PHP was
possible when AIR was first released, the recent partnership between Adobe and Zend introduced Adobe
sponsored Action Message Format (AMF) support for
the Zend Framework. AMF is a binary format that allows
for quick and easy communication with Flash, Flex, AIR
and other technologies. Now that you have some background information, lets get started.

Setting Up PHP
Im going to show you how to build a simple application that pulls current products from a database and allows a user to view the list from a desktop application.
28 | February 2009 www.phparch.com

The beginning stages of building our application are


very similar to what they would be for building a normal PHP website. The first thing were going to need
to do is set up our data source. I will be connecting
to a database called mycoolstore that contains a
product table. The product table will have three
fields called the productName, productDesc
and productPrice. Once we have a proper data
source set up, we need to create our product list class.
Lets call the class productList and place it in
productList.php inside a folder called includes.
See Listing 1.
As you can see, the class has one method
(getProducts), which connects to a MySQL database. This function retrieves the Name, Description and
Price of all the rows in the product table and returns
an array of the products. I used the PDO class to connect, but you can use any method you desire to get the
information. Whether you are pulling from a flat file

REQUIREMENTS
PHP: 5.2.4+
Useful/Related Links:
Zend Framework 1.7 - http://framework.zend.com/
Adobe Flex Builder 3 - http://www.adobe.com/
products/flex/

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

by Ricky Robinett

or hard coding the data, just make sure you return an


array that is formatted the same as the one I created in
this example, and everything should work flawlessly.

Setting Up Zend_Amf_Server
Now that we have set up our class, we need to start up
our AMF server. Make sure you have a project set up in
the Zend Framework and have version 1.7 installed. If
you do not, please visit the Zend website and get your
project set up. I will be placing this in the webroot and
calling the file air.php. Using the Zend Framework,
we can set up this file with just 5 lines of code.
require_once('Zend/Amf/Server.php');
require_once('includes/productList.php');
$server = new Zend_Amf_Server();
$server->setClass('productList');
echo ( $server->handle() );

The first line adds the Zend_Amf_Server class from


the Zend Framework as a required included file. The
second is including the productList class we created earlier. On the third line, we instantiate a new
Zend_Amf_Server object and assign it to the variable
$server. The fourth line tells the AMF server object
that we will be receiving communications that interact
with the productList class we created. On the last
line, we set the script to handle any incoming AMF calls
and to output the response.
Now that we have created the php page to handle
the server calls, lets browse to it and test that it is
functioning properly. If you browse to your page, you
should see the output Zend Amf Endpoint. If you see
this, then your page is set up correctly. If not, then ensure that you have properly set up the Zend Framework
and that your apache is properly configured and running.
We now have everything set up in our PHP project to
communicate directly with our AIR application. When
you are developing an application that is using the AMF
server, it is important to create a test file to make sure
there are not any issues with the setup of your class. It
can be very frustrating to receive an error in AIR, spend
hours debugging, and eventually discover there was an
issue in the setup of your PHP class or functions.

Setting Up Your AIR Application


Now that everything is set up in PHP, we can begin
building our AIR application. To our advantage, Flex
Builder makes the process of setting up an AIR application extremely simple. Just start up Flex Builder, go
29 | February 2009 www.phparch.com

to file, select new and then select Flex project.


From here, well be able to name our project. Lets call
ours My Cool Store. Select the project location, and
make sure to select the application type of Desktop
Application (Runs in Adobe AIR). Then, you will set the
Application server type to PHP. Go to the next page
and set the path to the web root as well as the root
URL. Now, were ready to start building our AIR application.
The first thing youll notice is Flex Builder has already
created an MXML file. MXML is an XML-based language
originally introduced by Macromedia. It is the language
used by Flex Builder to generate SWF files. This MXML
file will be the home of our application. Before we get
started here, we need to configure the application to
connect to our AMF server. Go to the root of your AIR
application, and put the contents of Listing 2 into a
file called services-config.xml.
Before we continue, lets examine this configuration
so we fully understand what we have done. The first
tag with an attribute is the service tag. We set the id
attribute of this tag as zend-service. We then have
a destination tag which we set with the attribute id
as zend. This will be the information we use in our
MXML file to tell our application to communicate with
PHP. We then set up a channel which has an endpoint
directed at the location of the file we set up to handle
LISTING 1
1.<?php
2.
3.class ProductList{
4.
5. public function getProducts(){
6.
7. $aProducts = array();
8. $i = 0;
9.
10. $dsn = 'mysql:dbname=mycoolstore;host=127.0.0.1';
11. $user = 'user';
12. $password = 'password';
13.
14. try{
15. $db = new PDO($dsn, $user, $password);
16. } catch(PDOException $e) {
17. $aProducts[] = 'Error Connecting to Database';
18. }
19.
20. $sql = 'SELECT productName, productDesc, productPrice FROM product';
21. foreach($db->query($sql) as $row){
22.
23. $aProducts[$i]['productName'] = $row['productName'];
24. $aProducts[$i]['productDescription'] = $row['productDesc'];
25. $aProducts[$i]['productPrice'] = '$'.$row['productPrice'];
26. $i++;
27. }
28.
29. return $aProducts;
30.
31. }
32.
33.}
34.
35.?>

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

Taking the Desktop Back

FEATURE

-services "../services-config.xml"

Now, our app is looking at this configuration file and


recognizes that we have the AMF server available with
the destination ID of zend.
Before we take a step by step look at the development of the MXML code, lets do a quick overview of the
final code we are working towards (see Listing 3). By
looking at the final outcome, it will be easier to understand what each block of code is doing when we take
a step-by-step look. The mx:WindowedApplication
tag defines some specifics about what type of application Flex will generate. The mx:RemoteObject tag
is the tag well be using to communicate with PHP.
Nested within this tag is a single mx:Method tag we
will be using to trigger the PHP method we created earlier. We then have an mx:Script tag which lets us
use ActionScript code within our MXML. This is where
we will be defining a method called ResultHandler.
We will be using this method to handle the result of
our RemoteObjects single method. Finally, we
have two display-related tags, mx:DataGrid and
mx:Button, which we will take a further look at a bit
later.
Now that we have taken a brief look at the final
MXML code, lets return to the MXML file that was initially created for us by Flex Builder. The first thing to
LISTING 2
1.<?xml version="1.0" encoding="UTF-8"?>
2.<services-config>
3. <services>
4. <service id="zend-service" class="flex.messaging.services.
RemotingService" messageTypes="flex.messaging.messages.RemotingMessage">
5. <destination id="zend">
6. <channels>
7. <channel ref="zend-endpoint"/>
8. </channels>
9. <properties>
10. <source>*</source>
11. </properties>
12. </destination>
13. </service>
14. </services>
15. <channels>
16. <channel-definition id="zend-endpoint" class="mx.messaging.channels.
AMFChannel">
17. <endpoint uri="http://www.yourdomain.com:80/air.php" class="flex.
messaging.endpoints.AMFEndpoint"/>
18. </channel-definition>
19. </channels>
20.</services-config>

30 | February 2009 www.phparch.com

notice is that the MXML file is a properly-formed XML


file which means anything you do in the file will be tag
based and will need to be properly closed. The file Flex
creates for you will currently look something like this:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.
com/2006/mxml" layout="absolute">
</mx:WindowedApplication>

All of the work we do on our project will be enclosed


within the mx:WindowedApplication tag. This is
also the tag that tells Flex Builder were creating an
AIR Application. Within this code, we need to set up
our application to connect to the productList object
in our PHP application. We do this by adding the following code:
<mx:RemoteObject id="myservice" source="productList"
destination="zend">
<mx:method name="getProducts"
result="resultHandler(event)" />
</mx:RemoteObject>

This sets up a RemoteObject called myservice. It


also tells our application that this object is related to
the zend-service service we set up in our configuration ID by referencing its destination ID. By setting
the source as productList, it is telling our application
that it is going to be making calls on the productList
class on the destination service. It tells our application
LISTING 3
1.<?xml version="1.0" encoding="utf-8"?>
2.<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute">
3. <mx:RemoteObject id="myservice" fault="faultHandler(event)"
source="ProductList" destination="zend">
4. <mx:method name="getProducts" result="resultHandler(event)" />
5. </mx:RemoteObject>
6.
7. <mx:DataGrid id="productGrid" editable="false" x="10" y="10"
width="450"/>
8. <mx:Button x="354" y="170" label="Get Products" id="send_btn"
click="myservice.getProducts()" height="25"/>
9.
10. <mx:Script>
11. <![CDATA[
12. import mx.rpc.events.ResultEvent;
13. private function resultHandler(event:ResultEvent):void
14. {
15. productGrid.dataProvider = event.result as Array;
16. }
17.
18. import mx.rpc.events.FaultEvent;
19. import mx.controls.Alert;
20. private function faultHandler(fault:FaultEvent):void
21. {
22. Alert.show("code:\n" + fault.fault.faultCode + "\n\nMessage:\n"
+ fault.fault.faultString + "\n\nDetail:\n" + fault.fault.faultDetail);
23. }
24. ]]>
25. </mx:Script>
26.</mx:WindowedApplication>
27.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

AMF communications in PHP. Now that we have created


our configuration file, we need to tell our project to
read the information from this file when it compiles.
Right-click on your project, select properties and go
to Flex Compiler. Under Additional compiler arguments
add the following string:

Taking the Desktop Back

FEATURE

Taking the Desktop Back

<mx:DataGrid id="productGrid" editable="false"


x="10" y="10" width="450"/>

Now that we have a place to display our data, we need


to create a button that will run a function to populate
our grid.
<mx:Button x="354" y="170" label="Get Products"
id="send_btn" click="myservice.getProducts()"
height="25"/>

At this point, we have set up a remote object, set


up a button to call a method on our remote object
and set up a place to display the information included in the response we receive from our remote object. The only thing we need to do now is set up our
AIR application to handle the events related to our
getProducts method. To handle our getProducts
method, well be taking advantage of the mx:Script
tag. This tag defines a block of ActionScript code
within our MXML file. Well use the code in Listing 4 to
handle the getProducts method.
The first thing you will notice is that weve wrapped
the ActionScript within a CDATA construct to prevent the compiler from interpreting the ActionScript
as XML. Next, we use the import function to import the ResultEvent library. Then, we declare our
resultHandler function, which is the function we
defined in our getProducts method to handle the
results of the method. We will pass one argument to
this function called event and are declaring this argument as a ResultEvent. The next line uses the
ActionScript DataProvider class. This class serves as the
source of data for the dataGrid. Here we are setting
this to the results of our getProducts method and
defining these results as an array. This function is all
we need to populate and format the dataGrid.
31 | February 2009 www.phparch.com

Let's See this Baby in Action


Now, we have all the components in place to have a
functioning AIR application. In order to test our application, click the run button in Flex Builder in the
top toolbar (it looks like a play button). After a short
pause, you will see the application pop up on your
screen. If you press the Get Products button, you
can watch your dataGrid populate with the information from your database. If, instead of populating your
dataGrid, your application crashes, you receive an error
or nothing happens at all, the following section will be
beneficial to you.

Error Handling
I intentionally did not implement error handling because it is a very important part of any application. I
wanted to leave it separated from the initial application build to give it the focus it deserves. In this section, I will go through all the steps needed to set up
error handling in our application.
The first thing well want to do is set up our remote
object to call a function when an error happens. In
MXML, errors are referred to as faults. We can do this
by adding the fault attribute to our remoteObject
tag and setting it to call the faultHandler function
with an argument of event on fault. As a result, the
code will look like this:
<mx:RemoteObject id="myservice"
fault="faultHandler(event)" source="productList"
destination="zend">
<mx:method name="getProducts"
result="resultHandler(event)" />
</mx:RemoteObject>

Now that we have our object set up to call the


faultHandler function, we need to set this
function up in our code. Put this function within the mx:script tag where we set up our
eventHandler function earlier. Well need to import
the FaultEvent library and use the trace function to
track our error. The trace function is used to output
information to the debug screen displayed by Flex
LISTING 4
1.<mx:Script>
2. <![CDATA[
3. import mx.rpc.events.ResultEvent;
4. private function resultHandler(event:ResultEvent):void
5. {
6. productGrid.dataProvider = event.result as Array;
7. }
8. ]]>
9.</mx:Script>

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

this object has a method of getProducts and that it


should take the results of this method and pass it to
the resultHandler method.
Now, lets create the layout of our application. First,
we need to make a place to display our array of products. AIR provides us with a dataGrid which could be
described as a highly functional and visually appealing
table. The data grid is a very powerful because it gives
us the ability to load an array. It also gives the user
the ability to order the data based on columns and edit
the data. It is important to note that if we set editable
to true, the user is only editing the display of the data,
and to have these changes reflected in the database,
we would have to create a setter based on the grid.

FEATURE

import mx.rpc.events.FaultEvent;
private function faultHandler(fault:FaultEvent):void
{
trace("code:\n" + fault.fault.faultCode + "\n\
nMessage:\n" + fault.fault.faultString + "\n\
nDetail:\n" + fault.fault.faultDetail);
}

If your application was not functioning correctly when


you ran it earlier, you can now run in debug mode, by
hitting the button with a bug on it next to the run
button. When you hit the Get Products button, you
should see what the issue is in the output of your Flex
Builder window. If youre application was working, you
can also see this by breaking the connection with your
PHP application. This is done by shutting down your
server (if running a local server) or disconnecting from
the internet (if using a remote server). Personally, I
like to have my errors displayed in an alert window.
This gives me the ability to handle the errors and output a custom alert that users would see when they are
using my application. Lets set up our application to
show an alert instead of using the trace for errors.
The first thing youll need to do is import the
alert library. Now, we can display our alert using the
Alert.show() function and passing the desired
display string as the first argument. For this example,
we will just output the trace string into an alert popup.
The code will look like this:
import mx.rpc.events.FaultEvent;
import mx.controls.Alert;
private function faultHandler(fault:FaultEvent):void
{
Alert.show("code:\n" + fault.fault.faultCode +
"\n\nMessage:\n" + fault.fault.faultString + "\n\
nDetail:\n" + fault.fault.faultDetail);
}

I Have An Error. Now What?!


When I built my first AIR application that communicated with PHP using the Zend_Amf_Server, I spent
hours battling errors. As a PHP developer, I have
my own process for determining the source of
an error and fixing it. Whether it is something
quickly pointed out by the error information
provided or something that takes a little
32 | February 2009 www.phparch.com

more digging, the addition of another language and


another communication method forced me to completely change the way I debugged.
The first thing I discovered is that the errors provided by AIR are much less informative than what I
am used to working with PHP. The error I was initially
faced with was the infamous Channel.Connection.
Failed, NetConnection.Call.BadVersion error. I knew
it meant there was an issue connecting to the
Zend_Amf_Server. But why? I could browse to the page
and receive the proper message. I tried setting up my
configuration to have the port number in the connection. I also attempted to rename almost everything,
but only found myself more frustrated and discouraged.
As a last resort, I ended up rewriting my function. To
my surprise, I discovered that this resolved everything.
My issue was that I did not instantiate my class and
test its methods in PHP before trying to communicate
with it via AMF. I cant go through all the possible errors you may encounter, but I can recommend looking
in the simple places first.

What Now?
You have now successfully built a desktop RIA
using Adobe AIR and PHP. We covered the new
Zend_Amf_Server included in version 1.7 of the Zend
Framework and generated all the needed PHP code to
set up a server linked to a specific class. We then created an AIR application using Flex Builder that successfully talked to our PHP class. Now that you have
the basics, I would encourage you to explore and try
new things. There are endless possibilities of where this
technology can take you, so dive in and most importantly - have fun.

Ricky is currently a Senior Developer at Nylon Technology

in New York, NY. He is a Zend Certified Engineer for PHP5


and a Coldfusion 8 Adobe Certified Expert. At Nylon, he
has had the opportunity to be Lead Developer on several
large-scale projects, including a multi-media resource site
for a start-up entertainment company and a custom-built
CMS using object-oriented programing to integrate reusable
and modular custom APIs. Ricky is constantly working to
expand his knowledge and eager to share this knowledge at
user groups and conferences.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Builder when running your project in debug mode. It


also prevents error messages from displaying to the application users. We will set the trace to output our error
code, the error string, and the complete error detail.
The code will look like this as a result:

Taking the Desktop Back

FEATURE

Optimizing Dojo
and
Zend Framework
Integration
In April 2008, Zend Framework announced a partnership with the Dojo Foundation
for delivering out-of-the-box Ajax and rich user interface support for Zend Framework
applications. This partnership came to fruition in August 2008 with the release of
version 1.6.0 of Zend Framework, the first release to ship with Dojo and built-in
support for Dojo.

ojo is a DHTML framework written in JavaScript.


At its most basic, it provides a small core, dojo.
js (generally referred to as Dojo Base), that
provides a rich and useful set of functionality generally
required by DHTML developers: retrieving elements by
id or CSS selector, performing XmlHttpRequests, event
binding, etc. It also provides a gateway to the Dojo
packaging system, which provides a simple provide/
require namespace system very similar to PHPs own
class/autoload system. The Dojo packaging system is
perhaps Dojos greatest strength, as it provides use-atwill capability to JavaScript without requiring additional <script> tags.
Dojo itself ships with several subprojects, if you
will: Dijit (Dojos widget system), DojoX (Dojo eXtensions), and DOH (Dojo Objective Harness, Dojos unit
testing framework). Dijit provides a set of high quality, tested widgets for layouts, forms, dialog boxes,
WYSIWYG editing, and more. DojoX provides a rich set
of extensions to the main toolkit, some experimental and others production stable. Examples include
dojox.Grid, a dynamic, editable data grid component;

33 | February 2009 www.phparch.com

dojox.Offline, which provides interfaces to Google

Gears and Adobes AIR environments for developing


offline applications; and dojox.Gfx, which provides
a rich API for creating 2D graphics such as charts and
graphs. DOH (pronounced Doh!, per Homer Simpson)
provides a testing harness for your Dojo applications,
and is used by Dojo to test Dojo.

REQUIREMENTS
PHP: 5.2.1+
Other Software: Zend Framework 1.6.0+, Dojo 1.1.0+
(optional)
Useful/Related Links:
http://framework.zend.com
http://dojotoolkit.org/
http://github.com/weierophinney/pastebin

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

by Matthew Weier OPhinney

As noted earlier, one hallmark of Dojo is its packaging system. Dojo defines a rich interface for defining
namespaced JavaScript classes and objects, as well as a
harness for loading them at will. As an example, if you
decided you wanted to use dijit.Dialog to pop up
a dialog message to your users, you can pull this in at
will:
dojo.require("dijit.Dialog");

This instructs Dojo to load the dijit/Dialog.js file, as


well as any dependencies it may have. The real strength
of this approach will be seen later when creating custom builds.
Dojo pushes web standards, and in some cases disagrees with existing standards in order to push for new
and better standards. One place where this is noticeable is with Dijit. In creating the Dijit ecosystem, Dojo
decided to use markup semantically. However, to do
so, the Dojo developers felt the cleanest, most fluent
syntax was to use custom HTML attributes. See Listing
1 for an example.
Semantically, this makes a lot of sense: it defines a
dialog with the title Hello, World!, some content, and
a button with the text Close that binds the onclick
event to hide the dialog. However, its not valid
HTML; The W3C validator will choke on the dojoType,
title, and event attributes. However, the interesting
thing about this is that the document doesnt validate
against the HTML DTDs, while the HTML specification
actually states that any attribute not recognized is to
be ignored by the rendering engine; the DTDs actually
conflict with the specifications. The fact of the matter
is that no existing browser will have an issue with the
syntax, and it provides a convenient and expedient way
to define widgets. Dojo refers to this syntax as declarative markup.
That said, all dijits may be created programmatically
as well. For example, the above dialog, minus the close
LISTING 1
1.<code html>
2.<div dojoType="dijit.Dialog"
3. id="my-dialog" title="Hello, World!">
4. This is the dialog content.
5. <button dojoType="dijit.Form.Button" type="submit">
6. Close
7. <script type="dojo/method" event="onclick">
8. dijit.byId("my-dialog").hide();
9. </script>
10. </button>
11.</div>
12.</code>
13.

34 | February 2009 www.phparch.com

Optimizing Dojo and Zend Framework Integration


button, could be created as shown in Listing 2.
This creates a new dijit.Dialog after the DOM
has finished loading and Dojo has finished processing
the various dojo.require() statements provided. We
can then pop open the dialog at any time by calling
myDialog.show().
At the beginning of this discussion, I mentioned that
Dojo is a DHTML framework. This is particularly evident
with Dijit. If you try the above samples without specifying any CSS, they basically fail to look or act correctly. However, Dijit itself provides several CSS themes
that decorate dijits, giving them a consistent and
polished look and feel. The themes are built such that
they require a surrounding block with a class attribute
specifying the theme name. As an example, the following would specify the tundra theme (one of three
shipped with Dojo):
<div class="tundra">
...
</div>

This allows you to sprinkle your dijits into your existing


site without affecting your existing stylesheets. It also
makes it possible to build your own themes to decorate
dijits.
For reasons that will be explained later, Dojo conventions have you load your themes via the @import CSS
syntax:
<style type="text/css">
@import "http://o.aolcdn.com/dojo/1.2/dijit/
themes/tundra/tundra.css";
</style>

Now that we have explored Dojo a little, lets look at


how Zend Framework has integrated it.

What does the integration look like?


Zend Framework offers five basic areas of integration
with Dojo:

LISTING 2
1.<code javascript>
2.var myDialog;
3.dojo.addOnLoad(function() {
4. myDialog = new dijit.Dialog({
5. title: "Hello, World!",
6. content: "This is the dialog content."
7. });
8. dojo.body().appendChild(myDialog.domNode);
9. myDialog.startup();
10.});
11.</code>
12.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

FEATURE

Optimizing Dojo and Zend Framework Integration

Dijit-specific view helpers and form elements. Dijit provides a large number of UI
widgets; Zend_Dojo provides view helpers,
form elements, and form decorators corresponding to most layout and form dijits.
dojo.data support. dojo.data is a uniform
data-access layer used by a variety of Dojo
modules to abstract access to data stores
which may be in-memory data structures, files
on the server, or even dynamically generated
server-side content. Zend_Dojo_Data provides
the ability to create dojo.data-compatible
response payloads from your Zend Framework
applications.
JSON-RPC server implementation. Dojo
has led the efforts to create the JSON-RPC
specifications and has long had a JSON-RPC
client implementation. Zend Framework now
provides a JSON-RPC server implementation via Zend_Json_Server. This feature is
particularly useful when creating client-side
heavy applications that will be making many
XmlHttpRequests (XHR) to the server to retrieve data.
Dojo source distribution. In its minimal
distribution, Zend Framework does not ship
Dojo, but because it defaults to using an established CDN, all Dojo-specific functionality
will continue to work. In its full distribution,
Zend Framework provides a source distribution
of Dojo, which allows the end-user developer
to create custom builds of Dojo (more on that
later) as well as unit test their Dojo applications via Dojos DOH unit test framework.

Getting started using Dojo with Zend


Framework
Using Dojo in Zend Framework requires three steps: informing your view object of the Zend_Dojo view helper
path, enabling Dojo in your view, and rendering the
dojo() view helper in your layout script.
Note: Dojo integration works best with Two Step
and Composite Views.
The dojo() view helper aggregates Dojo settings. As
a result, you must first render any views that specify
Dojo settings prior to rendering the dojo() view helper. For this reason, Zend Framework recommends using
Zend_Layout when using the dojo() view helper.
Since all Dojo-specific view helpers are contained in the Zend_Dojo component tree, you need
to specify a prefix path for these helpers in order
for your Zend_View object to be able to use them.
Zend_Dojo provides a convenience method for this:
Zend_Dojo::enableView():
$view = new Zend_View();
Zend_Dojo::enableView($view);

Once this is done, you can then enable Dojo in your


view via the dojo() view
helper:
$view->dojo()->enable();
// or, within a view script:
$this->dojo()->enable();

We recommend only performing the above step in the


view scripts where Dojo is actually needed. This will
ensure Dojo is only loaded when needed, instead of
on every page request. That said, if Dojo is necessary
throughout the site, enabling it globally in your bootstrap is a good idea.
Regardless of whether or not the dojo() view helper
has been enabled, you then simply echo the helper in
your view script:
echo $this->dojo();

If Dojo has not been enabled, or explicitly disabled,


nothing will be rendered; if it has been enabled, the
view helper will render any necessary stylesheet and
script tags, based on what you have specified in other
Dojo view helper calls or via form elements.
Note: Dijit generation defaults to programmatic
declaration.

35 | February 2009 www.phparch.com

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

dojo() view helper. The dojo() view helper


allows you to setup the Dojo environment for
your application. You may specify a Content
Delivery Network (CDN) to use, or a local Dojo
installation. Additionally, methods are provided to allow specifying dojo.require statements, paths to custom modules, registration
of onLoad events, specifying Dijit themes, and
much more.

Remember in the introduction when we discussed


declarative and programmatic creation of dijits? Many
Zend Framework users were concerned about the declarative syntax as they utilize the W3C validators to
verify and validate the markup they generate. As a result, Zend decided to default to programmatic markup.
However, you may choose either method, using the
following syntax:
// Specify declarative usage:
Zend_Dojo_View_Helper_Dojo::setUseDeclarative();
// Specify programmatic usage:
Zend_Dojo_View_Helper_Dojo::setUseProgrammatic();

All examples below will work in either case, but will


generate different markup.
Declarative markup is particularly useful when serving
content to an XmlHttpRequest. As a security measure,
<script> tags embedded in an HTML response will not
be executed once the HTML is inserted into the DOM
effectively making programmatic declaration impossible. However, with declarative markup, you can run
the Dojo parser over the new nodes, and achieve the
same results. When mixed with the ContentPane dijit,
this can actually be automated.

LISTING 3
1.<code php>
2.<?php
3.$view->tabContainer()->captureStart('master');
4.$view->contentPane()->captureStart(
5. 'tab1',
6. array('title' => 'Tab 1')
7.);
8.?>
9.This is the content of tab 1.
10.<?php echo $view->form; ?>
11.And it contains a form.
12.<?php
13.echo $view->contentPane()->captureStop('tab1');
14.echo $view->contentPane('tab2', '', array(
15. 'href' => '/remote/source',
16. 'parseOnLoad' => true,
17.));
18.echo $view->tabContainer()->captureStop('master');
19.</code>
20.

LISTING 4
1.<code php>
2.// Using Zend_Dojo_Form:
3.$form = new Zend_Dojo_Form;
4.
5.// Extending Zend_Dojo_Form:
6.class My_Form extends Zend_Dojo_Form
7.{
8. public function init()
9. {
10. // ...
11. }
12.}
13.</code>
14.

36 | February 2009 www.phparch.com

Optimizing Dojo and Zend Framework Integration

Creating forms containing dijits


As noted earlier, Zend_Dojo provides view helpers,
form elements, and form decorators that map to dijits.
All dijit view helpers have the following signature:
<dijitName>($id, $content|$value, $dijitParams,
$attributes)

As one might expect, $id is the DOM identifier. The


second parameter will either be content for the dijit
or the dijit value. The fourth parameter should contain
any HTML attributes you wish to specify. Backing up to
the third parameter, most dijits have a set of parameters they can utilize such things as the title, events,
placement, etc.; specify these with the $dijitParams
parameter. A sample call might look like the following:
echo $view->button(
'foo',
'Show me!',
array('iconClass' => 'myButtons'),
array('class' => 'foo-button')
);

A number of dijits for which Zend_Dojo provides integration are containers; they wrap other content. Rather
than require the developer to pass in the content via
a string or pre-generate it, these containers have the
ability to capture content. As an example, Listing 3
shows the creation of a TabContainer with several
ContentPanes; both dijits are containers, and this example shows multi-level capturing.
Note that when starting capturing, no echo statement is provided. You can echo when ending the capture, or simply assign the return value to a variable.
The second tab is an interesting case. It specifies
that its content should come from a remote source.
This is an easy way to lazy-load content and keep your
initial page loads slim.
Most often, unless you are using the various layout
dijits, you wont use the dijit view helpers; instead,
youll utilize the corresponding form elements and decorators (the latter actually consume the view helpers).
You can Dojo-enable an existing form object easily:
Zend_Dojo::enableForm($form);

This sets the appropriate plugin paths for finding the


dijit elements and decorators. However, its easiest to
simply extend or consume Zend_Dojo_Form, which has
these paths set by default as shown in Listing 4.
Adding elements is the same as for any other
Zend_Form element. For example, if you wanted to add
a dijit.form.TextBox element to the form in order

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

FEATURE

Optimizing Dojo and Zend Framework Integration

$form->addElement('TextBox', 'name');

Each element has a variety of configuration keys mapping to methods that allow you to set specific dijit
parameters; this makes them a convenience over the
view helpers as your favorite IDE can provide hinting
for you. See Listing 5 for an example.
By default, all dijit elements have appropriate decorators that ensure the correct view helpers are utilized.
For your form, sub forms, and display groups, there are
also a variety of decorators corresponding to layout
dijits. This can give you the opportunity to build some
wizard-like forms. For instance, you might want to decorate your sub forms as ContentPanes and your form
with a TabContainer, giving you a multi-tab form as
shown in Listing 6.
Basically, if you are familiar with Zend_Form, using
Zend_Dojo_Form will be familiar. More importantly,
youll find that you wont need to learn much Dojo in
order to get some great looking, usable forms immediately.
Note: Dont forget to use a Dijit theme.
For Zend_Dojos form integration to render correctly,
you must remember to both inform the dojo() view
helper of the Dijit theme, as well as build a containing
element that has the dijit theme specified. See Listing
7 for an example view script.
addStylesheetModule() will set up the appropriate
CSS @import URL path for you (maps to dijit/themes/
tundra/tundra.css in this example), and the dojo()
view helper will then create a <style> tag with it. The
containing block then ensures that all content below it
is styled with the theme.

LISTING 5
1.<code php>
2.// Tell the element to use the proper case and trim filters:
3.$name->setLabel('Name:')
4. ->setPropercase(true)
5. ->setTrim(true);
6.
7.// Or, at creation:
8.$form->addElement('TextBox', 'textbox', array(
9. 'label' => 'Name:',
10. 'propercase' => true,
11. 'trim' => true,
12.));
13.</code>
14.

37 | February 2009 www.phparch.com

Leveraging Dojo's modularity


Using Zend Framework and Dojo together is fairly easy,
and allows you to create consistent, usable, dynamic
functionality very quickly. However, this comes at
a price. Remember the discussion of Dojos modular
architecture? Each dojo.require() spawns a request
back to the server in some cases, many requests. A
full-featured form using a good sampling of dijits may
require dozens of calls to the server. This will degrade
the user experience, and, in a worst case scenario,
flood your web server with requests. Fortunately, the
good folks at Dojo have already come up with a solution: custom builds.
At its most basic, a custom build compiles all dependencies to a single file. What this means is that
when using a custom build, all those dojo.require()
statements become no-ops the functionality is already loaded. Additionally, the build process can also
do such things as minify the JavaScript stripping
LISTING 6
1.<code php>
2.$subForm1->setDecorators(array(
3. 'FormElements',
4. array('HtmlTag', array('tag' => 'dl')),
5. array('ContentPane', array(
6. 'title' => 'About You'
7. )),
8.));
9.$subForm2->setDecorators(array(
10. 'FormElements',
11. array('HtmlTag', array('tag' => 'dl')),
12. array('ContentPane', array(
13. 'title' => 'Your Contact Info'
14. )),
15.));
16.$subForm3->setDecorators(array(
17. 'FormElements',
18. array('HtmlTag', array('tag' => 'dl')),
19. array('ContentPane', array(
20. 'title' => 'Your Order'
21. )),
22.));
23.$form->addSubForms(array($subForm1, $subForm2, $subForm3))
24. ->setDecorators(array(
25. 'FormElements',
26. array('TabContainer', array(
27. 'style' => 'width: 400px; height: 300px;'
28. )),
29. 'Form',
30. ));
31.</code>
32.

LISTING 7
1.<code php>
2.<?php
3.$this->dojo()->enable()
4. ->addStyleSheetModule('dijit.themes.tundra');
5.?>
6.<div class="tundra">
7. <?php echo $this->form; ?>
8.</div>
9.</code>
10.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

to capture a name entry, specify the TextBox element


type:

out comments and whitespace, optionally performing


heuristics to shorten variable and function names (and
providing an internal method map), and compressing
the result, if desired.
Additionally, you can leverage the build system for
your stylesheets. If you look internally in one of the
dijit themes, youll see that it may read something like
Listing 8.
The build process can be configured to merge the
various CSS imports into a single file, as well as strip
whitespace and comments. Creating a custom build can
change a request from pulling dozens of files of several kilobytes each to pulling one or two files of a few
kilobytes total. The end result is a responsive, snappy
user interface for the end user, and fewer and smaller
requests to your server.
However, how can you leverage both the modularity
that leads to rapid development and the size and raw
performance of a custom build? The answer is through
a layer file.

Creating a layer file


A build layer is simply a JavaScript file. It uses
dojo.provide() to declare a Dojo module.
dojo.provide() simply ensures that a JavaScript
object is created and/or present. For example, the following code:
dojo.provide("custom._base");

Optimizing Dojo and Zend Framework Integration


specifying a stylesheet theme, the string custom.
themes.site would correspond to custom/themes/
site/site.css, so lets create that file, with the following contents:
@import url("../../../dijit/themes/tundra/tundra.
css");

We can then append additional CSS rules to this file,


but this ensures we have selected the appropriate
theme for our site and also gives us a specific place
to change it later if we want to.
Next, lets create our layer file. In custom/_base.js,
well place the contents of Listing 10.
Lets dissect this a bit. First, dojo.provide() tells
Dojo that were providing a module for Dojo to utilize;
this allows us to load functionality dynamically using
dojo.require(). Second, weve provided a series of
dojo.require() statements mimicking those present

LISTING 8
1.<code css>
2.@import url("../dijit.css");
3.@import url("Common.css");
4.
5.@import url("layout/ContentPane.css");
6.@import url("layout/TabContainer.css");
7.@import url("layout/AccordionContainer.css");
8.@import url("layout/SplitContainer.css");
9.@import url("layout/BorderContainer.css");
10.@import url("form/Common.css");
11./* ... */
12.</code>
13.

will create the following JavaScript object:


var custom = {_base: {}};

This does several things for you. First, you now have
a namespace for your custom JavaScript. Just like the
PHP project recommends prefixing your functions and
classes with a unique namespace, Dojo recommends
that you namespace your code via dojo.provide().
Second, you have now created the basis for your own
module simply by virtue of having a namespace.
Third, you now have a scope in which to list the dependencies for your application.
From here, the next step is to determine what those
dependencies may be. Lets say weve created a basic
authentication form using Zend_Dojo_Form. We can
then view source on that form, look in our HTML header, and may see something resembling Listing 9.
From here, well do two things. First, lets create
a CSS theme. Zend_Dojos convention is that when
38 | February 2009 www.phparch.com

LISTING 9
1.<code html>
2.<style>
3. @import url("/js/dijit/themes/tundra/tundra.css");
4.</style>
5.<script type="text/javascript" src="/js/dojo/dojo.js">
6.</script>
7.<script type="text/javascript">
8. dojo.require("dijit.form.Form");
9. dojo.require("dijit.form.ValidationTextBox");
10. dojo.require("dijit.form.Button");
11.</script>
12.</code>
13.

LISTING 10
1.<code javascript>
2.dojo.provide("custom._base");
3.function() {
4. dojo.require("dijit.form.Form");
5. dojo.require("dijit.form.ValidationTextBox");
6. dojo.require("dijit.form.Button");
7.}();
8.</code>
9.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

in our HTML document. While this may seem redundant,


the points to remember are (a) any successive calls to
dojo.require() from the same module will be no-ops,
and (b) we can include more functionality in the layer
file than is`present on any single page, allowing us
to provide a single custom build that covers multiple
pages. Third, note the function() {...}(); notation.
This ensures that the code executed exists in its own
variable scope and will not bleed into the global scope.
This is an idiom recommended by Dojo, and is considered a best practice when using JavaScript.

"

You can swap CSS


imports as necessary,
or add new rules, and
have a single location
for doing so.

You are not limited to only dojo.require() statements. This layer file can perform a variety of tasks
creating onLoad events, binding events to objects,
setting up module paths, declaring classes or extending
the base module, and more. Its an excellent place to
put common functionality that will be called throughout your site.
In our Zend Framework application, well now do a
little bootstrapping. First, we need to indicate that
were using a local Dojo installation; next, well indicate that were using a custom module; also, we need
to tell Dojo to load our custom theme; and finally, we
need to tell Dojo about our build layer.
$view->dojo()->setLocalPath('/js/dojo/dojo.js')
->registerModulePath('custom', '../
custom')
->addStylesheetModule('custom.themes.
site')
->addLayer('/js/custom/_base.js');

This will spit out Listing 11. At first glance, this looks
like more code. The benefits are in maintenance, in creating your build profile, and finally, as a result of the
custom build, in reducing the number of files included
in each request.
First, when it comes to maintenance, the above ensures several things. You can change CSS files in one

39 | February 2009 www.phparch.com

place, without needing to alter any code for loading


them. You can swap CSS imports as necessary, or add
new rules, and have a single location for doing so. This
also allows you to restrict your designers to a particular tree in your repository, which could be an important consideration. In terms of your Zend Framework
application, you will not need to update code when
you alter CSS it will continue to point to the same
location. The same goes for the Dojo layer created;
you can update the code, alter the dojo.require()
statements, etc, without needing to change anything
in your bootstrap. Additionally, once the custom build
has been created, you can continue to use the Zend
Framework code in exactly the same way.
Second, if you are performing Ajax requests back
to your server, the content you return cannot contain
<script> tags (they will be ignored). As a result, you
need to declare any dojo.require() statements relevant to such content in your initial request. The most
expedient place to do this is your build layer, as it
should be loaded on each page.
Third, lets now look at how the build profile is created. A build profile is simply a JavaScript file that
creates a data structure detailing options for the build
LISTING 11
1.<code html>
2.<style>
3. @import url("/js/custom/themes/site/site.css");
4.</style>
5.<script type="text/javascript" src="/js/dojo/dojo.js">
6.</script>
7.<script type="text/javascript" src="/js/custom/_base.js">
8.</script>
9.<script type="text/javascript">
10. dojo.registerModulePath("../custom", "custom");
11. dojo.require("dijit.form.Form");
12. dojo.require("dijit.form.ValidationTextBox");
13. dojo.require("dijit.form.Button");
14.</script>
15.</code>
16.

LISTING 12
1.<code javascript>
2.dependencies = {
3. layers: [
4. {
5. name: "../custom/_base.js",
6. dependencies: [
7. "custom._base",
8. ]
9. },
10. ],
11. prefixes: [
12. [ "dijit", "../dijit" ],
13. [ "custom", "../custom" ],
14. ]
15.}
16.</code>
17.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

Optimizing Dojo and Zend Framework Integration

system. In it, you indicate dependencies, modules to


include, and build options. See Listing 12 for an example.
The profile indicates that it should create a custom
build layer in custom/_base.js that depends on...
custom._base. This ensures that the functionality we
wrote is bundled into the final result. When we create
the build, Rhino (a JavaScript engine written in Java,
and used in the build system) will traverse into the dependencies and look for other dojo.require() statements and create a single file with all of them.
To complete the profile, you can specify a variety
of options about how the packaging system should
build the layer. By default, it will include all JavaScript
files, strip whitespace and comments, intern template
files into JavaScript strings, and run the whole thing
through ShrinkSafe. You can specify alternatives as well
as customize how some of these tasks are performed
(such as: Are newlines kept? Should templates be interned into the JavaScript; etc.). Since putting these
explicitly in your profile makes running the build script
easier, lets add those as shown in Listing 13.
Finally, lets see what the end result of this is. In the
original situation, pre-build, the application was making the following includes:
/js/dijit/themes/tundra/tundra.css
/js/dijit/themes/dijit.css
/js/dijit/themes/tundra/layout/ContentPane.css
At least 28 more CSS files...
/js/dijit/form/ValidationTextBox.js
/js/dijit/form/TextBox.js
/js/dijit/Tooltip.js
/js/dijit/form/nls/validate.js
And several other JavaScript files that act as
dependencies for the above
When the layer is created, we add two files to the mix,
/js/custom/_base.js and /js/custom/themes/site/
site.css. However, after we package the build, we effectively reduce the number of initially required files to
only two!
At this point, the benefits of the Dojo packaging
system should be readily apparent. While it requires a
slight shift in development methodologies, the payoffs
and rewards for your end users are tremendous while
sacrificing none of the simplicity of development that
Dojos module system provides.

40 | February 2009 www.phparch.com

Optimizing Dojo and Zend Framework Integration

The Future
Right now, while Zend Frameworks Dojo integration
does a fantastic job of providing tools for rapidly developing Dojo-ized applications and provides the tools
necessary to create custom builds, at the time of this
writing, it does nothing to assist in creating these
builds. In the future, Zend Framework plans to create
a logging mechanism that will help automate the creation of custom layers and build profiles. This will allow
users to create build tasks that hook into them during
deployment, giving a simple, end-to-end solution for
creating dynamic, Dojo-driven user interfaces coupled
to your Zend Framework application.
Hopefully this article has given some insight
into the power of Dojos packaging and deployment solutions, as well as a starting point for hooking your Zend Framework applications to Dojo. The
Zend_Dojo manual pages provide additional information on the integration, and http://dojotoolkit.org and
http://dojocampus.org provide additional resources for
utilizing Dojo to its full potential.

LISTING 13
1.<code javascript>
2.dependencies = {
3. action: "release",
4. version: "1.2.1-custom",
5. releaseName: "custom",
6. loader: "default",
7. cssOptimize: "comments.keepLines",
8. optimize: "shrinksafe",
9. layerOptimize: "shrinksafe",
10. copyTests: false,
11. /* ... */
12.}
13.</code>
14.

Matthew Weier OPhinney is Software Architect for Zend

Framework, where he helps shape its standards and


practices. Zend Frameworks Dojo integration consumed
his time during the summer of 2008. Matthew is also a
supporter of open source in general, with contributions to a
variety of PHP and other projects.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

FEATURE

Grokking the REST


Architectural
Style

Representational State Transfer, or REST, has become


the hip, new buzzword of Web 2.0. But what really
makes an application RESTful? Is it pretty URLs? The
use of XML over HTTP? Is it any web service that
doesnt use SOAP? In all of the hype, the definition
of REST has become clouded and diluted.

orget what you thought you knew about REST. Cast


it aside. Leave it at the door. Its time to take a
fresh look at REST. This article re-examines REST,
placing it under a microscope to uncover each of the
constraints that form the crucial principles of the REST
style.
Imagine a massive, dark cloud. It is so dark and vast
that light cannot penetrate its interior, nor can one
in the cloud ever conceive the concept of light at all.
Light simply does not exist here. Chaos reigns in the
darkness. There are voices and whispers in languages
incomprehensible to human ears. It is deafening. Yet,
despite the clear presence of a multitude of others
moving every which way through the darkness, it is
cold and lonely in this lawless land.
Sound like the early days of our universe? Its not.
This is the Web.
When Roy Fielding set out to define the principles of
the Representational State Transfer (REST) style in his
2000 dissertation, he did not begin with a blank slate,
deciding on components and fleshing out the details

41 | February 2009 www.phparch.com

with the luxury afforded to an artist with a plain canvas. No, he began with a network already in existence:
the Web. In an attempt to describe the way applications behave across that network, he conceived of a
Web with no constraints-the dark, formless cloud-and
began adding constraints to it, giving it shape. These
constraints became the core principles of REST.
Forget what you thought you knew about REST. Cast
it aside. Leave it at the door. Lets take a journey
through the Web, adding the constraints of the REST
style one-by-one as we move forward to see how the
Web-and REST-takes shape under these constraints.
The problem with many so-called RESTful services
is that they arent RESTful at all. Perhaps they exhibit
some of the traits of the REST style, but they miss the
point of many of the constraints. For an application
to take full advantage of the REST style, the entire
network on which the application runs must be RESTful.
This is because the REST style is intended for use in
network-based software applications. Calling a single
service RESTful is not enough because the service

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

by Ben Ramsey

Principles of REST
A network-based application is considered
RESTful when the following constraints are applied and none are broken.
Client-server: Provides full separation
of concerns
Stateless: Each request contains all of
the information necessary to be understood and processed; no shared context
exists between the client and server
(i.e. cookies, sessions)
Cache: Clients may reuse data that is
labeled as cacheable, improving network
efficiency
Uniform interface: Components
throughout the network share a uniform
interface
Resources: There are an infinite number
of resources, all of which have unique
addresses and share a common interface
for manipulation
Representations: A resource may be
represented by multiple media types,
and the representation is the primary
vehicle for a resources transfer of state
Hypermedia (Links): Resources should
be linked to other resources
Metadata: Describes the data contained
in the representation or other metadata
Layered: All components in the network can understand all requests as they
travel from client to server but they
cannot see beyond the current layer;
provides scalability and efficiency of
requests
Code-on-demand: Extends the functionality of the client with client-side
scripts, etc.

42 | February 2009 www.phparch.com

Grokking the REST Architectural Style


exists only on the server. There must be more, and this
brings us to the first constraint of the REST style.

Of Clients and Servers


The constraints of the client-server architectural style
are crucial to a RESTful application.
Let there be light. Now the cloud begins to take
shape. It is no longer a dark, formless mass of meaningless messages traveling back and forth. There is a
clear relationship between clients and servers, providing a separation of concerns.
In my talks, I have often stated that resources are
the most important principle of the REST style, but
this is not the full story. While resources are important, and Ill discuss them later in this article, it is the
client-server relationship that is the most important
constraint of the REST style. It is this relationship that
provides for a separation of concerns, simplifying the
server component to improve scalability while the user
interface component lives on the client side. As long
as the interface between the client and server doesnt
change, the components may evolve independently.
In an application environment such as the Web, the
client-server relationship is all-too-familiar. A web
browser acts as a client. The web server is, well, the
server. So, you may be scratching your head saying,
Well, duh, Ben! Yet, I think we take this constraint
for granted. The separation of concerns provided by
this relationship enables many of the other constraints
of the REST style, which is why I believe this to be the
most important constraint. Without the client-server
nature of the REST style, many of the other constraints
would not apply.

No State Allowed
The next constraint is that of statelessness.
Statelessness is an important part of the client-server
relationship. Every request from the client to the server
must contain all of the information needed for the
server to sufficiently process the request. That is, all
requests must be self-contained, or atomic. The client
cannot send a request that relies upon previous requests. Every request must be interpreted in isolation.
Of course, since the early days of the Web, developers have been breaking its RESTful nature by implementing state in the form of cookies. In PHP and other
web programming languages, even server-side sessions
are not RESTful because a cookie must still be set in

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

FEATURE

Grokking the REST Architectural Style

43 | February 2009 www.phparch.com

REST Vocabulary
Hypermedia: The use of media as elements of a hypertext system in which
elements are connected by links
Layer: An individual component within
the network; may be a client, server,
gateway, proxy, etc.
Representation: A media type (e.g. text/
html) used to communicate a change in
the state of the resource
Resource: Anything that has identity
RESTful: An application is said to be
RESTful when it adheres to the principles of the REST style
RESTafarian: An advocate or extreme
zealot of the REST style

For More Information


Architectural Styles and the Design of
Network-based Software Architectures
by Roy Fielding. This is the dissertation
where REST was first described. http://
www.ics.uci.edu/~fielding/pubs/dissertation/
top.htm
RestWiki. An excellent reference for
researching REST and seeing a compilation of much of the discussion from the
REST community. http://rest.blueoxen.net
rest-discuss. The Yahoo Groups discussion list for the REST community. http://
tech.groups.yahoo.com/group/rest-discuss/
Hypertext Transfer Protocol (RFC 2616).
This is HTTP, the protocol that drives
the Web. The constraints of the REST
style can be applied to this protocol.
http://tools.ietf.org/html/rfc2616
Atom Publishing Protocol (RFC 5023).
A RESTful publishing protocol that sits
on top of HTTP. http://tools.ietf.org/html/
rfc5023

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

order for the client to tell the server which session to


use. If the cookie goes away (either through expiration
or some other means), then the server no longer knows
which session to associate with the request. If cookies
did not expire, were always guaranteed to be present
in every request, and did not rely on a stored context
on the server, then an argument could be made that
the use of cookies can be RESTful. However, cookies
are intended to expire, either at the end of the browser
session or at some date set in the future. They cannot
be relied upon, and thus, they cannot be thought of as
part of an atomic request. Cookies are a way to maintain client-server state and, as a result, are not RESTful.
One may argue that client-server state provides valuable functionality, such as user login and functionality
tailored to users preferences, but the REST style dictates that there should be no shared client-server state
and, instead, the client should maintain all application
state. This approach emphasizes scalability on the server and flexibility in the client implementation. Server
scalability is an obvious benefit because there is no
need to maintain a session store on disk, in a database,
or in memory, so this is one less thing to consider and
implement when scaling horizontally. Client flexibility
may not be so obvious.
By allowing the client to control the state, the client
can make data presentation decisions independent of
the server. Take a simple RESTful shopping cart example. The client stores a users login information and
sends it to the server through authentication headers
only when a request requires authenticated access, such
as finalizing a purchase. The client requests a catalog
of items to purchase from the server, but when a user
adds items to her cart, the actual cart information is
stored locally in the client memory. The only time the
cart data is sent to the server is at the point the user
finalizes the purchase and checks out with her payment
information. The server need never keep track from
request to request of what items are in the cart. The request to purchase the items in the cart includes all the
information necessary to complete the transaction.
Now, I understand that web browsers are not smart
enough to provide this kind of rich client experience, but JavaScript and other client-side code are.
This is another principle of the REST style called
code-on-demand, which I will discuss later.

FEATURE

Next, we add the cache constraint. Again, this relies


on the client-server relationship. The cache constraint
specifies that data within a response be labeled as
cacheable or non-cacheable. A cacheable response allows the client to store the response and use it again
later when the same request is made, rather than sending the request all the way to the server. This improves
scalability over the network by reducing the number
of round-trip requests. The user sees a faster response
time in the client, and the server never receives the
request, so it doesnt need to process any data.
As I mentioned earlier, the REST style is a style
for network-based applications, so if a server returns
metadata telling a client how to cache a response, then
the client should respect the caching information and
cache the response to reuse on subsequent requests.
If it fails to do so, then the client breaks the RESTful
nature of the application and also increases the load on
the server by continuing to send requests for responses
it might already have stored in its cache-or could have
stored there.
In theory, all data in the application could be set as
non-cacheable, but this decreases network efficiency
and increases latency. The REST style seeks to improve
performance over the network by allowing clients to
cache responses, reducing the overall network traffic.

Speaking the Same Language


The next set of constraints defined by the REST style
work together to form a uniform interface between the
client and server. This is the constraint on which most
tend to focus when discussing REST. I think this is
because it is the most concrete concept, lending itself
well to pseudo-code and real-world examples, particularly with Hypertext Transfer Protocol (HTTP).
The uniform interface is a distinguishing characteristic of the REST style. While other architectural stylessuch as remote procedure call, or RPC-focus on the
diversity of actions that the application can perform,
giving rise to disparate systems across the network that
all require different interfaces to communicate with
each other, the REST style simplifies interactions by
defining a uniform interface between components. This
allows independent components, such as the client or
server, to change while maintaining the same interface.
Also, the same request may be made to other servers in
the network, and each receiving server can understand
the request. They may not be able to fulfill the request,
44 | February 2009 www.phparch.com

but they all can understand it.


Fielding describes the uniform interface of REST as
being composed of four constraints: identification of
resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as
the engine of application state.

Identity Matters
The first interface constraint, identification of resources, is often described as two separate topics when
discussing REST: resources and addresses. Yet, these
are one and the same in the context of the REST style,
since a resource must have an address. Another word
often used in the place of resource is noun.
Resources are all around. Take a look. I dare you.

"

The uniform interface


is a distinguishing
characteristic of REST.

Every object you see is bound to be a resource. The


monitor in front you. The pen lying on top of the
notepad that is sitting in your letter tray on your desk.
These are all resources, and youll be hard-pressed to
find something that isnt a resource, but what makes a
resource a resource?
Wiktionary defines a resource as something that one
uses to achieve an objective. With this broad of a definition, practically everything can be considered a resource because everything can be used to achieve some
objective or another. My monitor conveys information
from the computer in a way that I can understand. I
use the pen to write in the notepad, which I use to
store my notes. The letter tray holds papers-and, in my
case, mostly junk-and I use the desk as a workspace
that supports my computer and all the resources I need
to do my work.
In our case, though, were not talking about tangible
resources, physical objects one can touch and interact
with in the physical world. Rather, were interested in
virtual resources on a network, like a document, image,
or service. If you can request it over the network, its

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

To Cache or Not To Cache

Grokking the REST Architectural Style

FEATURE

Grokking the REST Architectural Style

resources over a network by transferring representations between components to communicate changes in


state.
Representations of resources are made up of media
types, on the Web the most common of which is text/
html, but others-specifically those common in web
services-might include application/xml, application/xhtml+xml, application/atom+xml, application/
soap+xml, application/json, and others, including
binary media types, such as images. These media types
all compose hypermedia elements of a greater hypertext
system.

Resources Are Related


Hypermedia, the third interface constraint, is important in RESTful systems because the REST style places
emphasis on the links between resources. In HTML, the
most familiar links between hypermedia resources are
found in the href attribute of the a element. These
links allow users to move between resources as they
wish.
In a RESTful service, resources should be linked together. Besides HTML, an excellent example of a format
that makes use of links is the Atom Syndication Format
(RFC 4287). Atom provides link elements that use
rel attributes to specify relationships to the current
resource. Listing 1 provides an example Atom Entry
document with link elements for various types of related resources. An Atom client uses this information to
expose these links to users.

One Identity, Many Representations

LISTING 1

The second interface constraint is that of representations. Each resource has a representation such that the
client never requests the resource itself but a representation, or a concept, of that resource. This allows the
server to respond dynamically through content negotiation with a representation that satisfies the requesting
client. There is never a need to change the links to the
resource when the representation changes. The identity
remains the same, though the representation changes.
In the REST style, whenever actions are performed
on a resource, the client uses a representation of the
current state of that resource and transfers that representation to the server to communicate a change in
state. This is where the REST style gets its name. This is
representational state transfer: the act of manipulating

1.<?xml version="1.0" encoding="utf-8"?>


2.<entry xmlns="http://www.w3.org/2005/Atom">
3. <title>Grokking the REST Architectural Style</title>
4. <link rel="self" type="application/atom+xml;type=entry"
5. href="http://example.org/articles/rest.atom"/>
6. <link rel="alternate" type="text/html" hreflang="en"
7. href="http://example.org/articles/rest.en.html"/>
8. <link rel="alternate" type="text/html" hreflang="es"
9. href="http://example.org/articles/rest.es.html"/>
10. <link rel="enclosure" type="audio/mpeg" length="1337"
11. href="http://example.org/audio/rest.mp3"/>
12. <link rel="related" type="application/atom+xml;type=entry"
13. href="http://example.org/articles/atompub.atom"/>
14. <id>tag:example.org,2009-02:articles/rest</id>
15. <updated>2009-02-01T12:29:29Z</updated>
16. <published>2009-02-01T08:29:29-05:00</published>
17. <author>
18. <name>Ben Ramsey</name>
19. <uri>http://benramsey.com/</uri>
20. </author>
21. <content type="xhtml" xml:lang="en">
22. <div xmlns="http://www.w3.org/1999/xhtml">
23. <p>Imagine a massive, dark cloud...</p>
24. </div>
25. </content>
26.</entry>

45 | February 2009 www.phparch.com

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

a resource, but a better way to define these types of


resources is: if it has identity, its a resource.
Identity matters. When thinking about physical resources, a particular resource may or may not have an
identity that specifies its location in space. Certainly,
our brains give objects a kind of identity.
Please pick up the pen that is on top of my desk.
Which pen?
The one lying next to the beer glass.
Oh. That pen.
Objects in the real world have spatial identity. This
is the same for resources in a network, but the space is
virtual, and the address identifying a resources location is more exact. On the Web, were familiar with a
Uniform Resource Locator (URL) as an address for a
resource.
In the REST style, the focus is on resources and their
identifiers, rather than on methods and actions. The diversity of resources is an important concept, since the
network is capable of expanding to an infinite number
of resources.
A RESTful system should expose these resources
through hypermedia (which will be discussed later
under Resources Are Related), and all resources
should share the same interface for access and transfer
of state. Clients may get resources, update them, and
delete them. In addition, clients may create resources.
These are analogous to the HTTP methods GET, PUT,
DELETE, and POST. Without addressable resources with
a uniform interface, there is no way for clients to make
requests of servers, so the client-server relationship,
again, is crucial to this constraint of the REST style.

Resources Are Self-descriptive


The fourth and final interface constraint of the REST
style is that of self-descriptive messages, or metadata. Metadata comes in the form of name-value pairs
that can describe both the representation and the
resource data returned in the response. Metadata provides extra information to the client about the representation, including the content type, the length of
the data, the data encoding, etc. It may also contain
control data, telling clients or other components how
to cache the data or whether the resource has changed
since the last request.

"

The client-server
relationship is the most
important constraint.

On the Web, metadata is contained in HTTP headers,


such as in the Content-Type, Cache-Control, ContentLanguage, Content-Encoding, Content-Location, and
Expires headers and more. The representation itself
can also contain metadata. Again, Listing 1 shows
an example of how a representation might contain
metadata describing the resource it represents. The
title, updated, published, and author elements all
represent metadata describing the data contained in
the content element. Even the content element has its
own metadata in the type and xml:lang attributes.

Layers Bring It All Together


As the massive cloud that is the Web takes shape and
gains structure imposed by these constraints, we come
to the fifth constraint of the REST style, the layered
system. This constraint builds upon each of the previous constraints to provide perhaps the most beneficial
feature of the style. It is also the concept that many
fail to grok when building RESTful applications.
In order to think about the constraint of the layered
system, you must recall that REST is an architectural
style to describe network-based software applications.
The key word here is network. The REST style depends
on the presence of a network. All of these constraints
46 | February 2009 www.phparch.com

Grokking the REST Architectural Style


work together over the network to reduce load on the
server while improving application response in the
client (reduced latency, etc.). This creates a highly efficient network application that scales horizontally with
the network.
The layering effect of the network restricts each component from being able to see beyond the current layer.
This makes each layer independent of the others. Each
layer only needs to know about the request or response
and the destination of the message.
This is where statelessness, caching, and a uniform
interface play major roles. It is these constraints that
allow the layering to take place at all because all components along the path of the request can understand
the request (a benefit of the uniform interface) and
store and replay that request (due to the statelessness
of the self-contained messages) and even serve the responses (stored in the local cache) rather than sending
the request along to the server.
This type of system makes it very easy to drop in
intermediaries in the form of load balancers, proxies,
gateways, firewalls, etc., each of which can respect the
cache metadata to store the response of the request
in cache. This means that the layers work within the
network to improve the performance of the overall
application-remember, the network is part of the application-by reducing the number of round-trip requests
to the server and returning a response to the client in a
shorter amount of time than it would take the server to
process the request.
I believe that many so-called RESTful applications
forget that the network and its layers are part of the
complete application. This short-sightedness means
that these applications fail to take advantage of caching and statelessness, requiring that every request
go from the client all the way to the server and back.
These applications miss the point of the REST style,
dumbing it down to POX (Plain Old XML) over HTTP
transactions, usually focusing on pretty URLs.

Extending the Client


Finally, there is one last constraint of the REST style,
though it is considered optional. It is the code-ondemand style, which I mentioned earlier when discussing statelessness. This style of application architecture
should be all-too-familiar to modern web developers
since it is a way to allow the server to extend client
functionality by telling the client to download and
execute extra code to improve and enhance the client

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

FEATURE

FEATURE

Grokking the REST Architectural Style


experience independent of server interaction.
These days, we do this in the form of JavaScript,
Cascading Style Sheets (CSS), Flash, and more. A
RESTful application should take advantage of code-ondemand to move all state functionality to the client,
as well as providing other functionality that is more
appropriate and efficient to handle in the client rather
than on the server.

of the principles of the REST style and will be able to


take these principles and apply to them to your own
network-based (web) applications, taking full advantage of the network and its components to build highly
scalable applications with rich clients.
Now, go get some REST!

Weve taken a journey through the Web, one-by-one


adding the constraints of the REST style to see how the
massive, formless beast of the Web has a shape and
a form and that, beyond the seeming chaos, there is
order and structure. Yet, the structure is very lightweight, and all of the components are contained in
distinct and separate layers that know nothing of each
other. Still, the uniform interface they share makes it
simple enough for each layer to understand the messages sent back and forth and to relay those messages,
caching data, as needed, to provide a more efficient
and scalable network.
This is the REST style in a nutshell. Client-server,
stateless, cacheable, uniform, layered. It is not a
web service. It is not a protocol. It does not dictate
a particular data format. REST is the manipulation of
resources by transferring representations between network components that share a uniform interface.
While this has not provided a practical discussion of
how to design and implement RESTful applications, it
is my hope that you now have a greater understanding

Ben Ramsey is a Software Architect for Schematic and the


founder and organizer of the Atlanta PHP user group. He has
a passion for HTTP and web services and longs for the day
when the Semantic Web is a reality. He likes zombie movies,
loves good beer, and blogs at http://benramsey.com/.

Get your framework-based site up and running in no time.


Hosting customized.

47 | February 2009 www.phparch.com

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Getting Some REST

Security

Securing Software
& File Uploads
by Arne Blankerts

n December 2008, various big players in the IT security sector issued a serious and unusual warning:
Do not use Microsoft Internet Explorer. While the
majority of web developers would probably favor this
anyways, they did this for a different reason. Due to
unpatched security holes, which are actively exploited
already as so-called zero day exploits every user of
IE is in danger. This is nothing new to an experienced
user, but this time, the scenario has changed. Instead
of trying to lure users into visiting prepared websites,
as has been done in the past, todays attacks try to
exploit existing websites by automatically scanning
for XSS and SQL injection opportunities. When found,
these are used to inject the actual exploit code for the
Microsoft browser into these websites. Even though by
now, Microsoft has managed to produce a fix for the
current problem, there will always be security problems
in browsers. This scenario in mind, it becomes more
and more obvious how important it is to develop secure
web applications and keep all 3rd party applications
up-to-date.
Lets look at a few of the 3rd party applications:
The MediaWiki Foundation (see [1] in Related Urls)
released a new version to fix various XSS bugs and one
CSRF problem (versions 1.13.3 and 1.6.11 respectively,
users of older versions are encouraged to upgrade to at
least 1.13.3) in their free wiki application, making the
update a recommended release.
Also recommended for all users of PHP is the update
of the language itself. Version 5.2.8 contains various
bug fixes including some that do have a security-related background. If your code relies on magic_quotes
being enabled and your server currently runs on version

RELATED URLS
[1] http://lists.wikimedia.org/pipermail/mediawikiannounce/2008-December/000080.html
[2] http://www.hardened-php.net/suhosin/

48 | February 2009 www.phparch.com

Roundup
5.2.7, be advised that this release had broken
magic_quotes and has thus been pulled from distribution and should be upgraded as soon as possible to
5.2.8.
Using the latest versions does not guarantee protection against bad software design though. A very
problematic aspect in building a secure web application
seems to be the handling of file uploads. Probably the
worst mistake to make, from a security standpoint, is
the idea to store user-provided files within the document root of the webserver, allowing direct access from
the outside and by that, remote code execution. Blindly
trusting any kind of information provided by a remote
client is considered a bad idea for almost every use
case, but still, people often trust the mime-type information and original filename provided by the browser.
Instead of using the given mime-type, a secure upload
handler should run its own detection either by using
ext/fileinfo, the old mime functions, or, when run on
unix/linux, by manually executing the mime binary. A
good idea is to additionally install a virus scanner, and
thus make use of the hook provided by the suhosin security extension (see [2] in Related Urls) to automatically scan uploaded files even before granting access to
them in PHP.
The content of the user contributed file might not
be the only danger to the server or website user. There
is almost no limit in what can be used as a filename
in terms of characters. Thus, html tags could very well
be part of a filename in almost all operating systems.
So, using the provided name without any escaping, as
always, opens up the xss universe to any attacker with
upload privileges.
Summarizing, one could say that securely handling
file uploads is actually quite an easy task, assuming
some basic rules are applied: Do not store files in a location directly accessible by a remote user, do not trust
mime-type nor filename and, when possible, run a virus
scan before continuing the processing.

Arne Blankerts is the head of development at NonFood


advertising agency in Hamburg, Germany. Arne is the
inventor and lead developer of an open source site system
fCMS (http://fcms.de) that is written in object-oriented
PHP and makes heavy use of XML. Furthermore he is a
trainer, regular author writing articles for the German PHP
Magazine, co-authoring books and speaking at (PHP-)
conferences. In the unusual case of spare time, he helps
maintaining the German translation of the PHP manual.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

COLUMN

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

My Way or
the UNIX
Way
by Marco Tabini

t so happens that I have recently come into


possession of an iPhone. This was by complete accident, because, you see, my wife wanted a
"Jesus Phone" for our tenth anniversary, and anniversaries are not occasions in which you want to be caught
short. Therefore, in an act of ultimate redundancy, I
went and bought twojust in case one of them didnt
work.
My initial disdain for the iBlower was almost palpable, which explains why it sat in a box for nearly
three months. I am a touch typist, and, as the name
subtly suggests, I need to touch the keys of a keyboard
in order to type properly. In fact, I have been trying to
type this column using the hunt-and-peck method that
so many would-be computer users favour, and I ended
up making so many mistakes that I had to start over at
least five timesif I didnt know any better, Id begin
to think that English is not my first language, and
writing is not exactly my slice of pie. Thus, I wasnt expecting an on-screen keyboard to be really compatible
with the pork butts that are attached to the palms of
my hands and have been using a key-ful Nokia phone,
where my hams happily oink away at the keyboard at
the amazing speed of approximately three words a
minute.
But I digress. After having safely stowed the iHorn
away for a quarter or so, I decided to give it another try. After all, I had some holiday comingand I
couldnt possibly live with myself if I didnt find yet another reason for remaining firmly glued to my computer. From a users perspective, the Almighty Handset is
quite a nice machinewhich, it turns out, is compatible with fingers of porcine proportions.
Being the geek that I am, however, the users

50 | February 2009 www.phparch.com

exit(0);
perspective didnt interest me all that much. I didnt
want to useI wanted to understand, dissect, learn
and generally, get my hands dirty. After hearing so
many stories about lone programmers making money
hand over fist by selling scatological masterpieces
through the App Store, I figured I had to at least see
what the hubbub was all about.
Along the road to discovery, I stumbled upon a few
rather unhappy programmers who seem to think that
no App Store that sells virtual whoopee cushions for a
mere $0.99 could be taken seriously by serious development outfits who want to sell serious applications at
serious prices. On the surface, thats a fair pointas
I have two young children of my own, I do not need
technology to hear my fill of bodily noises on a daily
basis (on the other hand, if someone could come up
with technology capable of stopping said noises, Id be
all over it), and the App Store does seem to be overflowing with programs of questionable value. Whats
more, Apples insistence on being the ultimate arbiter
of whats fair game and what isnt, makes any significant investment in developing applications for the
Phone Formerly Known as as secure as investing the
American automotive industry.
Interestingly, the proliferation of simple, one-off applications has resulted in a strange fact: the iPhoney is,
in fact, an almost UNIX-like environment. I dont mean
this from a technical perspective, but from a philosophical one: just like under UNIX, each application is
designed to perform one task, and perform it as well as
it can. Whats really missing is the glue between applicationsin a shell, we have pipes, but on the iPuppy
the only way of channeling virtual farts from a whoopee
cushion app to the other is via URLs which are not that
well supported by the underlying operating system.
So, it seems to me that the Fruit Company has a
tough choice ahead of itself. On one hand, they could
raise the bar for getting into the App Store, or change
the store itself so that more complex applications sit in
their own space, well separated from the simpler ones.
On the other, they could foster the cooperation between applications and create a collaborative environment in which duplication just for the sake of duplication doesnt make nearly as much sense as it does
nowafter all, its worked for Unix, I dont see why it
shouldnt work for the Little Phone That Could.

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

COLUMN

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Licensed to 63883 - Joseph Crawford (info@josephcrawford.com)

Vous aimerez peut-être aussi