1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu Exploring XSLT Processing Options Within PHP docx

72 396 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Exploring XSLT Processing Options Within PHP
Trường học Technologies Ltd.
Chuyên ngành PHP/Web Development
Thể loại magazine article
Năm xuất bản 2003
Định dạng
Số trang 72
Dung lượng 2,07 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Blazing Site Performance Using Objects and Sessions Turn XML into HTML with various proven methods Plus: Tips&Tricks, Book Reviews, Product Reviews and much more... FEATURES FreeTrade,

Trang 1

Blazing Site Performance

Using Objects and Sessions

Turn XML into HTML with

various proven methods

Plus:

Tips&Tricks, Book Reviews, Product Reviews

and much more

Web-Free PHP: Using PHP's CLI Interpreter

Creating an RSS Client With PHP

Beauty and Brains:

Using Flash's ActionScript, XML and

PHP for Easy Multi-tier Solutions

FreeTrade:

A PHP-Based E-Commerce Solution

The Magazine For PHP Professionals

php|architect

Trang 2

As 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 http://www.phparch.com/grant and submit 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 3

32 Blazing Site Performance Using

Objects and Sessions

Trang 4

Visit 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 5

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.

Contact Information:

General mailbox: info@phparch.com Editorial: editors@phparch.com Subscriptions: subs@phparch.com Sales & advertising: sales@phparch.com Technical support: support@phparch.com

Copyright © 2002-2003 Marco Tabini & Associates,

Inc — All Rights Reserved

Awwww Yeah

These were the first words I uttered after

accept-ing an invitation to take the reins as editor-in-chief

for php|architect magazine About 3 weeks later,

Marco, our fearless publisher, reminded me that I

still had to write the ‘Editor’s Rants’ aritcle This is

essentially what you see at the beginning of

seem-ingly every magazine ever published ‘Letter from

the Editor’, ‘From the Editor’s Desk’ Whatever

you want to call it – it’s all the same – and as far

as I can tell, it’s all pretty meaningless

Over the past few weeks I’ve read no fewer than

30 of these articles, trying to get a clue as to this

article’s purpose in life I read magazines covering

every conceivable topic, formal and informal,

from the politically perfect to the underground,

grass-roots publications and found that these

edi-torial columns all seem to accomplish a single

goal: to make the editor look like the most

preten-tious, micro-managing, self-important species

ever to roam the earth Did these people lack

attention as children or something? The more I

read, the more I came under the suspicion that

the species I had been recruited to emulate might

be well not my cup of tea I also couldn’t help

but ask myself out loud on several occasions, ‘who

reads these things?’

But alas, this is not meant to be an editorial on

editorials (or a ‘metatorial’ if you will) If I’m

forced to partake in this charade, then I will

endeavor to make it something useful It so

hap-pens that, being my first month at the helm, I

have plenty to share with whoever is reading this,

specifically with regard to my vision for php|a over

the coming months I do welcome comments on

all of this, by the way: brian@phparch.com

I’ll break my thoughts down into sections

cover-ing our current status, the near future, and the

longer haul

Where We AreFrom rather humble beginnings, I think php|a has

accomplished much with regard to the vision of

its creator – Marco Tabini This vision was

two-fold, so I’ll cover them seperately

First, php|architect has become known as a

rep-utable resource for well written, well edited

docu-mentation covering all aspects of PHP

develop-ment While I will not bore you with the laborious

details of how challenging it can be to combine

EDITORIAL

March 2003 · PHP Architect · www.phparch.com

Trang 6

editorial precision with technical savvy, I will say

that this process and this accomplishment both

fall under the heading of ‘non-trivial’ tasks

Certainly a very large thank you is in order for

each of the many authors who collaborate with

our editorial staff each month Working together,

we have been able to overcome challenges

rang-ing from differences in opinion to differences in

time zone, culture, and even language Their time,

patience, and hard work is very much appreciated

Second, php|architect continues to make great

strides in establishing itself as a voice for the PHP

developer community, as well as an advocate for

the deployment, evolution, and progress of the

PHP platform We haven’t sought to glorify the

state of PHP, nor to shun its more proprietary

peers Instead, we try to maintain a realistic focus

on the use of PHP in production environments

We also take a decidedly optimistic view of the

future of PHP, which at times finds itself at odds

with what some of the larger names in

communi-ty might have in mind Nevertheless, we feel that

the opinions of our authors, the editors, and the

community are an important part in shaping any

project which lists ‘open development’ as a goal

The Months AheadThe months ahead will continue to build upon

the foundation laid in the first months of our

exis-tence The main goals in the immediate future

focus largely on quality and efficiency – in other

words, bringing you even better quality content

whithout breaking our necks or collapsing from

exhaustion in the process To that end, there have

already been improvements, tweaks and hacks put

in place

First, we’ve convinced a one-time volunteer

edi-tor, Peter James, to come on staff as a full-fledged

editor Peter has proven himself to be a tireless

worker and a great collaborator He has already

done wonderful work here, and he will

undoubt-edly leave an indelible mark upon the pages of

php|architect over the coming months

Second, as further proof of our commitment to

the community at large, we are very proud to

announce this month the launch of a grant

pro-gram to aid fledgling (or not-so-fledgling) projects

to continue to progress and bring PHP into the

places where no man has gone before – or at least

the road less traveled See this months pages and

the php|architect website for more details

The Longer TermLooking out and attempting to predict ourfuture at such an early stage, while fun, is proba-bly also an exercise in futility All that can be saidfor sure is that there are plans of great size andgreat number More huge ideas are born everyday Surprisingly, only some of the ideas belong to

us ‘staffers’ The rest come from you!

So far, most of the changes and adjustmentswe’ve made, and some which we’re working on,have come directly from our readers We’re allconstantly monitoring emails, looking in thephp|architect forums, and even monitoring thePHP mailing lists in search of yet another unful-filled need that we might be able to lend a hand

to Please keep these requests coming! There ishardly a greater compliment that can be paid to apublication than constructive feedback

In Conclusion

So now that I’ve firmly planted the image inyour head of an SUV-driving, tie-wearing, clean-shaven, pretty boy editor sitting in his overstuffedcouch with a $4.00 cup of coffee and a laptop, let

me assure you that while I take the publication

and my work seriously, I don’t take myself all that

seriously at all The reality is that I have hardly aclue how I got here I can only be thankful forMarco’s obvious and complete insanity in choos-ing me for this post

I am grateful both to Marco for this opportunity,those authors with whom I’ve had (and continue

to have) the distinct honor of collaborating, andthe many readers who have offered their feedbackand encouragement

Until next month

Trang 7

version 4.3.1 of the PHP interpreter The new

release addresses a bug in the CGI version of the

interpreter that invalidates the effectiveness of the

—enable-force-cgi-redirect compile-time switch

This, in turn, makes PHP-CGI susceptible to

out-side hacking attacks that could result in the

execu-tion of arbitrary PHP code

For more information, visit

http://ca.php.net/release_4_3_1.php

ADODB 3.20 Available

A new version of ADODB, the popular and

effi-cient database abstraction library, has been

released by its maintainer, PHPEverywhere blog

author John Lim

ADODB 3.20 supports several new features,

including abstracted capabilities for creating

tables and indexes, although this functionality is

still considered in its alpha stage

According to its website, available at

http://php.weblogs.com/adodb, ADODB is twice

as fast as PEAR-DB and 10% faster than PHP-Lib

Nova: A P2P Client In PHP

The Nova Project has released Nova, a

peer-to-peer application compatible with the popular

GNUtella file-sharing network Nova is written

entirely in PHP using the PHP-GTK extension, and

provides an excellent example of how PHP can be

used to develop application outside the Web

space

Nova, which is based on the GnucDNA library,

currently supports only basic functionality and is

only compatible with Windows You can find more

information at the project’s homepage

