Jump to content

$session->redirect with arbitrary 30x status code


schwarzdesign
 Share

Recommended Posts

I'm having a problem with the built-in $session->redirect() method, namely that it supports only the 302 and 301 status codes. I'm currently working on a form that uses POST requests to update some page fields. After processing the request, I want to send the visitor to another page. The correct HTTP response code for this situation is 303 See Other, because the user-agent is not supposed to repeat the POST request to the new page.

It would be a great addition for $session->redirect to support any of the possible 30x status codes, so it can be used in cases like this. For now, I have added this functionality with a hook (see below), but there are two problems with that:

  1. $session->redirect does some additional work, namely making sure current notices are correctly queued up as well as forcing graceful shutdown in some situations. This can't be done in a hook because, for example, the method calls $this->queueNotice, which is a protected method, so it can't be called from outside the class.
  2. Hooking before or after the redirect method isn't an option here either:
    1. Hooking after won't work at all, because the method calls exit(0) at the end, so any hook after that won't be executed.
    2. Hooking before may work in some situations, but the method may still overwrite headers set in the before hook, so it won't be reliable in any way.

Can you give this a look @ryan? Maybe the method could allow integer arguments as well as booleans, and set the status accordingly if it's one of the allowed 30x codes?

For reference, here's my workaround, though this does not perform all the graceful shutdown actions the built-in $session->redirect handles ...

// site/ready.php
wire()->addHook('Session::redirectStatus', function (HookEvent $e) {
    $session = $e->object;
    $url = $e->arguments(0);
    $httpCode = $e->arguments(1) ?: 302;
    if (!in_array($httpCode, [300, 301, 302, 303, 304, 307, 308])) {
        throw new \InvalidArgumentException('HTTP response code for redirect must be a valid 30X code.');
    }

    $statusData = array('redirectUrl' => $url, 'redirectType' => $httpCode); 
    $e->wire()->setStatus(ProcessWire::statusFinished, $statusData);
    header("Location: $url", true, $httpCode);
    exit(0);
});

// somewhere in a template file
$session->redirectStatus($somePage->url(), 303);

 

Link to comment
Share on other sites

  • 1 month later...

Actually you can directly use the  $session->redirect() method for sending any 30X status code, by taking advantage of its second parameter 'http301'.

When this parameter is set to false, ProcessWire uses PHP default behavior regarding location headers (PHP Manual says[…]  "Location:" header. Not only does it send this header back to the browser, but it also returns a REDIRECT (302) status code to the browser unless the 201 or a 3xx status code has already been set.)

Therefore, to send a 303 status code, you can simply write:

header("HTTP/1.1 303 See Other");
$session->redirect ($someUrl, /*$http301=*/false);

 

  • Like 2
Link to comment
Share on other sites

  • 7 months later...

Just an update in case anyone is looking for this, setting arbitrary 3XX response codes is now possible! As of ProcessWire 3.0.166, $session->redirect now accepts an integer as the second argument, which may be any HTTP response code in the 3XX-range. The blog post above doesn't really mention this, but you can see the change in this commit.

Thanks @ryan!

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...