Tải bản đầy đủ (.pdf) (92 trang)

Secure PHP Building 50 Practical Applications Development phần 2 doc

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (455.02 KB, 92 trang )

Developing Intranet Solutions
CHAPTER 4
Architecture of an Intranet Application
CHAPTER 5
Central Authentication System
CHAPTER 6
Central User Management System
CHAPTER 7
Intranet System
CHAPTER 8
Intranet Simple Document Publisher
CHAPTER 9
Intranet Contact Manager
CHAPTER 10
Intranet Calendar Manager
CHAPTER 11
Internet Resource Manager
CHAPTER 12
Online Help System
Part
II
06 549669 PP02.qxd 4/4/03 9:24 AM Page 63
06 549669 PP02.qxd 4/4/03 9:24 AM Page 64
Chapter 4
Architecture of an Intranet
Application
INTRANET APPLICATIONS ARE PRIMARILY focused on automating an organization’s
daily business processes. A modern company has many intranet applications that
are available to its employees to help them be more productive and efficient. For
example, a group calendar system or task-tracking system can save a great deal of
time and resources for most companies with more than five employees. This chap-


ter focuses on the underlying architecture of intranet applications and discusses an
open-source framework that enables you to develop intranet PHP applications in a
rapid manner.
Understanding Intranet
Requirements
To develop intranet applications, you need to understand how a typical intranet is
deployed. A company with two employees can have an intranet, but the average
intranet application is deployed in an organization with tens to hundreds of users.
Figure 4-1 shows how an intranet “connects” employees in multiple departments of
a company that uses an intranet application server to manage its daily internal
business functions.
A company generally uses its intranet server to automate interdepartment com-
munication activities such as a shared calendar, shared contact database, document
management, project/task tracking, and so forth.
Before you develop the framework that will enable you to create intranet appli-
cations in PHP, you need to understand the intranet user requirements. Figure 4-2
shows how a single department within an organization appears from an intranet-
requirements point of view.
Users in organizations work in teams. A team usually has a team leader and a
project assignment. The projects are managed by the department head. This type of
hierarchical user base is very common in modern organizations.
65
07 549669 ch04.qxd 4/4/03 9:24 AM Page 65
Figure 4-1: A typical intranet-enabled company.
Figure 4-2: User requirements for a typical intranet-enabled company.
Each intranet application you develop must be able to authenticate and autho-
rize different types of users. For example, an employee vacation management
application has to incorporate the hierarchical chain of command that enables
employee vacation requests to be reviewed and approved first by team leaders and
then by the department head. So far, our intranet application framework has the

following requirements:

Central authentication: Users need to be authenticated to access intranet
applications. There are likely to be many intranet applications within an
organization and therefore user authentication should be done such that
a user logs in only once to access any application. A session should be
Any Department
Department Head
Team
Employee
Project 1
Team Leader
Team
Employee
Project (n)
Team Leader
Marketing
PC
PC PC
Engineering
PC PCPC
PC PC
Sales MIS
PC PCPC
PC PC
Intranet
Server
Firewall
Database
Server

Administration
PC PCPC
PC PC
66 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 66
created that allows all applications to identify an authenticated user.
When a user attempts to access an intranet application without logging in
first, the application should automatically redirect the user to the login
application. When the user is successfully authenticated via the login
application, she should be automatically forwarded back to the applica-
tion she had been attempting to access. The login process should be seam-
less. Similarly, a central, seamless logout facility should be provided to
allow the users to log out from the intranet.

Application-specific authorization: Different types of users exist in an
intranet and, therefore, intranet applications must discriminate when
authorizing users. Employee access to an intranet application will vary.
Because each application will have different requirements for authorizing
the user, the task of authorization should be left to the application itself.

A shared database: Most intranet activity involves collaboration or group
efforts. For example, users working in a team within a project might need
to report the status of the project tasks individually, but the team leader or
department head needs to access the information from the entire team to
make technical or business decisions. A shared database is therefore the
solution to store data.
Based on these requirements, let’s go ahead and build an intranet application
framework.
Building an Intranet Application
Framework

