Licensed to 48409 - Primoz Klemensek ( klemensek @ gmail . com )

russianmiserableSecurity

Jun 13, 2012 (4 years and 10 months ago)

1,055 views

Licensed to:
Primoz Klemensek
klemensek@gmail.com
User #48409
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

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!
CONTENTS
April 2009
FEATUrES
20
Rich Internet Applications with Flex and PHP: Part 3
The Final Steps for Your RIA
Richard Bates
26
Black Box Penetration Tests
Expand Your Developer Knowledge by Gaining Insight into Attackers
Ben Sgro
32
PHundamental Security
Ecosystem Review, Coding Secure with PHP, and Best Practices
Hans Zaunere
38
Who Says PHP Security Sucks?
Increase Your Knowledge and Security
Barry Austin
43
Storing Multilingual Records in the MySQL Database
Three Solutions for Storing Your Translated Text
Jakub Vrána
COlUMNS
4
Editorial
Near and Dear
Elizabeth Tucker Long
14
From the Cloud
OAuth: Under the Hood
Ben Ramsey
6
Pear Corner

Backwards Compatibility
Helgi Þormar Þorbjörnsson
49
Security Roundup
Validation
Arne Blankerts
8
Enterprise PHP
The Estimation Monster
Ivo Jansch
50
exit(0);
Shift Happens
Marco Tabini
11
Garbage Collection
PHP's Take on Variables
Derick Rethans
51
ElePHPants
!
Download this
month’s code at:
http://phparch.com/code
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

4
|
April

2009

www.phparch.com
EDITORIAL
April 2009
Volume 8 - Issue 4
Publisher
Arbi Arzoumani
Editor-in-Chief
Elizabeth Tucker Long
Author Liaison
Elizabeth Naramore
Cathleen MacIsaac
Technical Editors
Matthew Turland
Simon Harris
Ian Lessing
Clark Everetts
Graphics & Layout
Arbi Arzoumani
Managing Editor
Arbi Arzoumani
Authors
Barry Austin, Richard Bates,
Arne Blankerts, Ivo Jansch,
Ben Ramsey, Helgi Þormar Þorbjörnsson,
Derick Rethans, Ben Sgaro,

Marco Tabini, Hans Zaunere,

Jakub Vrána
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
Copyright
©
2003-2009
Marco Tabini & Associates, Inc.
All Rights Reserved
Near and Dear
Elizabeth Tucker Long
by
T
his month, we have the exciting conclusion of our three-part article on
building rich internet applications with Richard Bates, and we invite you
to start thinking globally with Jakub Vrána’s article on storing multilin
-
gual records in MySQL. Join us for discussions on best practices for businesses
as Ivo Jansch discusses project estimating and Helgi Þormar Þorbjörnsson
discusses backwards compatibility. Derick Rethans takes us deep into the PHP
internals, and Marco Tabini takes us to Disney World. If security is on your mind
this month, then we’ve got a great line up for you. Learn more about security
ecosystems with Hans Zaunere, black box penetration tests with Ben Sgro, and
OAuth with Ben Ramsey. You can round out your afternoon reading with Arne
Blankert’s column on validation and a lively discussion with Barry Austin on
whether or not PHP’s security sucks.
Security is a topic that is near and dear to my heart.
It’s my own personal opinion that it’s one of the best
and most difficult parts of our jobs as programmers, and
also one of the greatest services that we can provide
our employers and customers. I say it’s the best because
it’s an ever-changing challenge, a puzzle to keep us on
our toes and make our jobs a little more exciting. This also makes it one of
the most difficult parts of our jobs since there’s no one simple answer to the
question “How can I be sure this is secure?” This issue, we’ve dedicated a good
chunk of space to security-related topics. I hope you’ll consider this a starting
point for your own security research because this is just the tip of the prover
-
bial iceberg, and knowledge is our best ally.
What's New at Python Magazine
Learn more at:
http://pythonmagazine.co
m

April 2009 Topics:
Using Python to Validate a California County's Election


(Mitch Trachtenberg)
ElectionAudits: an interview with Neal McBurnett

Plone: Python's Killer App? (Christopher Johnson)

Create Your Own Domain-Specific Language (Paul McGuire)

Protocol Simulation Using SimPy (Pablo Troncoso)

Welcome to Python — Dictionaries (Mark Mruss)

and much more...

Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

6
|
April

2009

www.phparch.com
COLUMN
PEAR Corner
N
ow in my introduction last time around, I said
I would be writing about the good and the bad
about PEAR. I believe last time I focused only on
a good thing, but now I’m going to focus on something
that is both good and at the same time bad for PEAR,
something people have both praised and condemned
PEAR for. I did touch on the subject a little in my last
column. Yes people, it is backwards compatibility.
The Good, the Bad, the Ugly
As I mentioned, people have praised us for our stance
on backwards compatibility and people have told us
that we are idiots for it. Let’s look at the “issue” from
both sides, shall we.
The good thing about keeping backwards compatibil
-
ity (or as it is better known, BC) religiously is that if I,
as a company or a project, decide to use library X from
Y repository and said library is in a stable state, then I
can rest assured that that my application will still run
as intended even if library X gets upgraded from 1.1.0
-> 1.3.0 -> 1.20.0. This is very important for me as an
end user because I can sleep at night, and it makes my
development efforts a whole lot easier.
The bad thing about backwards compatibility is that
you have to, well ... maintain backwards compatibility,
a bit of a circle reference there, huh ? ;-) As a library/
API maintainer, I feel absolutely horrible about keeping
BC in my code. I need to make sure that function foo()
will stay the same, return the same, and accept the
same parameters, even if I refactor the internals of the
code. The fact is that sometimes you release something
which you believe to have awesome code as well as
the most superb API design ever made, but then some
new requirements, new features, or unexpected bugs
happen which directly or indirectly mean you need to
alter the API. Now, you need to make a decision: try to
preserve backwards compatibility and thus cause more
coding and headache for you or release a new major
version that breaks backwards compatibility and means
that you will be supporting two code bases until the
majority of your users have moved over allowing you
to finally put the old code base to rest (a good library
maintainer would try to maintain both ;-) ).
Having heard about the good, the bad, and the ugly
of backwards compatibility, how does this really af
-
fect PEAR? Simply put, it has caused PEAR to accumu
-
late a good amount of PHP 4 code that can not really
be turned into PHP 5+ only code unless a completely
new release is done under a new version number with
a changed class name, 2 appended or similar. And for
Backwards
Compatibility


The Good, The Bad, The Ugly
Helgi Þormar Þorbjörnsson
by
In my last column, I went on a little rant about version naming standards and how
that standard has helped PEAR, and other projects, to deal with their version naming
and what users and developers can expect from the naming rules (e.g. seeing Foo-
0.5.0beta5 = A backwards compatibility break could happen) and so on.
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
7
COLUMN
PEAR Corner
this reason, we have gotten some nasty stamps from
people for being too conservative, holding on to PHP
4, not supporting the adoption on PHP 5, and some
people have even gone so far as to say that PEAR died
many years ago.
Excuses, Excuses, Excuses
To answer those “stamps”, I have to go on the de
-
fensive a bit, but for a good reason. What we did in
regards to backwards compatibility has kept many com
-
panies extremely happy because we have not broken
stable code out of the blue.
First off, I’d like to say this: PEAR has only accepted
new packages that have PHP 5 dependency for 2 – 3
years so if anything, PEAR has been very pro PHP 5 for
a long time. Plus, we have made sure all of our PHP 4
packages work just fine on PHP 5. As part of being a
high quality repository of code, PEAR developers have
tried to ensure that old packages do not fall into a
Siberian no man’s land, so sometimes this can also be
perceived as holding on to the past.
Another thing PEAR did back in the days when PHP
5 was taking its baby steps was to make sure people
did not propose a package as PHP 5 only if it was just
going to utilize sugar features like public / protected
/ private, or ppp if you like, because, at the time, PHP
4 was going strong. Of course we allowed PHP 5 only
packages if people actually used PHP 5 specific fea
-
tures.
One thing to consider about promising people back
-
wards compatibility: it will strain your development
resources
heavily
, especially because it will mean
maintaining two or more branches of similar/same code
base. This resource strain is one of the reasons why
PEAR developers sometimes opt for maintaining PHP 4
code that also works on PHP 5 instead of maintaining
two copies of the code, PHP 4 code that works on PHP
5 and then also a PHP 5 only version. It’s open source,
and you only have so much time on your hands. :-)
As you can see, these are a bunch of excuses, but to
me they are fairly valid reasons because, in many cases,
we were putting our standards to work, enforcing them
where needed, and thinking about our end users, some
-
thing too few projects do, be it in PHP, C or whatever
language. One excellent example is ffmpeg, a very good
library to handle videos and similar formats, but they
don’t believe in backwards compatibility. They, in fact,
constantly break their API, don’t do any official re
-
leases to speak of, and just tell people to stuff it (just
go read the Download page on their website -
http://
ffmpeg.mplayerhq.hu/download.htm
l
). This has caused
many people to move away from a very good library to
other alternatives because they don’t want to be fixing
their code every other day because said library main
-
tainers are not playing ball with their end users.
Hopefully, this was useful to people that have been
wondering about backwards compatibility, as well as
projects/companies that are either going to role out
their own libraries to the public/customers or intend on
picking a library or five to use in their own projects.
Think long and hard about it: do you have the re
-
sources to use a library that doesn’t have any back
-
wards compatibility rules in place or do you have the
resources to maintain a library that has backwards com
-
patibility rules and everything that encompasses. Put
your thinking hats on ladies and gentlemen, and, until
the next time, cheerio.
"
With Situational
Applications 'time
to value' is more
important than
enduring value
On day to day basis
Helgi Þormar Þorbjörnsson
works
for a new and upcoming startup, echolibre, that specializes
in building APIs, creating top of the line web applications,
security audits, and systems scaling. 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 48409 - Primoz Klemensek (klemensek@gmail.com)

