0

I'm refactoring some old code and trying to understand headers a bit better.

I read an awesome answer in the following post on No output before sending headers! Now I understand the 'why' but when it comes to implementation Its still a bit fuzzy.

My current page redirects back when the cancel button is clicked with the value searched.

I store the page the request was made from and the value in session variables allowing me to do this:

if (isset($_SESSION['searchPage'])){
 header('Location:searchForm.php?ticket='.$_SESSION['product'].'&searchbtn=Search');
 exit();
}

However to make this work in the display page I had to to use ob_start().

To avoid this workaround I found that I could redirect via javascript:

if (isset($_SESSION['searchPage'])){
    echo '<script>window.location="searchForm.php?product='.$_SESSION['product'].'&searchbtn=Search";</script>';    
    exit(); 
}

Now to my questions

  1. Which method is better or acceptable?
  2. I can't seem to think of a way to design my page in such away where no output is sent before using header(). If a button click event causes redirection how do you handle redirection in php without using ob_start() ?
Community
  • 1
  • 1
kaizenCoder
  • 2,211
  • 6
  • 33
  • 64
  • PHP. Always PHP. Using `ob_start()` (and the other `ob_*` functions) is fine – Bojangles Jun 21 '13 at 11:53
  • _“I can't seem to think of a way to design my page in such away where no output is sent before using header().”_ – http://en.wikipedia.org/wiki/IPO_Model – CBroe Jun 21 '13 at 11:55

5 Answers5

4

edit
First and foremost, you might want to read up some more on redirecting using header. Instead of just setting header('Location:...');, redirect using the following code:

header ('HTTP/1.1 301 Moved Permanently');
header('Location:searchForm.php?ticket='.$_SESSION['product'].'&searchbtn=Search');

A 301 redirect is generally better for SEO, and most browsers will cache the redirect, so the client history stack will be more reliable, which is good news for the JS scripts that might use the history...

  1. Which is the better approach?

PHP. Relying solely on JS for redirecting the client is not a great idea. Clients might turn of your script, or if some error creeps in the JS code, the redirection won't work. Some borred teen might feel like messing with your code, and find possible security issues in your site.

   2. How to use ob_*, or how to use header without ob_*?

Just start your entry script (index.php) with an ob_start() call, to make sure. Perhaps use ob_implicit_flush(true), to implicitly flush your output buffer. But more importantly, just call ob_flush() right after setting your headers.
Alternatively look into using a framework like Symfony2 and/or ZendFW. Code to handle redirects has been written for you many times, why not use it?

If you want to steer clear of output buffering, perhaps you might want to consider following certain patterns, or design principles (like MVC, IPO and the like) and write your code to (+-) always follow this order to take care of business:

  • Get the request
  • Process data from request, determine what data client is asking for
  • structure data
  • render page
  • send response

Right after you've processed the request, you'll be able to redirect, and since you're not even close to rendering the output, let alone sending the headers, you're safe to redirect and or set the headers...

Update:
Just a link in response to your follow-up question Gruyere has a special secion on XSS attacks you might want to read... Though the main purpouse of the document is, I believe, how to safely use mashups (which are actually bonafide XSS injections). Anyway, they do a far better job at explaining why and how JS can be used to undermine security of any webapp.

Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
  • Thanks for the detailed answer. You're right. I probably do need to brush up on headers some more. – kaizenCoder Jun 22 '13 at 23:34
  • Just a follow up question, when developing websites, should you always take into account that users may be browsing with js switched off? specially with the advent of jQuery.. – kaizenCoder Jun 24 '13 at 07:34
  • 1
    @codingUnderdog: It all depends, really... Do you care about the ~2% of clients? if not, just include a `noscript` bit that notifies them that not all features of your site will be available to them. In a way, that's taking those clients into account, too. When it comes to redirection, though, my main concern would be: JS is open to the client, they can see (and manipulate) the code that redirects them. XSS attacks have been around for getting on 20 years now, and they're not getting any harder to pull off. As a developer, you should therefore _never trust the network_. Keeping it server side – Elias Van Ootegem Jun 24 '13 at 07:43
  • ... is a way to keep things under control (or controlling them more/better) – Elias Van Ootegem Jun 24 '13 at 07:45