An intranet consists of many applications. It is a good idea to create an application
framework that provides a set of commonly needed objects and services to imple-
ment applications. Typical intranet applications have user authentication require-
ments, database access requirements, user interfaces requirements, and business
logic requirements. Each application’s business logic, which is the work done by the
application, is unique and must be implemented in the application code itself.
However, each application can benefit from using a standard application frame-
work consisting of objects that standardize authentication, database access, user
interface, etc. The framework I will build here will do just that.
Figure 4-3 shows the high-level design diagram for an intranet application that
will use our application framework.
Now let’s discuss the components of this architecture.
Chapter 4: Architecture of an Intranet Application 67
07 549669 ch04.qxd 4/4/03 9:24 AM Page 67
Figure 4-3: High-level architecture diagram of an intranet application
using our framework.
Using an HTML template-based presentation layer
All input and output to and from the application is handled via a template-driven
HTML presentation layer. When the application needs input from the user, it pre-
sents an HTML page generated from an appropriate HTML template. Similarly,
when the application needs to display output, it generates an HTML page by replac-
ing special application-specific tags within the template. This ensures that cosmetic
changes to the input or output interfaces can be done without requiring help from
the application developer. For example, an application that uses the template-based
presentation layer can have its interface modified by an HTML writer or graphics
artist.
Using PHP Application Framework components
The components in the PHP Application Framework (PHPAF) layer implement the
base application by providing the following services:


Database abstraction support: See the “Relational database” section later
in this chapter for details.

Centralized authentication support: All applications defer the login and
logout to the central authentication facility, as discussed earlier in this
chapter.
Relational
Database
Business Logic
Your PHP
Application
PHP Application
Framework
Components
HTML Template-based
Presentation Layer
INPUT
OUTPUT
68 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 68

Override authorization support: Each application using the intranet
application defines its own authorization method.

Debugging support: An application needs to be debugged many times
during the development process. Because debugging is a core part of the
development process, the framework includes a built-in debugger. The
current implementation is very simple yet useful.

Internationalized error and status message handling support: Each

application using the framework must use a central error message
and status message repository. Both error and status messages can be
internationalized.
Business logic
Each application has its own business-logic requirements. The business-logic
objects will be given database connectivity from the application framework. This
ensures that database abstraction is maintained.
Relational database
The relational database access is abstracted from the application using an abstrac-
tion layer, which is part of the application framework. This ensures that application
database requirements can change without drastically affecting the application. For
example, an application can be developed with this framework such that it works
with the widely used, high-performance MySQL database and then deployed in an
environment where the database is Oracle. Of course, the developers have to be
careful not to use any vendor-specific features.
Figure 4-4 shows a block diagram of an application that uses the previously
mentioned application framework.
Figure 4-4: A block diagram of an application using the PHP Application Framework.
Application Specific
Error and Status
Messages
(Supports
Internationalization)
Database
Independent
Abstraction
Authentication
(Valid User Credentials)
Authorization
(Application Specific Authorization Requirements)

Application Run()
(Application Specific Driver Code)
Business Logic Objects
(Application Specific Code)
Chapter 4: Architecture of an Intranet Application 69
07 549669 ch04.qxd 4/4/03 9:24 AM Page 69
The application checks for valid user credentials in the authentication phase,
which is already supplied by the framework’s login application for valid users.
The authorization step involves application-specific privilege management. Not
all valid (authenticated) users are likely to have the same privilege based on the
type of application. For example, an Employee Information System (EIS) applica-
tion in an engineering firm can assign different privileges to executive manage-
ment, department heads, team leaders, and engineers. This is why the authorization
code is specific to the instance of the application and should be written by the
application developer and should not be provided by the framework.
When an application has gone through the authentication and authorization
phases, it will run the application. This code will involve invoking application spe-
cific business objects and database interaction.
The application will have database access via the database-independent abstrac-
tion and also will produce status messages and errors using the facilities provided
by the framework.
Figure 4-5 shows a real-world application framework that we will create in this
chapter.
Figure 4-5: A real-world PHP Application Framework.
The core of this framework is the class.PHPApplication.php. This class provides
an abstract PHP application that you can extend to incorporate facilities provided by
the error handler (class.ErrorHandler.php), the debugger (class.Debugger.php),
and the database abstraction (class.DBI.php).
DB.php (from PEAR)
class.PHPApplication.php