8
|
April

2009

www.phparch.com
COLUMN
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.co
m
. I might contact you for a short interview, or at least I will
use your input when writing this column!
Thank you!
Ivo
In this month’s installment of Ivo’s
Enterprise PHP column he takes a look
at arguably the most scary part of a
project. The estimation phase. “Hey, the
customer asks for this feature, how long
will that take you?” is the nightmare of
many PHP developers. Ivo looks at why
it’s such a nightmare and ways to deal
with it.
S
ome of us are lucky and are allowed to program
’carte blanche’ style. They just do their thing, it
doesn’t really matter how long things take, and
they can make a feature as cool as they can possibly
make it. The majority of us, however, don’t have that
luxury. Our projects have deadlines and budgets, and
we have to deal with customers that expect us to de
-
liver stuff within budget and before the deadline.
Often, that same customer hardly has a clue as to
what it takes to develop a feature, and some don’t
even have a clue as to what they want. Still, they often
expect us to be able to answer the question “I want a
webshop, how much does that cost?” accurately to the
dollar.
In an earlier article, I covered requirements gather
-
ing and how to make sure we know what it is that the
customer needs, so let’s focus on the other important
question. “How long will it take you?”.
The Importance of the Estimate
Why is it important to estimate the amount of work
before we start coding? Can’t we just write code, eat
pizza, and be happy? Here are a number of reasons why
it’s important to estimate the amount of work before
we do any development:
• It will help determine the deadline.
Sometimes, deadlines are hard and fixed and set by
commercial goals alone, but often the development
team can influence the deadline by determining how
long a feature will take. The project manager can then
create a project plan that takes deadline requirements
and the amount of work into account.
• It will help determine the cost.
The Estimation Monster
Ivo Jansch
by
PHP
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
9
COLUMN
The Estimation Monster
Before a customer approves a project, he will want to
know how much something is going to cost. Especially
when there are multiple parties bidding for a project,
the cost is a factor. Although not always the most
important one (quality and trust are examples of other
factors), it is always a factor to take into account. Most
people want to drive a Ferrari but given the cost, an
ordinary Ford might fill your needs just as well.
• It will help determine the value.
This is subtly different from cost. In particular, when
it comes to estimations for new features on an exist
-
ing project, your estimation will help determine the
value of a feature. A customer may want a whole list of
features, but not at any cost. Maybe once he realizes
that Fancy Pancy Feature costs a significant amount of
time, he may want to reconsider how much this feature
is worth to him and whether or not he wants it at all.
Or if he still wants it, what priority it will have.
• It helps avoid misunderstandings.
This might seem a weird one, but if you are open about
your estimation, you might discover misunderstandings
or misinterpretations in an early stage. If you estimate
a feature at say 3 days work, and you discuss that with
the customer, he might tell you that this is way beyond
what he thought, and might clarify the feature in such
a way that you see things more simply. The other way
round, if you estimate 5 minutes for something simple,
the customer might be able to explain how you under
-
estimated what he needs. Openness isn’t always pos
-
sible. Especially in fixed price projects, it is common to
not be open about hours, but I’ve found that in many
cases, openness does more good than harm.
• It will make your estimates better.
The only way to get better at estimating, is to esti
-
mate. And to evaluate your estimates. When your proj
-
ect is done, look back at your estimates. See where you
were right, where you were wrong, and why you were
wrong. This will help you become more aware of how
long things take.
The Student Syndrome
If you look at estimates from a statistics point of
view, then you should overestimate as much as you
underestimate. Yet, many developers often underes
-
timate a lot more than they overestimate. One of the
reasons this happens is what is called ’student syn
-
drome’. When students have 3 weeks to complete an as
-
signment, they’ll probably party the first 2 weeks, and
start working on their assignment halfway through the
last week. When the assignment turns out to be more
difficult than they thought, there’s no buffer left, and
they overrun their deadline.
In development, similar things happen, even though
most developers do not do this on purpose. If you
have 4 hours to complete a task, chances are that you
are going to always use up that 4 hours. Even if you
could do the feature in 2, you’d just make it a bit nicer,
spend a bit more time on testing it, etc. It is not until
most of the 4 hours have already been spent that you
get to the point where you seem to need more time
than you allocated, and your buffer has already been
used.
A way to cope with this is to give yourself less time
instead of more. This seems quite controversial. If
you’ve overrun your estimates a lot, you tend to in
-
crease your estimate. If you weren’t able to complete
a task in 4 hours this time, next time you’ll estimate
6 hours for it. However, if you give yourself 6 hours,
there’s a significant chance that you’ll actually use
those 6 hours. Or maybe again overrun it, leading to an
8 hour estimate the next time.
Instead, next time, if you’ve estimated something at
4 hours, give yourself 3 to complete the task when you
start on it. Do not think about the 4 hours anymore,
but consistently work with the estimate of 3 hours. This
will give you a 1 hour buffer at the end of the task (a
buffer you already calculated in the estimate but that
the student syndrome would’ve normally wasted), and
the chance that you meet your estimate increases. This
is all ’between the ears’ because you are still working
with the same estimates in essence, and you’re per
-
forming the same tasks, but by looking at them from a
slightly different angle and being aware of the buffers
and the student syndrome, you will create better esti
-
mates and be able to actually meet your own estimates.
Doubling the Numbers
There are other interesting things to discuss when it
comes to buffers in estimates. A bad estimate is one
where an arbitrary amount of hours was added as a buf
-
fer, or, even worse, but very common, “let’s just double
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

10
|
April

2009

