Conquer JpGraphXML Transformation With PEAR Using PEAR::XML_Transformer Advanced Features Revealed Form Validation From the Outside In A New And Interesting Perspective Practical Web Se
Trang 1Conquer JpGraph
XML Transformation With PEAR
Using PEAR::XML_Transformer
Advanced Features Revealed
Form Validation From the Outside In
A New And Interesting Perspective
Practical Web Services with PHP
Computer Science Concepts With PHP
Writing A Parser And Expression Evaluator
Trang 2As PHP’s importance grows on the IT
scene—something that is happening every
day—it’s clear that its true capabilities go
well beyond what it’s being used for
today The PHP platform itself has a lot of
potential as a general-purpose language,
and not just a scripting tool; just its basic
extensions, even discounting repositories
like PEAR and PECL, provide a
high-quality array of functionality that most of
its commercial competitors can’t afford
without expensive external components.
At php|a, we’ve always felt that our
mis-sion is not limited to try our best to
pro-vide the PHP community with a
publica-tion of the highest possible quality We
think that our role is also that of
reinvest-ing in the community that we serve in a
way that leads to tangible results.
To that end, this month we’re launching
the php|architect Grant Program, a new
initiative that will see us award two
$1,000 (US) grants to PHP-related
proj-ects at the end of June.
Participating to the program is easy We
invite all the leaders of PHP projects to register with our website at
their applications for a grant Our goal is
to provide a financial incentive to those projects that, in our opinion, have the opportunity to revolutionize PHP and its position in the IT world.
In order to be eligible for the Grant Program, a project must be strictly related
to PHP, but not necessarily written in PHP.
For example, a new PHP extension written
in C, or a new program in any language that lends itself to using PHP in new and interesting ways would also be acceptable The only other important restriction is that
the project must be released under either
the LGPL, the GPL or the PHP/Zend license Thus, commercial products are
Program
Trang 3Migrating From Proprietary Tools to PHP
From Electronic Microsystems
PostgreSQL Manager and MySQL Manager
Trang 4Visit www.zend.com
for evaluation version and ROI calculator
Zend Performance Suite
Reliable Performance Management for PHP
Serve More.
With Less.
The designers of PHP offer you the full spectrum of PHP solutions
Trang 5Marco Tabini
Editor-in-Chief
Brian K Jones brian@phparch.com
Editorial Team
Arbi ArzoumaniBrian JonesPeter JamesMarco Tabini
Graphics & Layout
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.
Copyright © 2002-2003 Marco Tabini & Associates,
Inc — All Rights Reserved
p
ph hp p||a ar rc ch hiit te ec ct t:: A A N Ne ew w
C
Co om mm mu un niit ty y
Since I first came on board as an editor
here (only days after the launch of
php|architect’s first issue), I’ve had the
dis-tinct pleasure of forming relationships
with some of the greatest minds in the
PHP community As a budding Editor in
Chief, it has become quite clear to me that
our ability to form synergistic,
collabora-tive relationships with our authors is
something of an anomaly in the magazine
publishing industry Lucky for me, it’s one
that is a welcome change to the authors
I’ve interacted with I’m proud to have a
part in creating this apparently new
para-digm in publishing, and this seemingly
new perspective on the editor-author
rela-tionship
I like to think of the editorial process as
the creation of what I am now dubbing ‘A
New Community’; A new community of
people from different walks of life, having
vastly different views on how different
technologies should work together,
differ-ent experiences to share, and from
dis-parate cultures and geographic regions of
the Earth A community bonding on the
common goals of furthering both the
development of PHP as a complete, stable,
mature development platform, and the
progress of other PHP developers.
The end result of this highly iterative,
interactive process is what is ultimately
delivered to you by php|architect every
month Not just a magazine, but a
some-what interactive experience in itself Let’s
not forget that in addition to working hard
to produce the magazine each month, the
members of our editorial staff are also
con-sumers of this magazine! As a result, we
experience along with all of you the
feel-ing that we are really befeel-ing taken by the
hand through what seems like a tour of a
particular project undertaken by a
particu-EDITORIAL
Trang 6lar developer At the end of the tour, we’re
handed the bits of code which are out in
production somewhere, making things
tick As a consumer, I find this amazingly
useful I hope anyone reading this agrees,
or will send me email telling me how we
can make things even better
In addition, I invite those who might
cur-rently be passive consumers of information
to get involved! If you’re reading this,
you’re quite likely a PHP developer.
Chances are also good that you have a
unique opinion or perspective on some
aspect of technology that touches us here
in the PHP community We invite you to
participate more actively in the ‘New
Community’ by sharing your knowledge,
thoughts, and ideas with the rest of us.
We’ve just released a new version of our
author’s guidelines , which can help get
you started Anything that this leaves you
wondering about can be addressed by
ask-ing our editorial staff at
write@phparch.com
It could very well be that you haven’t
participated yet because you haven’t seen
a product offered by php|architect that
looks like a good fit for your own work.
Maybe you want to write a book, or start a
new project of unforeseeable dimensions I
urge anyone in this position to write to
editors@phparch.com with your concerns
in this area It’s quite possible that we have
a project in the works that could benefit
from your input
The plain and unequivocal fact is that
php|architect is growing quite rapidly This
growth stems from the ideas of those
col-laborating on the direction of
php|archi-tect as a diversified company – not just a
magazine For example, php|architect has
recently been translated and redistributed
in Japanese for that market This has been
a successful venture for all of those
involved, as well as the community at
large, and we urge any other parties
inter-ested in localized versions of php|architect
to contact us – editors@phparch.com What’s more, php|architect will soon see the release of our first full-fledged book, with more work in this area ongoing I won’t use this space to divulge the details now, but stay tuned to my monthly edito- rial for more as things progress In the wake of Wrox’s disappearance from the publishing world (a result of their parent company’s apparent insolvency), we at php|architect feel some obligation to at least partially fill the gap that will inevitably result in the area of authoritative PHP coverage From someone who owns several Wrox books, I can sincerely say that their work is well appreciated, and will be sorely missed We can only hope to do our best to keep up with the needs of a con- stantly growing developer base Luckily,
we don’t have to have the breadth of erage in our books that Wrox had in theirs – I have no desire to work on a Java book! These are just a couple of the ideas we’re currently pursuing Since no entity can claim monopoly ownership over all good ideas, it’s only natural that we reach out and make it known that we are a compa-
cov-ny which fosters and values ideas If you have an idea for which an outlet has yet to
be identified, we hope you’ll consider tacting us for help in discovering how best
con-to pursue your goals
Now on with the show! I’m excited by what lies between this editorial and Marco’s exit(0) (actually, I kinda like the editorial and exit(0) as well) I hope you can find enlightenment and inspiration from the articles which follow Let us know your thoughts:
editors@phparch.com
Trang 7The PHING is Loose!
PHING (PHing Is Not Gnumake) is a make toolwritten in PHP and based on the ideas and con-cept of Apache Ant It can basically do anythingyou could do with a build system like Gnumake,for example, but uses XML for storing the targetsand commands Using XML, Phing avoids prob-lems like the “Space before tab problem” inGnumake Current features include processingfiles while copying (e.g do Token Replacement,XSLT transformation etc.) and various file systemoperations
Phing is written in the PHP scripting languageand designed to be extensible Thus, you can eas-ily add the behaviour you need for your project byadding a class (known as tasks) Additionally,Phing is platform independent and runs on Unixlike systems and Windows Phing is currently used
to build binarycloud, a PHP ApplicationFramework, and is maintained by its developers.For more information, or to download Phing,visit its website at http://binarycloud.com/phing/
PHP Architect Wo Yomitai!
We’re happy to announce the introduction of the Japanese edition of php|architect!Published by Asial Corporation, the best PHP company in Japan, the publication is called PHPProgrammer’s Magazine and it pro-
vides all the great content of php|a,
plus many localized features
specif-ic to the Japanese market
Asial (http://www.asial.co.jp) is a
Tokyo-based company that
special-izes in the production of PHP
sys-tems and the localization of
soft-ware and documentation for the
Japanese market
You can find the PHP
Programmer’s Magazine website at
http://www.phppro.jp
If you are interested in localizing
php|a in your language, don’t
hesi-tate to drop us a note at
info@phparch.com
ionCube Announces
Special Offer
The ionCube standalone PHP encoder is a high
per-formance and complete PHP encoding solution,
employing the technique of compiled code
encod-ing to maximize both runtime performance and
code protection Encoded scripts can be run by the
free Loader product with a standard PHP server in
one of two ways The Loader can be installed in
php.ini, and this delivers the best performance and
is compatible with safe mode For users with no
access to php.ini, on many systems the Loader can
be installed “on demand” by the scripts themselves
This requires no php.ini edits or server restart
The Base Edition comes with a single user license
and, as with all current ionCube products, full
sup-port and upgrades are included for Free
To download an evaluation or purchase of the
standalone encoder, you can visit the ionCube
web-site at http://www.ioncube.com
Trang 8NEW STUFF
eZ publish 3 Released
ezPublish 3 is a professional open source content
management system and development
frame-work
As a CMS its most notable feature is its
revolu-tionary, fully customizable and extendable content
model This is also what makes it suitable as a
plat-form for general 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
For more info, visit the eZPublish website at
http://ez.no
phpOpenTracker 1.1.1 Is
Unleashed!
phpOpenTracker is a framework solution for the
analysis of Web site traffic and visitor behaviour
It features a logging engine that, either invoked
as a Web bug by an HTML image tag or
embed-ded with two lines of code into your PHP
applica-tion, logs each request to a Web site into a
data-base One installation can track an arbitrary
num-access the gathered data and perform complexoperations on it (for instance, the analysis of yourvisitors’ click paths)
For more information, visit the phpOpenTrackerwebsite at http://www.phpopentracker.de/
MySQL AB Launches MySQL 4.0, Announces Certification Program
MySQL AB, producers of the popularMySQL database management system,have announced the release of version4.0 of their flagship product, which isnow officially ready for production Meanwhile,they have started development of version 4.1,which will include such long-awaited goodies assubqueries
Through the MySQL certification program,MySQL software developers can earn one or moreformal credentials that validate their knowledge,experience and skill with the MySQL database andrelated MySQL AB products
The MySQL certification program consists of eral unique certifications The first, which is nowgenerally available, is called the MySQL CoreCertification The Core Certification providesMySQL users with a formal credential that demon-strates proficiency in SQL, data entry and mainte-nance, data extraction for reporting and more.The MySQL Professional Certification, which will
sev-be available in Q3 of this year, is for the moreexperienced MySQL user who wants to certify his
or her knowledge in MySQL database ment, installation, security, disaster preventionand optimization MySQL Core certification will be
manage-a prerequisite for tmanage-aking the Professionmanage-alCertification exam
MySQL also plans to offer a MySQL PHPCertification by the end of the year, which isdesigned for the MySQL and PHP developer whowants to simultaneously certify his knowledge ofMySQL and of the PHP Web development tool Inaddition, a MySQL DBA Certification, a top-levelcertification for the most accomplished MySQLgurus, will be offered in 2004
If you are interested and want to know more,check out the MySQL website at
http://www.mysql.com
PHP 4.3.2RC1 Released
The first public release candidate of the
lat-est version of PHP was posted for
down-load on the PHP.Net website earlier this
month The new version includes several
bug fixes and a few new features
com-pared to version 4.3.1, which was released
in February in response to a CGI-related
security issue
For more information, visit the PHP
web-site at http://www.php.net
Trang 10class library that easily enables you to generate
profes-sional quality graphs using a minimal amount of code
This article is a case study illustrating some of JpGraph’s
advanced features; specifically, it covers the following:
• a generalized methodology for JpGraph script
development
• the evolutionary process of developing a
graph (in contrast to presenting only the final
product)
• the use of server-side caching with JpGraph
for performance
• the use of Client Side Image Maps (CSIM) to
implement “drill-down” functionality in your
graphs
Installation and Environment
The easiest way to get started with JpGraph is to
down-load the source, available at
http://www.aditus.nu/jpgraph/jpdownload.php Next,
unpack the source archive into a directory in PHP’s
include path Now you can modify the paths to your
installed fonts, as well as to the cache directory These
settings are found in jpgraph.php.
testsuit.php file in the examples directory This page
generates over 200 example graphs using JpGraph,and allows you to review the code for each of them
If you’re just learning JpGraph and exploring its bilities, you will find the manual very handy It’s avail-able athttp://www.aditus.nu/jpgraph/jpdownload.php, andhas both a narrative text and an excellent class refer-ence You might also want to visit the JpGraph supportforum at http://jpgraph.fan-atics.com/
capa-All of the scripts in this article were developed andtested using PHP 4.3.0 (with the built-in GD2 library)running as a module under Apache 1.3.27 on RedHatLinux 7.2
The code in this article was developed using MySQL(http://www.mysql.com/) as a database, and ADOdb(http://php.weblogs.com/adodb) as a databaseabstraction layer To this end, all of the scripts include
a common file called phpa_db.inc.php, shown in
Listing 1
JpGraph
By Jason E Sweat
This article originated as a case study in the newest book
in the Wrox Handbook series: PHP Graphics
(http://www.wrox.com/books/1861008368.htm).
This material was omitted in the final publication of the
book, and was modified for presentation here
PHP Version: 4.0.4 minimum, 4.1 recommended O/S: Any
Additional Software: JpGraph, GD Enabled PHP
REQUIREMENTS
Trang 11FEATURES Advanced Features in JpGraph
This include file creates an ADOdb connection object
named $conn which is used to access the database
throughout the rest of the scripts You'll want to
change the Connect() call's parameters to reflect
your setup, including the name of the database you
create for the examples
ADOdb needs to be installed in a directory in PHP's
include path For readers unfamiliar with the ADOdb
API, I'll give a very brief overview of some of the basic
functionality In ADOdb you can fetch the results of an
SQL statement using
If your query is successful, this method will return an
ADOdb resultset object If not, the method will return
false Two resultset methods that are useful are
return a vector of rows where each row is an associative
array of 'COLUMN' => 'VALUE' The GetAssoc()
method will return an associative array, instead of a
vec-tor, where the index of the returned array for each row
is the value of the first column
The examples below assume that you have the type 'Arial' font installed If this is not the case, JpGraphwill emit an error to this effect An easy way to getaround this is change all of the references to the
a built-in system font, and while it won't look as pretty
That should be enough to get you through the ples ahead Let's take a look at the case study
exam-Case StudyOur case study will look at the sales data for the ABCCompany, a fictitious manufacturer of widgets ABCmakes everything from the economical $12.99 Widget
B through to the ultra-deluxe $1,499.50 Widget E Thisstudy focuses on the sales in the continental UnitedStates, in which the company is divided into fourregions The company sells to resellers via three chan-nels: the Internet, a call center and various retail outlets.You are asked to create a graph depicting the sales inunits and dollars You'll need to further split this graph
by catalog item for each sales region, and make a parison to the forecasted sales ABC also requires thatyou create a graph showing the year-to-date sales bychannel for each region They need to be able to nav-igate quickly between the two graphs
com-Database DesignSix tables compose ABC's data model The central
table is abc_sales This table tracks information
about sales, including the time, the sales channel, thelocation, the item, the quantity sold, and the revenuegenerated
$rs = $conn -> Execute ( $sql_statement ,
$bind_array );
<?php
error_reporting ( E_ALL );
require_once 'adodb/adodb.inc.php' ;
define ( 'MYSQL_DT_FMT' , '%Y-%m-%d' );
$conn = & ADONewConnection ( 'mysql' );
Trang 12FEATURES Advanced Features in JpGraph
The other tables making up the data model are
abc_catalog , abc_channel, abc_forecast,
abc_region , and abc_state_region The
abc_catalog table provides a surrogate key for
par-ticular items customers can purchase, a description of
the item, and the current unit price of the item The
abc_channel table provides a surrogate key, name
and description of the market channel an item can be
purchased through (web, phone or retail in this study)
The abc_forecast table stores a forecasted sales plan
by item, channel, region and month For each of these
"slices" of data, the quantity and revenue expected are
also stored The abc_region table stores the
surro-gate key and description for each of the company's
sales regions The abc_state_region table is a
map-ping between state abbreviation code and the sales
region to which the state belongs
The SQL used to create the tables, along with 'INSERT'
statements to populate the smaller tables, is included in
this article's source directory in the mysql_ddl.sql
file As for the other tables, the sales and sales forecast
data for the year can be simulated using the scripts
abc_gen_sales.php and abc_fcst_ins.php,
respectively abc_gen_sales.php needs to be run
first, as abc_fcst_ins.php depends on that data it
creates
Sales vs Forecast Graph
Our first task is to create a dynamic graph comparing
the number of units sold and the revenue of those sales
to the forecasts made for each region This information
is considered proprietary by the company, and is not
intended for public distribution They would like the
chart to indicate this
In developing PHP scripts to generate graphs using
JpGraph, I have found the following four-step process
useful:
1 Retrieve and manipulate the data for
plot-ting
2 Create the Graph object and set general
graph properties (like colors and plot axes)
3 Create the Plots to add to the Graph object
graphFollowing this process for graph development, youfirst need to retrieve the sales and forecast data To seehow you use ADOdb to retrieve the data for thesegraphs, please review lines 26-122 of the
abc_reg_sales_graph.php file The focus of thisarticle is on graphing, so the database retrieval andgraph data construction will not be covered in detail.Because the graphs being produced are by region,your script will need to accept and validate a parame-ter for the region If the value passed is a valid region,assign it to the variable $region_id If it is not valid,generate an error
There could be a little problem here Since the put of this script is a graph, your site will most likely
out-refer to this script using an HTML <img> tag, like so:
<img src="abc_reg_sales_graph.php">
If your script outputs a text message (like a PHPerror), this would result in an invalid image, and theonly thing a user will see is the missing image symbolwhere your graph was supposed to be The codeshown in Listing 2 validates the region, and shows how
to create a "graphical" error message This codeassumes you have already queried the database forvalid regions, and stored them in a global array called
Note: These scripts were originally written in
December of 2002 The data is simulated as if the
current date is December 15, 2002 in order to show
graphs with nearly complete data for the year.
Because it is now 2003, the scripts have been
modi-fied to query and show the prior year.
1 $region_id = check_passed_region ( 'region' );
10 if ( array_key_exists ( $parm , $_GET )) {
11 $val = $_GET [ $parm ];
12 if ( array_key_exists ( $val , $regions )) {
Trang 13FEATURES Advanced Features in JpGraph
the jpgraph.php and jpgraph_canvas.php
library files
After retrieving the "raw" data from your database,
you often need to manipulate it into a format better
suited for graphing This often means making a series
of zero-indexed arrays of single data series' Rather
than have different global arrays for each series, I
pre-fer to have a single associative array named
individual arrays The code in Listing 3 assembles these
pieces into the $graphData array, which will be used
for graphing
Now let's take a look at some of the data by drawing
your first graph This graph
will compare the number
of units moved to the
fore-casted number of units
that should have moved
Listing 4 shows the code
for this
This code highlights the
lightweight nature of the
JpGraph API As you
enhance the appearance
of your graphs, the code
will expand, but the lines
of code required to
pro-duce a functional graph
really are minimal
These few lines of code
complete the four-step
process outlined earlier In
step 2 you create and
con-figure the Graph object
1 $graphData [ 'f_qty' ] = array();
2 $graphData [ 'labelX' ] = array();
3 for ( $i = , $j = count ( $salesData ); $i < $j ; $i ++) {
4 $row = $salesData [ $i ];
5 if ( 'A' == $row [ 'short_desc' ]) {
6 $graphData [ 'labelX' ][] = strftime ( '%b' , mktime ( , 0 , 0 , $row [ 'm' ], 1 , $row [ 'y' ]));
7 }
8 if (! array_key_exists ( $row [ 'm' ]- 1 , $graphData [ 'f_qty' ])) {
9 $graphData [ 'f_qty' ][ $row [ 'm' ]- 1 ] = $fcstData [ $row [ 'f_key' ]][ 'qty' ];
10 $graphData [ 'f_rev' ][ $row [ 'm' ]- 1 ] = $fcstData [ $row [ 'f_key' ]][ 'rev' ];
11 $graphData [ 'qty' ][ $row [ 'm' ]- 1 ] = $row [ 'qty' ];
12 $graphData [ 'rev' ][ $row [ 'm' ]- 1 ] = $row [ 'rev' ];
13 } else {
14 $graphData [ 'f_qty' ][ $row [ 'm' ]- 1 ] += $fcstData [ $row [ 'f_key' ]][ 'qty' ];
15 $graphData [ 'f_rev' ][ $row [ 'm' ]- 1 ] += $fcstData [ $row [ 'f_key' ]][ 'rev' ];
16 $graphData [ 'qty' ][ $row [ 'm' ]- 1 ] += $row [ 'qty' ];
17 $graphData [ 'rev' ][ $row [ 'm' ]- 1 ] += $row [ 'rev' ];
18 }
19 if(! array_key_exists ( $row [ 'short_desc' ], $graphData )) {
20 $graphData [ $row [ 'short_desc' ]][ 'qty' ] = array();
21 $graphData [ $row [ 'short_desc' ]][ 'rev' ] = array();
22 }
23 $graphData [ $row [ 'short_desc' ]][ 'qty' ][] = $row [ 'qty' ];
24 $graphData [ $row [ 'short_desc' ]][ 'rev' ][] = $row [ 'rev' ];
25 }
Listing 3: Composing a single $graphData array
sales_graphdata_loop.php
$graph = new graph ( WIDTH , HEIGHT );
$graph -> SetScale ( 'textlin' );
$b1 = new BarPlot ( $graphData [ 'qty' ]);
$l1 = new LinePlot ( $graphData [ 'f_qty' ]);
Trang 14FEATURES Advanced Features in JpGraph
In step 3, you create a BarPlot object and a LinePlot
object You complete the process in step 4 by adding
the plots to the graph and using the
Calling Graph::Stroke() with no arguments will
make JpGraph stream the image directly back to the
browser from the PHP script The resulting graph is
shown in Figure 1
The regular style line graph does not really seem
appropriate for this graph, since the data is not really
changing over the course of the month (forecasts are
fixed for the entire month) The forecasts might be
bet-ter represented using the 'step' line graph
Let's incorporate this change and, while we're at it,
take a look at the revenue numbers instead You can
do this by changing the two plots as shown in Listing
5 The output is shown in Figure 2
The next step is to look at both units and revenue on
the same graph Management is more concerned with
meeting the revenue forecast, so forecast revenue
should be the only line graph superimposed on the
chart (as opposed to forecasted units) There are two
challenges here First, by looking at the two charts, you
can see that units and revenue are definitely on
differ-ent scales Second, it would be nice to figure out a way
to have the last step of the line graph plot over the
December bar
To represent units and revenue you will need to usethe second Y-axis feature of Jpgraph Ideally you woulduse a grouped bar graph JpGraph, however, does notallow us to add bars from different scales to the samegrouped bar plot What you can do is use a littledeception to accomplish this Make them two differentgrouped bar plots, and then trick JpGraph into believ-ing that they are next to another bar plot on the samescale by adding a plot to each with all zero values Theeffect here is that one scale has the zero-value plot onthe right, pushing the real plot to the left, while theother scale has the zero-value plot on the left, pushingthe real plot to the right When they are finally com-bined on the graph, they will appear to be a singlegrouped bar plot, but will actually be scaled on theirrespective axes You will need some new data toaccomplish this effect, which we can get in Listing 6
$b1 = new BarPlot ( $graphData [ 'rev' ]);
$l1 = new LinePlot ( $graphData [ 'f_rev' ]);
Figure 2: Using a step-style line plot
for ( $i = , $j = count ( $graphData [ 'labelX' ]); $i < $j ; $i ++) {
$graphData [ 'zero' ][ $i ] = 0 ;
}
//extend the forecast revenue line by repeating the last value
$graphData [ 'f_rev' ][ $j ] = $graphData [ 'f_rev' ][ $j - ];
Listing 6: Creating a zerio-value plot.
Trang 15FEATURES Advanced Features in JpGraph
You can create a callback function for formatting the
second 'Y-axis' labels JpGraph will then call this
func-tion for each value to be labeled on the axis, and will
use the value returned by the function rather than the
raw number This allows us to format numbers to
dol-lars, for instance, as shown in Listing 7
To generate the plot (shown in Figure 3), modify your
graph generation script to include the code in Listing 8
You have a very presentable graph now, but some
additional information would be useful The company
would like to be able to differentiate between the
dif-ferent widgets' contributions to unit sales and revenue
This can be accomplished by generating a 'stacked' bar
graph, to be added to each of the grouped bar plots
This is shown in Listing 9
This now results in the graph shown in Figure 4
We're almost there Just a little more formatting to
the plot area, axis titles and location of the legend isneeded Also, we need make sure that viewers areaware this graph is for internal purposes only
One technique for marking an image as proprietary is
to add a background image to it In this case, we'll usethe string "ABC Co Proprietary" turned diagonally andrepeated Note the color is much darker than youwould normally want to see on a "watermark" You canadjust this with the
can adjust the brightness, contrast and saturation ofthe image prior to use in the graph This can save youthe effort of doing this externally in an image-process-
ing program See the img/abc-background.png
“ the lines of code required to
produce a functional graph
1 $graph -> SetY2Scale ( 'lin' );
2 $graph -> SetY2OrderBack ( false );
3
4 //generate the individual plots
5 $b1 = new BarPlot ( $graphData [ 'qty' ]);
6 $b2 = new BarPlot ( $graphData [ 'rev' ]);
7 $b2 -> SetFillColor ( 'lightgreen' );
8 $b1z = new BarPlot ( $graphData [ 'zero' ]);
9 $b2z = new BarPlot ( $graphData [ 'zero' ]);
10 $l1 = new LinePlot ( $graphData [ 'f_rev' ]);
11 $l1 -> SetStepStyle ();
12 $l1 -> SetColor ( 'darkgreen' );
13 $l1 -> SetWeight ( );
14
15 //create the grouped plots
16 $gb1 = new GroupBarPlot (array( $b1 , $b1z ));
17 $gb2 = new GroupBarPlot (array( $b2z , $b2 ));
Trang 16FEATURES Advanced Features in JpGraph
file in this article's source directory for an example of
what this background image could look like
You can use this image as the background by using
the code shown in Listing 10
You can use the code in Listing 11 to add the
finish-ing touches like graph and axis titles, and to adjust the
legend placement The output of this code is shown in
Figure 5
For performance reasons, you decide to implement
the JpGraph image-caching mechanism on this graph
This caching is accomplished by saving a copy of your
graph as a file on the server Instead of generating the
image on-the-fly, this cached file is streamed back (if
the cached copy is still valid) Note that the web
serv-er must have write access to the directory in which the
cached images are saved
Instead of creating the Graph class instance with just
the width and height parameters, you will need to also
pass in a name for the cached image, a timeout value
in minutes (how long the image is valid), and a final
parameter telling JpGraph to continue to stream the
images This means that you will still use the PHP script
itself as the image tag's 'src' parameter The code
nec-essary to implement caching is shown in Listing 12
Note: There is a conflict with the
the GD2 library that comes bundled with PHP 4.3.0.
If you have upgraded to this version, you will have to
fall back to the method of adjusting the image with
an editor until the conflict is resolved.
Figure 4: Using stacked bars
1 $colors = array( 'pink' , 'orange' , 'yellow' ,
'lightgreen' , 'lightblue' );
2
3 $abqAdd = array();
4 $abrAdd = array();
5 for( $i = , $j = count ( $items ); $i < $j ; $i ++) {
6 $key = $items [ $i ][ 'short_desc' ];
7 $b1 = new BarPlot ( $graphData [ $key ][ 'qty' ]);
16 $ab1 = new AccBarPlot ( $abqAdd );
17 $ab2 = new AccBarPlot ( $abrAdd );
18 $b1z = new BarPlot ( $graphData [ 'zero' ]);
19 $b2z = new BarPlot ( $graphData [ 'zero' ]);
20
21 $gb1 = new GroupBarPlot (array( $ab1 , $b1z ));
22 $gb2 = new GroupBarPlot (array( $b2z , $ab2 ));
web.”
Trang 17FEATURES Advanced Features in JpGraph
Now if the same graph - for the same region - is
requested more than once within 24 hours (our
time-out value of 60 minutes * 24 hours) , the cached
ver-sion will be streamed back to the browser, and no code
after the 'new Graph()' line will be executed This
means that in order to maximize the gains from
caching you will want to move the Graph object
instan-tiation prior to any expensive database queries
if ( USING_TRUECOLOR ) {
$graph -> SetBackgroundImage ( 'img/abc-background_prefade.png' , BGIMG_FILLFRAME );
} else {
//AdjBackgroundImage only works with GD, not GD2 true color
$graph -> SetBackgroundImage ( 'img/abc-background.png' , BGIMG_FILLFRAME );
$graph -> AdjBackgroundImage ( 0.9 , 0.3 );
}
Listing 10: Code to use and adjust the background image.
background_image.php
1 $graph -> title -> Set ( date ( 'Y' ) " Sales for { $regions [ $region_id ]} Region" );
2 $graph -> title -> SetFont ( FF_ARIAL , FS_BOLD , 12 );
3 $graph -> SetMarginColor ( 'white' );
4 $graph -> yaxis -> title -> Set ( 'Left Bar Units Sold' );
5 $graph -> yaxis -> title -> SetFont ( FF_ARIAL , FS_BOLD , 10 );
6 $graph -> yaxis -> SetLabelFormatCallback ( 'y_fmt' );
7 $graph -> yaxis -> SetTitleMargin ( 48 );
8 $graph -> y2axis -> title -> Set ( 'Right Bar Revenue ( $ 000 )' );
9 $graph -> y2axis -> title -> SetFont ( FF_ARIAL , FS_BOLD , 10 );
10 $graph -> y2axis -> SetTitleMargin ( 45 );
11 $graph -> y2axis -> SetLabelFormatCallback ( 'y_fmt_dol_thou' );
12 $graph -> xaxis -> SetTickLabels ( $graphData [ 'labelX' ]);
13
14 $graph -> legend -> Pos ( 0.5 , 0.95 , 'center' , 'center' );
15 $graph -> legend -> SetLayout ( LEGEND_HOR );
16 $graph -> legend -> SetFillColor ( 'white' );
17 $graph -> legend -> SetShadow ( false );
18 $graph -> legend -> SetLineWeight ( );
Listing 11: Code to finalize the graph in Figure 5.
fifth_graph.php
Figure 5: Completed regional graph
define ( 'GRAPH_NAME' , 'abc_reg_sales' );
$graphName = GRAPH_NAME $region_id '.png' ;
Trang 18FEATURES Advanced Features in JpGraph
Region-by-Channel Graph
The second type of graph you were asked to create
shows the sales for each region by channel, and needs to
provide an easy way of navigating to the first graph you
constructed This type of report means viewing the
infor-mation in proportions, so a pie graph may be effective
Again, please review lines 22-82 of the
abc_map_graph.phpfile in this article's source
directo-ry to understand the database queries and array creation
for the following graphs
Listing 13 shows the code necessary to generate the
pie graph shown in Figure 6
You can expand on the use of background images that
was introduced in the first set of graphs, and add
addi-tional information to your graph Consider a map of the
United States showing the divisions of each region for
the ABC Company If you use this map image as a
back-ground for your graph, you can actually place the pie
charts on each of the regions to make it clear what
region the pie chart represents See the
img/abc-regions.png file in this article's source directory for
the example background image used here
To use this example, you will need to add a couple of
more lines to the $graphData construction loop to
allow for dynamic placement of the pie charts for each
region:
Now let's look at the entire code, shown in Listing 14,
to generate the graph in Figure 7
The company's final request was to be able to drill
down from these pie charts to the regional sales data
graphs you constructed earlier You can implement thisfeature using Client Side Image Maps (CSIM) CSIM is
an HTML technology allowing you to specify regions of
an image to associate with a hyperlink To implementCSIM for this chart, you will need to make the CSIM tar-gets (hyperlinks) and image alts (tips for the user)
First we'll define a constant containing most of thelink to drill down to
Now in the $graphData loop we'll populate the gets and alts:
tar-$graphData [ 'r' $rIndex ][ 'targets' ][] = DRILL_GRAPH $regionData [ $i ][ 'region_id' ];
$graphData [ 'r' $rIndex ][ 'alts' ][] = "Click for more information regarding
{ $regions [ $rIndex ][ 'region' ]} sales." ;
Figure 6: Simple pie chart
$sliceColors = array( 'lightgreen' , 'pink' ,
'lightblue' );
$graph = new PieGraph ( WIDTH , HEIGHT );
$graph -> title -> Set ( $regions [ $region ][ 'region' ]
' Region' );
$graph -> subtitle -> Set ( 'Sales by Channel since '
GRAPH_START );
$p1 = new PiePlot ( $graphData [ $pickRegion ][ 'rev' ]);
$p1 -> SetLegends ( $graphData [ $pickRegion ][ 'label' ]);
Trang 19FEATURES Advanced Features in JpGraph
Because there is now HTML information (the CSIM)
in addition to the binary image content, you can't
stream it back to the browser like you normally would
The CSIM and the image depend on each other too
much In order to make this work, you need to cache
the image This allows you to output the image map,
as well as the image tag used to fetch the cached
image Instead of using the JpGraph cache outlined
above, we'll use another form of image caching and
store it in a place where we can request it directly To
accomplish this you will need to create a directory
called img immediately below the script directory This
directory must be writeable by the web server
When you are creating the graph, treat it as if you
were going to stream the image In the pie chart loop,
add the CSIM information like so:
To output the graph, use the code in Listing 15
This code instructs JpGraph to output the image to a
file called img/abc_channel_graph.png You then
fetch the image map generated by the graph into the
incorporated into a larger valid HTML document, buthere you can see the coupling between the image mapand the image tag The image tag specified allows the
$p1 -> SetCSIMTargets (
$graphData [ $pickRegion ][ 'targets' ]
$graphData [ $pickRegion ][ 'alts' ]
);
1 $graph = new PieGraph ( WIDTH , HEIGHT );
2 $graph -> SetBackgroundImage ( 'img/abc-regions.png' , BGIMG_FILLFRAME );
3
4 for ( $i = ; $i < $rIndex + ; $i ++) {
5 $pickRegion = 'r' $i ;
6
7 $p1 = new PiePlot ( $graphData [ $pickRegion ][ 'rev' ]);
8 $p1 -> SetCenter ( $graphData [ $pickRegion ][ 'map_x' ],
9 $graphData [ $pickRegion ][ 'map_y' ]);
Trang 20FEATURES Advanced Features in JpGraphimage to use the generated map.
Key Concepts
The following concepts, related to graphing and
JpGraph, were introduced or emphasized in this case
study:
• the use of the JpGraph Bar, Line and Pie plot
types
• the use of stacked and grouped bar graphs
• the use of an alternative scale on the Y axis
• the use of a callback function to perform
for-matting of labels
• the generation of error messages in an image
• the creation of a "watermark" using a
back-ground image
• the use of the JpGraph image caching - forboth performance, as well as to facilitate use
of the CSIM feature
• the use of a background image as part of thecharts information content (pie chart location
on the sales by region chart)
• the use of CSIM for drill-down capability ongraphs
ConclusionJpGraph is a lightweight API that allows you to quicklygenerate professional looking graphs CouplingJpGraph with PHP's database access capabilities pro-vides you with a powerful toolset for the generation ofdynamic graphs on the web This article has intro-duced you to some of the more advanced features ofJpGraph like caching, background images and ClientSide Image Maps Hopefully you are now familiarenough with these technologies for you to considerusing PHP and JpGraph for your next data mining proj-ect
define ( 'IMG_DIR' , 'img/' );
$graphName = IMG_DIR 'abc_channel_graph.png' ;
$graph = new PieGraph ( WIDTH , HEIGHT );
//the rest of the graph code
$graph -> Stroke ( $graphName );
$mapName = 'ABC_Region_Drill' ;
$imgMap = $graph -> GetHTMLImageMap ( $mapName );
print <<<EOS
$imgMap
<img src="$graphName" alt="ABC Sales by Channel"
ismap usemap="#$mapName" border="0">
EOS;
Listing 15: Code to handle CSIM's.
csim_stroke.php
Jason has been an IT professional for over ten years He is currently an application developer and intranet webmaster for a Fortune 100 compa-
ny He has written several tutorials and articles for the Zend website, and has recently contributed to the Wrox "PHP Graphics" handbook He resides in Iowa with his wife and two children.
Click HERE To Discuss This Article
https://www.phparch.com/discuss/viewforum.php?f=12
Publish your data fast with PHPLens
PHPLens is the fastest rapid application tool you can find for publishing your databases and creating sophisticated web applications Here’s what a satisfied customer, Ajit Dixit of Shreya Life Sciences Private Ltd has to say:
I have written more than 650 programs and have almost covered 70% of MIS, Collaboration, Project Management, Workflow based system just in two months This was only possible due to PHPLens You can develop high
quality programs at the speed of thinking with PHPLens
Visitphplens.comfor more details Free download
Trang 21It seems like every book I read on PHP has a chapter on
forms Of course, form handling is what server-side
languages are usually employed for, so it is good to see
it get this kind of coverage Unfortunately, most books
only provide slightly more information on form
pro-cessing than you’d find in a good HTML book They
usually only cover how to build a form, what the data
comes through as on the other side, and some
com-mon uses for it
So, while I know what forms are, what they’re for,
and how I can use them, I have yet to read a book (or
article) that answers my age-old question: What’s a
good way to validate forms?
Obviously, ‘good’ is the operative word here, and is
based solely on my opinion To be fair, I have seen
books and articles that talk about form validation They
just don’t talk about it the way I think it needs to be:
atomic I mean that the validation engine should be
fully-encapsulated Validation atomicity comes
part-and-parcel with functional separation You shouldn’t
be doing a check here and then a check there,
inter-spersed in the same script that will be using the data to
perform some operation Form validation needs to be
a separate entity You should know if it succeeds or
fails, and then be free to take the appropriate action
Over the course of this article, I’m going to talk about
the form validation system that I have developed This
system may be a little different than what you’re used
to, but it’s robust, reliable, and very extensible
I will first examine an evil necessity for our purposes:dynamic form generation Following this will be a dis-cussion of the form validation techniques presentedhere After all of this theory, I’ll throw a couple of class-
es at you, and tie it all together with a nice example.This should leave you feeling refreshed and invigorated,and ready to tackle your next form validation project.Let’s go
Dynamic Form Generation
In order to fully encapsulate the process, we will want
to build our form elements dynamically If you follow
phpclasses.org or hotscripts.com, you probably know
that everybody and their dog has created a class tomake form creation ‘easier’ While I’m not personallyconvinced that this is necessarily better or easier by
itself, it will make the rest of our process easier I’ll
dis-cuss, in detail, the reason for this a little later
In recognition of the composite nature of a form, wewill (just like everybody else’s dog) use a set of classesfor this task A number of element classes (Text, Button,
By Peter James
Staff editor and veteran PHP pro Peter James approaches
the age old problem of form validation from a new and
interesting perspective.
PHP Version: PHP 4.3 O/S: Any
Additional Software: N/A
REQUIREMENTS
Trang 22FEATURES Form Validation From the Outside In
Checkbox, etc) and a main form class should provide all
of the functionality we need
A form usually contains one or more form elements,
and one or more of a number of form tag attributes In
order to provide the most value, the form class needs
to follow a few guidelines, listed below It should
• provide intuitive defaults for the standard form
tag attributes (like method, etc), so that
sim-ple forms are easy to create
• provide an easy way to add extra attributes to
the form tag
• provide a simple way to add form elements to
the form
• be flexible enough to handle new form
ele-ment types transparently
Following the above guidelines will make the class
more robust and durable Let’s look at how the form
element classes fit into the picture
Each form element type can be represented with a
class The interface to the element classes should be
loose and generic Methods
should be provided for
things like setting the value
of the element, getting the
HTML representation of the
element, and adding tag
attributes to the element
Because there will be a
large amount of functionality
that is common across the
different element types, it makes sense to build an
abstract form element class, and have each type of
ele-ment class extend it This will also ensure that it is easy
to add a new element type You just extend the base
class and add to it to meet the needs of the new type
Easy as pie!
Once the form composition is done, the user should
be able to get the HTML representation of the form,
including all elements, for layout Some form classes
provide built-in layout capability In the interests of not
introducing any unnecessary limitations, I won’t deal
with this functionality here
“So,” you ask, “why do we need to dynamically
gen-erate the form to do validation?”
It all comes down to control It’s the same reason
that when you sell your house, your lawyer takes care
of all disbursements What if they gave you all the
money, and you decided that you’d rather live in a nice
tropical country with no extradition agreements? The
lawyer wants to make sure that they get paid, and that
the bank gets paid, and that the realtor gets paid
Likewise, while we technically don’t need to
dynami-cally generate the form, it makes sure that things
oper-ate in a consistent way, and that everything about the
erate the form, we know what type of form elements,
as well as how many, are present We know their ues, attributes, and names We are omniscient aboutthe form, and that is invaluable when we want to vali-date that form
val-Now that we have an idea of how the dynamic formgeneration will work, let’s explore how we’re going tovalidate forms
Form Validation in a NutshellAlthough web applications are state machines, the pro-tocol the web is built on (HTTP) is ironically stateless.Sessions are most commonly used to circumvent thislimitation, and they will play a large role in how we will
go about validating forms
Sessions allow us to maintain state, which means wecan develop our applications in a manner more similar
to client-side (desktop) development Client-side cations start and end with the user When the userstarts MS Word, an environment is created that knows
appli-as much appli-as it needs to about what they are doing Thisenvironment, containing their document, undo levels,
comments, an so on, is alivefor as long as they are work-ing When they are done,the environment isdestroyed
Compare this to a webapplication such as a con-tent management system.Every single time a user per-forms an action, the systemstarts from zero It must recognize who the user is,determine what actions they are allowed to take,understand what action they are trying to take, loadany context necessary, perform the action, store anycontext, output to the user, and exit back to zero This
There are many ways to do most things, and formprocessing is no different Some people, for instance,like to mix the screen and action code This means that
" You shouldn't be doing a check here and then a check there, inter- spersed in the same script that will
be using the data to perform some
operation."
Trang 23FEATURES Form Validation From the Outside In
process it A short example of this is shown in Listing
1
I have done a lot of this in my career It’s very
effi-cient, and allows you to display errors easily If the
val-idation code runs into a problem, you can abort
pro-cessing of the action code, and just redisplay the form
with the errors This is nice for most forms where there
are required fields If your validation code executes
cleanly and you don’t want to display the form, then
you can take any number of actions (exit, return, or
include another file, etc) This provides lots of options
The bad thing about this is that it promotes the
mix-ing of validation and processmix-ing with content You
might feel that there is a strong coupling between
val-idation code and processing code, but that is similar to
saying that there is a strong coupling between the
application and the presentation layer in a web
applica-tion A strong link between them is undeniable, but
there are big advantages to achieving maximum
sepa-ration
Another common way to process forms is to have
separate action pages and screen pages This means
that the screen resides in one file, and the form’s action
will point to the action page (whereas in the above
example it pointed to itself) This achieves better
sepa-ration, but still mixes the validation and processing An
even better way to process forms is to split it all out,
and have screen pages, validation pages, and action
pages This could quickly become unwieldy, though
All of the above methods suffer from redundancy and
duplication of effort You will no doubt need to do
sim-ilar types of checking on many forms With form
check-ing code all over the place, you may end up writcheck-ing in
the same functionality needlessly Function libraries are
an obvious solution to this
While there is nothing technically wrong with the
above solutions, they all miss the boat in terms of
encapsulation and atomicity No matter how long you
look at them, they are not clean, oiled form-validating
machines I think that perhaps the above methods are
looking at things from the wrong angle They are
look-ing at it on a need-by-need basis “I need a function
that checks this ”, rather than asking “what do I need
to check this form element for?” While we can slice upvalidation functionality along other lines, I believe thatthe best way is to slice it along form element lines
Validating on an element-by-element basis gives us agreat deal of power Attaching form validation ability
to each element means that an element can essentiallyvalidate itself By extension, his means that a form canessentially validate itself
Unfortunately, the reality of validating a form in thisway requires that we know everything about what ele-ments are in the form How can we do this on thereceiving side without any of the above methods? Wereally can’t Sure, we can check for what variablescame through, but we’d have to set up some expectantcode on the receiving side, and that really wouldn’t beany different than the above methods
It seems that we’ve come full circle The reason that
we need the dynamic form generation might now bemaking itself clear We build the form using our formobject, specifying how to validate each form elementwhen we create it Now we’ve got all of the informa-tion about the form, as well as how to validate it, in oneobject Unfortunately, this object is only available when
we make the form, not when we validate it
The need for the session now becomes obvious Inorder to validate the form, we need the form validationcode on the receiving side of the request Rememberthat we set up the form validation code on the initiat-ing side of the request, when the form was created Bystoring the validation configuration (the form object) inthe session, we are able to validate the form on thereceiving side atomically
In the end, this method might look a little
complicat-ed It really isn’t, especially considering the complexitysavings we’ll experience when we use it Not surpris-ingly, doing form validation this way satisfies the atom-icity and logical separation requirements that werespecified earlier It also means that when a formchanges, the validation changes are made in the samespot, reducing the risk of introducing subtle bugs andinconsistency
Specifying Form ValidationEarlier, we set up a bunch of requirements for formgeneration Now let’s look at some requirements forform validation
Specifying form element constraints should be easywhen it’s simple, and possible when it’s not If it’s asimple check, it should be easy to specify If it’s a com-plex check, like a multi-step dependency check, itshould still be possible to do This simply is not a use-ful solution if we can’t extend it to handle the specialcases
Constraint specification (what makes a form elementvalid) should be consistent, too One form elementtype shouldn’t implement a common check differently
1 <?php
2
3 // start action code
4 if (isset( $_REQUEST [ 'foo' ]))
13 <form action=" <?php print $_SERVER [ 'PHP_SELF' ];
14 <input type="text" name="foo" value="" />
15 </form>
Listing 1
Trang 24FEATURES Form Validation From the Outside In
than another The constraint specification interface to
a text box should be intuitively similar to a text area,
since they are similar in function
Because we are looking for atomicity, there must be
an easy way to see if a form is valid or not By
exten-sion, this is also a form element requirement
I think that we’ve talked enough talk, and we should
get busy on walking the walk Let’s get to some code
The Classes
The first class we’ll develop is the main form class It is
listed in Listing 2 (provided in this month’s code
pack-age)
Let’s examine the code listing in Listing 2, and talk
about the method (pardon the pun) to our madness
The constructor, Form(), simply takes an identifier as
an argument The identifier is the value of a form
vari-able that will identify the form Basically this translates
into a hidden field in the form with a name of “_form”
It’s really helpful when you have multiple forms on a
page It is used to identify the particular form object in
the session, so you know which form object to validate
with This should become clear a little later
the form The $element variable is an object derived
from the abstract form element class
name attribute for the form The name of the form
defaults to ‘form1’ The form name is really only useful
for client-side scripting, such as JavaScript, and can
usu-ally be ignored
method used to transfer the data to the server, and
defaults to ‘get’ This is generally either ‘get’ or ‘post’
associated with the form It defaults to
current page This is a common action, especially if you
are using a central controller script that delegates by
inclusion
window or frame of the form This is the window or
frame that will display the results of the submission It
defaults to ‘_self’
form tag attributes It accepts an attribute name and
an attribute value, which will be entered into the tag as
name=”value” You can add as many extra attributes
as you need As an example, you might add an “
enc-type” attribute with a value of “
multipart/form-data” if you were creating a file upload form
checks as to whether the form that was created by this
object was actually the one submitted on the last
request This is what the form’s identifier (from the
constructor, above) is used for If
then the form was submitted This function is used onthe receiving side of the form submission
our atomicity This function checks first if the form wasactually submitted (using the above function) and, if
so, loops through each element in the form to mine if the form itself is valid If any of the form ele-ments are not valid according to their own definitions,the form is not valid This function is also used on thereceiving side of the form submission
HTML representation of the form’s tag, including all ofthe specified attributes
gets the HTML representation of the hidden field thatcontains the identifier variable passed into the con-structor
gets an array of the HTMLrepresentations of the formand all of its elements It firstgets the form tag and theidentifier tag, then it loopsthrough all of the elements inthe order in which they wereadded Finally it adds theclosing form tag to the array
This array is indexed by ment name for layout pur-poses
function returns an array of messages produced by theform validation
the form object to access a form element’s value Thisfunction is generally used on the receiving side of theform submission
As you can see, this is a simple but powerful class forform creation and validation Now let’s see some of itspartners in crime: the form element classes
The abstract form element class is shown in Listing 3(provided in this month’s code package)
It’s not meant to be instantiated and implements a lot
of the element functionality Let’s walk through it
The class constructor, FormElement(), is used toset the properties common to all elements: type andname
to the function by the same name in the form class Itjust allows us to add extra attributes to the form ele-ment tag
said earlier that we were going to avoid any layoutcapabilities in the classes, but this looks suspiciously like
a layout capability Actually, this is mainly for the radiobutton elements Since radio buttons are really a num-
"A strong link between (validation code and content)
is undeniable, but there are big advantages to achieving maxi- mum separation."
Trang 25FEATURES Form Validation From the Outside In
allows you to layout the radio buttons If you’re
adven-turous, you could use this to provide limited layout
capabilities for other element types A sample layout for
radio buttons forming a boolean entry are shown
below This simply augments the HTML being
generat-ed for a set of radio buttons It takes a standard
printf() format
provided by set_format() to the element’s HTML
representation Any class, like the radio button element
class, that has special formatting
requirements would override this
function
func-tion specifies whether the form should
look for a $_REQUEST variable with
the same name as the element, and
use this as the element’s value when
displaying it This is handy when
redisplaying a form after an invalid
submission The default is to use the
will display the invalid values back to
the user automatically, which is nice
Any call to the set_value() function (described
below) will override this setting and use the value
pro-vided to it
pro-vides these classes with their immense extensibility It
allows the user to specify either an element-specific
check such as ‘regex’ (for textboxes) or ‘selected’ (for
dropdowns), or an external function An external
func-tion receives the validating element’s type, name and
value It returns true or false based on if the value was
found to be acceptable or not You can add as many
checking methods as you want This function accepts
an optional fourth parameter that is useful when
speci-fying an external checking function This parameter
allows you to specify the external file containing the
checking function (in case it’s not normally loaded)
The private _run_check_function() function is
used internally to actually implement the call to the
specified checking function(s) This function returns
true or false based on whether the check came back
successful or not
set-ting of element values You might use this with the
radio button form element to specify a default
selec-tion If no value is specified to this function, any
avail-able $_REQUEST value will be used if allowed by
abstract method It is meant to be implemented insubclasses, and should return the HTML representationspecific to the element In most cases this will just
return one HTML tag (an <input> tag) For radio
buttons, select boxes, and text areas, however, itreturns a set of HTML tags with some text
self-valida-tion It is called by the form class when the form isasked if it’s valid This function runs through all of thechecking methods that were specified for the element(if any) If a checking method returns false, which
means the value was not acceptable,
this element, and returns false to thecalling class (the form class)
The final function in this class,
method This is the function that
and must be implemented in the class according to the particular ele-ment type’s special checking require-ments A select box form element, forexample, exposes three checkingtypes: ‘selected’, ‘func’ and ‘’ The firsttype checks whether a selection was made from the thebox (applies when the default selection is not a validselection – like ‘select one’) The second type is present
sub-$e -> set_format ( ‘True % s & nbsp ; False % s’ );
7 // allows checking types:
8 // * 'regex' - pattern matching
9 // * 'func' - user-defined function
15 // call parent constructor
16 $this -> FormElement ( 'text' , $name );
Trang 26FEATURES Form Validation From the Outside In
in all elements, and is the external checking
function method The third type specifies no
checking method (we don’t care what the
value is)
As you can see, the base class takes care of
most of the form elements’ dirty work Our
element classes only have to implement a
minimal set of specific behavior For example,
in the text box element class, shown in Listing
4, only four methods have been defined or
overridden (and one of them is the
construc-tor!) Have a look at the class in Listing 4, and
then I’ll run through it
constructor, and in this class its function is
simply to call the parent class constructor In
other classes, such as the radio button class or
the select box class, it also sets up all of the
selection options
imple-ments the text box element’s built-in regular
expression checking This is the function that
is called when you specify the check method
to be ‘regex’ Other elements will have
func-tions specific to their operation In the select
box element class, there is an
built-in ‘selected’ check method
implementation of an abstract method from
the base form element class It simply returns
the HTML representation of the element
Assuming that the format has not been
mod-ified, this will return the ‘input’ tag for the
text box Other elements, such as the radio
button element, may return a number of tags in a
for-matted string
The final function, check(), is also a required
imple-mentation of an abstract method It implements thevalue-checking capabilities of the element This gener-ally includes at least one element-specific check such as
‘regex’ or ‘selected’ (specific to dropdowns), tioned earlier
men-In the interests of variety, and so that we can provide
a useful example later, lets look at another form ment subclass The class for the submit button is listed
ele-in Listele-ing 5
As you can see, there’s very little difference in theinterface to the subclass, which makes sense
and, like the FormTextbox() constructor, it calls theparent constructor The submit button class has anextra variable, $desc, that holds the button title This
is also set in the constructor
implementation from the base class It simply returnsthe HTML representation of the element
implemen-tation from the base class It simply directs the calls to
28
29 // render the element and return it
30 function get_element ()
31 {
32 $element = "<input type=\"text\" "
33 "name= \"{ $this -> name }\" "
34 "value= \"{ $this -> value }\" " ;
35
36 // add extra attributes
37 foreach ( $this -> attributes as $attribute => $value )
16 // call parent constructor
17 $this -> FormElement ( 'submit' , $name );
18 $this -> desc = $desc ;
19 }
20
Listing 5
Trang 27FEATURES Form Validation From the Outside In
The submit button form element is a great deal
simpler than any other element Mainly, this is
because it doesn’t implement any checking
capabilities With very little effort, checking
capabilities could be added to the submit
but-ton, although they probably have little use
So that’s it! Now we need an example to tie it
all together Since I only introduced the text box
form element and the submit button form
ele-ment, we’ll keep it simple That said, it should
still serve to demonstrate how powerful this
solu-tion is
An Example
Our example will be a very simple form
contain-ing a scontain-ingle text box and submit button The
value of this text box upon submission must be
numeric and even Let’s take a look at the code,
shown in Listing 6
We start out by simply including the Form.php
class file It takes care of all other dependencies
for us, so we don’t have to load any elements
Next, we start the session This is critical because
the form creation and validation code won’t
work without it Remember, the form object is
stored in the session for use on the next page
Next we check if the form was submitted on
the previous page If it was, we check if it’s valid
If the form checks out, we display a message,
‘form was valid’, to the user and exit
If the form was not valid, we display the error
mes-sages On a real form, these might be requiring the
user to enter an email address, or a postal code Next
we get into the actual form specification Considering
what we’re doing, the form specification is a fairly
non-intrusive process
We put two constraints on the text box element
One is a regular expression that requires a number The
other is a custom function that checks that the number
entered is even They have their own error messages sothat you can play around and see which constraint istaking effect Notice how simple it is to extend the val-idation with user-defined functions
The last step in the form generation is to output theform You can see how this form class lets you retaintotal control over the layout process The form isreturned in an array from the get_form() call
Although all elements are accessed by their names,there are two special indices: ‘form_start’ and
‘form_end’ These contain the form start tag and tifier hidden field, and the form end tag, respectively
iden-At the bottom of the file the custom checking tion is implemented We’re done! Play with this exam-ple a bit, and think about the flexibility it offers Forexample, by using a user-defined function, we can per-form form validation with information from a database,socket, or other external resource The possibilities real-
func-ly are limitless
As an example of how this form class could be usedfor other tasks, think about authentication Rather thanvalidating the form elements against ‘regular’ criterialike patterns, we could validate against the database,and check login information
Further Extension andImprovement
The form class, as it stands, is very useful and very
21 // render the element and return it
22 function get_element ()
23 {
24 $element = "<input type=\"submit\" "
25 "name= \"{ $this -> name }\" "
26 "value= \"{ $this -> desc }\" " ;
27
28 // add extra attributes
29 foreach ( $this -> attributes as $attribute => $value )
Listing 5: Continued from Page 26
dynamic web pages - german php.node
news scripts tutorials downloads books installation hints
D y namic Web Pages
www.dynamicwebpages.de
sex could not be better |
Trang 28FEATURES Form Validation From the Outside In
extensible As always, however, there’s a ton of room
for improvement and further abstraction
Each element contains only one or two specialized
checking methods (regex or selection, for example)
Adding more specialized text-checking methods like
‘email’, ‘phone’, and so on, would add lots of value,
and would cut down on the number of custom
func-tions that are required
Some current limitations of the class are a lack of
error checking There is lots of opportunity for
incor-rect input here Checking that user-defined callback
functions actually look like functions, and that they
exist, for instance, would be a good idea All of the
input to the classes should be checked for correctness
ConclusionAlthough the technique is a little unconventional, thisform validation solution performs well It excels inextensibility, atomicity and separation It provides aconsistent interface to the developer, and allows forfuture expansion of the types of form elements andattributes
In short, it provides a lot and assumes very little
Peter James is a developer and team lead working in Edmonton, Alberta.
In his spare time he tries to magically juggle his family, freelance work, tool development and learning You can reach Peter at
7 // check the forms validity
8 if (isset( $_REQUEST [ '_form' ]))
23 // set up the form and validation tests
24 $f = &new Form ( 'foo' );
25 $tb = &new FormTextbox ( 'foo_textbox' );
26 $tb -> add_check_method ( 'regex' , 'Invalid entry by regex' , '/^\d+$/' );
27 $tb -> add_check_method ( 'func' , 'Invalid entry by func' , 'foo_textbox_check' );
28 $sb = &new FormSubmit ( 'foo_submit' );
41 // special checking function (checks if the value is an even number)
42 function foo_textbox_check ( $type , $name , $value )
Trang 29PHP is an Open Source
scripting language with serious
technical muscle No wonder it’s the
language of choice for Yahoo, Inc and
over 8 million domains worldwide Whether
you’re a PHP pro or completely new to the language,
PHPCon East 2003 will take you to the next level
Meet and mingle with the experts during two conference days
PHPCon East 2003 Speakers include:
• Rasmus Lerdorf, Opening Keynote Speaker and Inventor of PHP
• Zeev Suraski, Closing Keynote Speaker, CTO of Zend
• Zak Greant, MySQL.com
• Shane Caraveo, ActiveState, Inc
• Luke Welling and Laura Thompson, Tangent Technologies
• George Schlossnagle, OmniTI
Technical learning at all levels
PHPCon has a full day of hands-on, technical
tutorials that offer something for everyone, including:
CHECK OUT THE PROGRAM
& REGISTER TODAY! http://www.php-con.com/pa
PHPCon East 2003 Park Central New York Hotel New York City, New YorkApril 23 - 25, 2003
Live PHP!
Use PHP?
Love PHP?
(for three days)
Trang 30We all come to open source software from different
tracks and for different reasons Because you are
reading this, you are at least somewhat interested in
open source and may even be an open source
advo-cate Your interest in open source web application
development has led you to PHP (I believe I can safely
assume this because you are, after all, reading a
maga-zine focused on PHP!) For myself, incorporating and
utilizing PHP (and open source software in general) into
my arsenal of tools was an evolutionary process It
start-ed slow, building steam to where I am now: a full
blown open source/PHP advocate
Of Zines and other things DIY
I was seriously involved in the underground zine
pub-lishing community for many years A zine (pronounced
“zeen”) is defined as a small publication typically
cov-ering non-mainstream topics published by an
individ-ual or a small group for the sole purposes of expression
and communication Zines are part of the much larger
DIY community The DIY (Do-It-Yourself) community is
comprised of independent musicians, record
compa-nies, distributors, zine publishers, artists, designers,
small business, writers, publishers, and crafts people
When I started dabbling in web development I found
that there was almost no representation on the web for
this extremely dynamic community I got down to
to catalog DIY projects on the web DIY’ers could entertheir URL on their own, and make it available to otherDIY’ers Diysearch was a place where DIY’ers could findother projects like their own, or look for resources fortheir projects
When I started working on Diysearch, I found outrather quickly that just plain HTML pages just weren’tgoing to cut it with respect to what I wanted to do Iwanted interaction and user participation, and had NOclue what made this possible That’s when I stumbledacross a few free Perl CGI scripts (a guestbook and alinks database/search engine script) I started playingaround with them and, even though I didn’t reallyknow what I was doing, it was fun Just getting thethings to work provided me with an incredible oppor-tunity to learn something Diysearch was born
So as it turned out, I came to the open source campquite by accident As a hapless newbie “hacker” dab-bling in Perl CGI in 1994, I was almost completelyunaware that there was an actual name for this com-munity movement
After many years, Diysearch strayed away from open
Freedom
By Dave Palmer
Veteran web application developer Dave Palmer shows you how to create killer
sites without being killed by things like vendor lock-in, software licenses and
expensive, yet inflexible and incomplete software tools
PHP Version: 4.3 or Above O/S: Any
Additional Software: N/A
REQUIREMENTS
Trang 31FEATURES Porting and Migrating and the Move to PHP
source and into the realm of propriety via ColdFusion
It suited me just fine The site worked, the user base
continued to grow, and I added patches here and there
as needed A few more years went by Finally, a few
months ago, I had an epiphany: Diysearch was a total
wreck The software I wrote was showing its age in a
big way (it was last updated in 1998!) Users were
growing frustrated over the lack of new functionality, as
well as the inability to manage the links they submitted
It finally occurred to me that it was time to re-engineer
the site
Over the years I had become more and more
involved in the open source community, mostly just by
adopting a lot of open source technology and making
minor contributions here and there I decided it was
now time to make a real commitment to open source
with something I had a vested interest in: my silly little
side project
I knew there was no way I would re-engineer the site
using ColdFusion Having worked with ColdFusion
since the “version 1.5” days, I am intimately aware of
all of its shortcomings and faults Because of this, I
decided that PHP would be my web application
plat-form of choice for this porting and migration project
I had come to PHP several years earlier when
explor-ing other options outside of CGI scriptexplor-ing (back when
PHP was still called Personal Home Page) I liked it
because it looked like Perl and worked like ColdFusion,
but I never gave it much thought I worked a little bit
with PHP here and there over the intervening years, but
it wasn’t until about a year ago that I saw it’s potential
I developed a commercial e-commerce site for a
com-pany in Atlanta using nothing but PHP (on Linux with
MySQL), and finally realized that this PHP stuff was for
real It became clear to me that PHP (pardon the
intro-duction of controversy) was technically (and in my
mind politically) superior to ColdFusion
With this minor revelation in hand, I set out to
con-vert Diysearch from a collection of ColdFusion hacks
into a unified and homogenous PHP-based web
appli-cation Having a revelation is one thing, but turning
that revelation into reality is something else entirely
The idea of writing a content management system
from scratch (which I had done before on many
occa-sions, but in a proprietary fashion) with user
manage-ment, link database managemanage-ment, and a sophisticated
search engine was just something I was not really into
doing
Enter PHPNuke
After several fits and starts and not really getting
any-where, something occurred to me The problem I was
trying to solve had already been solved in a whole slew
of different ways, many of which could be found in the
open source universe After some deliberation, I settled
on using PHPNuke (http://www.phpnuke.org)
For those that are not aware, PHPNuke or “Nuke”
-is an open source content management and portalmanagement system written in PHP Nuke implements
a modular design where all major pieces of
functionali-ty are set up as a group of modules Each moduleresides in a designated directory where the Nuke “ker-nel” can be made aware of the module Each moduleincludes a few lines of code to comply with the Nukemodule standard, but from there on out is writtenspecifically for whatever functionality the module isdesigned
This design, coupled with its “theme-based” and-feel implementation, made it quite suitable forwhat I needed to do Diysearch is a community-orient-
look-ed site with a strong concentration on user interaction.While Nuke was quite strong “out-of-the-box”, it was inneed of some changes for what I needed to do.Diysearch had specialized requirements that the Nukedevelopment team could not have anticipated Theseincluded:
•An upgraded search engine
•The ability for users to add, edit or delete linksthey “own”
•A “review” process for links submitted by users(to eliminate violations to the acceptableusage policy)
•A customized banner management and tion application (to enable real-time bannerpackage purchasing integrating with PayPal’sIPN system)
rota-•A volunteer mechanism to enable interestedusers to volunteer time in the managementand upkeep of the site
Working with modules in PHPNukeAdding new functionality to an existing framework orapplication typically ranges from being a difficult task(at best) to being nearly impossible (at worst) Because
of Nuke’s thoughtful design, adding new functionality
is a clear and straightforward process requiring a fewsteps These steps are a mixture of writing new code(your functionality) and modifying certain pieces ofNuke code
Actual functionality is often encapsulated in what isreferred to as a “module.” A module lives in a specifi-cally named directory under the main “modules” subdirectory and contains one or more PHP scripts Eachmodule contains an index.php script that includes aswitch statement for traffic control, and function defini-tions for carrying out the specific tasks See Listing 2 for
an example module’s index.php script, which shows
specifically what a module might look like This ule, called “Volunteers”, is responsible for enabling
Trang 32mod-FEATURES Porting and Migrating and the Move to PHP
users to sign up as a volunteer It’s a very simple
exam-ple, but clearly illustrates what modules consist of and
how they fit in the Nuke infrastructure
Taking a look at the anatomy of this (or any other)
module, you will notice the following at the top of the
index.phpscript:
This bit of logic implements some very basic security
so that malicious users cannot try to access the module
file directly; all requests must come through the main
‘modules.php’ script (in the root directory)
After this initial security check, you will notice several
function definitions which are responsible for carrying
out the specific tasks the module is responsible for In
keeping with the self referencing pattern used
through-out Nuke, the module’s source code ends with a switch
statement that controls the process flow
Some other interesting things to note are several
Nuke global variables and functions that come in rather
handy when developing modules
First, in the entry() function you’ll notice calls to
con-venience methods defined as part of the theme
archi-tecture, and are used for printing HTML table tags
These functions are available to all modules, which
makes creating a consistent look-and-feel across all
modules a simple task
Next, in the add_volunteer() function, you’ll
notice $dbi This global variable holds a reference to
the database connection used within Nuke This means
that you are not responsible for setting up database
connections within your module All of that work has
been taken care of for you Simply do a global $dbi;
in your function and use the database abstraction layer
included with Nuke This allows you to query the
data-base with very little coding overhead
The PHPNuke “kernel” automatically notices any
modules in the modules/ directory An illustration of
the file system for modules follows
If you create a new directory under “modules”, and
access the “Modules” option in PHPNuke’s
administra-tion secadministra-tion, you will see the newly created module
list-ed there (namlist-ed using your directory name) Modules
are initially marked as “inactive”, and can remain
inac-tive while testing occurs Nuke will provide navigation
into your module under the “Inactive modules” header
Enhancing the search engine module
The first thing I needed to do was upgrade the searchcapabilities Diysearch is, first and foremost, a searchengine organized like Yahoo It uses a hierarchy of cat-egories, into which links are logically filed The searchengine component is responsible for querying a linkdatabase (where all of the user-submitted links live) andreturning a ranked result set to the user
Nuke has a “Web links” module, but its functionality
if (! eregi ( "modules.php" , $PHP_SELF )) {
die ( "You can't access this file directly" );
}
1 <?php
2
3 /*
4 * This is a snipit of the Volunteers module
5 * developed to satisfy a specific requirement
6 * for Diysearch that was not covered by
7 * PHPNuke's core set of modules
8 */
9
10 // This is typically the first line in most
11 // modules for security reasons
12 if (! eregi ( "modules.php" , $PHP_SELF )) {
13 die ( "You can't access this file directly" );
14 }
15
16 // this is essentially the Nuke "kernel" and
17 // defines global variables and establishes
18 // the environment in which Nuke runs
42 * Our main operation switch statement which
43 * determins which function to call
Trang 33FEATURES Porting and Migrating and the Move to PHP
of Diysearch’s link database The first thing I did was
implement Lucene Lucene is a Java -based indexing
and search engine API provided by the Apache
Foundation as part of the Jakarta project Lucene
pro-vides a very elegant and powerful indexing and
search/query engine that rivals commercial products,
like Verity (http://www.verity.com)
I had been using Verity as the primary indexing and
search engine for Diysearch for years (as Verity is
distrib-uted with ColdFusion) Verity has some nice features
such as the ability to run query results and the provision
of a flexible query language, enabling complex
key-word searches Lucene, to my
delight, not only has similar features
but is also much simpler in design in
that it is simply an API The
imple-mentation of indexing and querying
is left to the developer While on the
surface this may seem like a Bad
Thing, it actually isn’t because the
developer is not constrained in how
the indexing or search engines are
implemented
Overall, the implementation of the
indexing and searching engines into
Lucene was pretty simple (my next
article will focus on the details of
using Lucene in a PHP application)
It did, however, take a few steps to
integrate this feature into PHPNuke
In the February issue of PHP Architect
I showed daring readers how to
inte-grate EJB’s (Enterprise Java Beans)
with PHP applications The
tech-nique involved using PHP’s Javaclass as an “interface”
between PHP and the actual Java object Following this
model, the code below shows how we talk to our
Java-based search engine class
In the first line I instantiate a Java object of the
“org.diysearch.searchengine.Searcher” type (which
implements the Lucene API) We can then perform a
search by calling the object’s “search” method This
method is passed the specific index we wish to search,
the type of search (for our purposes we just default to
a “OR” type of search, meaning keywords are joined by
“OR”), and our query (composed of one or more
key-words)
The search engine class, when queried, returns a
WDDX packet containing the search results WDDX is a
type of XML that describes simple or complex data
types so that those data types can be used by disparateprogramming languages Integrating the upgradedsearch functionality into Nuke was done using XML-RPC, and is just a matter of adding some code to the
“Search” module (see Listing 1)
Link databaseAnother of the key functions I needed to implementinto Nuke was the ability to enable registered users toadd URL’s for their projects into the search engine The
“Web Links” module that comes bundled with Nukewas insufficient for this purpose, so I created a new
module (following the procedure described above).This time, though, I also needed to modify some ofNuke’s administrative code so that site administratorscould review submitted links before they became
“active” in the search engine It’s crucial to have areview process when providing this sort of functionali-
ty to a very “diverse” group of users The integrity ofthe site must always be upheld
The old site just allowed anyone to submit anythingand then required me to review entries in the databaseone-by-one, deleting offending links by hand Therejust wasn’t a simple and easy way to add new function-ality in order to make management manageable Inorder to implement this “link queue” and “link brows-ing” functionality into Nuke, I simply added a new cus-tom module to Nuke
DIY banner rotationRunning a Web site isn’t cheap Ask anyone who does,and they will probably say the same thing Sites thathave specific technical requirements often rule outgoing with low-cost, shared hosting providers In order
$obj = new Java
( “org diysearch searchengine Searcher” );
$result = $obj -> search ( $index , $search_type ,
$query );
1 <?php
2
3 /*
4 * This code implements the searching of a Lucene index
5 * Using the XML-RPC bundled with PHP 4.3.0, we connect
6 * to the XML-RPC Web server (which is part of Apache's
7 * Web Services project: http://ws.apache.org)
8 *
9 * We establish a connection to the Web Service, and provide
10 * the name of the index, the query and the search type
11 * and are returned with a WDDX packet that we stuff into a
20 $args = array( $SearchIndex , "OR" , $q );
21 $request = compact ( 'host' , 'port' , 'uri' , 'method' , 'args' );
22 $result = xu_rpc_http_concise ( $request );
23 $sess_qrows = $result ;
24 ?>
Listing 1: Integrating the search engine with PHPNuke
Trang 34FEATURES Porting and Migrating and the Move to PHP
to offset some of those costs, banner rotation is
need-ed
While Nuke is bundled with a banner rotation
mod-ule, Diysearch had a specific need with respect to how
banners would be handled and uploaded into the site
The nature of the site is “do it yourself” This is a
recur-ring theme in that the direction and control of the site,
and its content, is in the control of the end user
Instead of a prospective sponsor contacting us, working
out payment, and then emailing us a banner, we’ve
automated the process
The solution enables anyone who wanted to
pur-chase banner ad space to simply follow a wizard This
wizard would allow them to select an impression
pack-age and upload their banner to the server Payment
(fulfillment) is done through PayPal, using their “single
item purchase” feature Once the customer completes
the payment process (after uploading their banner),
PayPal’s IPN (Instant Payment Notification) system
takes over
The IPN system accesses a URL in our site and passes
authentication and verification data, along with a
trans-action ID The URL is a simple PHP script which accepts
this input from PayPal and verifies the transaction If
verification is successful, the banner ad table is
updat-ed This marks the particular banner ad with a status
identifier, and places the banner in rotation This fully
automated system of handling banner management
and rotation opens up greater opportunities for users to
take part in sponsoring the site
Look and feel
Perhaps the most challenging task in this porting
proj-ect was implementing the new look-and-feel into Nuke
In the old site there was a custom look-and-feel
infra-structure which, while being rather simple (and old),
was quite effective and clean It was implemented as a
simple inclusion of header and footer files for each
ColdFusion template Nuke has something somewhat
similar but, in this writer’s opinion, it’s a bit convoluted
and messy
Nuke uses a “theme” system where the look-and-feel
elements are contained in HTML fragments These
fragments reside in named theme directories (under
the “themes” sub-directory) While on the surface this
may seem simple, it can quickly become rather
com-plex If you’re experienced in PHP, and you familiarize
yourself with Nuke’s design, adding functionality or
modifying existing functionality is often trivial
Creating a new theme or customizing an existing one,
however, is downright frustrating (for me anyway)
I used the PHPNuke “News” theme as a starting
point, and began to make changes to the HTML
“head-ers” and “content” area templates After battling with
HTML irregularities, and figuring out where and how
certain HTML templates were included (or in some
With no shortage of wrangling and gnashing of teeth(namely my own), the theme for the site was complet-
ed A significant amount of trial and error wasrequired, as well as modifications to the master themescript (all themes in Nuke have a theme.php scriptwhich includes required function definitions the kerneluses in order to “paint” the screen)
Wrapping upAfter starting this project in mid-January of this year,the new and vastly-improved site was re-launched onFebruary 15th (during the worst snowstorm inMaryland’s history) While fine-tuning, additions andbug fixes are always on-going, it is because of PHP’sand, more specifically, Nuke’s well-proven design andflexibility that I was able to completely scrap the oldsite
None of this would have been possible if it wasn’t foropen source software Open source’s natural evolutionand adoption, as well as the contributions of thousands
of gifted and dedicated developers and writers, has ated a rich environment for all Small-scale sites all theway up to large enterprises are able to take advantage
cre-of the work done by these folks, and are able to returnthe favor Open source projects are providing business-
es and organizations the tools they need to competeand stay current Businesses based on these technolo-gies are able to expand and grow in an almost organicway, losing the constraints associated with closed/pro-prietary solutions For these organizations, gone arethe days of hoping that a particular bug will be fixed inthe next release, or that a feature enhancement requestwill actually be entertained
Migrating from ColdFusion to PHP was a much pler task than I had originally thought When youremove the “write from scratch” from the re-engineer-ing equation, and replace it with “don’t re-invent thewheel”, the job just gets that much easier If this migra-tion case study has illustrated anything, it’s that nomatter how old and antiquated (dare I say “legacy”) aparticular Web application may be, PHP and one of thefew thousand PHP-based open source projects is able toprovide a real working solution
Dave is a professional geek specializing in java/j2ee, php (naturally), and perl development which is just a cover for his real passion for spend- ing large sums of money on home recording and musical equipment and generally making anuisance of himself it should also be noted that his / karma is currently "positive" which will surely fall.
Click HERE To Discuss This Article
Trang 35Being relatively new to the game, the first database
that I had any real contact with was Microsoft
Access 97 Back in those “dark days” I was playing
around with ASP using Windows 98 SE’s Personal Web
Server Ohhh, the stuff I dreamed of creating
Even though I’ve pretty much exclusively used
PostgreSQL and PHP since then, I’ve always missed
Access’s user-friendliness I remember the day I was
(rather rudely and abruptly) introduced to psql (the
PostgreSQL command-line utility) I sat there looking
at it sort of blankly, thinking that maybe if I ignored it,
it would go away I didn’t know what to type, or what
I was typing into
I’ve since come to terms with the psql and mysql
shells, learning to love them (in their own ways)
Sometimes, though, I wish I could go back to a kinder,
gentler time A time where the mouse was king, and I
could make mass changes with a single click The
hard-core Unix hackers out there are probably ready to move
on to the next article now, shaking their heads in
disap-proval Wait, though After reading this, you may just
push away your keyboard for a moment (when
nobody’s looking, of course)
Why on Earth would I want a
graphical database tool?
Hey, that’s a reasonable question I’ve used virtually
nothing but psql to talk to PostgreSQL for the last two
Windows and PostgreSQL
MySQL Manager 2.0 from Electronic