class.Debugger.phpclass.ErrorHandler.php
class.DBI.php
Your PHP Application Business
Logic
70 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 70
This framework is provided with the CD-ROM. You don’t need to create it
from scratch.Also note that the database abstraction uses DB.php from the
PEAR.
Now let’s create the classes needed to implement this application framework.
Creating a Database
Abstraction Class
Accessing a database using its own API is common in the PHP world. For example,
most PHP developers use PHP with MySQL and, therefore, they write code that is
specific to the MySQL API found in PHP.
There is nothing wrong with this approach if you know that your PHP applica-
tions will be used only for the MySQL database server. However, if there is a chance
that your applications will be used with other databases such as Oracle, Postgres,
and so forth, you need to avoid MySQL-specific API. A developer who has
abstracted the database API in a level above the vendor-specific API can enjoy the
speed of porting the application to different relational databases. Here, we will cre-
ate a class called class.DBI.php that will implement a database abstraction layer for
our application framework. Listing 4-1 shows class.DBI.php, which implements
the database abstraction using PEAR DB.
See for details on
PEAR DB, a unified API for accessing SQL-databases.
Listing 4-1: class.DBI.php
<?php
/*
Database abstraction class

Purpose: this class provides database abstraction using the PEAR
DB package.
Continued
Chapter 4: Architecture of an Intranet Application 71
07 549669 ch04.qxd 4/4/03 9:24 AM Page 71
Listing 4-1 (Continued)
*/
define(‘DBI_LOADED’, TRUE);
class DBI {
var $VERSION = “1.0.0”;
function DBI($DB_URL)
{
$this->db_url = $DB_URL;
$this->connect();
if ($this->connected == TRUE)
{
// set default mode for all resultset
$this->dbh->setFetchMode(DB_FETCHMODE_OBJECT);
}
}
function connect()
{
// connect to the database
$status = $this->dbh = DB::connect($this->db_url);
if (DB::isError($status))
{
$this->connected = FALSE;
$this->error = $status->getMessage();
} else {
$this->connected = TRUE;

}
return $this->connected;
}
function isConnected()
72 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 72
{
return $this->connected;
}
function disconnect()
{
if (isset($this->dbh)) {
$this->dbh->disconnect();
return 1;
} else {
return 0;
}
}
function query($statement)
{
$result = $this->dbh->query($statement);
if (DB::isError($result))
{
$this->setError($result->getMessage());
return null;
} else {
return $result;
}
}
function setError($msg = null)

{
global $TABLE_DOES_NOT_EXIST, $TABLE_UNKNOWN_ERROR;
$this->error = $msg;
if (strpos($msg, ‘no such table’))
{
$this->error_type = $TABLE_DOES_NOT_EXIST;
} else {
Continued
Chapter 4: Architecture of an Intranet Application 73
07 549669 ch04.qxd 4/4/03 9:24 AM Page 73
Listing 4-1 (Continued)
$this->error_type = $TABLE_UNKNOWN_ERROR;
}
}
function isError()
{
return (!empty($this->error)) ? 1 : 0;
}
function isErrorType($type = null)
{
return ($this->error_type == $type) ? 1 : 0;
}
function getError()
{
return $this->error;
}
function quote($str)
{
return “‘“ . $str . “‘“;
}

function apiVersion()
{
return $VERSION;
}
}
?>
Here are the functions the DBI class implements:

DBI(): This is the constructor method, which creates the instances of the
DBI object. For example, here is a script called test_dbi.php that creates a
DBI object.
<?php
// Turn on all error reporting
error_reporting(E_ALL);
// If you have installed PEAR packages in a different
// directory than %DocumentRoot%/pear change the
74 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 74
// setting below.
$PEAR_DIR = $_SERVER[‘DOCUMENT_ROOT’] . ‘/pear’ ;
// If you have installed PHPLIB in a different
// directory than %DocumentRoot%/phplib, change
// the setting below.
$PHPLIB_DIR = $_SERVER[‘DOCUMENT_ROOT’] . ‘/phplib’;
// If you have installed framework directory in
// a different directory than
// %DocumentRoot%/framework, change the setting below.
$APP_FRAMEWORK_DIR=$_SERVER[‘DOCUMENT_ROOT’] . ‘/framework’;
// Create a path consisting of the PEAR,
// PHPLIB and our application framework

