Tài liệu It’s All in a Day’s Work - Pdf 96

Crunching
Data
PHP
with
CrunchingCr unching
DataData
PHPPHP
withwith
From TAR to RAR in a ZIP From TAR to RAR in a ZIP
INTERVIEW
PRIMING PHP FOR THE ENTERPRISE
PRIMING PHP FOR THE ENTERPRISE
Idealabs Preps LAMP Up for the Big Time
TURNING A CLASS INTO TURNING A CLASS INTO
AN APPLICATION WITHAN APPLICATION WITH
PHP-GTKPHP-GTK
Automate your tasks with a GUI app
STRENGTHENING THE STRENGTHENING THE
AUTHENTICATION PROCESSAUTHENTICATION PROCESS
Make that login more secure without
HTTPS
An XML APPROACH TO TEMPLATING An XML APPROACH TO TEMPLATING
USING PHPTALUSING PHPTAL
Making the peace between designers and developers
MARCH 2005
VOLUME IV - ISSUE 3
MARCH 2005
VOLUME IV - ISSUE 3
www.phparch.com
Get Ready For:
Plus: Security Corner, Product Review, and much more

42 Test Pattern
The Three Inch High Design Tool
by Marcus Baker
48 Product Review
Vertrigo: The Utopia of All-in-One’s ?
by Peter B. MacIntyre
62 Security Corner
Magic Quotes
by Chris Shiflett
65 exit(0);
HELP! I’m a PHP beauty stuck in the
body of this Java programmer!
by Marco Tabini
10 Crunching Data with PHP
by Christian Wenz
19 Turning a Class Into an
Application With PHP-GTK
by Scott Mattocks
28 Interview
Priming PHP for the Enterprise
by Marco Tabini
33 Strengthening the
Authentication Process
by Graeme Foster
52 An XML approach to Templating
using PHPTAL
by José Pablo Ezequiel Fernández Silva
TABLE OF CONTENTS
php|architect
TM

side please. Now, I will have to perform a search of your person
because you ‘fit the profile.’ Of course, we can’t tell you what the
profile is, but this will only take a moment.”
So, on one side of the line someone tells you exactly “what the
profile is,” and, on the other, someone else tells you that the pro-
file is a secret. I hate to be stating the obvious, but that strikes me
as slightly odd—then again, there is no limit to government silli-
ness.
Meanwhile, back in Canada our government is training more
search dogs and pigs (yes, I said pigs) to sniff out smugglers.
“Drugs,” you may be thinking? No. Illegally-imported food. It’s
not the guy with the three-pound package of cocaine in his back-
pack that we should be worried about—the real criminal is the
eighty-year-old Italian lady with the salami in her purse.
Until next month, happy readings!
March 2005

PHP Architect

www.phparch.com
6
php|architect
Volume IV - Issue 3
March, 2005
Publisher
Marco Tabini
Editorial Team
Arbi Arzoumani
Peter MacIntyre
Eddie Peloke

EE DD II TT OO RR II AA LL RR AA NN TT SS
TM
NNEEWW SSTTUUFFFF
March 2005

PHP Architect

www.phparch.com
7
What’s New!
php|architect launches php|
tropics
2005
Ever wonder what it's like to learn PHP in paradise? Well, this year we've decided to give
you a chance to find out!
We're proud to announce php|tropics 2005, a new conference that will take place between
May 11-15 at the Moon Palace Resort in Cancun, Mexico. The Moon Palace is an all-
inclusive (yes, we said all inclusive!) resort with over 100 acres of ground and 3,000 ft. of
private beach, as well as excellent state-of-the-art meeting facilities.
As always, we've planned an in-depth set of tracks for you, combined with a generous
amount of downtime for your enjoyment (and your family's, if you can take them along
with you).
We even have a very special early-bird fee in effect for a limited time only.
For more information, go to
/>.
NN EE WW SS TT UU FF FF
ZEND Core for IBM
Zend Core for IBM is a complete, certified and fully supported distribution of PHP 5 that
tightly integrates with IBM's DB2 and CloudScape products, in addition to bundling all
required third-party libraries for interaction with the outside world.

Zend Technologies Inc. introduced Zend Studio 4.0, a
new version of their PHP integrated development envi-
ronment (IDE). Zend Studio runs on multiple operating
systems including Mac OS X.
The new release includes integrated support for all major database servers,
according to the developer, including IBM DB2, Cloudscape, MySQL, Oracle,
MS SQL Server, PostgreSQL, Derby and SQLite. New syntax highlighting
works for XML and CSS previously PHP, HTML, XHTML and JavaScript
were supported. PHPDocs support has been added and PHPDocumentor now
lets users create documentation directly from the PHP project source code.
Zend Studio 4 comes in a Standard edition for US$99 and a Professional
edition for $299. Both prices include tech support and one year of updates
and upgrades.
For more information visit:
hhttttpp::////wwwwww zzeenndd ccoomm//
NNEEWW SSTTUUFFFF
March 2005

