Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

The Art of Redirecting

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $4.00

The Art of Redirecting

Go back to the new pet form and fill it out again. Ok, it looks like it’s still working. Refresh a few times and check out pets.json. Woh, we have a lot of duplicate “Fidos” in our file! Each time I refreshed, the form resubmitted and added my pet again. Bad dog!

In the real world, we don’t want users to be able to create duplicate records accidentally or so easily. And that’s why you should redirect the user to a different page after handling a form submit.

Remember: we always send back an HTTP response to the user. And so far, a response is always an HTML page. But it could be something else, like a tiny bit of directions that tell the browser to go to a totally different URL. The browser would then make a second request to that URL and display that HTML page. This is called a redirect.

Returning a Redirect Response

After saving the new pet, let’s tell the user’s browser to redirect to the homepage. To do this, use a function called header and pass it a string with the word Location, a colon, then the URL. Finish up with our trusty die statement:

// ...

$json = json_encode($pets, JSON_PRETTY_PRINT);
file_put_contents('data/pets.json', $json);

header('Location: /index.php');
die;

And sure enough, this time when we fill out the form, we’re redirected to the homepage! Check out the network tab again in our debugging tools. It shows us the request for the current page like always, and the request of the last form submit.

Redirect: 2 Requests/Responses

Remember, 2 request-response cycles just happened all at once. When we submitted the form, a POST request was sent, which we can see. But the response that our PHP code sent back to the browser didn’t contain HTML. Actually, it didn’t contain anything, except for this little Location line that told the browser to redirect to the homepage.

When the browser sees this instruction line instead of HTML, it quickly makes a GET request to the homepage. This time, our code returns a response message with HTML and it displays it. It looked instant, but now we know that our browser just made 2 separate requests.

Headers

Let’s learn something that takes most web developers years to figure out. Ready?

Don’t crowd the elevator doors when it opens, people might be getting out of it.

Ok, want to learn something else that usually takes web developers years?

When our browser makes a request, the most important part is the URL. Of course! The server needs to know which page we want! But the request also has other information like our IP address and browser details. Each extra bit if info is called a request header. And we can read these in PHP from that $_SERVER array variable.

The response our code sends back also has extra information, called response headers. A response is basically 2 pieces: the HTML and these headers. Most of the time, we don’t think about headers or responses: we just write HTML and print some variables. This automatically becomes the content of the response and a few important headers are set for us.

But sometimes, you do need to send back a response with a bit of extra information. And in fact, when you want to tell a browser to redirect, we need to send back a response message with a Location header. This type of extra information is added to the response with the header function and each has the same format: a header name, a colon, then the value. Every browser is programmed to look for the Location header.

After, I put a die statement just to stop everything right there. We haven’t printed anything yet, so the response has no content. That’s perfect: I want the browser to go somewhere else, not display this page. But even if we did echo some HTML, the user would never see it because the browser would redirect so quickly.

I thought you said die was bad?

Ok, I admit, in episode 1, I said that you should never use die except for debugging. Yes, I’m violating that temporarily because we need to learn a few more things before we can re-organize code and get rid of this. We’ll see that in a future screencast.

Can’t Re-Submit: Mission Accomplished

We started all this redirect business because we didn’t want the user to be able to refresh a finished form and create duplicate pet data. And now, we’ve done that! Refresh here: instead of re-submitting the form, it just makes another GET request to the homepage. Whenever you process a form submit, add a redirect by setting the Location response header.

Leave a comment!

7
Login or Register to join the conversation
Default user avatar
Default user avatar Stephane | posted 5 years ago

Hello, my name is Stéphane and I am writing from Reunion Island. I just subscribed to your courses to refresh my knowledge in PHP. I am trying the redirect thing, but when I submit the form, I got the following message : "Warning: Cannot modify header information - headers already sent by...". And I guess it's because we have the "require 'layout/header.php'" instruction at the beginning of pets_new.php which already contains some html. So, how can I modify the code to make it redirect me to the homepage ?

Edit : Nevermind. I found the solution by moving the require instruction a few lines below just before the html code of the page.
Great courses !

2 Reply

Hey Stéphane,

Yeah, nice workaround! The another common way to solve this issue is to use output buffering for PHP. Enabling it in php.ini will allow PHP to buffer output instead of passing it to the web server instantly. PHP thus can aggregate HTTP headers even after your script already "echo" something to the browser.

Cheers!

1 Reply
MattWelander Avatar
MattWelander Avatar MattWelander | posted 9 months ago

Hi, I have an issue with redirects. Every now and then, my webhost's Nginx returns a "504 Bad Gateway" I have asked them for the logs, and they came back with this error message:

httpd[48541] [core:error] [pid 48541] [client 193.12.157.36:0] AH00124: Request exceeded the limit of 10 internal redirects due to probable configuration error. Use 'LimitInternalRecursion' to increase the limit if necessary.<br />

I only do 1 redirect in my code, like this:
return $this->redirectToRoute('operator_index');

But apparently that puts it through the roof of 10 (?). I also found some information (https://stackoverflow.com/questions/63728070/symfony5-too-many-redirect) that there may be a conflict between Symfony5 wanting to remove trailing slashes, and some webservers adding them back, (perhaps creating a redirect loop?)

My routing actually has two (probably unneccessary) trailing slashes

position_index GET ANY ANY /positionlog/positions/
operator_index GET ANY ANY /positionlog/operators/

But I don't know if that actually causes a 504 error?

I thought I probably wasn't the first one facing an issue with symfony redirects causing server problems.

Reply
MattWelander Avatar

I also just found out that faulty locale can cause an increased number of redirects. I had mine set to "se" which is incorrect, now changed to "sv" for swedish. I could also set it to "sv-SE"to include language AND country. However, not sure if that is responsible for a number of 504 errors =)

Reply
Jesse-Rushlow Avatar
Jesse-Rushlow Avatar Jesse-Rushlow | SFCASTS | MattWelander | posted 9 months ago | edited

Howdy Matt,

I typically do not add a trailing slash when defining routes because Symfony will redirect the request if the slash is not provided with GET requests.

e.g. #[Route('/some/path/')] and the requesting URL is /some/path, Symfony will 301 redirect to /some/path/ and vice versa.

Hope this helps!

Side Note: Here is a link to the docs page that references this: https://symfony.com/doc/current/routing.html#redirecting-urls-with-trailing-slashes

Reply

Couldn't you just check if the record already exists? If the user is editing their profile info they might not want to get redirected, maybe they want to stay on the profile page and verify that their info was all correct and actually saved to boot??

Reply

Hey RU,

Even in this case you need to redirect users, but instead of a different page you redirect them to the same page. Without redirect, when you sent POST request, if you try to reload the page - browser will ask you a message like: "Are you sure you want to resend your POST request?". And that's not something you want. To avoid this, you need that redirect. But redirect could lead to any URL, even to the same URL users are currently on.

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

userVoice