// path ($APP_FRAMEWORK_DIR)
$PATH = $PEAR_DIR . ‘:’ .
$PHPLIB_DIR . ‘:’ .
$APP_FRAMEWORK_DIR;
// Insert the path in the PHP include_path so that PHP
// looks for our PEAR, PHPLIB and application framework
// classes in these directories
ini_set( ‘include_path’, ‘:’ .
$PATH . ‘:’ .
ini_get(‘include_path’));
// Now load the DB.php class from PEAR
require_once ‘DB.php’;
// Now load our DBI class from application framework
// directory
require_once(‘class.DBI.php’);
// Set the database URL to point to a MySQL
// database. In this example, the database is
// pointing to a MySQL database called auth on
// the localhost server, which requires username
// (root) and password (foobar) to login
$DB_URL = ‘mysql://root:foobar@localhost/auth’;
// Create a DBI object using our DBI class
// Use the database URL to initialize the object
// and make connection to the database
$dbi = new DBI($DB_URL);
Chapter 4: Architecture of an Intranet Application 75
07 549669 ch04.qxd 4/4/03 9:24 AM Page 75
// Dump the contents of the DBI object to
// see what it contains.
echo “<pre>”;

print_r($dbi);
echo “</pre>”;
?>
Here, $dbi is an instance of the DBI object created from class.DBI.php.
The constructor method has to be passed a database URL which has the
following syntax:
database_type://username:password↓tabase_host/database_name
The $DB_URL variable was set to create a database URL that pointed to a
MySQL database (mysql) named mydb on host called localhost The data-
base can be accessed using the root user account and foobar password.
The DBI() method sets the DB URL passed to itself as db_url member
variable and calls the connect() method to connect to the given data-
base. The constructor sets the fetch mode to DB_FETCHMODE_OBJECT,
which allows us to fetch database rows as objects.

connect(): By default, the DBI() constructor method calls the connect()
function directly to establish the connection, so you don’t need to. con-
nect()
connects to the database specified in db_url member variable of
the object. It sets a member variable dbh to the database handle object
created by the DB::connect() method, which is found in the PEAR DB
package. connect also sets a member variable called connected to
Boolean TRUE or FALSE and returns that value.

disconnect(): The disconnect() function disconnects the DBI object
from the database.
The terminate() function in PHPApplication class (class.
PHPApplication.php
) calls the disconnect() function if the applica-
tion is connected to a database. See terminate() function in

PHPApplication class for details.

query(): This function performs a SQL query on the connected database.
The result of the query is stored in a result object called $result. If the
query returns SQL error(s), a member variable called $this->dbi->error
is set to the error message and null is returned.
76 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 76
If the query is successful, it returns the result object. The result object can
be used to fetch rows. For example, the test_query.php script tries to fetch
data from a table called PROD_TBL using a database URL such as
mysql://root:foobar@localhost/products.
<?php
// Turn on all error reporting
error_reporting(E_ALL);
// If you have installed PEAR packages in a different
// directory than %DocumentRoot%/pear change the
// setting below.
$PEAR_DIR = $_SERVER[‘DOCUMENT_ROOT’] . ‘/pear’ ;
// If you have installed PHPLIB in a different
// directory than %DocumentRoot%/phplib, change
// the setting below.
$PHPLIB_DIR = $_SERVER[‘DOCUMENT_ROOT’] . ‘/phplib’;
// If you have installed framework directory in
// a different directory than
// %DocumentRoot%/framework, change the setting below.
$APP_FRAMEWORK_DIR=$_SERVER[‘DOCUMENT_ROOT’] . ‘/framework’;
// Create a path consisting of the PEAR,
// PHPLIB and our application framework
// path ($APP_FRAMEWORK_DIR)

$PATH = $PEAR_DIR . ‘:’ .
$PHPLIB_DIR . ‘:’ .
$APP_FRAMEWORK_DIR;
// Insert the path in the PHP include_path so that PHP
// looks for our PEAR, PHPLIB and application framework
// classes in these directories
ini_set( ‘include_path’, ‘:’ .
$PATH . ‘:’ .
ini_get(‘include_path’));
// Now load the DB.php class from PEAR
require_once ‘DB.php’;
// Now load our DBI class from application framework
require_once(‘class.DBI.php’);
Chapter 4: Architecture of an Intranet Application 77
07 549669 ch04.qxd 4/4/03 9:24 AM Page 77
// Setup the database URL
$DB_URL = ‘mysql://root:foobar@localhost/products’;
// Create a DBI object that connects to the
// database URL
$dbi = new DBI($DB_URL);
if (! $dbi->isConnected())
{
echo “Connection failed for $DB_URL<br>”;
exit;
}
// Create a SQL statement to fetch data
$statement = ‘SELECT ID, NAME FROM PROD_TBL’;
// Execute the statement using DBI query method
$result = $dbi->query($statement);
// If the result of query is NULL then show

