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

Tài liệu THE PHP EMPIRE doc

68 415 0
Tài liệu đã được kiểm tra trùng lặp

Đ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 đề The PHP Empire
Trường học Unknown
Chuyên ngành Web Development and PHP Programming
Thể loại Bài luận
Năm xuất bản 2005
Thành phố Unknown
Định dạng
Số trang 68
Dung lượng 6,38 MB

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

Nội dung

Many modules, for example, depend on Flexinode, a module that allows non-programmers to create new node types from within the content types menu, without having to custom load database

Trang 2

A simple way to implement

logging in your applications

by KNUT URDALEN

A database solution to simplify your code and

help you create high-performance applications

by PETER LAVIN

SPECIAL REPORT

PHP Version Tracker Report

If you want to bring a php-related topic to the attention of the professional php community, whether it

is personal research, company software, or anything else, why not write an article for php|architect?

If you would like to contribute, contact us and one of our editors will be happy to help you hone your idea and turn it into a beautiful article for our magazine Visit www.phparch.com/writeforus.php

CONTENTS

WRITE FOR US!

Trang 4

Graphics & Layout

php|architect (ISSN 1709-7169) is published

twelve times a year by Marco Tabini & Associates, Inc., P.O Box 54526, 1771 Avenue Road, Toronto,

ON M5M 4N5, Canada

Although all possible care has been placed in assuring the accuracy of the contents of this magazine, including all associated source code, listings and figures, the publisher assumes

no responsibilities with regards of use of the information contained herein or in all associated material.

php|architect, php|a, the php|architect logo, Marco Tabini & Associates, Inc and the Mta Logo are trademarks of Marco Tabini & Associates, Inc.

Contact Information:

General mailbox: info@phparch.com

Editorial: editors@phparch.com

Subscriptions: subs@phparch.com

Sales & advertising: sales@phparch.com

Technical support: support@phparch.com

Printed in Canada Copyright © 2003-2005 Marco Tabini & Associates, Inc All Rights Reserved

If you follow PHP releases, closely, you’ll have noticed that PHP 5.1.0

was released on Thursday November 24, 2005 This release was billed as

paramount in PHP’s history, touted by many core developers as “the first

solid PHP 5 release.”

This supposed banner release was quickly overshadowed on the developers’

mailing list as problematic: a change that was made late in the release candidacy

cycle (a new internal Date class) will break hundreds, if not thousands (or perhaps

hundreds of thousands?) of deployed PHP applications It was generally accepted

knowledge that new functionality can’t break existing code, but this “knowledge”

proved simply incorrect

In this case, PEAR has an existing (and well-deployed) Date class of its own As

you know, PHP doesn’t currently have namespacing, so you obviously cannot have a

Date class in PHP and then declare a second one for PEAR

Much discussion ensued, including a strong push towards an accepted namespace

standard for PHP (perhaps we’ll see it in the 5.x series, and all signs point to

namespaces in PHP 6 at the latest) The really interesting discussion for me, though

was something along the lines of “why should core care about PEAR?”

Yet another political discussion It seems that the technical problems are

(relatively) easy to solve, and the real problem is on the social side So, should PHP

core care about PEAR? Tough call On one hand core should be given first-rights

to any sort of class, function, variable or constant name The other side (again) is

social: when most users download and install a package from PEAR, they do so from

pear.php.net As far as those users are concerned, they’re downloading both PHP

and PEAR from php.net, so they should work together

Unfortunately, there’s no easy and permanent solution to this problem However,

Ilia, the 5.1 release manager—and past author for php|architect—wisely reacted

quickly, and on November 28, 2005, PHP 5.1.1 was released, temporarily solving

this problem, by removing the new internal Date class One growing pain averted,

if only temporarily

PHP’s integration and many offerings from php.net gives it somewhat of an

“empire” status This metaphor is further extended when see how PHP has conquered

much of the web in its short lifetime Tips & Tricks takes a break this month to make

way for a special feature called “Where in the World is PHP?” In this piece, Damien

Seguy shares his company’s findings on how PHP has infiltrated nearly every market,

territory, and size of web application

This boom is no accident As you saw last month, PHP is making great strides

in the enterprise, and is shedding its “quick & dirty” reputation Long live the

dynamically typed variable!

THE

PHP

EMPIRE

Trang 6

PHP 5.5.1

“The PHP Development Team would like to

announce the immediate release of PHP 5.1.1

This is a regression correction release aimed at

addressing several issues introduced by PHP

5.1.0, the core changes as follows:

• Native date class is withdrawn

to prevent namespace conflict

with PEAR’s date package.

• Fixed fatal parse error when the last

line of the script is a PHP comment.

• eval() hangs when the code being

evaluated ends with a comment.

• Usage of \{$var} in PHP 5.1.0

resulted in the output of {$var}

instead of the $var variable’s

checks inside the cURL extension.

Get your hands on the latest release at

php.net!

PHPBase Alpha

Phpbase.org announces their alpha release.

What is it? According to phpbase.org,

“PhpBase is a set of Open Source PHP classes and functions aimed to help developers submitting their data to Google Base.

The main purpose for a tool like this is the need to keep data submissions accurate and avoid common errors that might occur when submitting to standard schemes recommended by Google.

The code still in development, and will be added to a subversion repository once we get the project approved at berlios.de.”

Get all the latest info from phpbase.org.

PHP applications across the enterprise Zend Studio 5, the most widely used Integrated Development Environment for PHP, has been enhanced with new features to assist

in the development, debugging, testing, and deployment of PHP applications, including easy integration with other enterprise applications.

Available in three editions; Standard, Professional, and Enterprise, Zend Studio 5 includes support for PHP 5 as well as an easy switching mechanism allowing users to move between PHP 4 and PHP 5 for full application development, and also seamlessly integrates with Zend Platform 2 to provide a complete development and deployment solution for business-critical, PHP-based applications.” Visit Zend.com to grab the latest release

and check out all the latest features.

OBM-Open Business Management 1.0.2

OBM is proud to announce the latest release

of their Business Management application version 1.0.2.

Need a free management application for your business? Check out OBM According

to OBM’s site:

“BM is an Intranet application which goal is to help manage a company or an organization

news

php|architect Releases New Design Patterns Book

We’re proud to announce the release of php|architect’s Guide to PHP Design Patterns, the latest release in our Nanobook series.

You have probably heard a lot about Design Patterns —a technique that helps you design rock-solid solutions to practical problems that programmers everywhere encounter

in their day-to-day work Even though there has been a lot of buzz, however, no-one has yet come up with a comprehensive resource on design patterns for PHP developers—until today.

Author Jason E Sweat’s book php|architect’s Guide to PHP Design Patterns is the first, comprehensive guide to design patterns designed specifically for the PHP developer This book includes coverage of 16 design patterns with a specific eye to their applications in PHP when building complex web applications, both in PHP 4 and PHP 5 (where appropriate, sample code for both versions of the language is provided).

For more information, http://www.phparch.com/shop_product.php?itemid=96.

Trang 7

Looking for a new PHP Extension? Check out the latest from PECL.

hash 1.0

Native implementations of common message digest algorithms using a generic factory method.

ps 1.3.3

ps is an extension similar to the pdf extension but for creating PostScript files Its api is modelled after the pdf extension.

Fileinfo 1.0.2

This extension allows retrieval of information regarding vast majority of files This information may include dimensions, quality, length etc.

Additionally, it can also be used to retrieve the mime type for a particular file and, for text files, the proper language encoding.

sdo 0.7.0

Service Data Objects (SDOs) enable PHP applications to work with data from different sources (like a database query, an XML file, or

a spreadsheet) using a single interface.

Check out the hottest new releases from PEAR.

2) Find the file you need Each function

is in its own file, e.g array_walk_

Log 1.9.3

The Log framework provides an abstracted logging system It supports logging to console, file, syslog, SQL, Sqlite, mail, and mcal targets It also provides a subject - observer mechanism.

File_SearchReplace 1.1.0

Provides various functions to perform search/

replace on files Preg/Ereg regex supported along with faster but more basic str_replace routine.

Cache_Lite 1.6.0

This package is a little cache system optimized for file containers It is fast and safe (because it uses file locking and/or anti-corruption tests).

Net_DNS 1.0.0rc3

A resolver library used to communicate with

a name server to perform DNS queries, zone transfers, dynamic DNS updates, etc

Creates an object hierarchy from a DNS server response, which allows you to view all

of the information given by the DNS server

It bypasses the system resolver library and communicates directly with the server.

HTML_QuickForm_

advmultiselect 1.1.0

The HTML_QuickForm_advmultiselect package adds an element to the HTML_ QuickForm package that is two select boxes next to each other emulating a multi-select.

tracking sections) but can be used simply as a

contact database or as a shared calendar.

OBM represents a framework above which

many modules are written.”

Interested? Get more info from

• Full PHP 5 support, phpDocumentor

both runs in and parses Zend

Engine 2 language constructs

Note that you must be running