www.phparch.com
COLUMN
The Estimation Monster
the numbers”. Doubling the numbers is the worst thing
you can do to an estimate. If you double the numbers,
student syndrome will still kick in and you will spend
more time on development than would be necessary.
Also, it makes estimating as accurate as a game of
roulette. I’ve witnessed teams that would just increase
their next estimates every time they would overrun
them, but this only leads to hilariously huge estimates
and they would still overrun them. At some point, the
estimates for projects become bigger than their com
-
mercial value. This means that a team would need so
much time to develop something that a project would
simply not be commercially viable. At the moment you
see customers respond with “I’m not going to pay THAT
for such a simple website”, you know that you need to
take a good look at how the estimates are created.
Instead of just arbitrarily adding buffers or doubling
the numbers, estimates should consist of a base num
-
ber for each feature; a number that you think that you
should realistically be able to develop the feature in,
without calculating any buffer per feature. Then, add a
30% buffer to the project as a whole. This helps avoid
student syndrome, because every individual feature has
a realistic estimate instead of one that has slack built
in, and it gives you a solid buffer should you still en
-
counter problems throughout the project.
Non-coding Tasks
A significant amount of time in a project is not spend
on coding, but on project management, testing, setting
up development environments etc. Yet, this is often
overlooked when creating estimates. When you create
an estimate for a project, try to also account for the
non-coding tasks. Estimating these parts gets better
over time, and you’ll get a feeling for how much time
you spend on them. The time needed for setting up an
environment is usually pretty much constant. The time
needed for project management tends to be a certain
percentage of the total project time, but depends on
several factors. Some customers and some projects may
require more project management time than others;
this is often related to the complexity of a project.
The Best Estimate Is Your Own Estimate
In bigger projects, the initial estimates are often done
by someone other than yourself. A good senior devel
-
oper with a lot of experience is able to create esti
-
mates that are accurate even when he’s not the person
actually writing the code. But even then, if you work
on a project that already has estimates, treat those
estimates as your budget, but still create your own
estimates beforehand. If your estimates deviate from
the original ones, talk to the person that created them
and see if maybe you misunderstood things, or maybe
that person overlooked some details that weren’t known
back then. Or maybe the both of you have different
solutions in mind, and talking about them may not only
lead to a more accurate estimate, but maybe even to a
better solution.
Conclusion
In this article, I’ve touched upon some aspects of
estimating, one of the most dreaded activities of a
software developer. I’ve given some background to why
estimation can be so hard and some guidelines that
may make it easier. The best advice I can give is to
continuously estimate and evaluate the estimates, be
-
cause that is the best way to improve them.
"
Doubling the numbers is
the worst thing you can
do to an estimate.
ivo janscH
is the CTO of Ibuildings, a PHP services company
based in Europe. He is the author of php|architect’s
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 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
11
COLUMN
Garbage Collection
The Basics
A PHP variable is stored in a container called a “zval”.
A zval container contains, besides the variable’s type
and value, two additional bits of information. The
first is called “is_ref” and is a boolean value indicat
-
ing whether or not the variable is part of a “reference
set”. With this bit, PHP’s engine knows how to differ
-
entiate between normal variables and references. Since
PHP allows user-land references, as created by the &
operator, a zval container also has an internal reference
counting mechanism to optimize memory usage. This
second piece of additional information, called “ref
-
count”, contains how many variable names—also called
symbols—point to this one zval container. All symbols
are stored in a symbol table, of which there is one per
scope. There is a scope for the main script (i.e., the
one requested through the browser), as well as one for
every function or method.
A zval container is created when a new variable is
created with a constant value, such as:
$a = "new string";
In this case, the new symbol name, “a”, is created in
the current scope, and a new variable container is cre
-
ated with type “string”, value “new string”. The “is_ref”
bit is by default set to “false” because no user-land
reference has been created. The “refcount” is set to “1”
as there is only one symbol that makes use of this vari
-
able container. Note that if “refcount” is “1”, “is_ref”
is always “false”. If you have Xdebug installed, you can
REQUIREMENTS
PHP:
5.3+
Other Software:

Xdebug:
http://xdebug.org
/
Useful/Related Links:

Note that Xdebug is not used in conjunction with
Zend Optimizer or other Zend extensions such as
DBG or APD.
PHP's Take on Variables
Derick Rethans
by
In this three part column, I will explain the merits of the new Garbage Collection
(also known as GC) mechanism that is part of PHP 5.3. Before we start with the
intricate details of PHP’s new GC engine, I will explain why it is actually needed.
This, combined with an introduction to how PHP deals with variables in general is
explained in this first part of the column. The second part will cover the solution and
some notes on the GC mechanism itself, and the third part covers some implications
of the GC mechanism, as well as some benchmarks. Now, on to the introduction.
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

12
|
April

2009

www.phparch.com
COLUMN
Garbage Collection
display this information by calling:
xdebug_debug_zval('a');
which displays:
a: (refcount=1, is_ref=0)='new string'
Assigning this variable to another variable name in
-
creases the refcount:
$a = "new string";
$b = $a;
xdebug_debug_zval( 'a' );
which displays:
a: (refcount=2, is_ref=0)='new string'
The refcount is “2” here, because the same variable
container is linked with both “a” and “b”. PHP is smart
enough not to copy the actual variable container when
it is not necessary. Variable containers get destroyed
when the “refcount” reaches zero. The “refcount” gets
decreased by one when any symbol linked to the vari
-
able container leaves the scope (e.g. when the function
ends) or when unset() is called on a symbol. The fol
-
lowing example shows this:
$a = "new string";
$c = $b = $a;
xdebug_debug_zval( 'a' );
unset( $b, $c );
xdebug_debug_zval( 'a' );
which displays:
a: (refcount=3, is_ref=0)='new string'
a: (refcount=1, is_ref=0)='new string'
If we now call “unset( $a );”, the variable container,
including the type and value, will be removed from
memory.
Compound Interest
Things get a tad more complex with compound types
such as arrays and objects. Instead of a scalar value,
arrays and objects store their properties in a symbol
table of their own. This means that the following ex
-
ample creates
three
zval containers:
$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
which displays (after formatting):
a: (refcount=1, is_ref=0)=array (
'meaning' => (refcount=1, is_ref=0)='life',
'number' => (refcount=1, is_ref=0)=42
)
Graphically, it looks like the picture in Figure 1.
The three zval containers are: “a”, “meaning”, and
“number”. Similar rules apply for increasing and de
-
creasing “refcounts”. Below, we add another element
to the array, and set its value to the contents of an
already existing element:
$a = array( 'meaning' => 'life', 'number' => 42 );
$a['life'] = $a['meaning'];
xdebug_debug_zval( 'a' );
which displays (after formatting):
a: (refcount=1, is_ref=0)=array (
'meaning' => (refcount=2, is_ref=0)='life',
'number' => (refcount=1, is_ref=0)=42,
'life' => (refcount=2, is_ref=0)='life'
)
Graphically, it looks like Figure 2.
From the above we see that both the old and new
array element now point to a zval container whose
“refcount” is “2”. Of course, there are now two zval
containers, but they are the same one. The xdebug_
debug_zval() function does not show this, but you
could see this by also displaying the memory pointer.
Removing an element from the array is like removing a
symbol from a scope. By doing so, the “refcount” of a
container that an array element points to is decreased.
Again, when the “refcount” reaches zero, the variable
container is removed from memory. Again, an example
to show this:
$a = array( 'meaning' => 'life', 'number' => 42 );
$a['life'] = $a['meaning'];
unset( $a['meaning'], $a['number'] );
xdebug_debug_zval( 'a' );
FIGURE 1
FIGURE 2
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
13
COLUMN
Garbage Collection
which displays (after formatting)
a: (refcount=1, is_ref=0)=array (
'life' => (refcount=1, is_ref=0)='life'
)
Now, things get interesting if we add the array itself
as an element of the array, which we do in the next
example, in which I also snuck in a reference operator,
since otherwise PHP would create a copy:
$a = array( 'one' );
$a[] =& $a;
xdebug_debug_zval( 'a' );
which displays (after formatting):
a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...
)
See Figure 3 for what this looks like graphically.
You can see that the array variable (“a”) as well
as the second element (“1”) now point to a variable
container that has a “refcount” of “2”. The “...” in the
display above shows that there is recursion involved,
which, of course, in this case means that the “...”
points back to the original array.
Just like before, unsetting a variable removes the
symbol, and the reference count of the variable con
-
tainer it points to is decreased by one. So, if we unset
variable $a after running the above code, the reference
count of the variable container that $a and element “1”
point to gets decreased by one, from “2” to “1”. This
can be represented as:
(refcount=1, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=1, is_ref=1)=...
)
Graphically, it looks like Figure 4.
The Problem
Although there is no longer a symbol in any scope
pointing to this structure, it cannot be cleaned up
because the array element “1” still points to this same
array. Because there is no external symbol pointing to
it, there is no way for a user to clean up this structure;
thus you get a memory leak. Fortunately, PHP will clean
up this data structure at the end of the request, but
before then, this is taking up valuable space in memo
-
ry. This situation happens often if you’re implementing
parsing algorithms or other things where you have a
child point back at a “parent” element. The same situ
-
ation can also happen with objects of course, where it
actually is more likely to occur, as objects are always
implicitly used by reference.
This might not be a problem if this only hap
-
pens once or twice, but if there are thousands, or
even millions, of these memory losses, this obviously
starts being a problem. This is especially problematic
in long running scripts, such as daemons where the
request basically never ends, or in large sets of unit
tests. The latter caused problems for us while running
the unit tests for the Template component of the eZ
Components library. In some cases, it would require
over 2 GB of memory, which our test server didn’t quite
have.
With that, we conclude this introduction. For more
information on how PHP deals with variables, I can
point you to the June 2005 issue of php|architect. That
article is also available on-line as a PDF here:
http://
derickrethans.nl/files/phparch-php-variables-
article.pd
f
. In the next installment, we’re going to
discuss the solution to the memory leak problem with
circular references.
FIGURE 3
FIGURE 4
Derick retHans
has contributed in a number of ways
to the PHP project, including the mcrypt, date and input-
filter extensions, bug fixes, additions and leading the QA
team. He’s a frequent lecturer at conferences, the author of
php|architect’s Guide to Date/Time Handling, and the co-
author of PHP 5 Power Programming. Derick now works
as project leader for the eZ components project for eZ
systems A.S. In his spare time he likes to travel, hike, ski
and practice photography. You can reach him at
derick@
derickrethans.n
l
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