// database error message
if ($result == NULL)
{
echo “Database error:” . $dbi->getError() . “\n”;
// Else check if there are no data available or not
} else if (! $result->numRows()){
echo “No rows found.”;
// Now data is available so fetch and print data
} else {
echo “<pre>ID\tNAME<br>”;
while ($row = $result->fetchRow())
{
echo $row->ID, “\t”, $row->NAME, “<br>”;
}
echo “</pre>”;
}
?>
78 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 78
The SQL statement SELECT ID, NAME FROM PROD_TBL is stored in
$statement variable and passed to the DBI::query() method. The result
is tested first for null. If the result is null, the database error is printed
using the DBI::getError() method.
If there are no database errors, the next check is made to see if there are
any rows using the numRow() method from the $result object. If there
are no rows, an appropriate message is printed.
If there are data in the returned $result object, the result is printed in a
loop using the fetchRow() method.
The row data is fetched in $row object. The $row->DATA_FIELD method is
used to get the data for each field. For example, to retrieve the NAME field

data, the $row->NAME value is accessed.

quote(): This is a utility function that puts a pair of single quotes around
a string to protect the string from being passed without quotation. Here’s
an example in which the $name field is single-quoted using $this->dbi-
>quote($name)
call:
<?php
// Turn on all error reporting
error_reporting(E_ALL);
// If you have installed PEAR packages in a different
// directory than %DocumentRoot%/pear change the
// setting below.
$PEAR_DIR = $_SERVER[‘DOCUMENT_ROOT’] . ‘/pear’ ;
// If you have installed PHPLIB in a different
// directory than %DocumentRoot%/phplib, change
// the setting below.
$PHPLIB_DIR = $_SERVER[‘DOCUMENT_ROOT’] . ‘/phplib’;
// If you have installed framework directory in
// a different directory than
// %DocumentRoot%/framework, change the setting below.
$APP_FRAMEWORK_DIR=$_SERVER[‘DOCUMENT_ROOT’] . ‘/framework’;
// Create a path consisting of the PEAR,
// PHPLIB and our application framework
// path ($APP_FRAMEWORK_DIR)
$PATH = $PEAR_DIR . ‘:’ .
$PHPLIB_DIR . ‘:’ .
$APP_FRAMEWORK_DIR;
Chapter 4: Architecture of an Intranet Application 79
07 549669 ch04.qxd 4/4/03 9:24 AM Page 79

// Insert the path in the PHP include_path so that PHP
// looks for our PEAR, PHPLIB and application framework
// classes in these directories
ini_set( ‘include_path’, ‘:’ .
$PATH . ‘:’ .
ini_get(‘include_path’));
// Now load the DB.php class from PEAR
require_once ‘DB.php’;
// Now load our DBI class from application framework
require_once(‘class.DBI.php’);
// Setup the database URL
$DB_URL = ‘mysql://root:foobar@localhost/foobar’;
// Create a DBI object that connects to the
// database URL
$dbi = new DBI($DB_URL);
if (! $dbi->isConnected())
{
echo “Connection failed for $DB_URL<br>”;
exit;
}
$id = 100;
$name = “Joe Gunchy”;
$name = $dbi->quote($name);
$statement = “INSERT INTO PROD_TBL (ID,NAME) “ .
“VALUES($id, $name)”;
$result = $dbi->query($statement);
if ($result == NULL)
{
echo “Database error:” . $dbi->getError() . “<BR>\n”;
} else {

echo “Added $name in database.<BR>\n”;
}
?>
80 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 80

