Handling Contact Form Failure

November 17, 2008

There is an article over a DZone today “What if your contact form fails?”. The article discusses what to do if the contact form on your website fails to send a message. The approach they suggest is to display a message to the user saying it failed, and presenting them with a mailto link so they can send you an email themselves.

This is one approach to the failed contact form problem, but it isn’t going to help much if the problem is actually with your email address. For example, you may have exceeded your disk quota, or you might have a badly configured mail server.

Another problem with the mail solution is that it requires the user to perform another action. They’ve gone to the trouble of filling out a contact form. If that fails they might not bother to send to send you an email too (although the suggested approach in the article does reduce the effort required).

An Alternative Approach

So what other approaches are there? What I do is store all contact form information in a database. Below is the SQL to create the basic messages table:

CREATE TABLE messages (
    id int auto_increment NOT NULL,
    sent timestamp NOT NULL,
    sender varchar(255) NOT NULL,
    message text,

    PRIMARY KEY(id)
);

Then when a contact form gets submitted you can store the information in the database before sending an email. Below is some sample PHP code, using PDO to access the database:

// Get the form data
$sender = $_POST['sender'];
$message = $_POST['message'];

// Add the message to the database
$query = "INSERT INTO messages(sender, message) VALUES (:sender, :message);
$stmt = $pdo->prepare($query);
$stmt->bindParam(':sender', $sender, PDO::PARAM_STR);
$stmt->bindParam(':message', $message, PDO::PARAM_STR);
$stmt->execute();

// Send the mail
mail("me@my.domain", "Contact Form Message", $message, "From: {$sender}");

All that is left to do is create an admin page that lists all messages, and allows us to delete them. We could even include a link to the admin page in the emails we send to ourselves. By using this approach we never lose the message content, even if the mail call fails, because they all get stored in the database. All we need to do is check the admin page every so often and we’ll soon see if there are any new messages there.

Of course, this approach doesn’t have to be used in isolation. We can combine it with the approach suggested in the DZone article, and present the user with a mail link if sending the mail does fail. If the user decides not to send a mail though, we haven’t lost anything.

Batch Image Processing with Python

November 15, 2008

If you want to make changes to a single image, such as resizing or converting from one file format to another, then you’ll probably load up the image in an editor and manually make the required changes. This approach is great for a single image, but it doesn’t really scale past more than a few images, at which point it becomes time consuming, not to mention boring!

This is where Python and the Python Imaging Library (or PIL) come in, allowing you to write scripts that process images in batch. The PNG2GIF converter I wrote back in August is just one example of batch image processing using Python and PIL. In this post I’m going to explore some other uses, and provide lots of example code.

Batch Processing

No matter what processing we want to do on our images the script outline will be the same: loop over all provided arguments, and perform the processing. The code to do this is shown below:

#!/usr/bin/env python
import sys
import Image

# Loop through all provided arguments
for i in range(1, len(sys.argv)):
	try:
		# Attempt to open an image file
		filepath = sys.argv[i]
		image = Image.open(filepath)
	except IOError, e:
		# Report error, and then skip to the next argument
		print "Problem opening", filepath, ":", e
		continue

	# Perform operations on the image here

This will allow our script to be called in all of the following ways:

batch_process.py image.gif
batch_process.py image1.png image2.gif image3.jpg
batch_process.py *.png
batch_process.py image1.gif, *.png

Processing

With the help of PIL the image processing is really simple. Below is a collection of just some of the operations we could perform. For more details see the PIL documentation.

# Resize an image
image = image.resize((width, height), Image.ANTIALIAS) 

# Convert to greyscale
image = image.convert('L')

# Blur
image = image.filter(ImageFilter.BLUR)

# Sharpen
image = image.filter(ImageFilter.SHARPEN)

Saving

Once we’ve processed the image we need to save the changes. In some instances we might just want to save over the original filename. If that’s the case we can just call the save method of image with its original filename. If we want to save the file under a different name, or as a different filetype we need to do a little more work:

	# Split our original filename into name and extension
	(name, extension) = os.path.splitext(filepath)

	# Save with "_changed" added to the filename
	image.save(name + '_changed' + extension)

	# Save the image as a JPG
	image.save(name + '.jpg')

Notice in the last example how PIL takes care of the conversion to JPG for us. All we do is provide the file extension and PIL does the rest for us.

A Complete Example

Each of the steps above can easily be put together to create a batch image processing script. Below is a complete script which creates thumbnails of all provided images, and saves them as PNG images, not matter what their original format:

#!/usr/bin/env python
# Batch thumbnail generation script using PIL

import sys
import os.path
import Image

thumbnail_size = (28, 28)

# Loop through all provided arguments
for i in range(1, len(sys.argv)):
	try:
		# Attempt to open an image file
		filepath = sys.argv[i]
		image = Image.open(filepath)
	except IOError, e:
		# Report error, and then skip to the next argument
		print "Problem opening", filepath, ":", e
		continue

	# Resize the image
	image = image.resize(thumbnail_size, Image.ANTIALIAS)

	# Split our original filename into name and extension
	(name, extension) = os.path.splitext(filepath)

	# Save the thumbnail as "(original_name)_thumb.png"
	image.save(name + '_thumb.png')