phpDocumentor in PHP 5 in

order to parse PHP 5 code

• XML:DocBook/peardoc2:

default converter now beautifies

the source using PEAR’s

XML_Beautifier if available

• inline {@example} tag - this works

just like {@source} except that it

displays the contents of another file.

• customizable README/

INSTALL/CHANGELOG files

• phpDocumentor tries to run

.ini files out of the current

directory first, to allow you to

put them anywhere you want

• multi-national characters are

now allowed in package/

subpackage names

• images in tutorials

• un-modified output

• html/xml source highlighting

This release also contains many bug fixes.

Get the latest info and start documenting at

phpdoc.org.

Trang 8

an introduction

In their every day development, most web

consulting companies encounter many of the

same components when designing pages for

non-profit organizations and activist groups These

requirements include forums, a donation system,

membership management, newsletters, and articles,

just to name a few Many of these organizations also

have small to mid-size e-commerce needs, to effectively

sell and distribute promotional materials, or to handle

signups for paid events

Developers often tackle this task by rolling their own

systems in an attempt to make their sites as customizable

as possible, while still providing core components to

build on for each individual client In theory, it sounds

like a good idea In practice, the limitations of their

underlying frameworks ultimately result in nothing more

than a mash of hacks that only loosely integrate the

unique elements required for their clients

In the worst case, web development shops end up

coding the entire thing from scratch, each and every

Organizations these days are demanding

content management applications,

from company homepages to large,

community websites Let Drupal help

you build these sites quickly and

efficiently by building on a common,

modular framework.

PHP: 4.4 O/S: Debian OTHER SOFTWARE: Drupal 4.6.3

by TITUS BARIK

Trang 9

time Somehow, rolling your own system

never quite works out the way it needs

to Even if you have two well-written

components, it is often the case that

it’s not the components themselves that

are the problem, but the integration

points that add burdensome complexity

Integrating disjoint components, say

Forum A with Shopping Cart B, has until

now, been a difficult problem to solve

This article introduces Drupal, a

modular, open source content management

platform that attempts to address these

difficult challenges Drupal provides

a flexible, extensible framework—an

alternative to roll-your-own content

management solutions It can be refit for

a variety of different content systems,

including community portal sites, personal

weblogs, and resource directories, simply

by adding and removing sophisticated

modules

Drupal offers you a working, tested

framework for building components, and

handles the insignificant but tedious

details of module management, user

management, and integration, so you

can focus on developing the core of your

project More importantly, Drupal has

a very large user base, and modules to

handle most common functionality are

already available When these modules

don’t exist, the hooks system allows

the developer to create custom modules

to interact with the Drupal core, while

leveraging the existing Drupal building

blocks

It’s not at all surprising, then, that

the focus of this article is not on complex

development or PHP code, at least not

directly In fact, it’s quite the opposite In

this article, we’ll develop a mock political

organization’s web site, Democratica,

without writing a single line of code

Along the way, I’ll demostrate the various

built-in and contributed modules that allow you to get a site up running quickly and effortlessly

Installation

This section discusses the installation and configuration details of Drupal, including the pre-requisite software requirements Our test installation consists of Drupal 4.6.3, PHP 4, and Apache 2, running on Linux with a MySQL 4.1 database server

Though Drupal supports both MySQL and PostgrseSQL, be advised that most available third-party modules are coded specifically for MySQL This effectively forces you to use the former, regardless of

what the Drupal core modules support

Drupal allows you to host multiple sites on a single Drupal instance These sites can be found under the sites folder For simplicity, I’ll only utilitize a single site setup in this article

After creating and assigning the appropriate permissions to your database, load the tables:

mysql -u nobody -p drupal < database/database.mysql

Next, enter the sites/default folder and modify settings.php; namely, modify the db_url, and base_url

Drupal works best on dedicated hosting systems Since Drupal

FIGURE 1

The first screen you’ll encounter after installing Drupal

Trang 10

memory requirements increase proportionally with the

number of active modules, the default PHP memory limit

of 8 MB provided by most shared hosting providers is

typically not enough To be safe, set this value to 32M

or 64M in php.ini If the memory requirements are not

successfully met, Drupal will behave strangely, displaying

broken administrative menus and erratic page rendering

Next, add the following to your crontab:

0 * * * * wget -O - -q http://democratica/cron.php

This allows for scheduled events to trigger properly

within Drupal Such events include search indexing, mass

mailing, and scheduled publishing

That’s all there is to the installation Navigate to

your Drupal site using your web browser, and you’ll be

presented with a base page, as shown in Figure 1

Finding Your Way

Around

It’s time to create your first

account User #1 is provided

with full administrative access

All subsequent users are given

authorized user access Additional

groups can be generated though

the Drupal system as well, providing

fine granularity amongst different

group types In Democratica, for

example, we may want special

access for employees, and different

access priveleges for members and

guests,

After logging in, select the

administer menu You’ll be presented

with Drupal’s recent system events,

a web-based logging system for

monitoring the activity on your web

site A typical administration page

is shown in Figure 2 For now, enter

the settings menu, and change the

Administration section of Drupal

default name of the site to Democratica You should also set your time zone Feel free to modify any other settings, as well

Perhaps the two most useful menus under administer are blocks and modules The modules menu allows you

to extend the core functionality of Drupal Within this menu, you’ll activate and install module components

to tailor the functionality that your site requires For example, you could enable search, forums, events, and so forth The blocks menu enables and disables boxes that can be positioned on the left and right side bars of your web site The available blocks vary, depending on which modules are currently active Under modules, notice that the page and story modules are checked by default

Now, jump up to the create content menu You’ll notice

that there are two available content types: page and

Trang 11

story, the same as the modules we previously witnessed

Enabling content modules will add additional content

types to this menu After initial setup, most interaction

with the Drupal site will occur through this menu

Finally, let’s examine the content menu, again under

administer This menu allows us to configure the properties

of content nodes, which at first, can be a bit perplexing

Unlike a dedicated content system such as WordPress for

blogging, or osCommerce for e-commerce, Drupal aims to

be flexible, to suit any type of web platform In order to

provide such flexiblility, the fundamental type of almost

all content is that of a simple node Custom behavior

is then implemented by simulating the base node type,

and subsequently adding or removing properties to that

node type The content menu allows us to set additional

properties, modify nodes, and add custom nodes to

facilitate our development process

Democratica Theme

In Drupal, themes are rendered through the use of

template engines Unfortunately, Drupal by default only

provides xtemplate, and the Democratica theme that

we’re interested in requires PHPTemplate Luckily, this

takes very little effort Simply download the PHPTemplate

engine from the Drupal web site, and extract it to the

themes/engines folder Next, download and extract the

Democratica theme, and place it in your themes folder

Login to your web site as administrator and access

the themes menu The Democratica theme is now

automatically available Set it to default, and save your

configuration Your new theme is now applied

Theming is a powerful component of the Drupal

framework that will greatly streamline development

Namely, it enables you to parallelize your backend

business logic and your presentation code Your graphic

designers, for example, can independently develop multiple, pluggable layouts, while your logic developers can write custom modules and other core functionality

Modules

The remainder of this article will focus on modules The process of installing some modules is more involved than others, though none of the modules are exceptionally difficult to integrate The typical installation procedure for a module is as follows:

First, load the database schema This is usually one or more iterations of the following command:

mysql -u user -p database < schema.sql

Next, copy the module to the modules directory Then

activate the module in the administer modules menu.

Then, set configuration parameters for the module

under the administer settings menu, and configure access

control permissions on the module through the access

control menu

Finally, if the module has a presentation layer, enable

the block in the block menu, specifying its location and

ordering

Some modules have dependencies on other modules

Many modules, for example, depend on Flexinode, a

module that allows non-programmers to create new node types from within the content types menu, without having to custom load database node schemas for each new node type

Before continuing, install and activate the Flexinode module A content type menu will appear under content, and a flexinode menu item will appear under settings.

Unlike a dedicated content system

such as WordPress for blogging,

or osCommerce for e-commerce, Drupal aims to be flexible,

to suit any type of web platform.

Trang 12

Our first module will be a simple one Most political

organizations have a need for donations, and our site

is no different The Donations module allows us to

accomplish just this goal, with seamless

integration to the Donorge.org donation

service Under settings, modify the

text as desired Since this isn’t a live

site, the donation ID doesn’t actually

matter

Nothing appears to have actually

happened, but that’s because we

haven’t told Drupal to place the

content block on the web site Let’s

do that now Click on the blocks

menu, enable Donations, and place it

on the right sidebar A third column

on the Democratica theme will now

be enabled, with your new donation

module, as shown in Figure 3

Without having to modify a

single line of code, we’ve managed

to add donation functionality to our

Democratica site Reusable components

such as the donations module are what

make developing under the Drupal

framework so efficient

Newsletter

After interviewing several non-profit

organizations, the most demanded

feature next to donations is that of

newsletters Newsletters, when used

effectively, are a vital method of