apiVersion(): This is a utility method that returns the version number of
the DBI object. The DBI abstraction class enables you to connect to any
database and perform any SQL query, such as SELECT, INSERT, UPDATE,
DELETE, and so forth. Because it hides the database vendor-specific details
from your application, porting to other databases become a much easier
task.
Now let’s look at how we can develop an error handler class.
Creating an Error Handler Class
Every application needs to display error messages. In the old days, error messages
were usually hard-coded in the executable programs and were very difficult to
understand, let alone modify!
Now, in the days of Web interface, we should not resort to the old way of show-
ing hard-coded error messaging because the application can be used in so many
parts of the world. Error messages written in English are just not friendly enough
for the world in this Internet age. So applications that have internationalizable
error message support will have broader reach.
Listing 4-2 shows an error message handler, which loads and displays error mes-
sages in the application’s default language. Because an application’s default lan-
guage can be changed in the configuration file, it becomes very easy to display
error messages in different languages.
Listing 4-2: class.ErrorHandler.php
<?php
/*
* CVS ID: $Id$

*/
/*
* Centalizes all error messages.
* Supports internationalization of error messages.
*
* @author EVOKNOW, Inc. <>
* @access public
*/
define(‘ERROR_HANDLER_LOADED’, TRUE);
class ErrorHandler
{
function ErrorHandler($params = null)
{
global $DEFAULT_LANGUAGE;
$this->language = $DEFAULT_LANGUAGE;
Continued
Chapter 4: Architecture of an Intranet Application 81
07 549669 ch04.qxd 4/4/03 9:24 AM Page 81
Listing 4-2 (Continued)
$this->caller_class = (!empty($params[‘caller’])) ? $params[‘caller’] :
null;
$this->error_message = array();
//error_reporting(E_ERROR | E_WARNING | E_NOTICE);
$this->load_error_code();
}
function alert($code = null, $flag = null)
{
$msg = $this->get_error_message($code);
if (!strlen($msg))
{

$msg = $code;
}
if ($flag == null)
{
echo “<script>alert(‘$msg’);history.go(-1);</script>”;
} else if (!strcmp($flag,’close’)){
echo “<script>alert(‘$msg’);window.close();</script>”;
} else {
echo “<script>alert(‘$msg’);</script>”;
}
}
function get_error_message($code = null)
{
if (isset($code))
{
if (is_array($code))
{
$out = array();
foreach ($code as $entry)
{
array_push($out, $this->error_message[$entry]);
}
return $out;
} else {
return (! empty($this->error_message[$code])) ? $this-
>error_message[$code] : null;
}
} else {
return (! empty($this->error_message[‘MISSING’])) ? $this-
>error_message[‘MISSING’] : null;

}
82 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 82
}
function load_error_code()
{
global $ERRORS;
if (empty($ERRORS[$this->language]))
{
return FALSE;
}
while (list($key, $value) = each ($ERRORS[$this->language])) {
$this->error_message[$key] = $value;
}
return TRUE;
}
}
?>
The class.ErrorHandler.php class assumes that the application has all its error
messages defined in an application-specific configuration file and all error mes-
sages are stored in a multidimensional array called $ERRORS. For example:
<?php
// US English
$ERRORS[‘US’][‘SAMPLE_ERR_CODE’] = “This is an error message.”;
// Spanish
$ERRORS[‘ES’][‘SAMPLE_ERR_CODE’] = “Esto es un mensaje de error.”;
//German
$ERRORS[‘DE’][‘SAMPLE_ERR_CODE’] = “Dieses ist eine Fehlermeldung.”;
?>
If this code is stored in appname.errors file and loaded by an application using

require_once(‘appname.errors’), then the ErrorHandler class can print the
SAMPLE_ERR_CODE error message in any of the three languages, depending on the
default language settings.
You can translate your error messages in multiple languages using
Language Translation Tools provided by Google at http://translate.
google.com/translate_t
. Be aware that not all automatic translations
are perfect.
Chapter 4: Architecture of an Intranet Application 83
07 549669 ch04.qxd 4/4/03 9:24 AM Page 83
You can set an application’s default language using the $DEFAULT_LANGUAGE
variable in a configuration file for your application. For example,
<?php
// appname.conf
// Default language for
$DEFAULT_LANGUAGE = ‘US’;
?>
If this configuration is loaded by an application using the ErrorHandler class, all
error messages will be displayed in U.S. English.
ErrorHandler() is the constructor function for the class.ErrorHandler.php.
This function sets the default language of the error handler to what is set in the
application configuration as global $DEFAULT_LANGUAGE variable.
This method can be passed an associative array as a parameter. If the parameter
array has a key=value pair called caller=class_name, then it sets the member
variable called caller_class to the value.
The constructor also initializes a member array called error_message and loads
the error code for the default language by calling the load_error_code() method.
The error handler class ErrorHandler is automatically invoked by the
PHPApplication class so you don’t need to create an error handler manually in
your application code.