PHP Architect

www.phparch.com
8
Check out some of the hottest new releases from PEAR.
DB_DataObject_FormBuilder 0.11.4
DDBB__DDaattaaOObbjjeecctt__FFoorrmmBBuuiillddeerr
will aid you in rapid application development using the
DDBB__DDaattaaOObbjjeecctt
and
HHTTMMLL__QQuuiicckkFFoorrmm
packages. In

• Transactions support
• Table information interface
• DocBook and phpDocumentor API documentation
Cache_Lite 1.4.1
This package is a little cache system optimized for file containers. It is fast and safe (because it uses file locking and/or anti-corruption
tests).
XML_RPC 1.2.1
A PEAR-ified version of Useful Inc's XML-RPC for PHP. It has support for HTTP/HTTPS transport, proxies and authentication.
I18Nv2 0.11.3
This package provides basic support to localize your application, like locale based formatting of dates, numbers and currencies.
Beside that it attempts to provide an OS independent way to
sseettllooccaallee(())
and aims to provide language, country and currency names
translated into many languages.
Maguma OpenStudio
Maguma GmbH (Bolzano, Italy) will make the source code of Maguma Studio, Maguma's Windows-
exclusive IDE, open!
Beginning in March 2005 the full source code of Studio will be available for download and community
participation. Maguma OpenStudio, as Maguma has named the product, is a milestone in the pursuit to
the realization of Maguma's Open Source strategy. Maguma OpenStudio is a fast, easy and effective
PHP IDE for beginners and professional developers alike. The newest product, the modular cross-plat-
form IDE, Maguma Workbench, is Maguma’s second generation IDE and is also community focused
through its flexibility to allows users to create custom modules for it. Maguma’s goal is to allow pro-
grammers to "Have Fun Programming!" In March Maguma OpenStudio will be available for download
on the Community site
wwwwww pphhppwwiizzaarrdd nneett
and on the Maguma Community site community
hhttttpp::////ccoomm
mmuunniittyy mmaagguummaa oorrgg//
.

intercept 0.2.0
Allows the user to request that a user-space function be called when a PHP function is executed. Support for class/object methods will
be added later.
mailparse 2.1.1
Mailparse is an extension for parsing and working with email messages.
It can deal with rfc822 and rfc2045 (MIME) compliant messages.
eZ publish 3.5.1
Ez.no announces the latest release of their content management system.
From the announcement:
”eZ publish is an open source content management system and development framework. As a
content management system (CMS) its most notable feature is its revolutionary, fully customiz-
able, and extendable content model. This is also what makes it suitable as a platform for gener-
al Web development. Its stand-alone libraries can be used for cross-platform, database independent PHP projects. eZ publish is also
well suited for news publishing, e-commerce (B2B and B2C), portals, and corporate Web sites, intranets, and extranets. eZ publish
is dual licenced between GPL and the eZ publish professional licence.”
Get all the details from
hhttttpp::////eezz nnoo//
The Zend PHP Certification Practice Test Book is now available!
We're happy to announce that, after many months of hard work, the Zend PHP
Certification Practice Test Book, written by John Coggeshall and Marco Tabini, is now
available for sale from our website and most book sellers worldwide!
The book provides 200 questions designed as a learning and practice tool for the
Zend PHP Certification exam. Each question has been written and edited by four
members of the Zend Education Board the very same group who prepared the
exam. The questions, which cover every topic in the exam, come with a detailed
answer that explains not only the correct choice, but also the question's intention,
pitfalls and the best strategy for tackling similar topics during the exam.
For more information, visit
hhttttpp::////wwwwww pphhppaarrcchh ccoomm//cceerrtt//mmoocckk__tteessttiinngg pphhpp
W

idea. There is even a PHP module that supports ZIP—
you can find it in the online manual at
hhttttpp::////pphhpp nneett//mmaannuuaall//eenn//rreeff zziipp pphhpp
. The module is
a wrapper for the ZZIPlib library, a SourceForge project
available at
hhttttpp::////zzzziipplliibb ssff nneett//
. This library sup-
ports only extracting data from an archive, not creating
new ZIP files. Therefore, it can only be used with exist-
ing ZIP files. Doing so, however, is relatively easy: first,
you have to ensure that the PHP module is present. If
you are building PHP by yourself, you have to run
ccoonn
ffiigguurree
with the
——wwiitthh zziipp==//ppaatthh//ttoo//zzzziipplliibb
switch;
Windows users just need to add the following line to
their
pphhpp iinnii
file:
extension=php_zip.dll
REQUIREMENTS
PHP 4.x , 5.x
OS Any
Other Software
The modules and packages refer-
enced in the article.
Code Directory crunch