directly addressing your members,

notifying them of important news and

issues Our political organization, in

particular, wants to let our subscribers

know about the latest campaign news

Drupal provides such functionality

through the simplenews module Install it now Like the donation module, it will appear as though nothing has changed Click the new newsletters menu item

under administration; this will create a default Drupal

newsletters Under the newsletters

tab, click edit type for Drupal, and change the name to “Democratica Newsletter.” The Newsletters interface allows you to create multiple newsletters, track the progress of newsletters, and track subscribers, as shown in Figure 4 Under blocks, activate the newly created newsletter, placing it on the right sidebar

Next, create a newsletter

from the create content menu

Creating a newsletter item is simple enough that it doesn’t require any further explanation here Assuming your PHP configuration and mail server are setup correctly, all subscribers will receive an e-mailed copy

of the newsletters you’ve just posted

Survey

Our political organization wants

to collect data that may help in predicting the outcome of the next election To do this, they would like to create a survey, asking various questions on the web site At first glance, such

a task seems like a great deal

of work We’d have to design

a backend database to store

a variety of survey questions,

FIGURE 5

Election survey.

FIGURE 6

Election survey, administrator perspective

Drupal provides an excellent, out of the box, event handling system.

Trang 13

modules In addition, activate

the cod module and the tangible

module, for tangible products

Under create content, a product

item will now appear Here, you can set the product title, description, price, and the type

of product For Democratica, the fulfillment house handles all inventory, and we thus disable inventory management

Under the block menu, enable the Shopping Cart module Under the create content

menu, create your product Once completed, it will appear in the top-level products menu From here, you can add it to your cart and checkout The e-commerce module can and probably will need to be customized through PHP to suit your particular needs However, the provided shopping cart already provides much of the required base functionality

Events

Democratica can’t be successful

in rallying support if it can’t successfully organize events Drupal provides an excellent, out of the box, event handling system

The event module relies on the Flexinode module, which was

installed earlier in this article A

close cousin of the event module

is the location module, which allows for additional location

information

The location module will add the final touch to

our event system Currently, the location module fully supports United States zip codes The module provides routines for conducting postal code proximity searches, linking to Google maps, and other functions for collecting locations Follow the directions for installing this module, carefully This module is unique in that it requires you to load three mysql data files: a location schema, a zipcode schema, and US zip code data Then, just as we’ve done

for all other modules, activate it through the module

menu

implement forms on the front-end,

and provide facilities to allow the

organization to collect and download

the data in a user-friendly format In

addition, we would have to provide

some sort of dynamic form creation

system to allow users to create their

own surveys

Unsurprisingly, Drupal makes this

task simple and reusable through the

survey module The survey module

depends on the forms module, which

provides an API for adding

user-customizable form elements within

modules First, install the form

module and activate it Then, install

and activate the survey module.

Under the create content menu, the

survey item will appear, in addition to

the standard story and page items

Let’s now create a survey called

“Election Survey.” After entering

the general information, you’ll find

yourself in a survey menu, from where

you’ll go to the form tab

Add a radio field We’d like to

know which political party you belong

to Under selection options, enter

“Republican; Democrat; Libertarian”

The semi-colon is used to delimit

the multiple options for the given

field type Add any additional desired

fields A non-administrator user will be

presented with the survey, as shown

in Figure 5 As an administrator, your

window will appear more like that in

Figure 6 When a user completes a

survey, his or her results can be found

under the responses tab.

E-Commerce

Throughout the political campaign, our organization

wants to sell tangible items through its fulfillment house

These items include bumper stickers, signs, buttons, and

so on

The e-commerce package includes several modules

Some of the modules are located in Figure 7

E-commerce preferences can set under the settings

menu Among other options, items include things like

whether customers must create an account to order,

shipping methods, and payment methods

For our purposes, activate all of the required

Trang 14

After enabling both modules, access the block menu

and enable List of upcoming events An empty upcoming

events listing will appear, depending on your sidebar

selection

Unlike most of our previous modules, an event is not

a node type in itself Specifically, event properties can be

added to any node type So, for example, you can create

your own Generic Event node type using Flexinodes, or

you can create a Birthday node type for birthdays, and so

on, to describe different categories of events

Let’s create a Generic Event node now Click on content

type in the content menu under administration, and click

the add content type tab Call our content type name

“event,” and give it a short blurb in the description

You’ll now be placed in the list tab, where you can add

additional fields to your custom node Title is already

included, so let’s add a text area for the event description

After following these steps, your screen should resemble

Figure 8

Though we’ve created a generic

event node, we have yet to bind

the event module properties to

it To do so, click on the content

menu, then the configure tab

From here, click the content type

subtype, where you’ll find the

configure option for the event

Yes, it’s deeply buried under a lot

of menus, so look at Figure 9 for

assistance

Under configure, scroll down

to “show in event calendar.” Set

this to all views to enable event

times for the generic event node

that you’ve just created Under

the blocks menu, enable “List of

upcoming events.” In addition,

select “Enable for location,” a

feature contributed by the location

module Set “Allow” for street, city,

state, postal, and country

You’re on the final stretch It’s

time to actually add an event Under

create content, you’ll now find an

event item Fill in the details for

your event In our example, we’re

celebrating the Democratica Launch

Party, shown in Figure 10 Notice

also, that the event has been

added to the upcoming events list

This is where the RSVP module comes in RSVP lets users invite people to attend an event It sends an invitation email to a list of people, and can the track which users have looked at the invitation and their responses Invitees can view and reply without having user accounts

After enabling the RSVP option, a Create RSVP link

will become active on all events From here, you can invite selected guests to your event An invite preview is shown in Figure 11

Other Modules

Our last module is as big one CiviCRM is a web-based,

open source, internationalized, constituent relationship management (CRM) application, designed specifically to meet the needs of advocacy, non-profit and non-governmental organizations

In short, it keeps track of people

CiviCRM is large enough to be

a product on its own It is also the most complicated of modules

to install, and its installation instructions would comprise an entire article by itself The CiviCRM module is also a dependency for the other modules which require contact management, and it is also an optional requirement for the event finder module, which allows the user to search for events based on event type, geographic location, and proximity to major metropolitan area

Thankfully, the OpenNGO web

site provides excellent installation

instructions for the CiviCRM module

Here, I’ll omit the installation steps and show you the brief demo of the

CiviCRM and Event Finder modules CiviCRM primarily enables

the Find Contacts feature, shown

in Figure 12 It also allows you

to manage groups, relationship types between contacts, and

Trang 15

TITUS BARIK is a content application developer with an interest in open source Enterprise solutions He has deployed both open source and proprietary content management systems successfully in corporate and non-profit environments His personal weblog is available at barik net, and he welcomes your comments and suggestions.

For those who don’t

have in-house contact

management tools,

CiviCRM may be a good

option

Event Finder takes

the functionality of the

existing events module

and adds the ability to

actively search for local

events by category,

event type, and zip

code It also enables

online registration for

events, where one can

specify the maximum

number of registrants

Conclusion

The final result is shown

in Figure 13 In the

course of about an hour

or two, you’ve created

a dynamic site that

each and every one of

these components for

your specific project,

the time saved in

comparison to writing

a custom solution from scratch is simply tremendous

Drupal is a large and powerful framework, and you’ll

no doubt run into a few obstacles here and there, along

the way When you do, the Drupal Handbook is available

online for your use The Drupal web site also provides

forums to address questions and issues that aren’t

covered by the Handbook

Sites that have successfully implemented Drupal

include Spread Firefox, Kernel Trap, Linux Journal, and

The Onion I hope that you’ll be next 

Trang 16

When we write a PHP application, it may

rely on a remote program that performs

certain operations what we can’t, or don’t

want to do locally

For instance, we may need to fetch some up-to-date data about, the weather in Los Angeles

Since it is unlikely that our application will have access

to this data through a local database, we must somehow

communicate with the web site of the local meteorological

station in L.A

We have a similar problem if we want to make our

user perform a web search without leaving the pages

of our site—our PHP application must send a query to

(e.g.) the Google Application Program Interface, and

retrieve the response

Perhaps you want to implement an online shop, with

a payment system based on PayPal; you’d have to set up

secure communications between your site and the PayPal

servers

Finally, you may have a local database of user names,

mails and contacts and want to make some of this

information available to a certain number of authorized

users

All of the examples above require the use of some sort of communication with a remote application: what

we are looking for are Web Services

A web service is a software system designed to support interoperable machine-to-machine interaction over a

Trang 17

network So, when we talk about WS, we are implicitly

referring to many parts:

• A client application, which can be written

in any language (e.g C, Java, Python, and

of course PHP) and run on any Operating

System

• A remote application, with which we want to

communicate

• A remote interface, often described by WSDL

(Web Service Description Language)

• A protocol, normally based on TCP/IP—the

most used are HTTP and HTTPS

• A document to be sent or received, which is

usually encoded using particular XML subsets

like SOAP (Simple Object Access Protocol) or

