Creating the Edit Author Page
Our application still lacks the add/edit author functionality. This page will be
somewhat simpler than the edit book page because it will not have the select box
for authors and no unique index. (You may want to create a unique index on the
author’s fi rst and last name columns to prevent duplicates there too, but we will
leave this up to you.)
Let’s call this page editAuthor.php. Here is its source code:
<?php
/**
* This page allows to add or edit an author
* PDO Library Management example application
* @author Dennis Popel
*/
// Don't forget the include
include('common.inc.php');
// See if we have the author ID passed in the request
$id = (int)$_REQUEST['author'];
if($id) {
// We have the ID, get the author details from the table
$q = $conn->query("SELECT * FROM authors WHERE id=$id");
$author = $q->fetch(PDO::FETCH_ASSOC);
$q->closeCursor();
$q = null;
}
else {
// We are creating a new book
$author = array();
}
// Now see if the form was submitted
if($_POST['submit']) {
// Validate every field
$warnings = array();
// First name should be non-empty
if(!$_POST['firstName']) {
$warnings[] = 'Please enter first name';
}
// Last name should be non-empty
if(!$_POST['lastName']) {
$warnings[] = 'Please enter last name';
}
// Bio should be non-empty
if(!$_POST['bio']) {
$warnings[] = 'Please enter bio';
}
// If there are no errors, we can update the database
// If there was book ID passed, update that book
if(count($warnings) == 0) {
if(@$author['id']) {
$sql = "UPDATE authors SET firstName=" .
$co>quote($_POST['firstName']) .
', lastName=' . $conn->quote($_POST['lastName']) .
', bio=' . $conn->quote($_POST['bio']) .
" WHERE id=$author[id]";
}
else {
$sql = "INSERT INTO authors(firstName, lastName, bio) VALUES(" .
$conn->quote($_POST['firstName']) .
', ' . $conn->quote($_POST['lastName']) .
', ' . $conn->quote($_POST['bio']) .
')';
}
$conn->query($sql);
header("Location: authors.php");
exit;
}
}
else {
// Form was not submitted.
// Populate the $_POST array with the author's details
$_POST = $author;
}
// Display the header
showHeader('Edit Author');
// If we have any warnings, display them now
if(count($warnings)) {
echo "<b>Please correct these errors:</b><br>";
foreach($warnings as $w)
{
echo "- ", htmlspecialchars($w), "<br>";
}
}
// Now display the form
?>
<form action="editAuthor.php" method="post">
<table border="1" cellpadding="3">
<tr>
<td>First name</td>
<td>
<input type="text" name="firstName"
value="<?=htmlspecialchars($_POST['firstName'])?>">
</td>
</tr>
<tr>
<td>Last name</td>
<td>
<input type="text" name="lastName"
value="<?=htmlspecialchars($_POST['lastName'])?>">
</td>
</tr>
<tr>
<td>Bio</td>
<td>
<textarea name="bio"><?=htmlspecialchars($_POST['bio'])?>
</textarea>
</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" name="submit" value="Save">
</td>
</tr>
</table>
<?php if(@$author['id']) { ?>
<input type="hidden" name="author" value="<?=$author['id']?>">
<?php } ?>
</form>
<?php
// Display footer
showFooter();
This source is built in the same way as the editBook.php page so you should be able
to follow it easily.
We will link to the editAuthors.php page in the same way as we linked to the
editBook.php page from the books.php page. Edit the authors.php fi le and change
lines 30-41 to the following:
while($r = $q->fetch(PDO::FETCH_ASSOC))
{
?>
<tr>
<td><?=htmlspecialchars($r['firstName'])?></td>
<td><?=htmlspecialchars($r['lastName'])?></td>
<td><?=htmlspecialchars($r['bio'])?></td>
<td>
<a href="editAuthor.php?author=<?=$r['id']?>">Edit</a>
</td>
</tr>
<?php
}
Add the following line just before the last PHP block:
<a href="editAuthor.php">Add Author...</a>
Now, if you refresh the authors.php page you will see the following:

You can click the Edit links in the rightmost column to edit every author’s details.
You can try submitting the form with empty values to see that invalid submissions
will be rejected. Also, you can try and add a new author to the system. After you
successfully do this, you may want to go back to books listing and edit some book.
You will see that newly created author is available in the authors select box.
Securing against Uncaught Exceptions
As we have seen previously, we place the try…catch blocks around code that can
throw exceptions. However, in very rare cases, there might be some unexpected
exceptions. We can imitate such an exception by modifying one of the queries so
that it contains some malformed SQL. For example, let’s edit authors.php, line 16
to the following:
$q = $conn->query("SELECT * FROM authors ORDER BY lastName,
firstName");
Now try to navigate to authors.php with your browser to see that an uncaught
exception has occurred. To correctly handle this situation, we either should create an
exception handler or wrap every block of code that calls PDO or PDOStatement class
methods in a try…catch block.
Let’s see how we can create the exception handler. This is an easier approach as it
does not require changing lots of code. However, for big applications this may be
bad practice as handling exceptions, where they occur may be more secure and
better recovery logic can be applied.
However, with our simple application we can use the global exception handler. It
will just use the showError() function to say that the site is under maintenance:
/**
* This is the default exception handler
* @param Exception $e the uncaught exception
*/
function exceptionHandler($e)
{
showError("Sorry, the site is under maintenance\n" .
$e->getMessage());
}
// Set the global excpetion handler
set_exception_handler('exceptionHandler');
Place this into common.inc.php, just before the connection creation code block. If
you refresh the authors.php page now, you will see that the handler gets called.
It is always a good idea to have the default exception handler. As you have
noticed, unhandled exceptions expose too much sensitive information including
database connection details. Also, in real world applications the error pages should
not display any information about the type of the error. (Note that our example
application does.) The default handler should write to the error log and alert site
maintainers about the error.
Summary
In this chapter, we examined how PDO handles errors and introduced exceptions. Also,
we investigated the sources of errors and saw how to counter them.
Our sample application was extended with some real-world administration
functionality that uses data validation and is secured against SQL injection attacks.
Of course, they should also allow database modifi cations only to certain users based
on login names and passwords. However, this is beyond the scope of this book.
In the next chapter, we will look at another very important aspect of PDO and
database programming in general—using prepared statements. We will see how
our administration pages can be simplifi ed with their help, leading to less code and
better maintenance.