the system path, e.g.
cc::\\wwiinnddoowwss\\ssyysstteemm3322
; under PHP
5, this DLL is located in the main installation directory.
Afterwards,
pphhppiinnffoo(())
shows that the library is there.
Then, accessing the data within the ZIP archive consists
of a number of standard steps:
• Open the ZIP archive with
zziipp__ooppeenn(())
.
• Use
zziipp__rreeaadd(())
to iterate through the con-
tents of the ZIP file.
• Open one single file within the archive with
zziipp__eennttrryy__ooppeenn(())
.
• Read its contents with
zziipp__eennttrryy__rreeaadd(())
.
• To clean up, use
zziipp__eennttrryy__cclloossee(())
and
zziipp__cclloossee(())
.
And here is how it’s done: an archive is opened and its
contents are written to the current directory. Here is the
relevant excerpt from the code:

5 return false;
6 }
7 $n = fwrite($file, $content);
8 fclose($file);
9 return $n ? $n : false;
10 }
11 }
12
13 $archive = dirname(__FILE__) . ‘/test.zip’;
14 if ($zip = zip_open($archive)) {
15 echo ‘Extracting files <br />’;
16 while ($entry = zip_read($zip)) {
17 if (zip_entry_open($zip, $entry, ‘rb’)) {
18 echo ‘ ‘ .
zip_entry_name($entry) . ‘<br />’;
19 file_put_contents(
20 zip_entry_name($entry),
21 zip_entry_read($entry,
22 zip_entry_filesize($entry)
23 )
24 );
25 zip_entry_close($entry);
26 }
27 }
28 zip_close($zip);
29 echo ‘done.’;
30 }
31 ?>
Listing 1
offers a compression mode that takes longer, uses more

ber of steps. For compressing data, the following pro-
cedure has to be followed:
• Create a BZIP2 archive using
bbzzooppeenn(())
.
• Use
bbzzwwrriittee(())
to successively write data to
the archive; the crunching is done automag-
ically.
• Finally, close the file with
bbzzcclloossee(())
.
Here is a short version of this algorithm that reads in
one file and writes it into a BZIP2 archive; Listing 2 con-
tains the complete code. Note that
ffiillee__ggeett__ccoonntteennttss(())
is binary-safe and, therefore, it
can be used to retrieve the original file’s contents.
Otherwise, you can use
ffooppeenn(())
in
‘‘wwbb’’
mode, iterate
through the file and provide the data to
bbzzwwrriittee(())
.
$infile = dirname(__FILE__) . ‘/php.ini-recommended’;
$outfile = dirname(__FILE__) . ‘/test.bz2’;
$out = bzopen($outfile, ‘wb’);

4
5 echo ‘Uncompressing file <br />’;
6 $in = bzopen($infile, “rb”);
7 $out = fopen($outfile, “wb”);
8 while ($data = bzread($in, 1024)) {
9 fputs($out, $data, 1024);
10 }
11 bzclose($in);
12 fclose($out);
13 echo ‘done.’;
14 ?>
Listing 3
ZIP Header
1 <?php
2 $infile = dirname(__FILE__) . ‘/php.ini-recommended’;
3 $outfile = dirname(__FILE__) . ‘/test.bz2’;
4
5 echo ‘Compressing file <br />’;
6 $out = bzopen($outfile, ‘wb’);
7 bzwrite(
8 $out,
9 file_get_contents($infile)
10 );
11 bzclose($out);
12 echo ‘done.<br />’;
13 printf(‘Old size: %d bytes; new size: %d bytes.’,
14 filesize($infile),
15 filesize($outfile));
16 ?>
Listing 2

ration or
pphhpp iinnii
tweaking required. This library is most
often used to GZIP data sent to the browser on the fly,
to make the transfer of web pages smaller and, there-
fore, quicker. Nowadays, most web browsers support
this functionality and advertise it by sending the
AAcccceepptt EEnnccooddiinngg:: ggzziipp
or
AAcccceepptt EEnnccooddiinngg:: ddeeffllaattee
HTTP headers (or both). If this is the case, PHP can send
compressed data across the wire if the following
pphhpp iinnii
setting is enabled:
zlib.output_compression = On
Note that (theoretically) nothing can go wrong if the
browser does not support GZIP compression because,
in that case, no corresponding
AAcccceepptt EEnnccooddiinngg
HTTP
header is sent and, therefore, PHP does not GZIP the
data. Older versions of Netscape have a bug with
embedded, compressed media, but do not have a rea-
sonable market share any longer.
However, the Zlib extension can also be used to com-
press files on the fly—as well as to uncompress them, of
course. In contrast to the ZZIPlib library, this extension
also allows to create archives. The standard steps apply,
again with a couple of new function names:
• Create an archive using