COLUMN
From the Cloud
I
f you’ve ever used Twitter, Delicious, or any other
service that has an API requiring your authentica
-
tion credentials, you’ve likely encountered a situ
-
ation in which a third-party website has asked for your
username and password in order to gain access to your
account through that API. These third parties often
make claims like, “Don’t worry! We’re not evil, and we
won’t steal your password.” These claims make me feel
safe. About as safe as jumping from a plane without a
parachute.
Luckily, representatives from organizations such as
Twitter, Flickr, Six Apart, Magnolia, Jaiku, Google, and
others have developed an open protocol to solve just
this problem. These organizations know of this problem
from first-hand experience, since they all provide APIs
to their users’ data, and, since these APIs require au
-
thentication, they all need a method allowing the user
to authorize third-party access to their data without
giving away their credentials to the third party. Enter
the OAuth protocol.
According to its specification, OAuth is an open
protocol that “enables websites or applications
(Consumers) to access Protected Resources from a web
service (Service Provider) via an API, without requir
-
ing Users to disclose their Service Provider credentials
to the Consumers.” You may implement OAuth as either
a Consumer or a Provider, and there are tools that can
help with the implementation. I’ll focus on the request
process from the point of view of a Consumer, showing
all of the requests and responses along the way in an
effort to demystify the process.
The OAuth Process
At first glance, OAuth is an extremely complex process.
One quick look at Figure 1 is all you need to see the
complexity and the numerous requests and responses
involved in authenticating a user. However, the com
-
plete OAuth process can be summed up in four simple
steps:
Ever been asked for your username and
password by a website that wants to
access your data from another service?
By all means, don’t give it to them! This
month’s
From the Cloud
takes a look
under the hood of OAuth to show how its
request process protects users from ever
having to give away their credentials
again.
OAuth

Under the Hood
Ben Ramsey
by
14
|
April

2009


www.phparch.com
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
15
COLUMN
From the Cloud
• The Consumer requests a Request Token from the
Provider (Step A)
• The user authenticates with the Provider (Step B)
• The Consumer requests an Access Token from the
Provider (Step C)
• The Consumer retrieves the user’s protected data
from the Provider (Step D)
Before we get started, there are a few terms to define.
The
Provider
is an application that allows access to its
API through OAuth. The
user
is a person who has an
account with the Provider. The
Consumer
is a website
or application using OAuth to access the Provider on
behalf of the user. The
Request Token
is used by the
Consumer to obtain authorization from the user. It
is exchanged for an Access Token. The
Access Token

is then used by the Consumer to gain access to the
user’s protected data on behalf of the user, rather than
directly using the user’s username and password. The
benefit is that the user never needs to give his or her
username or password to the Consumer.
Getting the Request Token
The very first step in the OAuth process is initiated by
the user. The user is the one who wants to use an ap
-
plication to access their data that exists on a third-par
-
ty service. Reasons for why users may want to do this
abound. Perhaps the application aggregates user con
-
tent from various services, or maybe it mashes-up user
data in a particular way, providing a unique visualiza
-
tion of that data. Whatever service is provided, the user
needs to grant the application access to their data, and
that’s where OAuth comes in.
To discuss this process in detail, we’ll envision a
fictional Consumer and Provider. The example that
the OAuth documentation provides is that of a photo-
sharing service as the Provider. So, following their
example, suppose our application needs to request a
user’s photos from a third-party service such as Flickr or
SmugMug. For the sake of example, we’ll call this third-
party photo sharing service FooPhoto (the Provider), a
service for sharing photos, and our service MyFooLife
(the Consumer), a service that aggregates users’ life
stream data from various third-party services, including
FooPhoto.
The first request made is that from the user’s cli
-
ent/browser to our service, identified here as
myfoolife.example.com
. Figure 1 represents this
request as Step 1.
GET /mypictures HTTP/1.1
Host: myfoolife.example.com
When a user makes this request of our service,
MyFooLife, to see their photos from FooPhoto, we must
send a request in the background to FooPhoto to get
a Request Token. The Request Token is the first part
of this process and we’ll use it to obtain authorization
from the user so that we may access their protected
data at FooPhoto. Listing 1 shows the
POST
request
we’ll make as the Consumer to the Provider to obtain
the Request Token (see Step 2 in Figure 1).
If all goes well and our OAuth parameters and sig
-
nature check out, FooPhoto will return a response
including the
oauth_token
and
oauth_token_secret

parameters. This response is Step 3 of Figure 1.
HTTP/1.1 200 OK
Server: FooPhoto
Content-Type: text/plain; charset=UTF-8
oauth_token=4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5&
oauth_token_secret=fs5sWCIWPmJKmhgNBpguFJ8C
User Authentication
Now that FooPhoto, has given us a Request Token—the
oauth_token
returned in the previous response—we
1.
POST /oauth/getRequestToken HTTP/
1.1
2.
Host: foophoto.example.com
3.
Authorization: OAuth realm=
"http://foophoto.example.com/"
,
4.
oauth_consumer_key=
"myfoolife.example.com"
,
5.
oauth_nonce=
"37c0712e605ff858f26211323adddcb3"
,
6.
oauth_signature_method=
"RSA-SHA1"
,
7.
oauth_timestamp=
"1234822009"
,
8.
oauth_version=
"1.0"
,
9.
oauth_signature=
"IgJbu19VwYBXyRAautunRRKfCfc2pD%2B3..."
10.
Content-Length:
0


LISTING 1
"
The user wants to
access their data that
exists on a third-party
service.
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

16
|
April

2009

www.phparch.com
COLUMN
From the Cloud
may now redirect the user to FooPhoto so that they
can authenticate with the service and grant MyFooLife
access to their protected photos. We do this by send
-
ing a redirect response to the user, redirecting them
to
foophoto.example.org
and including the oauth_
token in the request. This response is represented by
Step 4 in Figure 1.
HTTP/1.x 302 Moved Temporarily
Server: MyFooLife
Location: https://foophoto.example.org/oauth/
authorizeToken?
oauth_token=4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5
&oauth_callback=
http%3A%2F%2Fmyfoolife.example.com%2Fmypictures
Now the user is no longer on our application. They are
viewing a page on the FooPhoto website asking them
to either log in or, if they already have an active ses
-
sion, grant MyFooLife access to their protected data.
Once this process is complete and the user has either
granted or denied access, FooPhoto redirects the user
back to MyFooLife using the
oauth_callback
param
-
eter presented in the previous request. The Location
contains the Request Token authorized or denied by
the user. Step 5 in Figure 1 shows when this response
occurs.
HTTP/1.x 302 Moved Temporarily
Server: FooPhoto
Location: http://myfoolife.example.org/mypictures?
oauth_token=4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5
Requesting the Access Token
By now, the user has granted permission to MyFooLife
to access their photos on FooPhoto. Using the Location
header given in the previous response, the user’s
browser now sends a request to MyFooLife, includ
-
ing the authorized Request Token. MyFooLife may now
begin the process of obtaining the Access Token, which
is what we will need to get the user’s protected data
from FooPhoto. Step 6 represents this request.
GET /mypictures?oauth_token=
4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5 HTTP/1.1
Host: myfoolife.example.com
Now, the magic occurs. This is the moment we’ve
been waiting for. The next few series of requests and
responses will provide our service with access to the
user’s photos.
In Listing 2 (and Step 7 of Figure 1), MyFooLife
sends a
POST
request to FooPhoto to obtain an Access
Token. As with the request to retrieve a Request Token,
we include an
Authorization
header containing
OAuth parameters verifying the origin of the request
and including the Request Token, which we exchange
for an Access Token. The Provider will verify the au
-
thenticity of the request and check whether the user
has granted access to this Request Token. If all checks
out, then the Provider returns a response containing
the Access Token (Step 8).
1.
POST /oauth/getAccessToken HTTP/
1.1
2.
Host: foophoto.example.com
3.
Authorization: OAuth realm=
"http://foophoto.example.com/"
,
4.
oauth_consumer_key=
"myfoolife.example.com"
,
5.
oauth_nonce=
"91a851a9b2710d8a79d2a713a74c25a2"
,
6.
oauth_signature_method=
"RSA-SHA1"
,
7.
oauth_timestamp=
"1234822105"
,
8.
oauth_token=
"4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5"
,
9.
oauth_version=
"1.0"
,
10.
oauth_signature=
"CVxQXHlgS7HaGHZFg68Kdjb8mYgY0fHBg..."
11.
Content-Length:
0


