PHP Redirects: 302 to 301 Rock Solid Solution

I had a project recently that required all redirects on a website to change from 302 temporary to 301 permanent. If you’re asking yourself what a 301 redirect is, read this article by Matt Cutts. Why change this? Well, it’s for SEO reasons really. Google requires that all outdated pages return a HTTP 404 code if they have been removed; but if they have been replaced with a new page, a HTTP 301 code should be returned along with the Location header with the location of the new page.

At first, this seemed like a quick fix as every one of their outdated pages called a function called redirect() and passed a new location.

// This is http://www.example.com/oldpage.php
$newPage = 'http://www.example.com/newpage.php';
redirect($newPage);

The redirect function is as follows:

function redirect($url)
{
    header("Location: {$url}");
}

By default the php header function, when given a Location: string, it automatically returns a 302 apache response code. Why? Because PHP doesn’t know if you wanted to setup a permanent redirect to the new location or not; therefore it’s safer to asume not.

So I can simply amend the redirect function as follows and this will now return a 301 apache response code:

function redirect($url)
{
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: {$url}");
}

Great – checked the response headers using firebug‘s net tab (here’s how to do that). 301 Apache status code being received. All-in-all it seems to be fixed – 301 status being received for all pages tested.

However, after doing a little more digging in the code we realised that the function in hand is also used to redirect the user to success pages after form submissions. So, the following question came up…

What about where a form is submitted and the user is redirected to a success page? Could the 301 response be cached?

The possible impact of this is that if a form is submitted to a processing page and the form submission is valid, the user will be sent to a “form submission successful” page. What if the forum was submitted a second time? Would the browser cache the 301 response code and “throw” the user into the “form submission successful” page without processing the form information?

Quite honestly, although I suspected that this would not be a problem, I didn’t know the answer. So I did a little digging. I stated with the Apache response code definitions.

  • 301 Says: “This response is cacheable unless indicated otherwise.”
  • 302 Says: “This response is only cacheable if indicated by a Cache-Control or Expires header field.”

This indicates that we would in fact be sent directly to the “form submission successful” page without the form data being processed as the 301 response will be cached.

But wait – I remember reading (one upon  a time) that when there is a current PHP session, PHP automatically adds this to the list of response headers: “Cache-Control: no-store, no-cache”. (Edit: confirmed here too) This means that when a form is submitted and there is a valid PHP session, the browser shouldn’t cache the response.

But how can we be sure? Well, since almost all browsers mis-behave at times, we cannot assume that they will take notice of what PHP is telling them. The only safest way is to add the following to the redirect() function to absolutely ensure that no browser (or proxy) will cache the result:

function redirect($url)
{
    // Date in the past
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
 
    // always modified
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
 
    // HTTP/1.1
    header("Cache-Control: no-store, no-cache, must-revalidate");
    header("Cache-Control: post-check=0, pre-check=0", false);
 
    // HTTP/1.0
    header("Pragma: no-cache");
 
    // Set the 301 response code
    header('HTTP/1.1 301 Moved Permanently');
    header("Location: {$url}");
}

That’s it – cache problem sorted. The headers above ensure that the page is giving out headers that will not be cached. Mainly because the http client is explicitly telling the client to revalidate and also saying that it expires in the past.

This entry was posted in PHP, Seo. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">

Notify me of followup comments via e-mail. You can also subscribe without commenting.