(https://sourceforge.net/projects/novap2p/)

Zend Releases Studio 2.6

PHP powerhouse Zend Technologies has release

version 2.6 of their Zend Studio IDE The new

application includes several bug fixes, as well as

new features, such as CVSintegration, advancedproject managementcapabilities and improvedperformance on all plat-forms

The Zend Studio 2.6 ispriced starting at $195(US) More information isavailable from the Zendwebsite athttp://www.zend.com

Introducing the php|architect

Affiliate ProgramEarlier this month, we proudly announced theintroduction of our new affiliate program, whichpays a commission for each purchase madethrough our website by visitors referred from on ofour partners

Participation in the program is free, and open toall websites, without any minimum requirements.You can find more information on the php|a web-site at https://www.phparch.com/afflogin.php

PHP Conference in MontréalPHP Québec will hold their first PHP conference

in the city of Montréal on March 20 and 21.Speakers at the event include a who’s who of thePHP community, including Zeev Suraski, AndreiZmeivski and Rasmus Lerdorf php|architect willalso be there and our own Marco Tabini will give

a presentation on PHP-based business and ourexperience in the world of electronic publishing.For more information, you can visit the confer-ence’s web site athttp://phpconf.phpquebec.com/

php|a

Trang 8

Afew days before writing this review (which, at the

time, was another review), I had something of an

epiphany I was on the phone with a client,

boast-ing about how organized I am, when Arbi walked by

my office and laughed a typical “I know better” at

me My ego was bruised, so I wrote down a list of

ways that I am organized on a piece of paper I’d

gladly show you that piece of paper if I hadn’t, er,

temporarily misplaced it

As the saying goes, if you can’t blame anyone but

yourself, blame the process After all, a person can

only do so much on his own I set out to find a

decent groupware application that would allow me

to get more organized and, at the same time, better

manage the office’s internal processes (formatting

Arbi’s hard drive would have been a bonus, but I

couldn’t find any applications capable of the perfect

union between a calendar and that).

After a bit of searching, I came across TUTOS,

which stands for The Ultimate Team Organization

Software Created by German developer Gero

Kohnert as an internal application for his previous

employer, TUTOS has evolved into a complex

group-ware application that is used by the likes of Siemens

Best of all, it’s written entirely in PHP

Reviewed For You TUTOS

Borland Interbase 5 PHP 4 (minimum php4.1)

“I started a first TUTOS like system for my former

compa-ny back in 1997 or so They still use it alot to have an overview of all their customers , software installations and different products and to support the internal Quality Managment (ISO9600) After leaving this company I start-

ed TUTOS, an enhanced system based on the same thoughts with a lot more features On TUTOS I'm working now for more than a year and after making a first installa- tion in my department at my current employer I think it is time to release it to the public, giving something back to the Open Source Community.”

Trang 9

TUTOSGroupware, Anyone?

TUTOS is a complete groupware application in every

sense It includes a calendar, a contact management

system, a bug tracking system, a product/project

repos-itory, mail capabilities, a time tracking system, an

invoicing system, and much more The system is also

multilingual, supporting about fifteen languages right

out of the proverbial box

For companies whose groups work in different parts

of the world, TUTOS includes the ability to specify

time-zone information for each user profile, so that

every-thing remains properly synchronized and meaningful

to all users

Finally, the system includes a “watchlist” mechanism

that makes it possible to remain up-to-date, via e-mail,

on changes to systems such as the bug tracking base or the calendar schedule Even for a small work-group, this “active notification” approach is a veryimportant feature, particularly when the members of ateam do not all work in the same office

data-User Interface and Security Features

The system implements a very fine-grained permissionsystem, thus ensuring that the administrators haveevery way to control access to each function In addi-tion, a TUTOS administrator has prompt access to all ofthe security settings, including his/her own

TUTOS features a colourful and easy-to-use interfacethat is sure to please both lovers and haters of GUIs AsFigure 1

Trang 10

REVIEWS TUTOS

you can see in Figure 1, only a minimal amount of

information is kept on the left-side frame menu, leaving

as much real estate as possible available for the system’s

actual functionality

Documentation, Interoperability

and LimitationsIt’s interesting to notice that the ultimate goal of the

TUTOS project is to create a portable groupware

sys-tem whose interface can be written for a number of

dif-ferent platforms As such, the development team has

put a large amount of work into the design of the

underlying data structures themselves Naturally, that’s

good news because, in addition to the PHP interface,

other interfaces are likely to be developed In fact, a

KDE/Gnome version is currently in the works

From a portability perspective, TUTOS’ PHP interface

doesn’t use any proprietary components that are tied

to a particular architecture, and it supports several

dif-ferent database systems, including MySQL, PostgreSQL

and Oracle

In my opinion, the system could use a bit more work

as far as interoperability is concerned In particular, I

think that attention should be paid to integration withoutside services like LDAP and/or Microsoft Exchange.This could help make TUTOS a more appealing solutionfor larger organizations

Since the entire system is based on PHP, however, itshould be relatively simple to expand its functionality toinclude whatever elements one needs The code isquite clean and well documented, so it forms a goodfoundation on which to build a more complex and spe-cialized application

TUTOS includes a good deal of documentation Forthe developer, the TUTOS website provides a detailedanalysis of all the data structures and logical organiza-tion of the system, as well as an API reference and aninstallation guide As for the end user, they get a com-plete contextual help system, shown in Figure 2, thatincludes an accurate description of what each individ-ual screen does

ConclusionNow that I have TUTOS running on my computer, Ican say with confidence that I feel more organized Aswith all groupware systems, the trick to getting TUTOSinto an organization is to stimulate user acceptance.After all, your average user is normally not keen on try-ing new things, and prefers instead to stick with theapplication that he or she has learned to use well

TUTOS represents an excellent groupware solutionthat is easy to learn and offers a wide array of function-ality It is organized in a logical fashion, provides lots ofdocumentation, and its PHP codebase makes it easilyextensible

php|a

Figure 2

TUTOS doesn't use any

proprietary components that

are tied to a particular

architecture.

Trang 12

porting a new SAPI (Server Application Programming

Interface) called CLI (Command Line Interface) This

facility was introduced to help developers create small

shell applications with PHP that have no dependencies

on a web server

In version 4.2.0, the CLI SAPI was experimental, and

had to be explicitly enabled using the — enable-cli

option when running ./configure However, with

PHP 4.3.0, the CLI SAPI has been deemed stable and is

therefore enabled by default It can be explicitly

dis-abled by specifying the —disable-cli option to

./configure

Though it was technically always possible to create

independent shell-style scripts with PHP using a

stand-alone CGI interpreter, there are a few things that make

the new CLI SAPI an especially attractive and unique

tool:

- Unlike the CGI SAPI, no headers are written to

the output Though the CGI SAPI provides a

way to suppress HTTP headers, there’s no

equiv-alent switch to enable them in the CLI SAPI.

- The CLI starts up in quiet mode by default, though the -q switch is kept for compatibility so that you can use older CGI scripts.

- The CLI does not change the working directory

to that of the script (-C switch kept for bility)

compati Three words: Plain text errors! (no HTML formatcompati ting)

format-In this article, we’ll discuss how to use PHP’s CLI ture to exploit the power of PHP from the commandline We’ll assume that you have a fair understanding

fea-of PHP and that PHP is installed and working properly

on your computer Most of the examples in this

tutori-al were tested on a Windows platform (w2k, to be cise), but should work unaltered on a Linux box

By Jayesh Jain

PHP 4.3.0's new CLI SAPI improves greatly on the foundation laid by its CGI ancestor

Take it for a spin – no web server required!

PHP Version: 4.3 and Above O/S: Any

Additional Software: N/A REQUIREMENTS

FEATURES

Trang 13

Shell Scripting with PHP (PHP CLI)What is a PHP Shell Script?

The term ‘PHP shell script’ can cause some confusion

for those who are used to traditional UNIX-style shell

scripts The reason for the confusion is that PHP,

strict-ly speaking, does not provide a traditional interactive

environment for command execution Another source

of confusion is the fact that the name of the SAPI – ‘CLI’

is also an acronym used to refer to a UNIX shell, which

by definition is an interactive command execution

envi-ronment! Let’s clarify this right now by simply stating

that the PHP CLI is an interface to a PHP interpreter that

can be accessed via the command line - not an

interac-tive shell In reality, ‘PHP shell scripts’ are just PHP

scripts that can be run from a command line or a cron

job (which will be discussed later in the article) in the

same fashion as a shell or PERL script

A normal shell script consists of two main parts: the

very first line, which indicates the interpreter that

should be parsing the script, and the code to be

exe-cuted by the interpreter Normally, the interpreter that

is specified is a UNIX shell, or some other interpreter,

like PERL However, since the creation of a PHP

inter-preter which can be executed directly from a shell

(without the help of a web server), we can specify PHP

as the interpreter for our script, and then fill the file

with PHP code For all you Windows users, PHP shell

scripts are just like batch (.bat) files in MS-DOS, but

with the power of the PHP programming language

Finding Your PHP CLIOutput on my Windows machine of the php.exe in the

‘cli’ folder was:

PHP 4.3.0 (cli) (built: Dec 27 2002

05:34:00)

Copyright (c) 1997-2002 The PHP Group

Zend Engine v1.3.0, Copyright (c)

This would indicate that the ‘php.exe’ file on my

machine in the php root folder is actually the old CGI

For the reasons mentioned earlier comparing the CGI

and CLI interpreters, and because the title of this article

says ‘CLI’ in it and not ‘CGI’, I’ll be refraining from

using the CGI in the examples going forward I just

wanted to point out a possible point of confusion

here so on we go!

Getting Started Let’s start with a small script (the most familiar one)which simply prints the words “Hello World” to thescreen Using your favorite text editor, create a text filecalled “world.php” in your PHP folder and enter the fol-lowing text

Save the file, ensure that you have the PHP CLI cutable in your path, and run the following command

exe-> php world.php

Surprised to see the output, ‘Hello World’ in the mand prompt instead of the web browser? Welcome

com-to the other dimension of PHP!

Note: If you are using PHP version 4.2 (or the CGI

Version) you may have noticed that the following

head-er is also in the output:

X-Powered-By: PHP/4.2.3 Content-type: text/html

The PHP CGI version does that by default, which canserve as an indicator that you’re using the CGI (in addi-tion to cluing you in on the PHP version you’re run-ning)

To suppress the HTTP headers and follow along withthe remaining examples, run the PHP CGI with the ‘-q’command line flag

> php -q world.php

Using the ‘-r’ option, you can also pass the PHP code

to be executed to the PHP CLI directly from the mand line For example:

com-> php -r ‘echo “Hello World\n”;’

Will output ‘Hello World’, the same exact message asour earlier example This is fine for small bits of codeyou only want to execute once Only as the code getslarger will you need the power of a script

You can redirect the output from any script to a file

by running:

> php world.php > outputfile

Linux and UNIX users can also redirect the script put to another command by using the | (pipe opera-tor) For example:

out-<?php echo "Hello World\n" ;

?>

Trang 14

FEATURES Shell Scripting with PHP (PHP CLI)

> php world.php | wc -w

Will return the word count of the output (in this case,

it will output the number ‘2’)

Conversely, you can also send output from some

application or command to the php interpreter by

using the pipe operator, for example:

> someapp | php

This might be useful if ‘someapp’ outputs PHP code

which can be immediately executed by the interpreter

instead of adding the overhead of first writing to a file

and then calling the interpreter separately – which will

then also be subject to the added overhead of opening

and reading a file from disk

Getting InteractivePHP has always made it very easy to interact and tradedata with a user via the traditional browser interface.Let’s have a look at how PHP’s ‘stream’ functions andassociated constants can extend this ease to the com-mand line interface There are three streams available

in PHP CLI If you’re familiar with the correspondingstandard UNIX device names, you’ll be right at homehere, as these streams emulate the same functionality

stdin (‘php://stdin’) stdout (‘php://stdout’) stderr (‘php://stderr’)

The following example will display “Hello World” inthe output window using the output stream

This time, we’ll demonstrate how to use an inputstream It will accept an input from the user, wait forthe user to press the Enter key and then display theentered text

The following example shows you how to output text

to an error stream

<?

$stdin = fopen ( 'php://stdin' , 'r' );

echo "Please Enter your Name: " ; $mystr = fgets ( $stdin , 100 );

echo "Your Name Is :\n" ; echo $mystr ;

fclose ( $stdin );

?>

<?

$stdout = fopen ( 'php://stdout' , 'w' );

fwrite ( $stdout , "Hello World" );

- Shell scripts can take input from,

and send output to a user via

STDIN/STDOUT, a regular text file,

or even another command In other

words, they’re very flexible

- Shell scripts are a ‘quick and dirty’

way to create your own

command-line tools and applications

- If you already use PHP for web

development, why learn another

language to write shell scripts?

- Shell scripts are commonly used to

automate day-to-day administration

tasks

Trang 15

Shell Scripting with PHP (PHP CLI)

To make accessing and moving data around in a shell

environment simpler, PHP has added the following

constants Again, for UNIX users, these names should

look familiar In UNIX, these typically map to the

key-board (STDIN) and the screen (STDOUT and STDERR)

by default

Using Arguments in Scripts

Anyone who has experience writing shell or PERL

scripts would probably consider the PHP CLI

complete-ly useless if the scripts weren’t able to handle

argu-ments passed to it from the command line The CLI

handles this with the use of the $argv and $argc

vari-ables

All of the arguments passed to your script are stored

in a zero based global array variable $argv Another

global variable, $argc, holds the number of

argu-ments passed to the script (everyone coming from a

C/C++ background, should be familiar with this

prac-tice) Here is the code, which displays the total

num-ber of arguments passed as well as the arguments:

$stderr = fopen ( 'php://stderr' , 'w' );

fwrite ( $stderr , "There was an Error" );

Here is an example of how to use a stream with constants:

For users of version 4.2, you’ll need to add these

addition-al lines to the top of your script in order for the above example to work:

define ( 'STDIN' , fopen ( "php://stdin" , "r" ));

define ( 'STDOUT' , fopen ( "php://stdout" , "w" )

define ( 'STDERR' , fopen ( "php://stderr" , "w" )

<?

fwrite ( STDOUT , "Hello World \n" );

?>

$stderr = fopen ( 'php://stderr' , 'w' );

$stdout = fopen ( 'php://stdout' , 'w' );

$stdin = fopen ( 'php://stdin' , 'r' );

Trang 16

FEATURES Shell Scripting with PHP (PHP CLI)

Assuming this is stored in a file argument.php you

could test this script by running:

> php argument.php arg1 arg2

Refer to Figure 2 for sample output

Important : You can use $argcand $argvin the

man-ner described above only if you have both the

regis-ter_globalsand register_argc_argvsettings in

php.iniset to ‘on’ As of PHP version 4.3,

regis-ter_globals is set to ‘off’ by default You should do

your best to write your scripts so that they do not require

register_globals to be on, to avoid possible security issues

in your incoming form variables You can still use $argv

and $argc if register_globals is set to ‘off’ Just

use the following code:

Using External commands

in Scripts

In order to run any external command from the script,

we will have to use the php function shell_exec.

Shell_execwill execute a command via the shell and

return complete output as a string

For Linux/UNIX Users

As we’ve discussed, the PHP executable runs

independ-ently of the web server An added benefit of using this

interface for your scripting is that it makes your scripts

more portable than using, say, ‘/bin/bash’ Using

‘#!/usr/bin/php’ at the top of your script will allow

you to invoke the PHP interpreter on a Linux machine,

and on Windows, this line will be skipped over to get to

the PHP code below Now you can write in your

famil-iar Linux environment, and still deploy to Windows

Tip: Don’t forget that Linux won’t let you do

any-thing until the script has its ‘execute’ bit set Assuming

your script is called ‘testscript.php’, you can just ‘cd’ to

the directory where the script lives and type:

> chmod +x testscript.php

Once you have set the executable attribute, you can

execute the file like this:

> /testscript.php

Also, don’t forget to add the PHP tags in the scriptfile, otherwise PHP will not interpret it properly Ifyou’re stuck with the CGI version and want to suppress

the HTTP headers, use #!/usr/bin/php -q.

Similarly, you can also use any other PHP arguments

Scheduling PHP Scripts PHP scripts can be scheduled to run automatically withthe help of ‘cron’ Cron is the name of the standardexecution scheduling mechanism that enables UNIXusers to execute commands or scripts automatically atsome regular interval A common use for it is to back-

up all of the file on the server, do some databasecleanup, or send emails to administrators about thestate of the system Try typing ‘man cron’ or ‘mancrontab’ on your Linux system to learn more abouthow to get your PHP scripts to run at regular intervals.This can be an extremely valuable tool to developerswho need to do major data crunching without the user

in the browser being adversely affected For example,while it’s possible to have a user click a button whichtriggers the collection of live network data comingfrom remote LDAP, SNMP or other sources, grabbingand manipulating this code to make it suitable for pres-entation can really take some time Why not poll thesesources in a cron job at regular intervals, store every-thing to a database in a more friendly format, and havethe front end simply grab from the database in a more

‘bite size’ format The possibilities are endless!

For Windows Users:

Configuring Windows to Execute

as the file extension, and click OK

<?

$command = "ls - al" ;

echo shell_exec ( $command );

?>

$argc = $_SERVER [ 'argc' ];

$argv = $_SERVER [ 'argv' ];

using PHP's CLI interface makes your scripts more portable than using, say, '/bin/bash'.

Trang 17

Shell Scripting with PHP (PHP CLI)

Refer to Figure 3

Select the PHP entry in the ‘Registered File Types’ list

box, click the ‘Advanced’ button, click ‘new’ and type

‘Run’ in the Action box In the ‘Application Used to

Perform Actions’ box, type C:\PHP\PHP.exe “%1”

%* (change the PHP path if it’s different on your

machine Note that ‘%*’ is used to send any command

line arguments) Click ‘OK’, ‘OK’ again and then the

‘Close’ button Your Windows machine is now

config-ured to run PHP Scripts Just double click on any PHP

file in Windows Explorer to run it

Refer to Figure 4

You can also register files with extension ‘.php3’ or

‘.php4’ in the same fashion mentioned above

More InformationThere are certain php.ini directives, which are over-ridden by the CLI SAPI because they do not make sense

in shell environments:

a) html_errors = FALSE

As the output of the PHP CLI does not go to a

brows-er, there is no need to echo HTML tags hence this tive defaults to FALSE

direc-Figure 3

Trang 18

FEATURES Shell Scripting with PHP (PHP CLI)

b) implicit_flush = TRUE

All the output coming from output commands need

to be shown instantly and should not be cached As a

result, this directive is defaulted to TRUE

c) max_execution_time = 0 (unlimited)

Because the PHP runs in the shell environment and

often does tasks which take a longer time, the

max_execution_time is defaulted to unlimited

d) register_argc_argv = TRUE