,
until
ggzzeeooff(())
returns
TTrruuee
.
• Close the file using
ggzzcclloossee(())
.
Again, here’s a simple snippet of code, taken straight
out of the larger example that you can find in Listing 5:
$in = gzopen($infile, “rb”);
$out = fopen($outfile, “wb”);
while (!gzeof($in)) {
fputs($out, gzread($in, 1024), 1024);
}
gzclose($in);
1 <?php
2 $infile = dirname(__FILE__) . ‘/php.ini-recommended’;
3 $outfile = dirname(__FILE__) . ‘/test.gz’;
4
5 echo ‘Compressing file <br />’;
6 $out = gzopen($outfile, ‘wb4’);
7 gzwrite(
8 $out,
9 file_get_contents($infile)
10 );
11 gzclose($out);
12 echo ‘done.<br />’;
13 printf(‘Old size: %d bytes; new size: %d bytes.’,

FFEEAATTUURREE
14
Crunching Data with PHP
fclose($out);
The Zlib extension offers some other functions, includ-
ing
ggzzffiillee(())
and
ggzzppaasssstthhrruu(())
, which work similarly to
ffiillee(())
and
ffppaasssstthhrruu(())
, but also uncompress data
from the (GZIP) file pointer provided. Similarly,
ggzzccoommpprreessss(())
allows to directly compress a string (that
was retrieved, for instance, by
ffiillee__ggeett__ccoonntteennttss(())
),
whereas
ggzzddeeffllaattee(())
uncompresses a GZIP string into
its original form.
PHP Streams
Starting with PHP 4.3.0, the concept of streams was
introduced. They already existed in previous versions,
but only in a very limited form: as HTTP wrappers for
ffooppeenn(())
), or for Zlib (

this functionality built-in in their binary distributions.
From there on, usage is as simple as working with any
stream—it’s like working with a file. You do not have to
worry or care about compressing or uncompressing,
but just work with it like you would with any other PHP
stream: just read from or write to it, and PHP takes care
of the rest in a completely transparent fashion. Here is
how it’s done for GZIP—a file is read in, compressed
and then deflated:
//Compressing
$data = file_get_contents($infile);
file_put_contents(“compress.zlib://$outfile”, $data);

//Uncompressing
$data = file_get_contents(“compress.zlib://$infile”);
file_put_contents($outfile, $data);
The download code for this issue contains the complete
listing, including a tweak to make it backwards-com-
CVS
11 <<??pphhpp
22 iiff ((!!ffuunnccttiioonn__eexxiissttss((‘‘ffiillee__ppuutt__ccoonntteennttss’’)))) {{
33 ffuunnccttiioonn ffiillee__ppuutt__ccoonntteennttss(($$ffiilleennaammee,, $$ccoonntteenntt)) {{
44 iiff ((!!(($$ffiillee == ffooppeenn(($$ffiilleennaammee,, ‘‘ww’’)))))) {{
55 rreettuurrnn ffaallssee;;
66 }}
77 $$nn == ffwwrriittee(($$ffiillee,, $$ccoonntteenntt));;

88 ffcclloossee(($$ffiillee));;
99 rreettuurrnn $$nn ?? $$nn :: ffaallssee;;
1100 }}

does not
exist); Listing 6 shows the complete source code for the
same task being performed using BZIP2 compression.
PEAR Packages
PEAR does not have a category specifically
dedicated to archive files, but for file types
(
pear.php.net/packages.php?catpid=33). There, you will
find (as of March 2005) two packages that are relevant
to our quest:

AArrcchhiivvee__TTaarr
(
ppeeaarr pphhpp nneett//ppaacckkaaggee//AArrcchhiivvee__TTaarr
)
for tarballs

AArrcchhiivvee__ZZiipp
(
ppeeaarr pphhpp nneett//ppaacckkaaggee//AArrcchhiivvee__ZZiipp
)
for ZIP files
The first of these two packages is automatically distrib-
uted with PEAR, since the installer uses it to deflate and
install PEAR modules. Nevertheless, it might be a good
idea to run
ppeeaarr lliisstt uuppggrraaddeess
to check whether new
versions exist (or, specifically,
ppeeaarr uuppggrraaddee AArrcchhiivvee__TTaarr

• Instead of using an array, you can also pro-
vide a space separated list of file names—if
your file names do not contain spaces.
Here is a small example that creates a mini PHP distri-
bution: We take three files from a PHP binary distribu-
tion package and compress them into a single tarball:
<?php
require_once ‘Archive/Tar.php’;
$tar = new Archive_Tar(‘test.tar’);
$tar->create(
‘php4embed.lib php.ini-recommended php.ini-
dist’);
?>
It is also possible to create subdirectories. In order to do
so, you can use
ccrreeaatteeMMooddiiffyy(())
instead of
ccrreeaattee(())
, or
aaddddMMooddiiffyy(())
instead of
aadddd(())
. As a second parameter,
you need to provide the name of the diretory where
the files shall be placed:
$tar->create(‘php4embed.lib’);
$tar->addModify(
array(
‘php.ini-recommended’,
‘php.ini-dist’

15 ?>
Listing 7
bzip vs. gzip
parameter are
‘‘bbzz22’’
for BZIP2 and
‘‘ggzz’’
for GZIP. Then,
the PEAR module automatically compresses the files
after merging them into a tarball. Thus, you get both
effects: compacting several files into one distribution
tarball and then making the latter’s file size significant-
ly smaller.
Extracting files from the TAR/TGZ/TAR’ed BZ2 archive
is even easier to implement: you just open the archive
and then extract its contents to the specified path:
<?php
require_once ‘Archive/Tar.php’;
$tar = new Archive_Tar(‘test.tar.gz’, ‘gz’);
$tar->extract(‘targetdir’);
?>
Now to the second relevant PEAR package,
AArrcchhiivvee__ZZiipp
, which, internally, requires PHP’s Zlib
extension. Unfortunately, as of the time of this writing,
the PEAR module has not seen any release yet (an
issue which is, interestingly, also filed as a bug).
However, the module maintainer, Vincent Blavet, does
react to bug reports and currently maintains the
package exclusively in PEAR’s CVS system. You find the

you set the
aadddd__ppaatthh
option when using
ccrreeaattee(())
or
aadddd(())
. The following code snippet shows this; Listing 8
contains the complete code for this example:
require_once ‘Archive/Zip.php’;
$zip = new Archive_Zip(‘test.zip’);
$zip->create(‘php4embed.lib’);
$zip->add(
‘php.ini-recommended,php.ini-dist’,
array(‘add_path’ => ‘ini’)
);
The file created by this script indeed uses the directory
name provided. Getting the files back can be accom-
plished with very little code as well: you just need to
open the file and call
eexxttrraacctt(())
. Again, the
aadddd__ppaatthh
parameter can set a path to be used, this time for
deflating the data in the archive into.
<?php
require_once ‘Archive/Zip.php’;
$zip = new Archive_Zip(‘test.zip’);
$zip->extract(
array(‘add_path’ => ‘targetdir’)
);

then include the
zziipplliibb pphhpp
file in your code and follow
these steps (great, more lists!):
• Instantiate the class:
$$zziipp == nneeww ZZiipplliibb;;
• Add some files with the method
zzll__aadddd__ffiillee(())
, providing the file’s contents,
its name and the compression method.
A few words about compression methods: the library
supports three possibilities.
nn
stands for none,
bb
for BZIP
compression and
gg
for GZIP compression. If the param-
eter is not provided, the class automatically uses GZIP.
After the character for the compression method, the
March 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
16
Crunching Data with PHP
1 <?php

search Google will turn up more alternatives.
Summary
As this article has shown, working with archives from
within PHP is both possible and quite easy—it is just not
as documented and talked-about as other aspects of
the language. There are several possible ways to use
archives, and all relevant file formats are supported.
This functionality can be really useful in your projects:
you can create your own download area where users
can retrieve files that are compressed on the fly before
being sent out to the user (In this case, however, you
should implement “funky caching”, meaning that once
you have crunched a file, you save the result so that
next time someone requests the same data, you save
the effort to crunch it again). Also, users may have the
opportunity to submit archives to your website and you
can have your script take a look what is inside.
FFEEAATTUURREE
March 2005

PHP Architect

www.phparch.com
Crunching Data with PHP
17
1 <?php
2 if (!function_exists(‘file_put_contents’)) {
3 function file_put_contents($filename, $content) {
4 if (!($file = fopen($filename, ‘w’))) {
5 return false;

/>Christian Wenz is author or co-author of over four dozen books, fre-
quently writes for renowned IT magazines and speaks at conferences
around the globe. He is Germany’s very first Zend Certified Professional,
principal at the PHP Security Consortium and maintainer or co-maintain-
er of several PEAR projects.
Have you had your PHP today?
Have you had your PHP today?
The Magazine For PHP Professionals

NEW COMBO NOW AVAILABLE: PDF + PRINT
NNEEWW
LLoowweerr PPrriiccee!!

FFEEAATTUURREE
March 2005

PHP Architect

www.phparch.com
19
O
ften times, a wonderful class is written that
makes a developer’s life much easier. But
almost just as often, the class requires a the
developer to write a script that loads a specific set of
data, which, in turn, can’t be used again. I first came
across this problem when writing dozens of scripts that
each loaded a different unit test and simply output the
results. I wondered how easy it would be to create an
application that loaded the test cases and showed the

Lupus in fabula—before getting down to work, we
should probably decide on a general layout for our
application. The
PPaacckkaaggeeFFiilleeMMaannaaggeerr
class performs
several tasks that are mostly independent of one anoth-
er. This isn’t to say that you can use just one method
Tired of having to write a new script for every PEAR pack-
age he released, Scott Mattocks decided to wrap the
PEAR_PackageFileManager class in a GUI to make gener-
ating package files a snap. The following article details the
process that he went through to create his application and
highlights how you can use PHP-GTK to do the same with
your classes.
FF EE AA TT UU RR EE
Turning a Class Into an Application
With PHP-GTK
by Scott Mattocks
REQUIREMENTS
PHP 4.3.x
OS N/A
Other Software PHP-GTK 1.01
Code Directory gtk
RESOURCES
URL
hhttttpp::////qqttkk pphhpp nneett
ii
and you have a valid package file, but adding a main-
tainer doesn’t rely on the user adding a dependency
first. Because of the design of

, and
descendants of
GGttkkBBiinn
can only have one child widget.
This may sound like a strange limitation, but it isn’t,
really. If you only have one child, you don’t have to
worry about ordering, positioning or anything else that
comes along with having multiple child widgets. It
keeps the notebook pages simple and leaves the more
complex container stuff to specialized widgets.
To allow us to have a page with more than one widg-
et in it, we just need to make sure that the page’s child
is some sort of container that can hold more than one
child of its own, like a
GGttkkHHBBooxx
. Then, we can fill the
child container up withever we want, and the notebook
page will still only have one child.
If you look at Listing 1, you’ll notice that I have sever-
al helper methods that take are of creating each page’s
widgets. Each helper method returns an array holding
the container for the page, and a label for the tab. You
should also notice that I have connected a method to
the
sswwiittcchh ppaaggee
signal. This is raised any time the top
page of the notebook changes. It doesn’t matter if the
page changes because the user clicks on a tab or if our
code tells the notebook to bring a different page to the
front—by connecting the signal to the

a
little later, but in this case it would just complicate
things needlessly.
Putting the Pieces Together
Ok. So we have our application all set up and ready to
start working. The feature we should probably add first
March 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
20
Turning a Class Into an Application With PHP-GTK
1 <?
2 function &_buildNotebook()
3 {
4 // Create the notebook.
5 $this->notebook =& new GtkNotebook();
6
7 // Add the addMaintainer page.
8 $this->_addNotebookPage($this->_createSetOptionsPage());
9
10 // Add the addMaintainer page.
11 $this->_addNotebookPage($this->_createAddMaintainerPage());
12
13 // Add the addDependencies page.
14 $this->_addNotebookPage($this->_createAddDependenciesPage());
15
16 // Add the warnings page.

GGttkkTTeexxtt
widget is very similar to an HTML
tteexxttaarreeaa
: it
allows for text to be easily added and will scroll when
there is too much to display at one time. We can also
set the text area so that the user cannot directly edit the
text—this is a good idea to ensure that nobody acci-
dentally deletes a few lines and then gets confused as
to why their package file didn’t get built properly.
The
sshhoowwWWaarrnniinnggss(())
method that is connected to the
notebook’s
sswwiittcchh ppaaggee
signal simply grabs the array of
errors from the package file manager and adds each
one on its own line in the warnings area. To add the
text, we just call the
iinnsseerrtt__tteexxtt(())
method of the
GGttkkTTeexxtt
widget.
iinnsseerrtt__tteexxtt(())
takes two parameters,
the text to add and the position. As with most string
functions in PHP,
11
indicates the end of the string.
Listing 2 shows the code for this page.

3 {
4 // Pack everything in a vBox.
5 $vBox =& new GtkVBox();
6
7 // Set up the warnings area.
8 $this->warningsArea =& new GtkText();
9 $this->warningsArea->set_editable(false);
10 $this->warningsArea->set_word_wrap(false);
11
12 // Add a button to clear the warnings area.
13 $hBox =& new GtkHBox();
14 $button =& new GtkButton(‘Clear’);
15 $button->connect_object(‘clicked’, array(&$this->warningsArea, ‘delete_text’), 0, -1);
16 $hBox->pack_end($button, false, false, 5);
17
18 // Pack everything in.
19 $vBox->pack_start($this->warningsArea, true, true, 10);
20 $vBox->pack_start($hBox, false, true);
21
22 return array($vBox, new GtkLabel(‘Warnings’));
23 }
24
25 function showWarnings($message = NULL)
26 {
27 if (!empty($message)) {
28 $this->warningsArea->insert_text($message . “\n”, $this->warningsArea->get_length());
29 }
30
31 foreach ($this->_packageFileManager->getWarnings() as $warning) {
32 $this->warningsArea->insert_text($warning[‘message’] . “\n”, $this->warningsArea->get_length());

GGttkkHHBBooxx
es, children are packed from right to left. There
will be more on packing widgets in just a few para-
graphs.
Next, let’s look at adding a maintainer. This is where
we get into really wrapping the
PPaacckkaaggeeFFiilleeMMaannaaggeerr
class into our GTK application.
A maintainer is someone who contributes to a PEAR
package. In the
ppaacckkaaggee xxmmll
file, they are identified by
four pieces of information: their handle, their name,
their email address, and their role in the package. As a
result, the
aaddddMMaaiinnttaaiinneerr(())
method expects these four
pieces of information as arguments. The number and
type of parameters a function takes gives us a clue as to
what kinds of widgets we will need. The developer’s
handle, name and email address can be just about any-
thing, so
GGttkkEEnnttrryy
fields will probably be the best fit. A
GGttkkEEnnttrryy
is very similar to an HTML text input box. It
allows the user to enter one line of text. The role, on
the other hand, has some predefined legal values;
therefore, a
GGttkkCCoommbboo

when it is added. The second,
eexxppaanndd
, lets the contain-
March 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
22
Turning a Class Into an Application With PHP-GTK
1 <?
2 function _createAddMaintainerPage()
3 {
4 // To lay things out, use a combination of h and v
boxes.
5 $mainVBox =& new GtkVBox();
6 $mainHBox =& new GtkHBox();
7 $leftVBox =& new GtkVBox();
8 $rightVBox =& new GtkVBox();
9 $subHBox =& new GtkHBox();
10
11 // We need a status label to let the user know what
happened.
12 $statusLabel =& new GtkLabel(‘’);
13
14 // We need three entries and three labels.
15 $handleEntry =& new GtkEntry();
16 $handleLabel =& new GtkLabel(‘Handle’);
17 $nameEntry =& new GtkEntry();

45 }
46
47 // We need a button to do the work.
48 $button =& new GtkButton(‘Add Maintainer’);
49 $button->connect_object(‘clicked’, array(&$this,
‘_addMaintainer’), $handleEntry, $roleCombo, $nameEntry,
$emailEntry, $statusLabel);
50
51 // Put it all together.
52 // The left VBox is for the labels.
53 $leftVBox->pack_start($handleLabel, false, true, 3);
54 $leftVBox->pack_start($nameLabel, false, true, 3);
55 $leftVBox->pack_start($emailLabel,
false, true, 3);
56 $leftVBox->pack_start($roleLabel, false, true, 3);
57
58 // The right VBox is for the entries and the combo.
59 $rightVBox->pack_start($handleEntry, false, false, 0);
60 $rightVBox->pack_start($nameEntry, false, false, 0);
61 $rightVBox->pack_start($emailEntry, false, false, 0);
62 $rightVBox->pack_start($roleCombo, false, false, 0);
63
64 // The two VBoxes go in the main HBox.
65 $mainHBox->pack_start($leftVBox, false, false, 2);
66 $mainHBox->pack_start($rightVBox, false, false, 0);
67
68 // The subHBox holds the button.
69 $subHBox->pack_end($button, false, false, 0);
70
71 // The label and the two HBoxes go in the main VBox.

. When we set up our page, we
can deal with each piece of the
GGttkkCCoommbboo
separately, but
still treat them as one widget when it comes time to
position them. First, let’s look at the
GGttkkEEnnttrryy
portion.
If we didn’t modify it, the entry part would function just
like any other
GGttkkEEnnttrryy
in our application, but the
whole idea of using the
GGttkkCCoommbboo
was so that users had
to select the role from a list, as opposed to typing it
themselves. To make sure that only the list values are
used, therefore, we need to prevent the user from edit-
ing the text in the entry area. This is done the same way
as we did for the warnings area, with
sseett__eeddiittaabbllee(())
.
Setting up the list is a little more complicated; a
GGttkkLLiisstt
is a container that will only accept
GGttkkLLiissttIItteemm
s as chil-
dren. To add the developer roles, we have to add one
GGttkkLLiissttIItteemm
for each. When the list items are created,

to the
ccoonnnneecctt__oobbjjeecctt(())
call because our method for
adding a maintainer needs to extract the developer’s
information. If you try to pass
$$eemmaaiillEEnnttrryy
>>ggeett__tteexxtt(())
, you are passing the return value from that
method at the time you connect the signal. I have seen
many developers do that and then wonder why their
application isn’t working the way they want. We need
to pass the widgets themselves so that we can get the
return value from
ggeett__tteexxtt(())
at the time the user clicks
the button. The method can then pass the correct val-
ues along to
PPaacckkaaggeeFFiillee__MMaannaaggeerr::::aaddddMMaaiinnttaaiinneerr(())
.
After we’ve added the maintainer, it is nice to let the
user know what happened and then clear out the old
data so they can add another developer. To do this, we
pass one more widget to our
__aaddddMMaaiinnttaaiinneerr(())
method—a
GGttkkLLaabbeell
. When the user hits the “Add
Maintainer” button, we just set the label text to an
appropriate message.
Ok, that was easy. Let’s take a look at something a lit-

23
Turning a Class Into an Application With PHP-GTK
1 <?php
2
3 require_once ‘HTML/QuickForm.php’;
4 $form = new HTML_QuickForm(‘frmTest’, ‘POST’,
5 $_SERVER[‘REQUEST_URI’]);
6 $form->addElement(‘text’, ‘email’, ‘Email’);
7 $form->addElement(‘text’, ‘name’, ‘Name’);
8
9 $form->addRule(‘email’, ‘That must be a valid email’,
10 ‘email’);
11 $form->addRule(‘name’, ‘Please enter your name’,
12 ‘required’);
13
14 if ($form->validate()) {
15 $form->freeze();
16 echo ‘validated!’;
17 }
18 $form->display();
19
20 ?>
Listing 4
“ PHP-GTK isn’t quite as diffi-
cult or scary as its reputation
may have led you to believe. “
but also the minimum version needed. Listing 4 shows
how to build the tree.
After a little set up, we instantiate a
PPEEAARR__RReeggiissttrryy

pass the number of columns and an array with the col-
umn labels. A
GGkkttCCLLiisstt
is a pretty complex widget if
you get into all the bells and whistles, but all we need
to do is add entries, sort them and resize the columns
as appropriate. Let’s start with sorting the columns,
because that is the easiest of our operations. After
building the widget, we just call the
sseett__aauuttoo__ssoorrtt(())
method—we don’t need to give it any parameters or
call any other methods. The
GGttkkCCLLiisstt
will now auto-
matically sort our packages by package name and ver-
sion number. Simple enough, right?
Now how about resizing the columns? This gets a lit-
tle tougher. You actually have to pass some parameters.
To have the columns automatically resize, call
ccoolluummnn__sseett__aauuttoo__rreessiizzee(())
passing the column number
(zero in our case) and
ttrruuee
. This will make the first col-
umn stretch and shrink to fit its widest entry. The other
columns will adjust as needed without affecting the size
of the widget.
Listing 5 shows how we grab the data from the tree
and pass it to the list and package file manager. When
a node from the tree is selected, our callback method

array of options where the key of each element pro-
vides the option’s name and the corresponding value
March 2005

PHP Architect

www.phparch.com
FFEEAATTUURREE
24
Turning a Class Into an Application With PHP-GTK
1 <?
2 function _addDependency($tree, $node, $unknown, $list)
3 {
4 $data = $tree->node_get_row_data($node);
5 if (count($data) == 2) {
6 $result = $this->_packageFileManager->addDependency($data[0],$data[1]);
7
8 // Check for errors.
9 if (PEAR::isError($result)) {
10 $this->_pushWarning($result->getCode(), array());
11 //return;
12 }
13
14 // Add the dependcy to the clist.
15 $list->insert(0, $data);
16 }
17 }
18 ?>
Listing 5
“The public methods of the class give a good indication as to

sseett__ppoossii
ttiioonn(())
method and passing
GGTTKK__WWIINN__PPOOSS__CCEENNTTEERR
to it.
The
GGttkkFFiilleeSSeelleeccttiioonn
widget is much like
GGttkkCCoommbboo
, in
that it is a collection of other widgets. The two pieces
that we are most interested in are the “OK” and
“Cancel” buttons. These buttons are not connected to
any methods by default, so it is up to us to set them up
correctly. If you try to call a method of a widget prop-
erty, PHP-GTK will stop you. First, you need to assign
the widget property to another variable. After that, you
can call
ccoonnnneecctt__oobbjjeecctt(())
on the buttons. The “OK”
button gets connected to a custom method that pass-
es the file path to the
GGttkkEEnnttrryy
on our main application
and then hides the file selection window, while the
“Cancel” button gets connected straight to the file
selection’s
hhiiddee(())
method. In both cases, we are using
the

GGttkkMMeennuuBBaarr
and
two
GGttkkMMeennuuIItteemm
s, one for the file operations and one
for the help operations. When you create a menu item,
you need to pass it a string that will be the label for the
menu item. Each
GGttkkMMeennuuIItteemm
is appended to the menu
bar and then has a
GGttkkMMeennuu
added to it by calling
sseett__ssuubbmmeennuu(())
and passing a
GGttkkMMeennuu
to it.
GGttkkMMeennuuIItteemm
s
emit the
aaccttiivvaattee
signal when they are selected; when
we add a sub menu, the
aaccttiivvaattee
signal is automatical-
ly connected to the
sshhooww(())
method for the sub menu.
For each operation, we need to create a new
GGttkkMMeennuuIItteemm

5 $menuBar =& new GtkMenuBar();
6 $accel =& new GtkAccelGroup();
7 $this->window->add_accel_group($accel);
8
9 // Create the main (only) menu item.
10 $fileHeader =& new GtkMenuItem(‘File’);
11 $helpHeader =& new GtkMenuItem(‘Help’);
12
13 // Add the menu item to the menu bar.
14 $menuBar->append($fileHeader);
15 $menuBar->append($helpHeader);
16
17 // Create the file menu
18 $fileMenu =& new GtkMenu();
19 $helpMenu =& new GtkMenu();
20
21 // Add the menu items
22 $about =& new GtkMenuItem(‘Open’);
23 $about->connect(‘activate’, array(&$this,
‘_openFile’));
24 $fileMenu->append($about);
25
26 $save =& new GtkMenuItem(‘’);
27 $saveLabel = $save->child;
28 $saveKey = $saveLabel->parse_uline(‘_Save’);
29 $save->add_accelerator(‘activate’, $accel, $saveKey,
GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
30 $save->lock_accelerators();
31 $save->connect_object(‘activate’, array(&$this,
‘_saveFile’));


Nhờ tải bản gốc
Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status