0

I have a URL that once handled GET and POST requests. I want it to now only handle POST requests, and do a redirect for other requests. Based on this question, it appears that I should use a 303 after processing a POST request, and a 301 for other requests.

My code flow would look like this:

if ('POST' === filter_input(INPUT_SERVER, 'REQUEST_METHOD')) {
    // process post request

    // set http status code
    header('HTTP/1.1 303 See Other');
} else {
    // set http status code
    header('HTTP/1.1 301 Moved Permanently');
}
header('Location: /newurl.php');

Is this the proper user of the redirect codes? I want to make sure the 301 won't be cached by browsers when a POST request is made.

Community
  • 1
  • 1
Sonny
  • 8,204
  • 7
  • 63
  • 134

2 Answers2

1

Your redirect should be

header('Location: http://www.example.com/newurl.php',true,301);

for 301 code, similar with 303 (so you don't need the last Location header). See the manual on header.

MarcinWolny
  • 1,600
  • 2
  • 27
  • 40
  • 1
    This appears to be a comment about code style and not an answer to the question. (Also note that the spec requires an absolute URI for location) – Quentin Jun 11 '14 at 16:13
  • Good point about absolute URI. And no, it's not a matter of code style. Doing what he did, as far as I remember, will always result in 302 (Found) redirect. My method is the one you need to use in order to have a proper redirect codes. – MarcinWolny Jun 11 '14 at 16:15
  • 1
    I used [this code](http://test-cases.dorward.me.uk/stackoverflow/24167607/test.phps) and got a `HTTP/1.1 303 See Other` response when I tested it with cURL. – Quentin Jun 11 '14 at 16:22
  • The Wikipedia page actually gives an example with relative URLs, so I'm not sure why you mention having to use an absolute URI. http://en.wikipedia.org/wiki/HTTP_location#Relative_URL_example – Sonny Jun 11 '14 at 18:06
  • 1
    Thanks for mentioning the additional arguments for the `header()` function. I will be using those. – Sonny Jun 11 '14 at 21:29
1

On 303 redirect you must specify a redirect URI:

<?php
header('HTTP/1.1 303 See Other');
header('location: http://www.example.com/some-url/');

As a workaround for caching the 301 response, you can set the expiration date in the past. This way the client is encouraged to mark the response as expired immediately:

<?php
header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
header('Expires: Sat, 1 Feb 1997 06:00:00 GMT');

The 303 response should not be cached by any client that respects RFC 2616:

The 303 response MUST NOT be cached, but the response to the second (redirected) request might be cacheable.

Considering the above, you could change initial code snippet to something like this:

if ('POST' === filter_input(INPUT_SERVER, 'REQUEST_METHOD')) {
    // process post request

    // set http status code
    header('HTTP/1.1 303 See Other');
    header('Location: http://www.example.com/newurl.php'); // FULL URI HERE
    exit;
}

// set http status code
header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('HTTP/1.1 301 Moved Permanently');
header('Location: http://www.example.com/other-page.php');

However, in your case a 307 redirect should be more appropriate. Although 307 is a temporary redirect and you will always redirect on any request that is not POST you can change this behavior in the future because as per RFC "Since the redirection MAY be altered on occasion, the client SHOULD continue to use the Request-URI for future requests". The second advantage is that: "This response is only cacheable if indicated by a Cache-Control or Expires header field."

The requested resource resides temporarily under a different URI.
Since the redirection MAY be altered on occasion, the client SHOULD
continue to use the Request-URI for future requests. This response
is only cacheable if indicated by a Cache-Control or Expires header
field.

See RFC 2616 sec. 10.3.8

Alexandru Guzinschi
  • 5,675
  • 1
  • 29
  • 40
  • Seems like using the 'Cache-Control' and 'Expires' headers defeats part of the utility of the 301 redirect. The answers in the question that I linked to allude to the browser caching based on the request type. Also, my code example specifies a URL in both cases, because it's outside of the `if/else` block. – Sonny Jun 11 '14 at 18:25
  • " *Seems like using the 'Cache-Control' and 'Expires' headers defeats part of the utility of the 301 redirect.* ". Can you give more details about that do you mean with that statement ? – Alexandru Guzinschi Jun 11 '14 at 18:34
  • 301 redirects are supposed to be cached by the client in order to enhance the user experience. It's discussed in the SO question that I linked to. http://stackoverflow.com/questions/4764297/difference-between-http-redirect-codes – Sonny Jun 11 '14 at 18:43
  • @Sonny Makes sense. See my updated answer (*at the end*) with an alternative. – Alexandru Guzinschi Jun 11 '14 at 18:56