This setting is TRUE so that you can always have

access to the number of arguments passed to the script

($argc) and array of the actual arguments ($argv) in

the CLI SAPI

ExtensionsNow that you know all about the PHP CLI, use the fol-

lowing code examples , or make up some of your own,

to test the power of PHP and the CLI

Sending Email in Scripts

The syntax used to send email is shown below You can

skip the header part, as it is an optional parameter

Using the MySQL Database in Your Scripts

You can connect to MySQL database exactly the sameway as you do in your normal php scripts except youshould not use HTML tags as the output is not sent tothe browser

Here is a simple example, which connects to aMySQL database and lists the username field for allrecords in the user table

print " $line [ ] \n " ; }

Jayesh Jain is working as a consultant in Auckland, New Zealand He has several years of n-Tier development experience and is currently work- ing with PHP to develop interactive client solutions He has a passion for Web development and in the spare time he likes to write articles Contact him at: jainjayesh74@yahoo.com

Click HERE To Discuss This Article

https://www.phparch.com/discuss/viewforum.php?f=6

Figure 4

Trang 19

E-commerce applications are one of the most

com-mon requests web developers receive today An

e-commerce solution should provide two different types

of functionality Site visitors should see a fully-featured

online shop, while business owners should have an

easy-to-use back end administration system

