Restoring PDO functionality

A few years ago, while PHP 5 was still in a state of flux, a change was made to the way that PDO handles parameters bound to prepared statements. Somewhere between versions 5.2.0 and 5.2.1 a change was made that gave rise to much annoyance and debate in bug 40417. Long story short, it used to be acceptable to reuse a placeholder in statement several times and bind a single variable to all of the instances thusly:

[sourcecode language=’php’]< ?php

// Connect to the database with defined constants
$dbh = safePDO_Factory::getInstance(PDO_DSN, PDO_USER, PDO_PASSWORD);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

try {

// Construct SQL query
$query = ‘
SELECT
*
FROM
tblnews
WHERE
title ILIKE :search
OR content ILIKE :search
‘;

// Prepare the statement
$stmt = $dbh->prepare($query);

// Bind the search string variable to the statement
$smt->bindParam(‘:search’, $search, PDO::PARAM_STR);

// Execute the query
$stmt->execute();

// Check to see if we have any results
if ($stmt->rowCount() > 0) {
// Process the results here . . .
} else {
echo ‘No search results were returned.';
}
} catch (Exception $e) {
echo $e->getMessage();
)

// Destroy the database connection
$dbh = null;

?>[/sourcecode]

But all of a sudden the above rudimentary news searching code would cease to work if you upgraded to PHP 5.2.1 and there was no notice in the PHP change log at the time, which obviously led to much confusion. The issue was that it was no longer acceptable to bind a single variable to multiple placeholders – each placeholder required a unique name and explicit variable binding.

In much the same way that I subclassed the PDO connection class, the individual PDO Statement class can be extended to restore this multiple placeholder / single variable behaviour.

Continue reading Restoring PDO functionality

I am the one and only

After previously explaining how to harden PDO I’m going to expand on the basic class I developed with the help of some design patterns.

A large part of using design patterns lies in recognising the situations in which each one should be used. The temptation is to implement the safePDO database class as a singleton so that only one instance of the object is used and extra connections are not made. An issue arises immediately as the constructor must be defined as public – the same as the parent PDO class – and therefore it will be able to be instantiated from anywhere. Besides, occasionally, you may also need to connect to another database which renders the singleton pattern useless.

A better choice for this situation, in my opinion, is the flyweight pattern. This is ordinarily used where a large number of similar items are to be used but can easily be applied in this situation so that database connection requests that have the same credentials can be reused.

In the following code a singleton factory pattern is used to handle and distribute requests for database connections, using the dsn and username as an array key for a pool of safePDO instances. You can rest assured that the database connection is wrapped in a try/catch block. As an added bonus, as all safePDO construction should be made from the factory class, we can make a check for this using a debug backtrace and therefore prevent a safePDO object from being instantiated at random.

If PHP code isn’t your thing – and assuming you’ve not already stopped reading by now – then you may want to give the code after the jump a miss. If your curiosity is piqued, read on . . .

Continue reading I am the one and only

Catching at source

If your application does not catch the exception thrown from the PDO constructor, the default action taken by the zend engine is to terminate the script and display a back trace. This back trace will likely reveal the full database connection details, including the username and password.
PDO Connections and Connection management

Ideally you shouldn’t be displaying any error messages to the outside world at all – especially on a production server. Even during development you should probably limit debugging output to approved IP addresses only.

You can take a very simple step to avoid displaying your username and password should the connection fail and you (or somebody else) forget to catch the error. By subclassing the PDO database abstraction layer you can make sure that you implicitly catch the exception message by temporarily changing the PHP exception handler.

You could generate your own backtrace here as well and sanitize the data to remove any passwords before display but I shall leave that as an exercise for the reader.

All you need to do now is remember to use the SafePDO class instead of instantiating a standard PDO object.

[sourcecode language=’php’]< ?php

Class SafePDO extends PDO {

public static function exception_handler($exception) {
// Output the exception details
die('Uncaught exception: ', $exception->getMessage());
}

public function __construct($dsn, $username=”, $password=”, $driver_options=array()) {

// Temporarily change the PHP exception handler while we . . .
set_exception_handler(array(__CLASS__, ‘exception_handler’));

// . . . create a PDO object
parent::__construct($dsn, $username, $password, $driver_options);

// Change the exception handler back to whatever it was before
restore_exception_handler();
}

}

try {

// Connect to the database with defined constants
$dbh = new SafePDO(PDO_DSN, PDO_USER, PDO_PASSWORD);

// The rest of your code goes here . . .

// Destroy the database connection
$dbh = null;

} catch (Exception $e) {
SafePDO::exception_handler($e);
}

?>[/sourcecode]