Now let’s look at the other functions available in ErrorHandler class.

alert(): This function displays an internationalized error message using
a simple JavaScript pop-up alert dialog box. It is called with the error
code. The get_error_message() method is used to retrieve the appropri-
ate error message in default application language from the application’s
error configuration file.

get_error_message(): This function retrieves the error messages for
given error code. If an array of error codes is supplied as parameter, the
function returns an array of error messages. If no error code is supplied,
the function returns a default error message using the MISSING error code.

load_error_code(): This function loads the application’s error code in
from the global $ERRORS array to its own member array variable
error_message. This function is called from the constructor method and
does not need to be called manually, unless you want to reload error mes-
sages from $ERRORS.
84 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 84
Creating a Built-In Debugger Class
When developing applications, each developer uses at least some form of debug-
ging. Although PHP-supported Integrated Development Environments (IDEs) are
becoming available, they’re still not the primary development tools for most PHP
developers, who are still using echo, print, and printf functions to display
debugging information during development.
The debugging class called class.Debugger.php is a bit more advanced than
the standard echo, print, and printf messages.
It provides a set of facilities that include


Color-coding debug messages

Automatically printing debug line numbers

Optionally buffering debug messages

Prefixing debug messages with a given tag to make it easy to identify
messages in a large application
Listing 4-3 shows the debugger class that is part of our application framework.
It can be used to perform basis application debugging.
Listing 4-3: class.Debugger.php
<?php
/*
* CVS ID: $Id$
*/
define(‘DEBUGGER_LOADED’, TRUE);
class Debugger {
var $myTextColor = ‘red’;
function Debugger($params = null)
{
// Debugger constructor method
$this->color = $params[‘color’];
$this->prefix = $params[‘prefix’];
$this->line = 0;
$this->buffer_str = null;
$this->buffer = $params[‘buffer’];
$this->banner_printed = FALSE;
Continued
Chapter 4: Architecture of an Intranet Application 85
07 549669 ch04.qxd 4/4/03 9:24 AM Page 85

Listing 4-3 (Continued)
}
function print_banner()
{
if ($this->banner_printed == TRUE)
{
return 0;
}
$out = “<br><br><font color=’$this->myTextColor’>” .
“<strong>Debugger started for $this->prefix</strong>” .
“</font><br><hr>”;
if ($this->buffer == TRUE ){
$this->buffer_str .= $out;
} else {
echo $out;
$this->banner_printed = TRUE;
}
return 1;
}
function write($msg)
{
$out = sprintf(“<font color=’%s’>%03d &nbsp;</font>” .
“<font color=%s>%s</font><br>\n”,
$this->myTextColor,
$this->line++,
$this->color,
$msg);
if ($this->buffer == TRUE)
{
$this->buffer_str .= $out;

} else {
echo $out;
}
}
86 Part II: Developing Intranet Solutions
07 549669 ch04.qxd 4/4/03 9:24 AM Page 86
function debug_array($hash = null)
{
while(list($k, $v) = each($hash))
{
$this->write(“$k = $v”);
}
}
function set_buffer()
{
$this->buffer = TRUE;
}
function reset_buffer()
{
$this->buffer = FALSE;
$this->buffer_str = null;
}
function flush_buffer()
{
$this->buffer = FALSE;
$this->print_banner();
echo $this->buffer_str;
}
}
?>

The debugger class has the following methods:

Debugger(): This is the constructor function for the debugger class
(class.Debugger.php). This function initializes the color, prefix, line, and
buffer_str, banner_printed member variables. The color is used to
display the debug information in a given color. The prefix variable is used
to prefix each debug message displayed, which allows for easier identifi-
cation of messages.
The line variable is initialized to zero, which is automatically incremented
to help locate debug information quickly. The buffer_str variable is used
to store buffered debug information. The banner_printed variable, which
Chapter 4: Architecture of an Intranet Application 87
07 549669 ch04.qxd 4/4/03 9:24 AM Page 87

×