XML-RPC (Remote Procedure Call)

In Figure 1 you can see an example of an application

which connects to a remote Application Program Interface

to fetch data from its database: while the communication

between the program and the user (at least, his browser)

is encoded in HTML, the traffic between the two machines

is transported via SOAP

This article is a short introduction to web services

Our purpose is to explore what we can do with them

and how they work We will have a closer look at

SOAP-based web services over HTTP, as they are the most

common, and are pretty easy to use We will also take a

look at a sample application which consists of a client

& server system, and performs a simple operation (in

our case, retrieves data from a remote MySQL database)

Out sample takes advantage of NuSOAP, a predefined PHP

library, designed to perform Remote Procedure Calls

Before we get into the real work, however, we will

cover SOAP and WSDL basics, without getting too deep,

just to make things a bit clearer We won’t, however,

see any complex practical application of Web Services In

fact, this article’s intent is introductory If you’re looking

for a little more meat, you should take a look at the

upcoming php|a NanoBook, “Practical Web Services,”

which I will quote several times in the following text

Simple Object Access Protocol:

an overview

SOAP is an XML-based protocol, created by the World

Wide Web Consortium It was created to help server

applications exchange structured and typed information

in a distributed environment A SOAP message can be

sent on any Internet protocol (HTTP and HTTPS are the

most common)

What makes SOAP so powerful is that the application

that receives the message doesn’t need to be written in

the same programming language, or even to be run on the same operating system as the one that originated the request The platform is simply irrelevant—so you could easily make a NET application exchange data with one written in Python

A SOAP message is normally composed of three

elements: an envelope, a header and a body When dealing with an error condition, a SOAP fault element will also

be present

The envelope is the first element in a SOAP message, and it’s mandatory It may contain namespace declarations or additional attributes, which must be namespace-qualified It may also contain additional namespace-qualified sub-elements that must follow the

body element.

The header is optional and, if used, must be the first child element of the envelope It may contain a set of

namespace-qualified header entries as an immediate

child element of the header element, and it may also

contain general information about the message, such as language, date, etc

The body is mandatory, and must be an immediate child element of the envelope (and follow the header,

if it’s present) It may contain a set of body entries,

Trang 18

which must be an immediate child of the body element

and each entry may be namespace-qualified This is the

most important part of the message, since it contains

the request or the response, and the part that is used to

perform Remote Procedure Calls (RPCs)

As I mentioned, a particular type of body entry,

named fault, is used to indicate error messages Its

sub-elements are used to report information about the error

(the error code and name, what caused it, etc.) Any type

of application may need to use this kind entry, so we will

examine it, too (briefly)

For a detailed description of the SOAP language,

check the World Wide Web Consortium documentation

at http://www.w3.org/TR/SOAP We won’t examine WSDL

in depth, as it is quite a complex topic, but we can’t

completely overlook it because of its importance—it’s

definitely worth a quick glance, if for nothing else, then

to understand its main purpose

SOAP Envelope element

This element must always contain a namespace URI to

define the SOAP versioning model The only valid namespace

URI is: http://schemas.xmlsoap.org/soap/envelope/

The envelope may also contain an encodingStyle

attribute to indicate the serialization rules used; here

are some examples of valid URIs:

http://schemas.xmlsoap.org/soap/encoding/

http://example.com/enc/spec/

http://www.example.com/enc/

As you can see, you can use more than one URI

separated by a space (ordered from the most specific to

the least specific) A blank URI means that there are no

claims for the encoding style

Here is an example of a valid envelope element:

It has namespace and encoding style declarations We

will insert our other elements or sub-elements within

this main tag

SOAP Header Element

The SOAP header is qualified by its local name and

namespace URI It is optional, and may contain general

information about the message The encodingStyle

attribute may be used to indicate the encoding style

Two attributes are frequently used in this element:

mustUnderstand and actor

The mustUnderstand attribute indicates whether the

header entry must be processed by the recipient Its value can be 1 or 0 (if it’s absent, a default value of 0 is assumed) If it’s set to 1, the entry must be processed.The actor attribute is useful for messages that travel from the originator to their final destination by passing through one or more intermediaries (SOAP servers can have the ability to both receive and forward a SOAP message) actor specifies which of these intermediaries should receive and process the header entry (which, when processed, will be no longer forwarded) The value of actor is the URI of the recipient There are, however, two special cases: if the attribute is absent, then the recipient automatically becomes the recipient; if the attribute

is set to http://schemas.xmlsoap.org/soap/actor/next the destination is intended to be the first intermediary

SOAP Body element

The body element is used to send RPC calls or responses, and to report errors A body entry is defined by its name, composed by a valid namespace URI and a local name Immediate child elements of body element may be namespace-qualified

When sending the message over HTTP (as we will), the POST method should be used to both send the call and obtain the response In PHP, we can do this using the socket functions The content type we should specify

is text/xml, but text/plain also works The encoding depends on the application that we are dealing with

In the first part of Listing 1, there is an example of

a valid RPC call, performed using SOAP In this message, there is no header element, and that’s OK, since it is optional Look at the body element: in sub-element GetPrice (defined by the URI Some-URI), we store the product code and name, to obtain the price The second part of Listing 1 contains a possible response

Note that this is the bare XML response message, without HTTP headers (a few lines that the server sends

to indicate whether the operation was successful and additional information like date and content-length).This is a very basic example of a SOAP RPC call and response Real-life applications usually manage a larger amount of data, including arrays of sub-elements, which makes things more complex I’ve intentionally kept this example simple, to make things a bit clearer

SOAP Fault Element

If, during the execution of the remote application, an error occurs, preventing the program from producing the expected output, it is necessary to inform the client of

what happened This is exactly the purpose of SOAP fault element It is a child element of the envelope and the

Trang 19

1 # Dump of “transactions”

2