LISTING 2
For More Information
OAuth website:

http://oauth.net
/
OAuth 1.0 protocol spec (Dec 2007):

http://oauth.net/core/1.0
/
OAuth: HTTP Authorization Delegation Protocol (Sep 2008): The first Internet-Draft for the OAuth IETF working

group:
http://tools.ietf.org/html/draft-hammer-oauth-00
/
OAuth Implementers Google Group:

http://groups.google.com/group/oauth
/
OAuth PECL extension:

http://pecl.php.net/package/oauth
/
OAuth library in PHP:

http://oauth.googlecode.co
m
OAuth component for CakePHP:

http://cakebaker.42dh.com/downloads/oauth-component-for-cakephp
/
Zend_Oauth for the Zend Framework: At the time of this writing, this component is in the Zend Framework

incubator:
http://framework.zend.com/svn/framework/standard/incubator
/
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
17
COLUMN
From the Cloud
FIGURE 1
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

18
|
April

2009

www.phparch.com
COLUMN
From the Cloud
HTTP/1.1 200 OK
Server: FooPhoto
Content-Type: text/plain; charset=UTF-8
oauth_token=1%2FEthgm-YklKKxp5IrWNbJ4A&
oauth_token_secret=cWAo6%2Bhe4jduiZUEhaXcBhip
Accessing the User's Data
MyFooLife now has the proper credentials to access the
user’s photos. First, we got a Request Token, then the
user granted access to their photos for that Request
Token, and now we’ve exchanged the Request Token for
an Access Token. It’s time to get the user’s photos and
show them to the user.
While the previous requests will differ from service
to service mainly in where the OAuth parameters are
placed in the request—the
Authorization
header, the
request body, or the query string—the next requests
will depend on the service’s API, so they may be very
different from what you see here, but the concept is
still the same: we must send the Access Token along
with all of the other OAuth parameters in order to
authenticate our service with the Provider and re
-
trieve the user’s data. Listing 3 shows an example of a
request to get the user’s data from FooPhoto (Step 9).
The
Authorization
header will look familiar, but this
time, the
oauth_token
parameter contains the Access
Token.
FooPhoto checks the authorization credentials and
the Access Token and decides that MyFooLife may ac
-
cess the requested user’s data, and sends it back in the
format requested by the Consumer and depending on
the API of the service (Step 10).
HTTP/1.1 200 OK
Server: FooPhoto
Content-Type: application/xml; charset=UTF-8
{User's picture data}
MyFooLife now has the user’s photos and can send them
back to the user, and that’s exactly what we do in Step
11.
HTTP/1.1 200 OK
Server: MyFooLife
Content-type: text/html; charset=UTF-8
Here are your pictures...
A View from the Cloud
So, that’s the OAuth request process in eleven simple
steps. It is my hope that I’ve demystified the process,
and that, while there are many different steps along
the request cycle to gain access to a user’s protected
data, they are necessary to provide security and shield
the user from giving away their username and password
to third-party websites.
OAuth is still new, having been finalized as OAuth
1.0 in December 2007, and people are just now begin
-
ning to talk about it and advocate its use. In fact, at
the time of this writing, an OAuth working group is
being formed with the Internet Engineering Task Force
(IETF) for the purpose of producing one or more docu
-
ments for consideration as an IETF proposed standard,
otherwise known as an RFC. I’m certain we’ll begin to
see more and more OAuth implementations as this year
progresses, as well we should. Asking users to enter
their username and password on a third-party website
to access their protected data on another service is a
horrendous practice that should be avoided at all costs.
I hope that OAuth and similar authentication mecha
-
nisms will put an end to this practice once and for all.
To learn more about the OAuth protocol, including
details on all the OAuth parameters and how to sign
the requests, read the full protocol specification at
http://oauth.net/core/1.0
/
.
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.
co
m
.
Special thanks to Andrew Jones for designing the OAuth
web redirection flow diagram for Figure 1. Andrew Jones
is a designer, cartoonist, and web developer in Atlanta,
Georgia. His freelance company is FireBox Studios
(
http://fireboxstudios.co
m
), and he blogs at
http://
atlantajones.co
m
. He, too, loves zombie movies, comics,
and thinks “Weird Al” Yankovic is a god.
1.
GET /user/pictures HTTP/
1.1
2.
Host: foophoto.example.com
3.
Authorization: OAuth realm=
"http://foophoto.example.com/"
,
4.
oauth_consumer_key=
"myfoolife.example.com"
,
5.
oauth_nonce=
"3f26a264e990a358612a0a4187be215f"
,
6.
oauth_signature_method=
"RSA-SHA1"
,
7.
oauth_timestamp=
"1234822717"
,
8.
oauth_token=
"1%2FEthgm-YklKKxp5IrWNbJ4A"
,
9.
oauth_version=
"1.0"
,
10.
oauth_signature=
"YSRH5fbfmWEhLFMGAVYwOJwhWy8g..."


LISTING 3
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

+
ActivePerl Pro Studio
+ =
Komodo IDE 5.1Perl Dev Kit 8.0
Everything you need to develop, debug and deploy professional Perl applications in a single, easy-to-budget subscription.
All the Languages
Dynamic language expertise for Perl, PHP, Python, Ruby, and Tcl, plus JavaScript,
CSS, HTML, and XML, and template languages like RHTML, Template-Toolkit,
HTML-Smarty, and Django.
All the Tools
Award-winning feature set includes standard editor functionality, plus killer
debugging and more. And it’s extensible, so you can hack away!
All the Platforms
Windows? Mac? Linux? Yes! Yes! Yes!
User-based licensing makes it easy.
All the Team
Source code control integration, a project manager, and multi-user support assist
in team development. Rx Toolkit, and get instant feedback from syntax checking
and syntax coloring—Komodo IDE is jam-packed with intelligent tools to speed
development.
All the Support
You can rely on high-quality support and an active user community for help
when you need it.
Komodo IDE 5.1
Share the joy (and the workload) with
Komodo IDE 5.1’s new and improved
features for team development.
ActiveState and Komodo are registered trademarks of ActiveState Software Inc in the United States and/or other countries.
All other marks are property of their respective owners. © 2009 ActiveState Software Inc. All rights reserved.
komodo_5-1_activestate_fullpg_04-09.indd 1
3/16/2009 3:01:36 PM
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

Using View States to Communicate with
the User
Our ActionScript refers to a new view state called
processing
within the
UploadForm
component. Just
as in the
Docs.mxml
file, you’ll want to place the code
just below the root tag, which is
<mx:Canvas>
in the
case of Listing 1.
This view state takes care of two important UI is
-
sues. Firstly, the user needs to know that work is being
performed and that the form should not be edited until
the work is complete. Secondly, the user should be
informed of the status of the current task. The former
is addressed by placing a semi-transparent canvas over
the whole form, which effectively blocks the user from
manipulating the form beneath it. The latter concern is
addressed by adding a status label, the text of which
changes as progress is made.
Save
UploadForm.mxml
. To actually show the up
-
load form to the user, add an ActionScript function
to
Docs.mxml
. You specify the name of the function,
showUploadForm()
, in the
loggedIn
view state of
the application in the
Upload a Document
button’s click
handler. Here’s the ActionScript code destined for your
<mx:Script>
block:
20
|
April

2009

www.phparch.com
Rich Internet
Applications with Flex
and PHP
FEATURE
Related URLs
PHP:
5.1.4 (for Zend Framework)
Other Software:

Zend 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.co
m
ActionScript 3 CoreLib:


http://code.google.com/p/as3corelib
/
Author’s Development Blog:


http://flexandair.co
m
PART 3
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

FEATURE
private function showUploadForm():void {
var form:UploadForm = new UploadForm();
form.x = this.width / 2 - form.width / 2;
form.y = 50;
addChild(form);
form.name = 'uploadform';
form.cancelBtn.addEventListener(
MouseEvent.CLICK, removeForm);
form.userid = user.id;
}
First, this function creates a new
UploadForm
object
in the variable form. The form’s x position is set to the
center of the application with some basic math. The
y position is set to a static 50 pixels, just to keep it
from being right up against the browser’s toolbar. The
addChild()
method is called to add the upload form
to the stage. You can use the name property elsewhere
in the application to refer to the form.
The ability to cancel and remove the upload form
from the screen is provided by adding a click event
listener to the form’s
Cancel
button, which has the ID
cancelBtn
. Finally, the form is informed of the active
user’s ID by the parent application. Next, create the
removeForm()
function so that the user can remove
the document upload form:
private function removeForm(
event:MouseEvent):void {
removeChild(event.target.parent);
}
The
removeForm()
function accepts a
MouseEvent
,
the target of which is the
Cancel
button on the upload
form. The
removeChild()
method is then called and
passed the parameter of
event.target.parent
. The
parent of the target (the
Cancel
button) is the upload
form. So, when the user clicks
Cancel
, the form disap
-
pears rather unceremoniously. Before moving on, be
sure to add an import statement below the others so
that your application can find the
UploadForm
compo
-
nent:
import com.flexandair.UploadForm;
1.
<mx:states>
2.
<mx:State name=
"processing"
>
3.
<mx:AddChild position=
"lastChild"
>
4.
<mx:Canvas x=
"-3"
y=
"-3"
5.
width=
"400"
height=
"300"
6.
backgroundColor=
"#7C7B7B"
7.
backgroundAlpha=
"0.75"
>
8.
<mx:Label id=
"statusLabel"
9.
x=
"94"
y=
"123"
10.
text=
"Uploading, please wait."
11.
fontSize=
"16"
color=
"#FEFFFF"
/>
12.
</mx:Canvas>
13.
</mx:AddChild>
14.
</mx:State>
15.
</mx:states>

LISTING 1
Richard Bates
by
In last month’s issue, we learned about the benefits of Flex
and started setting up our application. When we left off,
we were working on uploading the file to the server and
saving it. Now, we will continue adding information to
keep the user updated about the script’s actions.
www.phparch.com


April

2009

|
21
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

22
|
April

2009

www.phparch.com
Rich Internet Applications with Flex and PHP: Part 3
FEATURE
Creating a Custom itemRenderer in
MXML
If you direct your attention to the
TileList
you cre
-
ated as part of the
loggedIn
view state, you’ll notice
that a property called
itemRenderer
is specified.
The value is
com.flexandair.DocumentDetailTile
.
This is a custom MXML component you’ll use to rep
-
resent stored documents to a user. Each stored docu
-
ment will be represented with a tile in the
TileList
,
and the tiles themselves will be instances of the
DocumentDetailTile
.
You will create this custom component much as you
did the
UploadForm
: In the left pane of Flex Builder,
right-click the
flexandair
folder, then click
New >
MXML Component
. In the dialog that appears, type
DocumentDetailTile
as the name, select
Canvas
in the
Based On
field, then set the dimensions to 384 pixels
wide by 174 pixels high. Click
Finish
, and your new
component will be generated and opened in the editor
pane.
The
DocumentDetailTile
component shows the
user some relevant details about the document and
allows the user to download the file. There is also an
SWF icon that measures 125 by 150 pixels. You can
use an image or images of your own, but you should
be aware that the code presented here expects to find
the icon in the path
/com/flexandair/assets
, and
the file name is expected to be the document type fol
-
lowed by
Icon.swf
. For example, if the document is a
Microsoft Office Word document, the icon file should be
located at
/com/flexandair/assets/docIcon.swf
.
Now, onto the code. The file should open with the
standard XML tag and an opening
<mx:Canvas>
tag.
Within the opening canvas tag, after the auto-generat
-
ed properties, add three more properties:
<mx:Canvas
backgroundAlpha="0"
horizontalScrollPolicy="off"
verticalScrollPolicy="off">
Adding these properties ensures that no scrollbars oc
-
cupy valuable component space. Next, add another
<mx:Canvas>
opening tag with similar attributes:
<mx:Canvas styleName="tileLabel"
width="380" height="170"
backgroundAlpha="0.75"
horizontalScrollPolicy="off"
verticalScrollPolicy="off"
borderStyle="solid" borderColor="#000000"
borderThickness="4" cornerRadius="4"
backgroundColor="#D8D8D8" alpha="1.0"
x="2" y="2">
Adding a border makes the boundaries of each item
more apparent, and lowering the background’s alpha to
0.75 (on a scale of 0-1) produces a clearer mouse-over
effect. The reason for placing this canvas within the
main canvas is simply to provide a means of padding
each item when it’s assembled into the TileList compo
-
nent. Under this sub-canvas, create these MXML compo
-
nents, and close the canvas tag as shown in Listing 2.
Notice several references to an object called
data
.
When using a custom
itemRenderer
like this one, you
refer to the properties of the particular object you’re
representing using the data object. In this case,
data

refers to the document represented by this tile in the
TileList
. Be sure to note the image’s
source
proper
-
ty; as stated earlier, this path should point to a folder
containing your appropriately named icons. Finally, cre
-
ate the
download()
function that the
Download
button
created above calls. Add a script block right after the
sub-canvas’ closing tag as shown in Listing 3.
The first thing this script block does is im
-
port the custom
DocumentVO
object. Then, a new
FileReference
called
fileToDownload
is instantiated.
1.
<mx:Script>
2.
<!
[
CDATA
[
3.
import com.flexandair.DocumentVO;
4.
private
var
fileToDownload:FileReference
5.
=
new
FileReference
()
;
6.

7.
private
function
download
()
:void
{
8.

var
doc:DocumentVO = data
as
DocumentVO;
9.

var
request:URLRequest =
new
URLRequest
(
10.

'http://localhost/docs/uploadedFiles/'
11.
+ doc.url
)
;
12.

var
pattern:RegExp = /s/gi;
13.

var
cleanName:String
14.
= doc.name.replace
(
pattern,
''
)
;
15.
fileToDownload.download
(
request,
16.
cleanName +
'.'
+ doc.type
)
;
17.
}
18.
]]
>
19.
</mx:Script>

LISTING 3
1.
<mx:Image id=
"documentIcon"
x=
"10"
y=
"6"
2.
width=
"125"
height=
"150"
3.
source=
"{'assets/'+data.type+'Icon.swf'}"
/>
4.
<mx:Label x=
"143"
y=
"10"
text=
"Name:"
/>
5.
<mx:Label x=
"143"
y=
"36"
text=
"Description:"
/>
6.
<mx:TextArea x=
"143"
y=
"54"
7.
width=
"227"
height=
"70"
8.

wordWrap
=
"true"
selectable=
"false"
9.
textAlign=
"left"
editable=
"false"
10.
borderStyle=
"none"
text=
"{data.description}"
11.
id=
"descriptionBox"
backgroundAlpha=
"0.0"
/>
12.
<mx:Label x=
"183"
y=
"10"
text=
"{data.name}"
13.
id=
"nameLabel"
/>
14.
<mx:Button x=
"277"
y=
"134"
label=
"Download"
15.
click=
"download()"
/>
16.
</mx:Canvas>

LISTING 2
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
23
Rich Internet Applications with Flex and PHP: Part 3
FEATURE
Be sure to declare this variable here, outside of
download()
. If you don’t, the download won’t be
saved to the user’s computer. Next is the
download()

function. You know that the source data for this
itemRenderer
will be a
DocumentVO
, so a local
doc

variable of type
DocumentVO
is created from the source
data.
Next, a
URLRequest
is assembled containing the URL
of the document on the server. The “friendly” name of
the document is modified to remove any spaces, then
stored as
cleanName
. The
download()
method of
the
’fileToDownload

FileReference
is then called.
The first argument is
URLRequest
; the second is the
save name shown by default in the user’s
Save
dia
-
log. In this case, it is the friendly name minus spaces,
plus a period and the document’s extension. Save
DocumentDetailTile.mxml
.
To tie everything together, you must make a cou
-
ple of additions to the main
Docs.mxml
file. In the
<mx:Script>
block, add this import statement below
the others:
import com.flexandair.DocumentDetailTile;
And below that, declare a new variable to hold the
user’s documents in an
ArrayCollection
:
[Bindable] public var myDocs:ArrayCollection;
Next, you need some functions to interact with
the
roDocumentService
so that you can send
requests and handle the results. First, create
onRetrieveDocumentsResult()
:
private function onRetrieveDocumentsResult(
event:ResultEvent):void {
myDocs = new ArrayCollection(
ArrayUtil.toArray(event.result));
tilelist1.dataProvider = myDocs;
}
onRetrieveDocumentsResult()
accepts the
ResultEvent
from the
roDocumentService

method
retrieveDocuments()
. Then, the re
-
sult is converted to an
ArrayCollection
suitable
for use in the
TileList
. Finally,
myDocs
is set as
the data provider for the
TileList
. Next, add the
onCreateDocumentResult()
function to handle
the
ResultEvent
of the
createDocument()
remote
method:
private function onCreateDocumentResult(
event:ResultEvent):void {
removeChild(getChildByName('uploadform'));
roDocumentService.retrieveDocuments(user.id);
}
This function first removes the
Upload Document
form.
Then, the
retrieveDocuments()
remote method is
called to refresh
myDocs
, updating the
TileList
to
reflect the newly added document.
To test the application, you’ll need to un-comment
the
roDocumentService
remote object. To do so,
select the commented code, right-click it, then click
Source > Toggle Block Comment
. Save your files, and run
the application.
When you log in, you’ll be presented with an empty
documents list. Click
Upload a Document
and com
-
plete the form. After you save the document, the list
refreshes and displays your document. Figure 1 shows
the completed application with a populated
TileList
.
Congratulations – you just built an RIA with Flex, PHP,
and Zend_Amf!
Porting the Application from Flex to AIR
Deploying applications with AIR can add the function
-
ality and convenience your users are accustomed to on
the desktop, such as drag-and-drop functionality and
native operating system windows. As the developer,
you’ll gain access to the file system and an expanded
security sandbox with minimal code revision.
Creating a desktop application that runs on AIR is a
relatively painless process if you’re starting out with
a Flex application. AIR projects built with Flex Builder
require a few auto-generated files, so the best approach
is typically to simply create a new AIR project and copy
the code over, adjusting it as needed.
Begin in Flex Builder by clicking
New > Flex Project
.
For the project name, type
DocsAIR
, and be sure to
select the application type
Desktop Application
. Click
Finish
, and Flex Builder generates the necessary project
files and structure. You should then be presented with
FIGURE 1
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

24
|
April

2009

www.phparch.com
Rich Internet Applications with Flex and PHP: Part 3
FEATURE
the
DocsAIR.mxml
file in the editor pane.
The first code you’ll copy from
Docs.mxml
to
DocsAIR.mxml
will be the at
-
tributes from the opening
<mx:Application>

tag. Select all the attributes after the namespace
(
xmlns:mx=“http://www.adobe.com/2006/mxml”
),
copy them, and paste them inside the
DocsAIR
open
-
ing
<mx:WindowedApplication>
tag. The result
should be:
<mx:WindowedApplication
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
backgroundGradientAlphas="[1.0, 1.0]"
backgroundGradientColors="[#000000, #2E2E2E]">
Back in the Flex version, select all the code be
-
tween the
<mx:Application>
tags. Copy it, then
paste it into
DocsAIR.mxml
beneath the opening
<mx:WindowedApplication>
tag. Use the file browser
in the left pane to locate the
com
folder under the
src
folder in the
Docs
Flex project. Right-click the file,
click
Copy
, and then paste it into the
src
folder of the
DocsAIR project. When the folder has been copied, save
the
DocsAIR
application and check the bottom pane of
Flex Builder for any errors.
If you are using the icons as we out
-
lined above, you’ll need to change a line in
DocumentDetailTile.mxml
. Open the file, and locate
the image control’s source property. Change it to read
source=“{’com/flexandair/assets/’

+ data.type

+

’Icon.swf’}”
, then save and run the AIR applica
-
tion; it should function just as the Flex version. If you
do get errors, ensure that all your MXML tags are prop
-
erly formatted and that all the files and folders under
-
neath the
com
folder were copied successfully to the
DocsAIR/src folder.
Adding Drag-and-Drop
One convenience made possible by porting your appli
-
cation to AIR is the ability to add drag-and-drop func
-
tionality to your application. The goal, in this case, will
be to allow the user to drag a supported document onto
the documents
TileList
in DocsAIR. The user should
then get the upload form with the dropped file already
selected and can then simply add a name and descrip
-
tion, then save.
Begin by creating a new ActionScript class. By using
a separate file for the drag-and-drop code, you’ll keep
the main application file simpler, and you’ll also be
able to reuse the class in other applications. In the
left pane of Flex Builder, right-click the
com/flexan
-
dair
folder, then click
New > ActionScript Class
. Name
the class
DragAndDrop
, and click
Finish
. The new file
appears in the editor pane. Delete the contents of the
file, and begin the code with these
import
statements:
import com.flexandair.UploadForm;
import flash.desktop.ClipboardFormats;
import flash.desktop.NativeDragManager;
import flash.events.NativeDragEvent;
import flash.filesystem.File;
import flash.net.FileReference;
These classes are necessary for drag-and-drop function
-
ality and to populate a new form with the details of the
dropped file. Next, create an
onLoggedIn()
function
to add the event listeners needed to detect a drag-and-
drop operation:
private function onLoggedIn():void
{
addEventListener(
NativeDragEvent.NATIVE_DRAG_ENTER,
onDragIn);
addEventListener(
NativeDragEvent.NATIVE_DRAG_DROP,
onDragDrop);
}
Now, when the user drops a file onto the application
window, the application listens and takes action. First,
you need the
onDragIn()
function, shown in Listing 4.
This function accepts the drag action after check
-
ing to make sure the user is dragging only one file.
Next, create the
onDragDrop()
function to handle the
dropped file. This function is shown in Listing 5.
This function gets the dropped file as a file ob
-
ject. Then, because the upload form expects a
FileReference
object, a
FileReference
is cre
-
ated from the
Fil
e
object. Because the
Fil
e

class is a descendant of the
FileReference
class,
you can treat it as a
FileReference
. Then, the
1.
private
function
onDragIn
(
e:NativeDragEvent
)
:void
2.
{
3.

// check and see if files are being dragged in
4.

if

(
e.clipboard.hasFormat
(
5.
ClipboardFormats.FILE_LIST_FORMAT
))

{
6.

// get the array of files
7.

var
files:
Array
=
8.
e.clipboard.getData
(
9.
ClipboardFormats.FILE_LIST_FORMAT
)
10.

as

Array
;
11.

// just one file, please!
12.

if

(
files.length ==
1)

{
13.

// accept the drag action
14.
NativeDragManager.acceptDragDrop
(
this
)
;
15.

}
16.

}
17.
}


LISTING 4
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
25
Rich Internet Applications with Flex and PHP: Part 3
FEATURE
showUploadFormPopulated()
function is called
and the
FileReference
is passed to it. Create the
showUploadFormPopulated()
function as shown in
Listing 6.
This function is similar to the
showUploadForm()

function in the main
DocsAIR.mxml
file, except that
it expects a
FileReference
to be passed in and it
populates the upload form with the file’s information.
To make this function work with the
UploadForm
com
-
ponent, make a small change in
UploadForm.mxml
.
Locate the
_refUploadFile
variable, and change the
private
keyword to
public
. Doing so allows you to
set the value from the
DragAndDrop
class.
Next, go back into the main
DocsAIR.mxml
file,
and find the
<mx:State>
tag for the
loggedIn
state.
Change the
enterState
attribute by adding a call to
the
onLoggedIn()
function. The result should be:
enterState =
"{roDocumentService.retrieveDocuments(user.id);
onLoggedIn();}"
Finally, import the
DragAndDrop.as
file into
DocsAIR.mxml
. Just above the existing
<mx:Script>