There are many open source e-commerce solutions

with many good features, and I have tried almost all of

them Specific to PHP there are a few cool scripts

which will help you accomplish everything needed to

set up an online store and to maintain it easily

Applications like osCommerce (

http://www.oscom-merce.com), FishCart (http://www.phpshop.org),

and phpShop (http://www.fishcart.org) are just

a few examples

How can you select a package to use as your

e-com-merce ‘solution of choice’? It’s not easy You must ask

yourself what you are looking for and identify the

prob-lems which need solving In my case I was looking for

a solution which met the following requirements:

•open source

•well written

• fully-featured

•not in an early beta version

•supported by the community

Additional Software: N/A REQUIREMENTS

FreeTrade on the Web

Trang 20

FreeTrade, e-commerce for developers

These requirements are not too strict, but some of

them do exclude a number of the solutions out there

After searching, configuring, testing, customizing, and

a good many sleepless nights, I believe that I have

found a good, although not well-known, solution for a

developer

FreeTrade is a fully-featured and highly configurable

PHP script for creating and maintaing e-commerce Web

applications FreeTrade is not a very well-known script,

and there are a few reasons for this For example, it

does not have its own domain name, the demo store is

very poorly designed , and FreeTrade uses a different

(and, at first glance, strange) development model

called FreeEnergy

FreeEnergyFreeEnergy is not a new concept in PHP develop-

ment, but it is also not a widely used one I am sure

that you use the include() function in your PHP

scripts frequently Some of the more common uses are

for headers, footers, and function libraries We had this

functionality before PHP, too, with Server-Side Includes

This include() functionality is the core of the

FreeEnergy concept

FreeEnergy uses the idea of ‘modules’ These

mod-ules are a set of directories, generally kept outside of

the web directory tree for security reasons Almost all

FreeEnergy code is kept in these modules Module files

are PHP scripts that are included when needed Some

standard modules are layout, navigation, action, utility

and screen These directories contain code specific to

their function, and will be examined in greater detail in

a moment

A FreeEnergy application has only one PHP script

inside the web directory, named index.php This is

the controlling code for the application, and it loads

modules when needed It is a small script, and we will

discuss it in the upcoming example

As an example of how the FreeEnergy concept works,

we’ll create the layout of an e-commerce site Design

and content are elements of every page in a site While

the design can be almost the same for groups of pages,

the content will be different on every page Since

mix-ing design and content is never a good idea, we should

try to keep them separate

Usually we have a few design schemes for a site For

example, we could have different schemes for the

home page, department and product pages, news

pages, and pop-up pages The FreeEnergy concept

calls each scheme a layout You may have as many

lay-outs for a site as you need, and these are housed in the

layout module directory.

Each layout consists of one or more components For

example, one layout might have a header, content, and

a footer as components Another layout might have a

header, a left-side navigation bar, content, and a

foot-er These components can be laid out in the layout fileusing HTML tables, div tags, or any other means Notethat none of the components of a layout are hardcod-

ed They are just included into it with a simple

include() Each component is saved in a separatefile The code making up each of the navigation, head-

er and footer components is kept in the navigation

module directory

The content component (or screen) is kept in a file in

the screen module directory A screen may be pure

HTML or PHP, but the screen file never performs anyaction past showing page content Listing 1 lists thecode for an example screen showing a user login page.This example login screen script would reside in the

login file in the modules/screen directory Module files have no file extension (like php) because they are

to be included, not executed I will stay focused on thisexample and explain a few things

FreeEnergy has a general module, called utility, which

contains common functions and libraries Some ofthese files are included in every FreeEnergy page InListing 1 we used functions such as StartForm(),

startTable(), and printLink(), which are

func-tions from the utility module

FreeEnergy doesn’t force you to use these functions(you may use print( “<table>” ) instead of

startTable()), but using them ensures that you cancontrol all site elements from single functions Thismeans that the StartForm()function controls all siteforms This is great because we can automatically add

as many hidden variables to all of the forms as we need.Site changes are very easy with this approach!

Let’s look at the definition of the StartForm()tion and compare it with the function call in our exam-ple screen in Listing 1

func-The $screenparameter defines which screen will beloaded when the form is submitted $methodspecifieswhether the GET or POST form method is to be used

$actionnames the action to be executed before thenext screen is shown $secure defines whether wewill use HTTP or HTTPS for this form These functionparameters are the most important For our purposes,the remaining parameters may be ignored

The action is a file in the modules/action

directo-function StartForm ( $screen ,

$method = ’get’ ,

$action = ’’ , $secure = FALSE ,

$extra = ’’ ,

$windowName = ’’ , $ encodingType = ’’ ,

$formName = ’’ ,

$onReset = ’’ , $ onSubmit = ’’ ,

$class = FALSE );

Trang 21

FreeTrade, e-commerce for developers

ry which will be included and executed before the

tar-get screen is loaded Actions never print text They

only take action and return a result to the

$ActionResultsarray Some actions are very simple

(ie add a news item to a site), but some are very

com-plex and require several steps (ie submit order) Each

step of an action must completed successfully for the

action to be successful

In our example, the target screen is ‘contents’ (which

will show the shopping cart contents), and the action

script is ‘LOGIN_USER’ When the form is submitted it

will load and execute the action script If the action

completes successfully, it will then transfer the user to a

page showing the contents of his shopping cart

Now that we know how FreeEnergy works, let’s take

a look at how FreeTrade builds on it

FreeTrade Organization

FreeTrade, a child of the FreeEnergy concept, follows

the same code organization we just described The

directory structure is as follows:

We already know the purpose of the general

FreeEnergy modules like layout, navigation, screen and

action Let’s examine the new FreeTrade-specific

mod-ules

The configuration module contains scripts for

specify-ing application parameters The well-commented

modules/configuration/global file defines allimportant global constants I will discuss this file indetail later

16 printEditRow ( localize ( 'Name' ), "inputLogin" , "" , 32 , 255 );

17 printEditRow ( localize ( 'Password' ), "inputPassword" , "" , 32 , 255 , "password" );

18 printSubmit ( localize ( 'Login' ));

27 print( localize ( "If you don't have an account, please" ) " " );

28 printLink ( localize ( 'create an account' ), "create_account" ,

Trang 22

FEATURES FreeTrade, e-commerce for developers

The modules/configuration/screenInfo

script describes every page (page=screen) of the site

The default screen definition is as follows:

SI_LAYOUT’ defines the layout to use for this screen

SI_PERMISSION’ is an array of user permissions

needed to view the page For instance, to limit page

access to the administrator, we would use:

All screen definitons are stored in an array called

$ScreenInfo Screen definitions don’t usually

speci-fy all of the parameters Any parameters that are

omit-ted will be filled in from $ScreenDefaults

An example of an administrative section for adding a

new product into the store database is as follows:

This page will have a default description, default

key-words, and default navigation (‘with_side_nav’) An

example of a screen with a different layout is as follows:

In this help screen we defined a different layout, but

omitted permissions This means that the default

per-missions will be used (everybody will be able to open

the page)

The database module is a kind of abstraction layer for

MySQL and PostgreSQL databases Which of them to

use is up to you The database type is set in the

mod-ules/configuration/global file, and the

data-base module contains function libraries for datadata-base

operations

The help module is a set of screens to create

context-sensitive help

The language module is used for localization.

FreeTrade may be totally localized and translated to any

language By default, it supports English, Italian,

German, French and Spanish

Now let’s see how to install and configure the script

Configuration and InstallationFreeTrade is easy to configure, but there are a fewthings which may cause problems FreeTrade requires

at least PHP 4.2

Take a look again at the FreeTrade directory structure

The modules directory is parallel to htdocs This implies that modules has to be outside the web direc-

tory If your host doesn’t allow such a configuration, it

can be a security problem You can place the modules directory within htdocs, but the module files don’t have php extensions This means that they may not

be parsed by PHP and everyone will be able to see yourconfiguration parameters Although you can protectthis directory, the only secure configuration is to place

modulesoutside of the Web directory

After you install the code, you will need to make adatabase for FreeTrade In the FreeTrade distribution

package, you will find an install directory with SQL

files for both MySQL and PostgreSQL Load the desired

database type’s build.sql into a new database You may also load sampledb.sql into the database to

populate it with sample data for testing

The last installation step is to modify the

modules/configuration/global file You willprobably need to change only database-related param-eters, but I will explain some other interesting parame-ters, too

The first section of this file defines the debug statusand the behaviour of error logging You can set the

DEBUG’ constant to ‘TRUE’ for site-wide debugging,but don’t forget to turn it off once the site is live Also,make sure that the error log directory you select in

LOG_DESTINATION’ exists and is writable by the webprocess

The next section of this file is for configuring globalnetwork behaviour

Setting ‘USE_FLAT_URLS’ to ‘TRUE’ will turn on flat

URLs (which will be decoded in index.php) Flat URLs

use a sneaky technique to pass data in like a tring A flat URL looks like this:

querys-http://www.site.com/index.php/item/depar tment/Green/item/Jacket.html

A normal URL would look like this:

http://www.site.com/index.php?SCREEN=ite m&department=2&item=3

Notice that the script being used here is actually just

http://www.site.com/index.php Many search engines

will not index dynamic-looking sites like the secondURL By passing in data using the method shown in thefirst (flat) URL, you can encourage search engines tospider the site

The network behavior section of the global file also

“help” =>array ( ‘SI_TITLE’ => ”Help” ,

‘SI_LAYOUT’ => ”plain”

)

“add_item” =>array (

‘SI_TITLE’ => ”Add item to Catalog” ,

‘SI_PERMISSION’ =>array( ‘Administrate’ ))

‘ SI_PERMISSION’ => array( ‘Administrate’ )

Trang 23

FreeTrade, e-commerce for developers

allows you to specify the use of department names,

instead of their IDs, in links (set ‘

USE_NAMED_DEPART-MENTS ’ to ‘ TRUE ’) The same is available for items (set

‘ USE_NAMED_ITEMS ’ to ‘ TRUE ’) Stores with these

options turned on will also be better listed on search

engines

The ‘DEFAULT_SCREEN’ constant defines the screen

to be loaded if no screen has been requested By

default, it is the welcome screen (home page)

SEND_EMAIL’ specifies whether or not the system will

send order confirmation emails The ‘USE_SSL

con-stant should be set to ‘TRUE’ if you want sensitive areas

of the system to only be viewed using an SSL

connec-tion (ie checkout process) This constant affects the

ScreenURL() and StartForm()functions

FreeTrade doesn’t force users to have cookies turned

on Session variables will be tracked anyway, but if you

want to use cookies, set the ‘USE_COOKIES’ constant

to ‘TRUE

The next section of the global configuration file is

dedicated to the store catalog Set ‘

ITEMS_IN_MUL-TIPLE_DEPARTMENTS’ to ‘TRUE’ if you want some

items to be shown in more than one department (very

useful) The ‘ALLOW_DUPLICATE_DEPT_NAMES

con-stant allows two departments to have the same name

in the same parent department I suggest that you turn

this option off, especially if you have

USE_FLAT_URLS’ turned on

FreeTrade users, by default, can buy items whether

they are registered or not If you want to force users to

be registered before checkout, set

SHOPPER_MUST_REGISTER’ to ‘TRUE

FreeTrade supports coupons and gift certificates as

well If you want to allow them on your site, you

should set the ‘USE_COUPONS’ and ‘

USE_GIFTCER-TIFICATES’ constants to ‘TRUE’ By default, coupons

are turned off and gift certificates are turned on

The most important parameters in this file are related

to the database Indeed, it will be ‘challenging’ at best

to run an online store without a successful connection

to a database! You can use MySQL (set the ‘DATABASE

constant to ‘mysql’) or PostgreSQL (set the ‘

DATA-BASE’ constant to ‘pgsql’) You will need to set

DATABASE_HOST’, ‘DATABASE_USER’,

DATABASE_PASSWORD’, and ‘DATABASE_NAME’ to

match your server settings

You may try the new FreeTrade caching option by

turning the ‘USE_CACHE’ constant on This option will

force FreeTrade to cache the results of database queries

This feature is still in the testing phase, so don’t use it

on live stores

Now you can play with your FreeTrade application

The default administrator login is a username of

admin’ and a password of ‘admin’ To test FreeTrade,

you may use the FreeTrade Test Specifications that are

located in the doc directory of your distribution

pack-age It covers all of the store functions

Troubleshooting

If the script fails to run properly and your tion parameters are correct, there may be two possiblecauses

configura-FreeTrade requires magic_quotes_gpc to be off

If magic quotes are on, FreeTrade will not function asexpected Throughout the site’s form handling codeFreeTrade uses addslashes() when inserting orupdating the database It does not do anything specialwhen setting the value of form variables, which maycause some headaches You can only change the value

of this setting in the system-wide php.ini file or in a htaccessfile in the site’s directory

Some installations may experience problems with filepaths FreeTrade automatically tries to find the right file

paths in index.php in order to provide the capability

to change hosts painlessly If it fails, you can set it upmanually I’ve never had problems with these paths onUnix/Apache, but I have experienced it a few times onWindows

Setting it up manually means hardcoding the file

paths in index.php The constants you may have to

hardcode are ‘SERVER_NAME’ (the name of the server,like ‘www.phparch.com’), ‘SCRIPT_NAME’ (the name

of the store script, which is ‘index.php’ by default),

APPLICATION_ROOT’ (the path on the Web server’sfilesystem where the modules directory is located, like

‘/www/’ or ‘/usr/local/apache/’), and ‘ NAL_PATH’ (the path from the root of the Web site to

EXTER-the index script, such as ‘/’ or ‘/store/’).

FreeTrade WorkflowMany first-time users have problems with under-standing how things work in FreeTrade, so I will explainthe FreeTrade execution process in detail

When a page is requested, the index script first fies that the PHP version is acceptable and that the con-figuration is correct If everything is in order, it locates

veri-the modules directory Next we include veri-the global

configuration file from the configuration module, as well

as standard libraries from the utility and database

mod-ules

Now that everything is ready for initialization, so we

include the initialization script from the utility

module This script will get the database initializationcode and the caching code (if caching is turned on),and blank out the global variable $ActionResults

The initialization script handles cases where no

session ID or department ID was provided, and setsthem to defaults Finally, this script detects the user’sbrowser, CSS support, Javascript settings, and anythingelse avaiable in the ‘HTTP_USER_AGENT’ variable

At this point, if everything is OK, we have finishedpreprocessing Now we get into the more interesingpart: executing actions As stated previously, the

Trang 24

FEATURES FreeTrade, e-commerce for developers

ACTION form variable, from the script which requested

the page, names a file in the modules/action

direc-tory to be included This script contains the action to

take on submission of the form For index.php, the

action is like a black box We include the requested

action and receive the results (or error message) from it

in $ActionResults

The action usually has several steps, and all of them

must be successfully completed FreeTrade uses an

interesting technique to process these steps Instead of

using nested if’s and ending up with highly nested

and hard-to-read code, it uses a nice feature of PHP4’s

include() statement

In PHP4 a file that has

been included can

prema-turely exit and return a value

with a return()

state-ment, like a function (this is

valid for PHP4+ only; PHP3

doesn’t function like this)

As actions are included files,

we may use return() if

any of the steps of an action

fails With this funcionality, we can organize the action

as a set of steps in ifblocks If any of them fails, the

others will be skipped This improves readability and

decreases the size of our code

Once an action has finished executing, we include

the modules/configuration/ScreenInfo file and

try to find the requested screen definition If the screen

is not found (or one has not been requested), we show

the default welcome screen to the user The default

screen is defined in the

modules/configuration/global file, as

men-tioned earlier (the ‘DEFAULT_SCREEN’ constant) The

welcome screen is located in modules/screen, just

like any other site screen If we did find the screen

def-inition, we read the layout and any other definitions for

the requested screen

Now we have the action results, the layout, and the

screen content We just need to print it out and we’re

done That’s all - the index.php script is over!

The workflow I’ve described is a general one Each

page is processed this way, whether it be user login or

registration, adding an item to the shopping cart, or

ordering

Real Life TipsFreeTrade has two sections One section is for shop-

pers and one is for administrators When logged in as

an administrator, you will have an additional menu

option (Admin Menu) in the left side navigation This is

a link to a set of protected pages for store

administra-tion There you will find options for managing

invoic-es, departments, products, gifts, coupons, taxinvoic-es, and so

on

There are a few things which may confuse you if youare new Some of them are related to FreeTrade, whilesome are related to e-commerce programming in gen-eral I will try to clear things up and save you sometime

First, let me explain the FreeTrade nomenclature andhow an online store basically works FreeTrade calls

your online shop a store A store may have many ferent departments and subdepartments For exam-

dif-ple, you might have two departments - one called

‘Books’, and another called ‘Music’ Each departmentcan contain subdepartments and products By default,

there is a department called Root All store

depart-ments are its ments You can place prod-ucts in the Root department,too

subdepart-A product is called an item

in FreeTrade A store user (ashopper) can add any item

to their own shopping cart

FreeTrade uses the term ket when talking about the

bas-shopping cart When a shopper is finished adding all ofthe items he plans to buy to his basket, he goes to the

checkout page On the checkout page, he is asked for

his shipping and billing details Finally, we save hisorder and eventually process his payment in real-time

Some other important terms are attributes and ations I will try to explain them using an example If

vari-you are planning to sell shirts in vari-your store, then a shirt

is an item This item can be different colors and ent sizes Color and size are referred to as attributes,and you are free to specify as many attributes as youneed In our example, the shirt’s color variations may

differ-be red, blue, white and black Size variations may differ-be S,

M, L, and XL Every variation may have an extra priceattached to it (an XL shirt may cost an extra $2) Youare free to specify as many variations you need You

can manage attributes and variations in the Attributes

and Variations administration menu

Now that we know what attributes and variations are,let’s go back to items again If we want to sell ourexample item (a shirt with different colors and sizes),

we must be able to give the selection of these attributes

to the shopper For some less powerful e-commercescripts, the only way to offer a selection of attributes is

to define a different item for each variation of eachattribute This means that we would create an item for

a green and size S shirt, and another item for red andsize XL shirt, and so on We would need items for allcombinations of sizes and colors After that, just imag-ine how to change the price of that shirt! You wouldhave to edit all items and change the price for everyone of them Obviously this is not a good approach.Let’s introduce a new, well known term in e-commerce:

a SKU

FreeTrade is a fully-featured and highly configurable PHP script for creating and main- taining e-commerce Web appli- cations.

Trang 25

FreeTrade, e-commerce for developers

SKU stands for Stock Keeping Unit and is an ID

asso-ciated with a product for inventory purposes Each SKU

in FreeTrade has external SKU information to help

con-nect a store’s offline business with its online business

FreeTrade uses this number to identify an individual

product A SKU is a subitem and it has its own name,

price, weight, inventory stock, and any number of

attributes and variations An item has none of this It

has only a name, a description and images All

addi-tional information for an item is stored in its SKUs

Each item has zero, one, or more SKUs FreeTrade

allows you to make items with no SKUs, but such items

make no sense As I said, you can select as many

attrib-utes and variations as you like for a SKU In our shirt

example, we can select all available colors and sizes for

our shirt If there is more than one variation of any

attribute (for example, there are 4 colors), the shopper

will see a selection box with all available colors for this

item and he will be able to select the color he likes For

each attribute with more than one variation, FreeTrade

will show a separate selection box In our example, the

shopper will see two selection boxes One selection

box will be for color selection and the other will be for

size selection

You will probably have only one SKU per item, but

sometimes it is good to have more than one SKU For

example, you may sell movies You might have one

SKU for the VHS version and another for the DVD

ver-sion of the same item Note that in this movie

exam-ple you don’t actually need to make two SKUs, since

you could define an attribute ‘Edition’ with two

varia-tions: ‘VHS’ and ‘DVD’ If, however, you need totally

different pricing for both of these editions, you will

have to define two SKUs

A SKU can have two prices; List Price and Sale Price

The Sale Price is the price the item sells for, and it’s the

only price used for calculating order totals If both

prices are defined, a user will see both prices You may

leave List Price blank if you wish to show only sale

prices

You can use the List Price to recalculate the prices for

a whole department If you implement a sale

(Administrate Sales option), you can set the Sale Price to

the List Price minus a defined discount

FreeTrade supports cross-selling For example, if you

are selling mobile phones, cross-selling allows you to

offer headphones, hands-free kits, and cases for a

phone model on that phone’s detail page This can

definitely increase sales If you want to cross-sell (show

similar items and/or accessories on the item page), you

have to define a relationship (Administrate Item-to-Item

Relationships option) Once a relationship has been

defined, you’ll need to specify all of the items in the

relationship (Administrate Departments and Items)

In order to actually show related items to the

shop-per, you’ll need to edit the modules/screen/item

file On line 240, you will find:

‘Cross-Sell’ and ‘Accessory’ are default relationships

To show any other relationship, you will need to add aline for each new relationship you’ve created The

showRelationship() function is defined in thesame file, so you are able to modify it to show relateditems in the way you would like The default way toshow related items is just a bulleted list of linked item’snames

Items may have up to 3 images: Thumbnail, Graphic and LargeGraphic The Thumbnail image is used in

the department listing The Graphic image is used on

an item’s detail page The LargeGraphic image is used

in a pop-up window opened by clicking the Graphicimage on the item detail page None of these imagesare required, so you can have items without havingimages FreeTrade does not support image uploads inthis version, which may be a problem for store owners

if they are not familiar with FTP Of course, the beauty

of open source is that you can always just add theupload option This would require changes in a few ofthe scripts for item administration

The checkout process takes a little getting used to atfirst, but I believe that this will be improved in futureversions As soon as the user steps into the checkoutprocedure, all of his shopping cart content is moved(cart becomes empty!) to a temporary invoice Thismay be a problem if a user decides to exit from thecheckout procedure to buy something else Although

no data will be lost, the shopping cart will show onlyitems added after he exited from the checkout Thecheckout process will collect all of the items and theuser will still be able to order all selected items, but itcan be really confusing A user expects all items toremain in his shopping cart until the checkout processfinishes Aside from this, the checkout procedure isquite smooth

A shopper with items in his basket can step into thecheckout page either from the basket content page orfrom the menu FreeTrade shows the complete content

of his basket, along with a form for the shopper’saddress If the shopper is already registered and logged

in, his address will be auto-filled Form submission willtransfer him to a billing page where he enters his billinginformation FreeTrade will check the credit card infor-mation that a shopper enters here before transferringhim to the last step: the confirmation page This verifi-cation is handled by the

modules/utility/validateCard script Notethat this verfication only checks that the credit cardnumber is valid; no charges occur If the card is

showRelationship ( $Item , ‘Cross - Sell’ ,

“Similar Items : );

showRelationship ( $Item , ‘Accessory’ ,

“Accessories : );

Trang 26

FEATURES FreeTrade, e-commerce for developers

acceptable and the shopper confirms the order,

FreeTrade will save it into the database

Extending FreeTradeFreeTrade is meant for developers It is very extensi-

ble and flexible The following is a practical example of

how easy it is to extend the FreeTrade system to meet

your specific needs

By default, FreeTrade stores credit card information in

the database table invoice_billing for each individual

order This is a problem, in my opinion, even when

using dedicated servers Redundant data in a database

is generally never good news, if not for reasons of

effi-ciency, than for the problems data redundancy can

cause in the area of maintaining data integrity There

are a few ways to avoid this problem The best way is

to use a third-party real-time credit card processor and

not collect credit card numbers at all If you are not

able to use a third-party credit card processor, youcould store the credit card information in the databasefor a day or two until you process the order At thatpoint, you can mask all but the last 3 or 4 of the creditcard number digits, or you could just delete the creditcard information I will give an example of how tomake this work using MySQL

First, open the

modules/database/mysql/invoice file and addthe function in Listing 2

Now make a new file,

modules/action/CLEAN_INVOICE_CC, containingthe code from Listing 3

Finally, add a button for credit card cleaning in the

modules/screen/edit_invoice file with the lowing:

fol-This is a good example of a simple extension to theoriginal FreeTrade behaviour The store administratorwill now be able to remove the credit card number assoon as it is no longer needed

By default, FreeTrade has no module for credit cardprocessing FreeTrade is a developer product, and theauthors assume that every developer will use themethod provided by the individual processor, as theparameters may vary from processor to processor Thisapproach is fine for experienced developers, but begin-ners may have problems, especially if the credit cardprocessor has poor documentation In order to addcredit card processing, you’ll need to obtain the

print( StartForm (

"edit_invoice" ,

'post' ,

'CLEAN_INVOICE_CC' , FALSE , array( "invoice_ID" =>

$_REQUEST [ 'invoice_ID' ]) )

$invoice = (integer) $invoice ;

$Query = "UPDATE invoice_billing SET " ;

$Query = "CreditCardNumber = \"[REMOVED]\" " ;

$Query = "WHERE Invoice = $invoice" ;

if(!( $DatabaseResult = mysql_query ( $Query ,

$DatabaseLink ))) {

Trang 27

FreeTrade, e-commerce for developers

processor’s documentation and change the

modules/action/SUBMIT_ORDER file.

Wrapping UpThere are a few things I would like to see included in

FreeTrade’s future versions; for instance, better

documen-tation, modules for credit card processing, better search

functions, better reports, bulk import solution, and an

image upload function However, I do find FreeTrade to

be a usable product for developers in its current state

FreeTrade is a great Open Source product, but it’s not

for everyone It is a framework, not a plug-and-play

solu-tion If you want a well-writen script, with lot of featuresand customization possibilities, give it a try

A few words with Leon Atkinson

Leon Atkinson (http://www.leonatkinson.com), author of

FreeTrade have been a big fan of PHP and MySQL What he

is best known for is the book Core PHP Programming, first

published in 1999 It was the first book in English about PHP.

In 2001, he wrote Core MySQL book too We asked him few

questions about FreeTrade.

What are your plans about FT in next period, after FT3

final release?

Customers inspire new features in FT I’m an independent

consultant working with several Web development

business-es My partners bring project to me I use what I have and

donate new code back to FT when appropriate So, in a

cer-tain sense, new features are out there, beyond the horizon.

(Low visibility as people like to say regarding the economy).

There are a few ideas floating around, waiting to be

imple-mented Sean Farley, a frequent contributor, is working on

implementing an affiliate program That is, a system that

allows the site operator to track sales referred from other

sites.

Amazon.com, being the pinnacle of online catalogs,

inspires new functionality In fact, customers often make

remarks like, “I want the checkout process to be like

Amazon.com” However, it’s important to keep in mind that

while Amazon.com is a great example of a mega-store,

ben-efiting from millions of dollars of development, FT is suited

for smaller online stores.

For the past several months I’ve been working on the third

edition of Core PHP Programming All the new features

appearing in PHP inspires me to work them into FT The

database interface is always an interesting topic in

open-source projects Being flexible means more people can use

your project, perhaps contributing On the other hand, I

dis-like sacraficing performance to a

lowest-common-denomina-tor approach That’s why we have separate database

mod-ules PostgreSQL support has been complete for some time

now Lately I’ve been considering coding a module using the

dbx_* functions.

I saw your A.G Ferrari

( http://www.agferrari.com ) site, it’s great Do you

have some other examples of good FT sites?

Thanks I have to give due respect to Clear Ink

( www.clearink.com ) who ran the project and Smashing

Pixels ( www.smashingpixels.com ) who did the graphical design work.

A great example no longer viewable is Restoration Hardware This site grew so successful, it outgrew FT It’s the nature of FT that once built, a site slowly drifts away from the original codebase Where as some software projects attempt

to be a closed box with lots of knobs for customization, FT attempts to be the engine you place in your own box A FT site is craftwork rather than something that comes off an assembly line Another early site that demonstrates this drift

is www.dantz.com , which still uses FT at its heart.

Because anyone can grab the source code and put up a site without any help, sites appear without me knowing I recently discovered Thrasher Magazine runs a version of FT ( http:// www.thrashermagazine.com ) Sometimes people post links to their own projects to the mailing list, such as VentureOut in New Zealand:

Then there are issues with handling credit card numbers, particularly with hosting sites on shared servers A successful online store deserves a dedicated server with most of its ports locked down I find it hard to accept that a site that can’t cover dedicated hosting costs needs to process credit cards, but there are other methods I try to encourge these lower- end sites to go with another payment solution, such as PayPal.

Do you have any particular suggestion for PHP opers planning to use FT?

devel-Participate in the mailing list There are several people who have used FT for quite awhile and will answer questions quickly.

Vladan Zirojevic is a Serbian web developer, educated in Computer Science He worked on more than 30 various PHP projects both as proj- ect leader and part of the team Some of them www.24sata.com ,

www.poljubac.com , www.trebinje.com , www.mobilnimagazin.com Currently, he is employed as a Senior Web Developer in SEENETIX, Belgrade He can be reached at: vladan@webmaster.co.yu

Click HERE To Discuss This Article

https://www.phparch.com/discuss/viewforum.php?f=7

Trang 28

PHP 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

Trang 29

March 2003 · PHP Architect · www.phparch.com

And now for the $64,000 question (someone should

really update these maxims—the money is not that

impressive anymore!): What happens when you

intro-duce your PHP script to a database? If you’re lucky and

have plenty of time (and money) on your hands, the

answer could be a well-built, dynamic website If time

comes at a premium, however, you might end up with

something that’s all too common in the IT world: an

unmeetable deadline and, even worse, an unhappy

client

This is where software like phpLens comes into play

The phpLens system is a complex, but not complicated,

application server that can be used to build dynamic,

data-driven websites Heard that one before? Hang on

to your hats

phpLens is a completely integrated, object-oriented

platform It includes the ability to edit and manage

your HTML templates (Smarty, or otherwise) directly

from a web browser, which makes creating different

views of your data easy and convenient Figure 1

shows one of the examples provided on the phpLens

website - there are almost thirty examples there - where

a complete calendar template has been created and

populated using a simple Smarty template and no

more than twenty lines of code Incredibly, the same

system can produce something as divergent as a bar

graph, shown in Figure 2, while still using fewer than

thirty lines of code

Database AccessibilityThe phpLens engine is written entirely in PHP and isbased on the well known ADOdb database abstractionlibrary developed by John Lim (who, incidentally, is alsothe technical lead of the phpLens team) Anyone whohas ever used ADOdb knows how seamlessly it worksacross a multitude of database systems, includingMySQL, Microsoft SQL Server and Oracle, to name afew

Perhaps one of the most impressive features of thissoftware is its data manipulation functionality Editingdatasets is a breeze in both the “standard” and “Hot

phpLens P

Trang 30

REVIEWS phpLens Review

editing” modes The “standard” mode refers to editing

records one-per-page “Hot editing” refers to a

method where multiple records can be modified at the

same time using an interface similar to that of a typical

electronic spreadsheet The data editing engine

auto-matically recognizes the data type of each field,

includ-ing enumerative types (managed through drop-down

lists) It’s also possible to specify very complex

relation-ships between tables

Security FeaturesphpLens offers both simple and sophisticated security

features Some of the simple features include the

abil-ity to password-protect the dynamic editing functions,

and to automatically filter user input for potential

dan-gerous HTML and SQL statements

One of the more sophisticated features is the

check-summing of records to ensure that the data is not

trans-formed in-transit by a third party Another is the

finger-printing of data, using the md5 digest algorithm, in

order to prevent a malicious user from creating

ficti-tious records without the proper authorization

It should be noted that phpLens does not implement

a full authentication system This is left to the

develop-er to implement using their own choice of tools, such

as Smarty

Finally, the phpLens documentation includes a by-step procedure for securing the folder in whichphpLens resides, without impeding its functionality

step-Documentation and SupportphpLens comes with an excellent set of user documen-tation By “user” I actually mean “developer”, sincephpLens doesn’t force its adopter to utilize a particularend-user interface

The entire documentation set is available online Itfollows a very natural path, from installation all the waydown to the smallest security details In addition, thephpLens website includes a complete reference of allthe objects, properties and methods used by the pack-age

Although support for the product is offered on acommercial basis, the phpLens website includes anastounding number of examples Also available are aFAQ area and a very active peer-support forum (alldeveloped using phpLens, of course)

Figure 1

Trang 31

REVIEWS phpLens Review

Packaging and Limitations

phpLens comes in three flavours: Basic, Advanced and

Enterprise The Basic version supports all the data

manipulation and presentation layer features, with the

exception of creating and editing records The

Advanced and Enterprise versions, on the other hand,

support all of the features The only difference between

the two is the number of database systems they each

support

Because it is based on pure PHP code, phpLens runs

on pretty much any platform PHP runs on The only

requirement is the presence of the Zend Optimizer, as

all of the phpLens scripts and include files are

encrypt-ed using the Zend Encoder This means that you won’t

be able to view and modify phpLens’ source code,

although this shouldn’t be much of a problem thanks

to its object-oriented design Incidentally, if you’re cerned that it might be difficult to find a hostingprovider that uses the Zend Optimizer, the phpLenswebsite includes a list of ISPs who do

con-The Bottom LinephpLens is not an expensive product Considering thestandard set by other similar applications, it offers anexcellent set of functionality for a very reasonable price

If you need to set up a complex, data-driven websiteand you’re in the game for the long term, phpLens isworth serious consideration It’s object-oriented struc-ture is a good bet for the future, and will easily fit intothe PHP 5 philosophy once the new version of the PHPplatform becomes available

Figure 2

php|a

Trang 32

In this article I’ll look at ways to match the best

fea-tures of objects with the best feafea-tures of sessions, to

build fast and efficient dynamic Web sites I’ll talk at

great length about performance considerations, and

look at ways to keep your session data small, and your

site’s performance blazing All of this theory will be

sup-plemented with a wealth of practical examples (and

some neat little tricks) which I hope you’ll find useful

Objects are based on classes, and after looking at the

programming books in the local bookshop, it seems

that there are around 287 ways to write classes In this

article, I will skip the style information and go straight

to the core structural issues relevant to building your

classes The information provided is useful for writing

all classes, whether used in sessions or not

The code included in this article has been tested with

Web sites using PHP 4.2.x and 4.3.0 Some examples

are stripped-down classes representing techniques used

in large-scale commercial sites Others will show you

what does not work The examples are tested using

ses-sions stored in files, as well as MySQL and Oracle

data-bases You might decide to change your session

config-uration, or switch databases, after reading this article

Session PerformanceOne of the first questions you might ask is, “How do

sessions perform when filled with objects?” When you

use sessions, PHP adds a file or database read at thestart of your script, and a file or database write at theend of your script The read should be instantaneousbecause the data should be cached in memory fromthe previous script execution The write will slow downyour script, but it usually occurs after you send your lastchunk of data to the visitor’s browser, so the visitorshould never be impacted by the write time

Oracle, MySQL or Files, Oh My!

Session records can be stored in files or databases.File access is fast on most systems Microsoft NTFSwrites files in 4KB chunks, while Linux ext2 uses 8KBchunks In effect, when you use files there is little differ-ence between writing a short session record containingonly a 32 bit session ID versus writing a 2KB sessionrecord containing a large object If your files are on aRAID device, the RAID device might be writing 64KBchunks This means you can ‘go crazy’ with storing bigobjects in the session, without worrying too muchabout the consequences

By Peter Moulding

Object Oriented Programming (OOP) is in! PHP 4 works with OOP, and PHP 5 will make it perfect Likewise, PHP

makes using sessions easy Sessions pass state information from one Web page to another You can place almost thing in a session, including objects By marrying the two and storing objects in your sessions, you can take advan-

any-tage of ‘run once, use everywhere’ processing.

PHP Version: 4.3 or Above O/S: Any

Additional Software: N/A REQUIREMENTS

FEATURES

Trang 33

Blazing Site Performance Using Objects and Sessions

Databases store rows in pages Pages are chunks of

disk, usually 4KB long If your session data is 50 bytes

long, a page stores 80 rows If your object blows the

session data out to 2KB, a page stores just 2 rows

Databases are more space efficient than files

However, from a performance perspective, a page write

is the same as a file block write, so a database should

not slow down your sessions

MySQL is slower than files on some systems and a

lit-tle faster than files on other systems, but generally there

should be almost no measurable difference between a

50 byte session row and a 2KB session row

Furthermore, the time difference is linear, which means

that adding an extra object produces little difference

Although MySQL lets you choose from three different

table types, the default native table is the best choice as

it has no transaction processing overhead

Oracle is different Oracle has 4KB text fields, so

any-thing larger has to go into a CLOB (Character Large

Object Binary) Tuning Oracle for optimum

perform-ance is painful, and tuning the use of CLOBs is even

more difficult Oracle sites report overheads of 50% or

more, unless you use techniques specific to Oracle To

me it seems silly to use database abstraction classes to

drive Oracle PL/SQL, or anything else that can work

only on Oracle Oracle is great for transaction-based

processing, but sessions do not need transactions! If

you have an Oracle expert on board, you can place

your session records in Oracle Otherwise, leave your

sessions in files

You may also consider leaving your sessions in files if

your database is on a different box from your Web

serv-er and you can’t use a local database for sessions

Whatever you do, do not place your sessions in a

data-base on another machine, or even on a disk shared

across the network, as the added network and system

complexities can increase overhead by 400% or more

Optimizing Code Structure for

SessionsWhen you place an object into a session, only the

data from the object gets stored in the session When

the session data is written out, the object is passed

through serialize(), which squashes the object

variables into a single string Code does not take up

space in the session, so why would we want to focus on

keeping the code small?

Basically, we want small code because it has to be

compiled at some point On many web sites, code is

compiled every time a script starts Imagine a class with

several thousand lines of code being compiled for every

web page An optimizer will cache the compiled code,

but not every ISP uses an optimizer, and optimizers

cannot cache all scripts

When we store an object in a session, the class code

will still need to be compiled again on each page when

the object is deserialized out of the session If we canminimize the amount of code that needs to be loadedand compiled in order for an object to be deserialized,

we gain efficiency

To this end, I prefer to split code into a structurebased on usage One block is the code used at thestart, then a block used in the middle and, finally, ablock used at the end It is a bit like splitting a web pageinto header, body and footer, or a file access operationinto open, read and close This approach is a good firststep towards cutting large blocks of code into small,manageable chunks, and has the added benefit ofbuilding memory efficient objects When thinkingabout storing objects in sessions, memory usage effi-ciency also means session usage efficiency

PHP classes offer a class constructor to perform theinitial work to be performed by the class Unfortunately,the constructor code remains with the class throughoutits life If our constructor code is huge, we can consid-

er putting the bulk of the constructor code into a arate class In the upcoming example classes, the class

sep-objective_foot has all of the construction code in

the constructor objective_foot2 is a reconstructed version of objective_foot where the constructor

contains just a single include of

Place all of your difficult-to-write code into the “useonce” class Keep the “use on every page” class sim-ple, easy to understand, and easy to maintain Once

your “use everywhere” class actually is used

every-where, making changes will be difficult You will reducemaintenance problems by organizing your code based

on usage

There is another objective for splitting your code:providing a layer of abstraction to afford yourself theflexibility of handling future changes in the logic sec-tion of your code The “use on every page” classshould contain just data File processing and other spe-cialized logic code should be in another class so that itcan be easily altered Next week you might have toreplace file processing with databases, or text inputmight become XML If you can split your code alongthese ‘logic vs data’ lines, you gain a level of abstrac-tion where the users of the “use on every page” codework only with data, and are not affected by changes

to the logic

Trang 34

FEATURES Blazing Site Performance Using Objects and Sessions

An Example or Two

I would like to show you a full content management

system, but the code listing would flood this magazine

and squeeze out the interesting stuff! The following

examples represent a real set of code that reads XML

and database sources to build page content, and are

minimal examples I use when teaching PHP

In actual web sites, the code builds input from many

sources, and the initial class constructor grows into

multiple includes, wrapped in miles of logic Individual

inclusions can have thousands of lines of code which

find, read and decode input For this discussion, all we

need are a few inclusions with a sample line of code in

each

Let’s pretend we have the task of creating a common

footer for all the web pages at petermoulding.com and

we are told to use existing formatting classes This

footer is a copyright notice centered on a blue

back-ground

You’ll notice that there are a number of small classes

in this example and you might wonder why We want

an example where there is a big chunk of code used

once, and one small object which is used repeatedly In

this example, all of the classes are used when the

visi-tor requests the first page from the site For every other

page request, only the class containing the formatted

HTML is needed

The Example Classes

objective_html is the base class for all of ourother HTML classes It provides a common $htmlvari-able and the get_html()method The class is stored

in a file named objective_html.class in the site’s

include directory and is shown in Listing 1

The next few classes are derived from the tive_html class and are shown in Listing 2 through6

objec-The objective_foot class includes all the

previ-ous classes in one big constructor and is shown inListing 7

The ResultListing 8 ties it all together The image in Figure 1shows the fruits of our labor This might seem like a lot

of work for this small result, but remember that theexamples are representative of code delivering a whole

8 $this -> html = '<table cellpadding="' $cellpadding '"'

9 ' width="' $width '">' $text '</table>' ;

Trang 35

Blazing Site Performance Using Objects and Sessions

web page constructed from 30 or more sources

Now let’s see what the code looks like when we apply

the optimizations we talked about earlier The

objec-tive_foot_startclass, shown in Listing 9, contains

all of the constructor code that can been removed from

the objective_foot class If any of the code in this

class prevents your optimizer from caching the

com-piled code, you will lose caching on only one page (the

first one)

Listing 10 shows the objective_foot class with all

the constructor code replaced by one

require_once(), including the

objective_foot_start class When this class is

compiled for your second and subsequent pages, the

compilation time is reduced and there is more chance

your optimizer can cache this simple class

Now, let’s see how to put these objects into the

ses-sion

Getting Objects into the SessionWhen you manually start the session in your codewith session_start(), placing objects in the ses-sion is easy On your first page, you can use the follow-

ing code to create an objective_foot object in the

session

On the first page, the require_once() and the

session_start()can go in any order At the end ofthe first page, PHP will run $_SESSION[‘ foot ’]

through serialize()to produce a string for storage

in the session record

Life is different on the second and subsequent pages

require_once( 'objective_foot.class' );

session_start ();

$_SESSION [ 'foot' ] = new objective_foot ();

print $_SESSION [ 'foot' ]-> get_html ();

Listing 5: objective_td class

Figure 1: Output from objective_foot class

17 $table = new objective_table ( $tr -> get_html (), 10 , '100%' );

18 parent :: objective_html ( $table -> get_html ());

Trang 36

FEATURES Blazing Site Performance Using Objects and Sessions

The session_start() on the second page will grab

the string from the session record and run the string

through unserialize()to recreate the object in the

$_SESSION[‘ foot ’] variable Remember that

objects require code, and code is not stored in

serial-ized objects The unserialize()function has to read

the object’s class code and add the code back to the

object, which means that you have to be sure to

include the class before using session_start() This

works:

but this does not work:

The next question is what to do when your ISP sets

PHP to automatically start sessions and will not change

the setting for you You should consider changing your

ISP :-)

There is something less dramatic than changing your

ISP, and it is something you might want to do anyway

to lower your overhead I mentioned before that you

might want to restructure in order to minimize the

code you include on every page You can go one step

further to solve the problem of including unnecessaryclasses on every page

Close your eyes and visualize a complete, perfectcontent management system written to do absolutelyeverything you want (and everything you will everwant) The code is optimized to include the bare mini-mum number of classes on every page The trouble isthat the bare minimum includes hundreds of classes,with most classes used only on a few pages In front ofyour session_start() are 200 lines of

require_once() This would normally be quite aproblem with automatically started sessions

Here is a way to prevent including every class onevery page which also solves the problem of

session_start() happening before your code gets

a chance to include any classes

On your first page, write:

(Note that if you want to use this method and youdon’t have sessions automatically starting, you willneed a session_start()call at the beginning.)

require_once( 'objective_foot.class' );

$foot = new objective_foot ();

$_SESSION [ 'foot' ] = serialize ( $foot );

5 $foot = new objective_foot ();

6 print $foot -> get_html ();

10 $foot = new objective_foot_start ();

11 parent :: objective_html ( $foot -> get_html ());

16 $table = new objective_table ( $tr -> get_html (), 10 , '100%' );

17 parent :: objective_html ( $table -> get_html ());

Ngày đăng: 11/12/2013, 02:15

TỪ KHÓA LIÊN QUAN