Post-Redirect-Get Pattern
June 2nd, 2008
Ah design patterns, a breath of fresh air for solving annoying little problems, especially in the web world. Today’s design pattern is the Post-Redirect-Get pattern. It’s not a crucial pattern to follow though it’s one of those things that can change a site from ‘good’ to ‘great’ in terms of usability.
The goal of this pattern is to separate control URLs with user displayed URLs. For example, I might have a registration URL: http://mysite.com/register. On that page is a submit button that will POST to http://mysite.com/register?action=go. Normally, after registering for a site, this second page might say “thank you for registering for mysite.com.” However, the URL /register?action=go doesn’t match the content of the page. What’s worse is that if a user hits the refresh button on the browser, most browsers will ask if they would like to re-post data which could mean multiple registration attempts.
What Post-Redirect-Get does is give the programmer much more control over how URLs are handled. A simple example on how to improve the registration page would be as follows:
- User goes to http://mysite.com/register and fills out data, hits submit
- The web form sends a POST request to http://mysite.com/register?action=go with the form data
- The script does the form processing and issues a header(”Location: http://mysite.com/thankyou”) in PHP
- When the web browser sees the ‘Location’ header, it then issues a GET request for that URL.
- User sees http://mysite.com/thankyou.
The end result of this pattern is that a user starts at http://mysite.com/register, fills out the form, submits it, and is then brought right to http://mysite.com/thankyou. The user never sees the ugly and potentially cryptic URL of http://mysite.com/register?action=go.
To make this pattern more flexible, PHP sessions can be used to store status and error messages. Using a reserved value, like $_SESSION['error_message'] can be set before the redirect and the display page can check if this value is set and act accordingly.
Perhaps a simple concrete example will shed more light on this design pattern. Below is the code for the registration page. Please note that this is example code and will probably not run if simply copied and pasted into a page called ‘register.php’.
<?php session_start(); include 'db.php'; if ($_GET['action'] == 'go') { $status = $db->query("INSERT INTO users (first, last) VALUES ('" . $_POST['first'] . "', '" . $_POST['last'] . "');"); if ($status != 0) { $_SESSION['error_message'] = 'There was a database error!'; header("Location: http://mysite.com/register"); } else { $_SESSION['status_message'] = 'Registration complete!'; header("Location: http://mysite.com/thankyou"); } } ?> <html> <head> <title>Registration Page</title> </head> <body> <h1>Registration</h1> <?php if(isset($_SESSION['error_message'])): ?> <p>ERROR: <?=$_SESSION['error_message']?></p> <?php endif; ?> <form action="/register?action=go" method="post"> <p>First Name: <input type="text" name="first" /></p> <p>Last Name: <input type="text" name="last" /></p> </form> </body> </html>
And here is the ‘thank you’ page:
<?php session_start(); ?> <html> <head> <title>Thanks for registering</title> </head> <body> <?php if(isset($_SESSION['status_message'])): ?> <p>NOTICE: <?=$_SESSION['status_message']?></p> <?php endif; ?> <p>Thank you for registering!</p> </body> </html>
Leave a Reply