block, create another
<mx:Script>
tag like this one:
<mx:Script source="com/flexandair/DragAndDrop.as"/>
This line causes the application to treat the code
within
DragAndDrop.as
as if it were in the main script
block of
DocsAIR.mxml
. Save and run the application.
If you drag a file onto the application window before
logging in, nothing happens. After logging in, you’ll
be able to drag files onto the application and receive
an upload form with the dragged file already selected.
Remember that this example has no file type check
-
ing, so there will not be a file type filter for dragged-in
files.
What Now?
Now that you have a working application, you might
want to fill out the rest of the functionality by adding
the other Create, Retrieve, Update, and Delete (CRUD)
functions in your PHP service classes.
In terms of expanding the application’s feature set,
your options are virtually unlimited. Consider these
possible features:
- If you’re using a dedicated server or virtual private
server (VPS), you can install OpenOffice.org to convert
your documents to PDF.

- If your documents are PDFs and your host has
ImageMagick installed, you can generate thumbnails for
each uploaded document rather than using stock icons.

- If you use an electronic fax service, see if your pro
-
vider offers email-to-fax capability. If so, you can write
a PHP mail function to send your documents to the fax
provider and on to a fax recipient.

- You can use the pdf2swf program from the open
source SWFTools package to convert PDF documents to
SWFs and display them to your users within the Flex
application.