1

It’s always better to do it server-side. Both from an SEO point of view and because JavaScript redirects if a user has JavaScript disabled or there’s a problem downloading your JS file, or there’s an error in it that stops execution.

Martin Bean
  • 38,379
  • 25
  • 128
  • 201
  • SEO argument would require a 301 redirect, OP is currently redirecting using HTTP 302 (temporily moved)... Google prefers 301 – Elias Van Ootegem Jun 21 '13 at 12:11
  • I meant for any redirect. Search engines will pick up a server-side redirect, but may not pick up a client-side one. – Martin Bean Jun 21 '13 at 13:00
  • [Well, googlebot might](http://www.searchnewz.com/seo-interview-with-matt-cutts-2010-03), they've been at it for years, and they do pick up on JS redirects... but generally speaking, you're right (just thought you mind find the article interesting, as I did) – Elias Van Ootegem Jun 21 '13 at 13:04
0

PHP redirection is best. Because even if a user has disable the script in his browser.

If you're using a noscript redirection then you can go for JS instead of PHP, so that in this case you can avoid ob_start().

Anand
  • 1
0

If you want just to send a user to another page on a button click, why not just to implement a link:

<a href="searchForm.php?ticket=<?=$product?>&searchbtn=Search">go back</a>

or button:

<button onclick="window.location='searchForm.php?ticket=<?=$product?>&searchbtn=Search'">go back</button>
claustrofob
  • 5,448
  • 2
  • 19
  • 22
  • That doesn't solve the OP's queation one bit... it's a question about setting the headers, this is just a workaround (and not a very user-friendly one at that) – Elias Van Ootegem Jun 21 '13 at 12:12
  • @EliasVanOotegem The solution looks overengineered. Instead of trying to fix it why not to suggest a different one? – claustrofob Jun 21 '13 at 12:15
  • IMO, if the OP wants to get to greps with something, that's what the answer should explain. Secondly, sessions are often used like this: a webshop that redirects you to the latest search-results (or product group) you were browsing last time you were on is quite common, IMHO, it'd feel clunky if I were asked to click a link to restore my session, rather then clicking a link to return to the home page. Well hey, that's just me – Elias Van Ootegem Jun 21 '13 at 12:28
  • Thanks man. I got your IMHO. But i am still convinced that doing 2 requests instead of one is a bad idea. – claustrofob Jun 21 '13 at 12:35
  • Well, the way you'd handle this, you're first generating an entire DOM, then (if the client clicks the link) you're processing a second request, too, _and_ generating an entire page again. Whereas using the redirect, you can skip just `exit()` and process the second response, only generating one page. If the client doesn't click the link, your suggestion won't process 2 requests, but I think ppl are likely to click the link. Eitherway, your answer is technically valid, and there'll always be Pro's and Con's to any approach – Elias Van Ootegem Jun 21 '13 at 14:20
  • 1
    Not sure that i fully understand your point. My answer is based on this sentence from the question "My current page redirects back when the cancel button is clicked with the value searched." As i understand he wants to show another page on button click. Technically a redirect is just a header that forces a browser to make one more request. I consider this as an overhead in this case. – claustrofob Jun 21 '13 at 14:28
  • Sorry, forgot about that cancel btn thing in the question... you're right, of course – Elias Van Ootegem Jun 21 '13 at 14:30
0

I suggest a following approach:

function universal_redirect($url, $force_js = false) {
    if (headers_sent() || $force_js) {
        print('<script type="text/javascript">');
        printf("location.href='%s';", $url);
        print('</script>');
    } else {
        header('Location: ' . $url);
    }
}

It is not always applicable but it is a good solution if you build admin-pages or when your project is big and complicated enough that you can't always guarantee that output was not yet started.

In general PHP redirect is much better for reasons given by @Elias Van Ootegem.

Ruslan Bes
  • 2,715
  • 2
  • 25
  • 32
  • _and_ don't care about the arguments given to _not_ use JS, either? Nor bother understanding headers? if so, why didn't you just answer _"why ask this question?"_ – Elias Van Ootegem Jun 21 '13 at 12:30
  • I agree with your reasons. Though this solution have some applications too. Corrected the answer. – Ruslan Bes Jun 21 '13 at 12:43