3 CREATE TABLE transactions(

4 tid INT UNSIGNED NOT NULL AUTO_INCREMENT ,

5 cid INT UNSIGNED NOT NULL ,

6 description VARCHAR(30) NOT NULL ,

7 amount FLOAT(7,2) UNSIGNED NOT NULL ,

8 STATUS ENUM(‘pending’,’failed’,’OK’)

9 DEFAULT ‘pending’ NOT NULL ,

10 PRIMARY KEY (tid)

5 $s = new soapclient ( “http://host/server.php” );

6 /* Creates a client object */

7

8 $params = array( ‘tid’ => 4636 , //Transaction ID

9 ‘cid’ => 1059 ); //Customer ID

10

11 $res = $s -> call ( ‘get_transaction’ , $params );

12 /* Invokes the remote method */

13

14 if(isset( $fault )) // If a fault occurred

15 die( $fault ); // Prints it and exits

16

17 if( $params [ ‘tid’ ] != $res [ ‘tid’ ])

18 die( ‘Transaction ID does not match’ );

19 if( $params [ ‘cid’ ] != $res [ ‘cid’ ])

20 die( ‘Costumer ID does not match’ );

21 /* Checks tid & cid */

4 if( $_SERVER [ “REQUEST_METHOD” ] != “POST” )

5 exit; // Check whether the req method was POST

16 if(! is_int ( $tid ) || ! is_int ( $cid ))

17 return new soap_fault ( “Sender” , “Input err” ,

18 “ID type must be INTEGER” ); //DataType fault

19

20 $q = “SELECT tid,cid,amount,status FROM transactions”

21 ” WHERE tid = $tid AND cid = $cid” ; //MySQL query

22

23 if(( $conn = @ mysql_connect ()) === FALSE )

24 return new soap_fault ( “Receiver” , “MySQL” ,

25 mysql_error ()); //MySQL connect fault

26

27 if((@ mysql_select_db ( “liceogiovio_” , $conn )) === FALSE )

28 return new soap_fault ( “Receiver” , “MySQL” ,

29 mysql_error ()); //MySQL selectDB fault

30

31 $res = @ mysql_query ( $q , $conn );

32 if( mysql_num_rows ( $res ) != 1 )

33 return new soap_fault ( “Sender” , “Bad IDs” ,

34 “No record matches the IDs” ); //No results

35

36 $resp = @ mysql_fetch_array ( $res , MYSQL_ASSOC );

37 @ mysql_close ( $conn );

38 $resp [ “time” ] = time (); //Add time() value

39 return $resp ; //Returns the result

A fault mainly consists of a mandatory standard error

code named Code, which identifies the problem (e g Sender or Receiver to identify the party responsible for the fault) and a mandatory Reason explaining what went wrong (e g Timeout) It may contain additional information, like Node which explains which node of the SOAP message path caused the error, and Role, which

is used to describe the role of that node Additionally,

a Detail element is available to explain precisely what went wrong

We will actually use these fault sub-elements in our

A WSDL document contains all the information needed about how to reach the web service—the methods to be used, the parameters they require and the type of output they will produce

If you want to learn more about WSDL, you can check the World Wide Web Consortium page about it at

http://www.w3.org/TR/wsdl

How to Write an Application

The application that we will write consists of two parts: client.php (Listing 3) is designed to send a request

to a remote application and fetch its response, while server.php (Listing 4) will receive the request, process

it, and produce output to send as a response

As we have seen in the previous paragraphs, SOAP

is simple enough that we could write the request

“manually”, simply by concatenating strings and variables The problem comes when we have to parse an XML document: there are several PHP functions designed for this purpose, but a parsing application is often quite complex to write, especially when receiving long and complex messages

Fortunately, there are open source libraries which can handle the tricky part for us This will allow us to spend more time on the other parts of our application—security, for example, is the most important aspect of a Web Service!

Of course, writing our own code is generally the best approach, as in doing so, we are fully aware of how it

Trang 20

If, during the execution of the remote

application, an error occurs, it is necessary

to inform the client of what happened.

works and how to optimize it But this takes a lot of

work, and may introduce some errors in our app—it’s not

only a matter of laziness

So there isn’t a best way of coding—avoiding libraries

or using them—as it all depends on our particular situation

and time limits In this article we will use NuSOAP, an

open source PHP library, to simplify our task

PHP NuSOAP library

NuSOAP, a group of classes designed to allow developers

to manage SOAP web services, is licensed under LGPL and

is available for free at http://dietrich.ganx4.com/nusoap/

All we have to do to use it is to include nusoap.php in our

scripts, by using require()

Writing a client with this library is really easy Instead

of building a SOAP message and sending it to the remote

API we can just pass to a class the variables we need and

instruct it to send the SOAP-encoded variables over HTTP

or any of the most common TCP/IP protocols

Let’s see an example:

First of all, we include NuSOAP, then we store the

parameters we will use for the RPC in the associative array,

$params We create an object passing two arguments:

the SOAP server address $remote (a string) and $wsdl, a

boolean value which indicates if the server uses a WSDL

document

As we have seen, a WSDL (Web Services Description

Language) document contains information about the Web

Service, its methods and properties and is often used by

Web Services, especially if they reach a certain degree of

complexity

Once we have created the object, we only have to

execute the RPC: we invoke the call() method, specifying the remote method name and the parameters to be passed (contained in $params) NuSOAP automatically fetches the result and stores it in the $result associative array

If we are working with a WSDL-based server (and consequently $wsdl is set to TRUE), once created, $clientcan also invoke the remote method in this way:

<?php

$proxy = $client->getproxy();

$results = $proxy->getbyid($params);

?>

This can be useful to simplify our code: first we create

a proxy client ($proxy), then we can invoke any remote

method specified in the WSDL document using the proxy, without having to use NuSOAP call() method

Now, let’s see how to configure a basic remote interface with NuSOAP:

we pass to the server object all of the HTTP POST data we received, and it will automatically produce output

Designing the Application

Remember, our application will consist of two PHP files, both based on NuSOAP library: client.php and server.php

We won’t use a WSDL file, as our web service will be very basic Let’s have a look to his structure

In client.php we will send a SOAP message to retrieve

Trang 21

information about a transaction, sending a transaction

ID (tid) and a customer ID (cid) as parameters to the

remote method, get_transaction() We expect the remote

application to send back a status code (“OK”, “pending”,

“failed”), the amount of the transaction, and the two

IDs (to verify that no errors have occurred) In addition,

server.php will append the current value of date() to

those variables

In server.php, we will first check that the remote

method has been invoked in the right way (e.g via

POST), next that all the data required is provided So, we

try to retrieve the data required from our database (we

will use MySQL), and send it back

In Listing 2, you can find the dump of the table we

will use

Writing the Client

Look at Listing 3: first, we include NuSOAP and create the

client object as we have done in the previous examples

Note that the $wsdl boolean parameter is absent: this

means that it is assumed FALSE and no WSDL file is

available for this Web Service

Next, we store the input data for the remote

application in the $params associative array Note that

if this had been a “real life” application, the input data

could have come from a form submitted by the user, from

the $_SESSION array, or from our database In order to

simplify our code, let’s assume that, no matter where the

data may have come from, it is now stored in this array

Now, the heavy lifting is done by NuSOAP: just one

line of code to build a request, send it, retrieve and parse

the response Sounds fantastic, doesn’t it?

Once the results are stored in $res, we check whether

any fault occurred (we analyze the $fault variable

created by NuSOAP), whether the IDs sent match the

ones returned, and eventually print the result

This was a really basic program, just to get started

with the simplest possible application of Web Services—

a sort of “Hello World.” Writing the server will be a bit

more difficult

Writing the server file

In Listing 4, you can find the code for the server

As the server file is not designed to be reached by a

browser, but only by a remote application via POST, we

first check whether the request method is POST; otherwise

the program exits We could also check the IP of the

remote application or require a username & password In

this case, remember that to ensure secure transmission

of data we must use HTTPS instead of HTTP

Next, we include NuSOAP, create the server object

($s) and register a method (get_transaction())

The interesting part of the code is this function It requires two parameters—the transaction ID and the customer ID—which we will use to build our MySQL query

The first step of the function is to check that the data type of the parameters is “integer”; otherwise, it will produce an error message This message is worth a closer look, as we don’t use die() but we produce a SOAP Fault document using NuSOAP soap_fault() method We specify three properties:

• the fault Code—which can be either the client

or the server—is set to “Sender”, as the problem lies in the wrong data type of the input the client sent

• the Reason, set to “Input err”,

• and the Detail, which explains the problem that occurred

Of course, using return to produce the SOAP Fault document we prevent get_transaction() from performing any other operation

Next, we build the MySQL query and store it in $q We connect to MySQL and select a database, verifying that each step was successful—producing a Fault if it wasn’t Once we have executed the query, we count the results returned An error occurs if N < 1, because this means that the query produced no result—likely because the transaction ID & customer ID sequence wasn’t correct—but also the case N > 1, which is even less probable, and represents an error, as each transaction must be unique

So, we join these two conditions as N != 1.Finally, we retrieve an associative array with the results, append a time element, in which we record the value of time(), when the operation has been performed, and return the $resp array All we have to do to execute the remote procedure call is pass the raw POST data as input to service()

So what our application will do, in the end, is fetch (over HTTP) information stored in the database of a remote machine, and make it available to our user It’s something really simple, but the underlying idea is the same at the base of Amazon or PayPal web services

A first step to Practical Web Services

This article is just a first step to the practical use of web services, as it may be regarded as a general introduction

to SOAP and to remote procedure calls There are many other things to say about SOAP, about writing a client

or server without using libraries, and also about using NuSOAP in a more sophisticated way

Of course, all of this would require a deeper theoretical introduction and—more importantly—many more

Trang 22

ALESSANDRO SFONDRINI is a young programmer from Como, Italy His interests are mainly related to PHP and C, with a particular focus on Web Services Alessandro is the author of the upcoming php|a Nanobook, “Practical Web Services.” You can contact him at

alesfo@yahoo.it.

examples It is clear that an article is not the right place

to talk in an exhaustive way about a topic as elaborate

as web services

Furthermore, even if we could have dealt with the

topics above, we would still have been far away from

what mainly interests a PHP developer: how can I

use all these things in my job? What about payments

with PayPal, or online shopping with eBay? If you are

interested in any of these topics, or simply would like to

have a deeper view of PHP & Web Services, you might like

to know the topics of the upcoming NanoBook “Practical

Web Services”

Practical Web Services

The book overlooks a complete theoretical lesson about

SOAP: this article provided a brief one which is enough

to start working

As the title underlines, the attention is focused

on the practical aspects, so after a short introduction

to Web Services, we dive straight into some code In

fact, the majority of the work is composed of examples

of real-life applications, realized with many different

programming techniques and commented almost line by

line, sometimes with the help of pictures

Conclusions

Coordinating data with a remote application, or sharing local data with public or private clients is becoming more and more necessary as the Web evolves For these reasons Web Services are gaining a central position in the world

of web based application, and for a programmer is an often required skill

I hope that this article has been an useful introduction

to SOAP and Web Services, even if represents just a starting point for a developer interested in writing applications using these technologies and acquiring an important skill If you have any doubt about the content

of this article, drop me a note at alesfo@yahoo.it or leave

a message on php|a online discussion board 

Trang 23

In this article, I will demonstrate how you can

apply and maintain logging and monitoring in

your own web applications using log4php The

text is based on my experience with log4php in

some of our latest in-house products at Telio

The first part contains a brief introduction with some

sample code of core functionality; the second part covers

some more advanced topics and useful examples on how

to deal with errors, and how to apply context data to

logging events, as well as some optimization tips In the

last part, I will also show you how to create a centralized

logging server

Introduction

You never know what could happen with your code

Errors will always occur, either because of bugs in your

own code, or an external interface or resource going

down You could have lost your network connection to

the MySQL server, the hard disk could have become full,

there can be bugs in third party code, or there may be

bugs in your code that you did not catch before you

released your product

CODE DIRECTORY: log4php

Logging in PHP applications is traditionally done by using your own logging function to send a message to

a file or by mail, or through a small 3rd party logging class However, writing logging code with a configurable logging system lets you write this code once and allows the system administrator to decide what kind of messages

he wants to capture, and where those messages should

be sent When serving a mission critical application, you

Trang 24

1 <?php

2 require_once ‘log4php/LoggerManager.php’ ;

3 $logger =& LoggerManager :: getRootLogger ();

4 $logger -> debug ( “Hello World!” );

In most companies, application monitoring is the

responsibility of administrators or an operation team It

is critical for these attendants to establish procedures

and strategies on how to handle application monitoring

Communicating these strategies to developers within the

development team will help both teams work together

on improving logging and monitoring information that,

in the end, will help resolve small issues before they

become bigger problems

It is not an easy task to apply logging to a large

base of preexisting code A better approach is to make a

strategic decision early in the design phase to determine

the manner in which you will apply error logging,

monitoring and audit logging

What is log4php?

log4php is a port of the popular log4j open source logging

API for Java and has been around since early 2003

In looking at the adoption of log4php in open source

projects and activity on the project’s own mailing lists,

it does not seem that many PHP developers are actually

using it However, it is a robust and flexible logging

system and does not have any real competitors Earlier

this year, log4php was adopted by Apache’s Logging

Services Project whose intention is to provide

cross-language logging services based on the work of log4j

That means that log4php will be backed up in the same

way as log4j, log4cxx and log4net when the incubation

stage is finished

How does it work?

Log4php logically consists of three main components:

appenders, layouts and loggers.

• An appender is responsible for appending a

log message to a resource Some available

appenders are console, database, file, email,

socket and daily rotating logfiles

• A layout is the view of an appender and

how the log message should be formatted

Typically, these are HTML, XML or text based

on a pattern string

• A logger combines a set of appenders with a

unique name, which is used to reference the

logger from program code One and only one

log level is attached to a logger

Additionally, there are two other terms that are very

common: log level and root logger.

• A log level is a defined severity for the log

6 $logger =& LoggerManager :: getRootLogger ();

7 $logger -> debug ( “Hello World!” );

8 $logger -> fatal ( “System crash!” );

5 log4php.appender.email.subject = Log4php test

6 log4php.rootLogger = FATAL, email

Trang 25

The root logger will catch all logging events, so you may create other loggers for different logging purposes Using the configuration in Listing 1 as a base, we can add another logger called “audit” for tracking audit messages and send them to a file with more information

in the layout (see Listing 3)

To get the new logger you can call LoggerManager::getLogger(‘audit’):

$logger =& LoggerManager::getLogger(‘audit’);

$logger->info(“User profile updated“);

Configuration

By default, log4php will look for a configuration file called log4php.properties within the current directory and use the LoggerPropertyConfigurator to parse the property file which is in a simple INI-file format The filename is set by the LOG4PHP_CONFIGURATION constant, and can be changed to whatever you’d like to name your configuration file (e.g log4php.ini)

You can also configure log4php through an XML based configuration file which tends to be a bit more readable than the simple key-value format Listing 4 shows an example of the configuration from Listing 1 converted

to an XML configuration Using XML, you get a better feeling of what you’ve put into the different parts of your configuration In order to enable the use of an XML based configuration file, you need to change that class log4php uses to parse a configuration file This is done through the LOG4PHP_CONFIGURATOR_CLASS constant Listing 5 shows a complete sample script for using the configuration from Listing 4

If you do not get log messages from log4php, you should check your setup once more If log4php does not find a resource needed for appending a logging event,

or your configuration is wrong, it will drop the logging event and continue execution This way, it does not get in the way for your application You should ensure that you get the expected messages when you configure log4php the first time to verify your setup

If you have problems with configuration you can always turn on internal debugging in log4php by adding log4php.debug = true to your configuration file This will give more output about what log4php is actually doing

If your configuration is wrong you will get warning messages like this:

Warning: LoggerDOMConfigurator::tagOpen() APPENDER cannot instantiate appender ‘default’

However, never leave this on by default; use it only for debugging

message Standard log levels are debug, info,

warn, error and fatal

• A root logger is the base logger that log events

if a named logger does not exist, or when a

logging event is caught by another logger

The root logger sits on the top of the logger

hierarchy

To get started and be able try out some of the code in

this article, you should grab the latest version of log4php

from http://logging.apache.org After unpacking the archive,

you should add the src directory within log4php to your

include_path so it is available from all scripts

I will start with an absolute minimal “Hello World!”

example, to give you an idea of how the system works

The first thing you need to do is to set up a log4php

configuration file (see Listing 1) Save this code to a

file called log4php.properties A minimal configuration

should contain at least a logger and an appender I’ve

first defined an appender named “default” attaching the

LoggerAppenderEcho class and giving it a simple layout

using the LoggerLayoutSimple class I then attach the

appender to the root logger with the log level set to

DEBUG

Listing 2 contains a small script that makes use of this

configuration file For simplicity, you should save this

code to a file in the same directory as the configuration

file, since log4php looks for the configuration file in the

same directory by default—more on this in a moment

The first thing that is done here is to include the

LoggerManager which is responsible for providing logger

instances that are defined by the configuration file The

LoggerManager operates as a singleton pattern, and the

configuration is read only once per request The last

thing in this code is to get the root logger by calling

LoggerManager::getRootLogger() and call its debug()

function with a message

Running this code will give you this result:

DEBUG - Hello World!

The most used functions for a logger are:

• debug() - used for debug messages

• info() - used in an informational context like

“username logged in” or “user typed wrong

password”

• warn() - used when entering a potentially

harmful situation

• error() - used when something goes wrong,

does not cause the application to terminate

(non-fatal)

• fatal() - used for really bad situations where

execution must be aborted

Trang 26

Useful Appenders

Log4php comes with a number of appenders to choose

from Figure 1 shows a list of all available appenders

The most typical appenders for operational purpose are

LoggerAppenderDailyFile for logging events to files on

daily basis and LoggerAppenderDb for logging events to

a database, which gives you more flexibility in terms of

statistics and extracting logging data later on

Listing 6 shows how to configure a daily file appender

Notice how you apply the date pattern through the

datePattern parameter and use the conversion modifier

%s to place the date in the filename provided in the file

parameter The LoggerAppenderDailyFile makes use of

PHP’s date() function, so you can make it a weekly or

monthly appender if you like

In a mission critical application, you need instant

feedback from the application if something goes seriously

wrong Most people like to use an email appender for

that Listing 7 shows a minimal configuration for an email

appender, setting from and to addresses, and a subject

The layout provides the body of the email message You

should not use the email appender to anything above log

level FATAL or ERROR since it will most likely fill up your

mailbox with more messages than you actually want

Useful Layouts

You also have a range of layout possibilities Figure 2

shows a list of available layouts If you are logging to

file, LoggerLayoutTTCC will be a good default layout The

layout is compiled like this:

time [thread] LEVEL category - message

And here’s an actual example:

Sat Nov 26 16:56:48 2005,121 [887] FATAL root - System crash!

Listing 8 contains an example of how you can tweak

this layout to remove thread and microseconds and

modify the date format

If you want logs available through your browser you

should consider using the HTML layout and combine

it with a daily file appender so you can download the

log files in your browser Listing 9 shows a suggested

configuration for this I’ve set the loglevel to WARN here

because you probably only want to look for problems in

this type of appender I’ve also enabled locationInfo on

this layout to add the line number and file in which an

event occurred, to each message

The pattern layout is the most flexible of all the

layouts The result of this layout depends on a conversion

pattern closely related to the sprintf() function added to

the conversionPattern property of LoggerPatternLayout

socket LoggerAppenderSyslog Log event using syslog()

LoggerLayoutTTCC A text layout containing time, thread, category and

nested diagnostic context.

LoggerPatternLayout A flexible layout based on a pattern string LoggerXmlLayout An XML file with an ‘event’ element per logging

event.

FIGURE 2

CONVERSION SPECIFIER DESCRIPTION

%d Date of logging event (may be followed by a date format

specifier enclosed between braces which follows the PHP date() pattern In example: %d{d M Y H:i:s})

%n Platform-dependent newline (\n, \r\n etc.)

%p Priority of the logging event

%r Milliseconds elapsed since the start of the execution until

the creation of the logging event

%t Thread (process id)

%x NDC (nested diagnostic context) associated with the

thread

%X MDC (mapped diagnostic context) associated with the

thread The conversion character must be followed by the key for the map placed between braces (for example:

%X{referrer})

FIGURE 3

Trang 27

(see Listing 10 for a complete configuration example)

A conversion pattern is a string composed of conversion specifiers A conversion specifier starts with a percentage character, an optional format modifier and a conversion character For example, the conversion pattern

“%d{Y-m-d H:i:s} %-5p %c: %m%n” will look like this:

2005-11-26 21:26:36 INFO root: User data updated ok

The first part is the date on a specified format; the second part is log level; the third part is the logger category; the fourth part is your message; and the last part is the platform dependent newline character(s) Figure 3 shows

a complete list of conversion specifiers that can be used

in a pattern layout

By default, the result of all conversion specifiers is rendered as-is However, it is possible to use a format modifier between the percent sign and the conversion character to change the minimum field width, the maximum field width and text justification within a field Use a positive integer to specify the minimum field width, a period followed by a positive integer to specify maximum field width Left-justify within a field by using the minus sign (-), or else it will be justified right Here are a few examples:

• %-5p – left-justify the priority within 5 characters

• %10c – right-justify the category if within 10 characters

• %10.15c – right-justify the category if shorter than 10 characters; if category is longer than

15 characters, truncate from the beginning

Adding Additional Filters

By using filters, you can fine tune which messages you want to receive from an appender, by specifying matching log levels or strings that you want to drop This is particularly useful when you need to attach appenders to

a logger with a different kind of log level than you really want messages from For example, if you want to attach

an email appender to only get notifications about fatal events, but the log level of the logger is set to something else Figure 4 contains a list of available filters

Listing 11 shows the configuration of an appender which drops debug events using a LoggerLevelMatchFilterwith the parameter levelToMatch set to DEBUG and acceptOnMatch to false Note that filters are only supported in XML based configuration and not in the simple property configuration You can add as many filter rules as you like to a given appender

8 <param name=”LevelToMatch” value=”DEBUG” />

9 <param name=”AcceptOnMatch” value=”false” />

3 ; CREATE TABLE log4php (

4 ; `timestamp` varchar(32) default NULL,

5 ; `logger` varchar(32) default NULL,

6 ; `username` int(11) default NULL,

7 ; `ip_address` varchar(15) default NULL,

8 ; `uri` varchar(255) default NULL,

9 ; `level` varchar(32) default NULL,

10 ; `message` varchar(64) default NULL,

11 ; `thread` varchar(32) default NULL,

12 ; `file` varchar(64) default NULL,

13 ; `line` varchar(4) default NULL,

20 log4php.appender.mysql.sql = INSERT INTO log4php

(timestamp, logger, username, ip_address, uri, level,

message, thread, file, line) VALUES (‘%d{Y-m-d H:i:s}’,’%c’,

4 LoggerMDC :: put ( ‘username’ , $_SERVER [ ‘REMOTE_USER’ ]);

5 LoggerMDC :: put ( ‘ip_address’ , $_SERVER [ ‘REMOTE_ADDR’ ]);

6 LoggerMDC :: put ( ‘uri’ , $_SERVER [ ‘REQUEST_URI’ ]);

7

8 $logger =& LoggerManager :: getRootLogger ();

9 $logger -> info ( “Testing MDC” );

10 ?>

LISTING 13

Trang 28

Debugging Objects

You can pass any PHP object to any of the logging

functions in a logger, and it will be rendered through the

log4php’s object rendering mechanism This is a useful

feature when debugging instead of using print_r() or

var_dump() which will output result to screen The default

implementation of object rendering uses var_export() to

return the string representation of the instance you apply

Be careful with large objects and recursion You should

only use it for your own business objects or similar

Diagnostic Context

In a web application, you are serving multiple clients

simultaneously and you probably want to add more

information to your logging events about the request,

such as user identification: IP address and/or the

current request URI Mapped Diagnostic Context, or MDC

for short, is a technique used to distinguish between

interleaved log messages MDC properties can be set

statically anywhere before using the logger using

LoggerMDC::put(‘key’, $value)

LoggerMDC::put(‘remote_addr’, $_SERVER[‘REMOTE_ADDR’]);

To map MDC properties in your layout, you should use

the pattern conversion character “X” followed by the key,

between braces For example, %X{remote_addr}

log4php.appender.Test.layout = LoggerPatternLayout

log4php.appender.Test.layout.conversionPattern =

“%d{Y-m-d H:i:s} %-5p %c: %X{remote_addr} %m%n”

Listing 12 shows how to use LoggerAppenderDb to setup

an MDC configuration to append logging events to a

MySQL database You need to create the table that you

want to append to, yourself, in order to have fields ready

for MDC properties For that reason I’ve also disabled

the createTable property on the database appender The

sql property of the database appender can include every

conversion specifier from the pattern layout

Listing 13 contains a sample script using MDC to map

additional context data into all logging events

Dealing with Errors

When it comes to monitoring, you want to know about

all kinds of errors that are happening during runtime, in

a controlled manner It is never a good idea to display

error messages to the end user when something goes

wrong Not only does it look bad, but it can also give

potential hackers valuable information You should store

all error messages and hide them from the end user The

simplest way to fix this is to turn off display_errors

and turn on log_errors in php.ini to log them to a file

defined by error_log, but a better way is to let log4php

FILTER DESCRIPTION

LoggerLevelMatchFilter Filtering based on a level to match in the LevelToMatch

property Set AcceptOnMatch to true or false whether or not you will accept the logging event.

LoggerLevelRangeFilter Used to reject messages with levels without a certain

range based on the LevelMin and LevelMax property Set AcceptOnMatch to true or false whether or not you will accept the logging event within the range LoggerStringMatchFilter Filtering based on a string to match in the

StringToMatch property Set AcceptOnMatch to true

or false whether or not you will accept the logging event.

LoggerDenyAllFilter Drop all logging events.

41 static function exceptionHandler ( $e ) {

42 $logger =& LoggerManager :: getRootLogger ();

43 $logger -> error ( $e -> getMessage () ’ in ‘ $e -> getFile ()

50 trigger_error ( “Triggered user error” , E_USER_ERROR );

51 throw new Exception ( ‘Uncaught Exception’ );

52 }

53 }

54 $handlers = new LoggerHandlers ();

55 $test = new Test ();

56 ?>

LISTING 14

Trang 29

that you get the messages and not the end user.

What about Performance?

Logging comes at a cost, and appending logger messages

to various destinations will slow down your application There are, however, some guidelines to be aware of when using log4php that can help you minimize unnecessary overhead

First of all, you should use the right log levels in the right situations For example, you should distinguish

between fatal and error as well as info and warn levels

and what they mean in your application Then you will get the most valuable output from your configuration.Second, it is a good practice to test if the log level

is enabled on a logger before logging Testing is pretty fast compared to the operation you will be doing with appending a message to a logger You can always use the functions isDebugEnabled() and isEnabledFor() for this purpose

if($logger->isDebugEnabled()) { $a = 1;

is the structure that contains all loggers that were created, based on your configuration By caching this structure, you do not have to rebuild it upon each request

Listing 15 provides a simple example of implementing this concept, first by naming a cache filename and checking if this file already exists If not, get the reference to the current LoggerHierarchy instance

take care of the messages

PHP contains both normal PHP errors and exceptions

(as of PHP5) Listing 14 shows an example of how to

implement a custom error and exception handler for

uncaught errors I’ve implemented a LoggerHandlers class

with a static function errorHandler() which appends

log messages, based on the error code, when an error

occurs This implementation is a bit strict in terms of

log levels, but I find it more useful to be strict during

development and loosen up a bit later on if necessary I’ve

also implemented a static function exceptionHandler()

to use as the exception handler Both are initialized

in the constructor with set_error_handler() and

set_exception_handler() This is a nice way of ensuring

When it comes to monitoring, you want to know about all kinds of

errors that are happening during runtime,

Trang 30

through LoggerManager::getLoggerRepository() and

store a serialized version of it in the cache file You will

get the logger hierarchy back when unserializing the

cache Then you will get access to all loggers by calling

getLogger(‘name’) or in this case getRootLogger() on the

logger hierarchy instance

To create more reusable code for this concept you

could create your own cached logger configurator

extending the LoggerPropertyConfigurator or

LoggerDOMConfigurator and override the configure()

function to do the caching

The performance gain of caching the logger hierarchy

will increase the more configuration you add to your

setup In general, if performance is really critical to you

it may be a good idea to minimize the use of appenders

and only log one place, for example to a database Then

set up a cron job to do some post processing like looking

for fatal errors and sending them by email, and creating

your own script to search for messages in the database

instead of using the HTML appender with the daily file

appender described earlier

Create Your Own Logging Server

Log4php can be used extensively in a distributed

environment with many applications Whether you want

to optimize performance overhead or gather logging

messages in one central place, you can create a logging

server to send logging events to and let the logging

server do the actual logging for you Figure 5 illustrates

the centralization of logging from having all logging

configuration set up in each application to have that

configuration on a logging server With this approach,

each application then only has to define one appender

which logs directly to the logging server If you are

familiar with log4j you have probably used or heard of

Chainsaw, a utility to read and receive logging events

from log4j using an XML layout You could use Chainsaw

as your logging server, but I prefer not to use the XML

layout and write my own implementation just to show

you how easy it can be done

Listing 16 contains an application logging

configuration using a socket appender This is the only

appender needed for an application since the logging

server should do the rest of the work A socket appender

takes three parameters The first parameter remoteHost

contains the protocol combined with the host name or

IP address The second parameter port is which port

the socket appender should connect to on the remote

host And the third parameter useXml will generate

payload using the XML layout if set to true In my

example I have set this to false which will serialize the

LoggerLoggingEvent object instead and is way faster to

1 <?php

2 require_once ‘log4php/LoggerManager.php’ ;

3 $cache = ‘log4php.cache’ ;

4

5 if(! file_exists ( $cache )) {

6 $hierarchy =& LoggerManager :: getLoggerRepository ();

7 file_put_contents ( $cache , serialize ( $hierarchy ));

8 }

9 $hierarchy =& unserialize ( file_get_contents ( $cache ));

10 $logger =& $hierarchy -> getRootLogger ();

4 $logger =& LoggerManager :: getRootLogger ();

5 $logger -> info ( “Here I am :)” );

work with than parsing XML data

Listing 17 is our sample application that contains a few logging events that will be using the socket appender

in Listing 16 Listing 18 will be the logging server’s configuration which logs to screen and to a file

Listing 19 contains code for a logging server using the PEAR::Net_Server package PEAR::Net_Server is a generic server interface to create daemon scripts based on the socket extension You can choose from two different server drivers: sequential and fork I have chosen the fork driver where a new process is forked for each client that connects to the server This driver requires the pcntlextension which enables process control support on *nix based platforms If you are on Windows or can’t enable process control support on your installation, you can always use the sequential driver

Net_Server has an object oriented approach and you need to create a handler class that extends

Trang 31

appender’s doAppend() function with the logging event

It will also add events to the root logger The handler is connected to the server through the setCallbackObject()function on the server driver and the server is started at the end with the start() function

Save Listing 19 as server.php and start it with the command line:

php server.php

It will start listening on port 9090 on localhost Now you can try to connect to it with the application code from Listing 17

A logging server is a good alternative to tailing log files for each application If you want to use it, you should consider using it together with Mapped Diagnostic

Context data and add properties like product and product

version, and location data like host name or request URI

to make your life a little bit easier

This example is too simple to be copied and used directly in any kind of production environment, but I hope you get some ideas on how you can make use of it

in your own environment

Where do I learn more?

Without log4php’s API manual, you have to look to log4j documentation to find some readable end user documentation about the logging API The best place

to learn about how to configure log4php is in its own tests/ directory, where you can find a sample file for most available features

If you have any questions related to log4php, you can always post them on the log4php-user@logging.apache.org

mailing list If you have any suggestions on how to improve log4php, or want to help out developing the software, you should join the log4php-dev@logging.apache.org mailing list

Final Words

log4php is a robust logging framework and a good way

to add debug, monitoring and audit logging Logging is managed by configuration files and you can keep logging statements in shipped code without worrying about heavy performance cost 

16 function onReceiveData ( $clientId = 0 , $data = “” ) {

17 $events = $this -> getEvents ( $data );

18 foreach( $events as $event ) {

19 $root = $this -> hierarchy -> getRootLogger ();

20 if( $event -> getLoggerName () === ‘root’ ) {

21 $root -> callAppenders ( $event );

22 } else {

23 $loggers = $this -> hierarchy -> getCurrentLoggers ();

24 foreach( $loggers as $logger ) {

25 $root -> callAppenders ( $event );

26 $appenders = $logger -> getAllAppenders ();

27 foreach( $appenders as $appender ) {

28 $appender -> doAppend ( $event );

35 function getEvents ( $data ) {

36 preg_match ( ‘/^(O:\d+)/’ , $data , $parts );

37 $events = split ( $parts [ ], $data );

49 $server =& Net_Server :: create ( ‘fork’ , $host , $port );

50 $handler =& new Net_Server_Handler_Log ();

51 $server -> setCallbackObject ( $handler );

52 $server -> start ();

53 ?>

LISTING 19

Net_Server_Handler that can be used as a callback object

when a client connects Handlers have a set of broadcast

functions you can override and hack in your functionality

when those broadcast functions are executed I have

only defined one property in my handler, which will

hold the LoggerHierarchy object The onStart() function

is called when the server driver is initialized and

LoggerManager::getLoggerRepository() returns the whole

logger hierarchy structure with logger and appender

objects constructed from the configuration The logic

part of this server example goes into the onReceiveData()

function which is called when a client sends data to the

server The second parameter $data contains a serialized

version of all logging events that have been appended

The getEvents() function is a helper function to extract

an array of logging events from this data After all

events are in place, it will iterate through all loggers and

their appenders in the logger hierarchy, and call each

Telio Telecom AS He’s also maintainer of wsdl2php , a PHP 5 Web Service Proxy Generator His personal blog is http://www.urdalen.com/.

Trang 32

application that outperforms other solutions.

This article will develop a link management

application using an SQLite database as the data

store The front end will display alphabetically

ordered web site links as shown in Figure 1

An alphabetic navigation bar of hyperlinks will

make any specific link easily accessible, and recently

added links will be highlighted

A submission form will allow visitors to suggest

additional links These links will not appear on the site

until they have been reviewed There will be a back-end

to review and maintain links

How it’s Done

In this application we take advantage of some of SQLite’s

advanced capabilities Both triggers and views will be

used A trigger will be used to mimic a datestamp field—

records will be automatically stamped whenever they are

added/changed

Views are a convenient way of storing queries and

can replace tables in a FROM clause They can also be

used with triggers so that “updating” a view updates the

associated table

No database used in conjunction with PHP can escape

comparison to MySQL Where appropriate, we will point

out differences in SQL syntax between SQLite and MySQL

Likewise, SQLite has a variety of different query methods

These will also be contrasted with MySQL functions

Throwing exceptions rather than error trapping makes

for cleaner code SQLite has a built-in OO interface and

PHP: 5.1.0 OTHER SOFTWARE: SQLite 2.8.14

LINKS:

http://sqlite.org http://zend.com/php5/articles/php5-sqlite.php http://php.net/manual/en/ref.sqlite.php http://www-128.ibm.com/developerworks/library/os-sqlite/ http://www.sqlitemanager.org/

Advanced SQLite

Development

CODE DIRECTORY: sqlite

through extending the SQLite database class we can override the query methods of SQLite so that a failed query throws an exception By extracting metadata from

a database, data verification methods will be added to the derived class This will be done by querying the sqlite_master table and through the use of pragmas

A limited number of functions are available for use with SQLite’s dialect of SQL This shortcoming can be overcome by creating User Defined Functions (UDF)

Trang 33

Getting Started

SQLite comes bundled with PHP 5 so you can immediately

start writing PHP code to create a database, tables and

indices—whatever you might need

However, this approach has a couple of disadvantages

If you do things this way you’ll have to write code just

to view your data or to examine the structure of your

database Instead, download the command-line version

of SQLite PHP 5.1 RC1 comes with version 2.8.14 I

downloaded 2.8.16 and didn’t run into any problems

Don’t use version 3 though—the file format is different

and incompatible with version 2 For convenience, you

might want to install the binary of sqlite in the same

directory as your database

Creating a database is as simple as typing

sqlite dbname.ext at the command line Doing so will

run sqlite and create or open an existing database of the

specified name You can now create a table using SQL

from the command line However, let me make one more

suggestion At some point you will want to dump your

database and if you have created it from the command

line the output won’t be very readable If you use a text

editor to format your CREATE TABLE statement and then

redirect this file to the database, the results will be much

more acceptable Do this whenever you create tables,

views or triggers

The database used in this application is called

resources.sqlite and is stored in a subdirectory named

dbdir To create it and all associated database objects

redirect the dump.sql file from the command line in the

following way:

sqlite resources.sqlite < dump.sql

A database dump is formatted as a transaction, so, if everything went okay, you’ve already used one of SQLite’s advanced features

Creating a Table

The SQL used to create the tblresources table in our database is shown in Listing 1 Let’s have a look at the details

To create a table with an autonumber field named

id, the data type INTEGER is used in conjunction with PRIMARY KEY This is equivalent to identifying a field as INTEGER auto_increment PRIMARY KEY in MySQL In SQLite, this field definition is the one exception to the rule that SQLite fields are typeless—otherwise all fields are strings Creating fields as types other than string helps document the data types we are expecting but will not restrict the value entered You can put a string into a float type field and a float into a boolean Further, specifying the length of a VARCHAR type field will not truncate data that exceeds the defined length Any length of string can be entered into any field Otherwise, the syntax for creating

a table functions exactly as you might expect

The field names used in creating this table are documenting, but a few comments are in order A resource won’t be displayed until the reviewed field is set to true The field with the data type TIMESTAMP, whenaltered, will be maintained using a trigger as will the whenaddedfield

self-Views

Views are stored SELECT queries If you repeatedly use the same query, it is worthwhile creating it as a view

To make resource links easily accessible we are going

to order them alphabetically and create hyperlinks to each letter of the alphabet It is with this in mind that

FIGURE 1

FIGURE 2

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

TỪ KHÓA LIÊN QUAN