- Move the upload directory below the Web root and
use a script to return them, rather than exposing them
to any passer-by on the Web.

1.
private
function
onDragDrop
(
e:NativeDragEvent
)
:void
2.
{
3.

// get the array of files being dragged in
4.

var
filesArray:
Array
=
5.
e.clipboard.getData
(
6.
ClipboardFormats.FILE_LIST_FORMAT
)
7.

as

Array
;
8.

// grab the 1st file only
9.

var
f:
File
=
File
(
filesArray
[0])
;
10.

var
ref:FileReference = f
as
FileReference;
11.
showUploadFormPopulated
(
ref
)
;
12.
}


LISTING 5
1.
private
function
showUploadFormPopulated
(
2.
ref:FileReference
3.
)
:void
{
4.

var
form:UploadForm =
new
UploadForm
()
;
5.
form.x = this.width /
2
- form.width /
2
;
6.
form.y =
50
;
7.
addChild
(
form
)
;
8.
form.name =
'uploadform'
;
9.
form._refUploadFile = ref;
10.
form.fileTI.text = ref.name;
11.
form.cancelBtn.addEventListener
(
12.
MouseEvent.CLICK,
13.
removeForm
14.

)
;
15.
form.userid = user.id;
16.
}


LISTING 6
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 48409 - Primoz Klemensek (klemensek@gmail.com)

