Developing Effectively with PEAR Packages

by Justin Patrin, edited by Gregory Beaver

Introduction

This document is the result of years of collected helpful hints that everyone using PEAR packages should know about. Users who come on IRC often need to know this information, and so now this knowledge is available for all to learn from.

Error Handling

Most PEAR packages will return errors from a function call. These errors take the form of PEAR_Error objects. The correct way to handle these is:


<?php
require_once 'PEAR/DB.php';
$db DB::connect($dsn);
if (
PEAR::isError($db)) {
    
//This is an example of what you can do when an error happens. You could also log the error or try to recover from it.
    
die($db->getMessage() . ' ' print_r($db->getUserInfo(), true));
}
?>

This should be done for all calls which are documented to return an error. If you don't check for an error return you will get error messages such as Fatal error: Call to undefined function: PEAR_Error::fetchRow(). in /usr/share/php5/MDB2.php on line 1921.

Another way to handle errors in PEAR is to use a global error handler. A simple example is below. This will die on all PEAR_Errors and show the reason for the error:


<?php
function handle_pear_error($e) {
    die(
$e->getMessage() . ' ' print_r($e->getUserInfo(), true));
}
require_once 
'PEAR.php';
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK'handle_pear_error');
?>

You can also get a backtrace from the error object so that you can see where the error came from. This is especially helpful when you're using a global error handler and you can't tell where the error is coming from.


<?php
function handle_pear_error($e) {
    echo 
'Backtrace:
'
;
    foreach (
$e->getBacktrace() as $l) {
        echo 
'File: ' $l['file'] . ' Line: ' $l['line'] .
             
' Class: ' $l['class'] . ' Function: ' $l['function'] . '
'
;
    }
    die(
$e->getMessage() . ' ' print_r($e->getUserInfo(), true));
}
require_once 
'PEAR.php';
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK'handle_pear_error');
?>

The first line output will be from PEAR_Error and can usually be ignored. It is the next line that tells you where the error was raised.

Backtrace:
File: /usr/lib/php/PEAR.php Line: 572 Class: PEAR_Error Function: PEAR_Error
File: /home/papercrane/public_html/test.php Line: 13 Class: PEAR Function: raiseError
Some Error

Newer PEAR packages which are written for PHP5 use PEAR_Exception instead of PEAR_Error. See the Error Handling Guidelines for PHP5 packages RFC, the wiki page it is based on, and the PHP documentation for how to handle these. Be careful with your input and output

Security Concerns

Handling the superglobals such as $_POST, $_GET, and $_REQUEST can be tricky and leave you open to Injection and XSS attacks as well as cause annoying problems such as multiplying backslashes.

It is always best to let a well tested package, such as HTML_QuickForm2, MDB2, or DB handle these values for you.

For input and output of form values, use HTML_QuickForm2. It will automatically quote your values so as to stop XSS and will also make sure that magic_quotes_gpc isn't corrupting your values.


<?php
$value 
'inject">XX<input name="password" type="hidden" value="h4cked';
require_once 
'HTML/QuickForm2.php';
$form = new HTML_QuickForm2();
$password_control $form->addElement('password''password')->setLabel('Enter your password')->setValue($value);

if (
$form->validate()) {
    echo 
'Password entered: ' htmlentities($password_control->getValue('password'));
}
$form->display();

If you had simply output $value without passing it through HTML_QuickForm2 you would have had injected HTML in your form. If you happened to have

magic_quotes_gpc
turned on (you should never have this on) then the value output would have had extra backslashes before any quotes passed in. If htmlentities() hadn't been run before outputting the value then any HTML entered would have been injected into your page.

Then when you want to insert into your database: With MDB2:


<?php
$mdb2 
MDB2::connect($dsn);
$sth $mdb2->query('SELECT * FROM table WHERE col = ' .
    
$mdb2->quote($value'string'));

// With DB:

$db DB::connect($dsn);
$sth $db->query('SELECT * FROM table WHERE col = ' .
    
$db->quoteSmart($value));
?>