26
|
April

2009

www.phparch.com
Black Box
Penetration
Tests
Develop insight
into the tools and
methodology of
those attacking PHP
Applications
Ben Sgro
Generally, a penetration or pen tester is
not given access to source code. In the
real world, attackers never have access
to source code or intimate knowledge of
the application they are attacking. In
this article, we will examine some of the
typical vectors an attacker would employ
and gain insight to the methodology,
processes and tools used when conducting
a black box penetration test. The goal is
to expand the knowledge of developers
while gaining insight into an attacker’s
mind.
FEATURE
REQUIREMENTS
Other Software:

BurpSuite Ð

http://portswigger.ne
t
DirBuster -

http://www.owasp.org/index.php/
Category:OWASP_DirBuster_Projec
t
Useful/Related Links:

Article on SQL Injection:

http://dev.mysql.
com/tech-resources/articles/guide-to-php-
security-ch3.pd
f
Article on XSS:

http://www.net-security.org/
dl/articles/xss_anatomy.pd
f
Article on XSS:

http://ferruh.mavituna.com/
sql-injection-cheatsheet-oku
/
Assorted PHP Security articles:

http://www.
madirish.net
/
Blog of Bannedit, Security Researcher:

http://
vulnfun.blogspot.com
/
Personal blog of Wirepair, Security Researcher:

http://kougekiryoku.blogspot.com
/
The Open Web Application Security Project

(OWASP) is a worldwide free and open com
-
munity focused on improving the security
of application software. Excellent resource:
http://www.owasp.or
g
All PHP developers should read this book: Pro

PHP Security, Chris Snyder and Michael South-
well, Apress.
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

www.phparch.com


April

2009

|
27
Black Box Penetration Tests
FEATURE
C
onsider (Scenario) ’Xmple’, a savvy application
developer, is preparing for the release of the new
-
est content delivery platform. The application has
passed internal QA and is on its way to a production
environment. Xmple has a solid development team but
is still worried about issues that might be encountered
due to malicious users.
This article will highlight some techniques used by
penetration testers and malicious attackers. By better
understanding adversaries, developers can work to con
-
struct more robust and secure software.
Before We Begin
It is important to mention that the author is not claim
-
ing to have invented any of the approaches described
here. This is a collection of basic to intermediate attack
techniques. If you are interested in acquiring addition
-
al information, please refer to any of the links provided
in the Additional Resources section.
Black Box Penetration Test: Approach
An attacker targeting Xmple’s application will not have
access to the source. Thus, this is deemed a black box
penetration test. With no source code and little to no
understanding of the company, the attacker must rely
on tricks and tools to maneuver around the applica
-
tion. At the same time, Xmple is busy preparing for the
release and may not be prepared to deal with additional
security issues.
Enumerate, Examine and Discovery
An attacker’s first move will often be to map the ap
-
plication through enumeration. This is an aggressive
move, but the attacker is betting that Xmple will not
be prepared to discover or combat this probing. If the
attacker is worried that a detection or logging system
is in place, they can tone down the frequency with
which requests are made to mimic a user navigating the
website.
Burp suite (
http://portswigger.ne
t
) is a collection
of tools that provide an impressive amount of
functionality. The tool doesn’t provide an attacker
or tester with pre-cooked vulnerabilities. Instead,
it provides a group of highly customizable tools to
facilitate a wide variety of attacks, enumeration, and
brute forcing techniques. Within the Burp suite is
Burp spider (
http://portswigger.net/suite/spider.
htm
l
), a tool that can be utilized to enumerate
resources of the target application. Typically, it is
aimed at the application root and works its magic
by enumerating all available recourses. Burp Spider
conducts the equivalent of navigating the application
“clicking” every link it can find. The tool’s scope can
be configured so it does not go “off-site” and run
rampant.
During the discovery and enumeration phase, the at
-
tacker will develop an effectively detailed layout of the
application, naming conventions and discover some of
the technologies at play. Note Xmple’s site layout in
Figure 1.
The Burp spider has enumerated files that are part of
Licensed to 48409 - Primoz Klemensek (klemensek@gmail.com)

28
|
April

2009

www.phparch.com
Black Box Penetration Tests
FEATURE
the default apache installation, plus numerous directo
-
ries filled with web monitoring and statistical data. An
attacker will use these files to gain insight that they
would otherwise never have, such as private links (not
linked to/from the main site) and additional techno
-
logical discoveries; the attacker could even retrieve
additional hostnames and network information. While
developers are often busy meeting the deadlines and
making sure that software meets the business require
-
ments, it is equally as important to get in the habit
of removing non-critical information from servers that
will be publicly accessible. It is common for develop
-
ers to utilize the phpinfo() method (
http://php.net/
phpinf
o
) to see if a module installed successfully or
if a needed feature was installed with PHP. However,
these files are often not removed, as is the case with
Xmple. The dirBuster (
http://www.owasp.org/index.php/
Category:OWASP_DirBuster_Projec
t
) enumeration at
-
tempts found a file named “test.php” located in a con
-
tent directory that was world readable (Figure 2). While
phpinfo() provides a wealth of information to develop
-
ers, it is information that shouldn’t fall into the hands
of attackers. It should also be removed promptly after
use and, if possible, not placed in a directory served by
the web server.
Digging Deeper: Examining Responses
After the initial probing has been conducted, an at
-
tacker very often will want to get details about how the
application handles various requests and what informa
-
tion is provided in the response.
Using Burp proxy, all traffic is recorded and offered
for analysis. Here are the details of a response from
Xmple:
HTTP/1.1 200 OK
Date: Sat, 31 Jan 2009 20:46:13 GMT
Server: Apache/1.3.37 (Unix) mod_auth_
passthrough/1.8
mod_log_bytes/1.2 mod_bwlimited/1.4 PHP/4.4.4
FrontPage/
5.0.2.2635.SR1.2 mod_ssl/2.8.28 OpenSSL/0.9.7a
X-Powered-By: PHP/4.4.4
Cache-Control: no-cache, must-revalidate
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Content-Type: text/html
Content-Length: 17121
To an attacker, two entries in this response will stick
out, the “Server” and “X-Powered-By” values. The first
reveals Xmple’s web server is Apache 1.3.37 on (Unix)
with a variety of modules installed. A pen tester will
respect the fact that the scope of the attack is limited