-6

Everytime I create a website or application in PHP I must use the header() function to redirect people from page to page, but since the typical header is almost always sent before I find myself having to use output buffering functions that slow down the page. It's either that or suppress the "header already sent" errors. I just can't really find any example where an application can be built in PHP without having to violate either the two.

I am trying to know more, about how some redirect to pages without using output buffering.

edit

This is what some people assume is the possible.

<?php
$stack_errors = NULL;
if($_POST && isset($_POST['username']) && isset($_POST['password'])){

 $stmt = $pdo->prepare('SELECT * FROM users where username = ? AND password = ?');
 $stmt->execute(array($_POST['username'], $_POST['password']);
 if($stmt->rowCount() == 0){
   $stack_errors = 'error, username or password is incorrect';
 }else{
   $stack_errors = false; 
 }
}else{
  $stack_errors = 'please enter username and password to log in';
}
if(false === $stack_errors){
  header('Location: /success.php');
  exit;
}
?>
<html> 
<head></head>
<body>
<form>
 <input ...>
 <input ...>
 <?php if($stack_errors){
   echo $stack_errors; 
 }
<form>
Boann
  • 48,794
  • 16
  • 117
  • 146
spartak
  • 143
  • 1
  • 2
  • 8
  • 6
    Yes it's possible, just send the header before anything – Emilio Gort Jul 01 '14 at 23:44
  • 3
    It looks to me you're just doing it all wrong if you're setting headers twice and getting that warn. – Prix Jul 01 '14 at 23:45
  • 1
    Separate business logic from presentation logic and perform `header()` redirects before outputting anything to the screen. – showdev Jul 01 '14 at 23:46
  • From the looks of [your other question](http://stackoverflow.com/q/24482385/) why are you asking this now? – Funk Forty Niner Jul 01 '14 at 23:47
  • @showdev Trust me it is not possible. In every case I have tried, there must be some content sent before the header() for the application not to break. – spartak Jul 01 '14 at 23:48
  • @Fred-ii- Because [the I found out meta refresh was a bad idea too](http://stackoverflow.com/questions/4529379/is-it-good-practise-to-use-meta-refresh-tags-for-redirects-instead-of-header-f) – spartak Jul 01 '14 at 23:50
  • 7
    trust us, it IS possible. Unless you have no control over the code and you've been hired to only touch a small portion of the code. why don't you provide sample code? – Kai Qing Jul 01 '14 at 23:51
  • If you had a sample piece of code, we may be able to help you. Usually, you'd want to use header within a conditional statement which usually works best. If that doesn't work, then you may have a byte order mark problem somewhere; way too broad a subject at this point in time. – Funk Forty Niner Jul 01 '14 at 23:51
  • 4
    Note that suppressing the "header already sent" error doesn't solve the problem. Even if you suppress the message, your custom header will still be ignored because it's too late to send it. – Wyzard Jul 01 '14 at 23:54
  • @KaiQing **OK, I have update the question by creating** a small script as to what *I Know* you are referring to as POSSIBLE. Now you know, what I am not asking for. – spartak Jul 01 '14 at 23:59
  • @Fred-ii- Check the update. Using the simple script I just wrote, `header()` can be used without a problem. But that is a simple case scenario. You can not do the same thing for a very huge application. Only people who have worked on huge project can know what I mean – spartak Jul 02 '14 at 00:01
  • @EmilioGort Now you know that is not what I am asking – spartak Jul 02 '14 at 00:03
  • 4
    It doesn't matter how big the project is if your `header()` call is in a ` – Wyzard Jul 02 '14 at 00:04
  • 2
    @spartak If you're so convinced that it's impossible that you assume anyone saying otherwise had less experience than you, why even ask? – IMSoP Jul 02 '14 at 00:05
  • 4
    @spartak you must be working on some badly written programs then. – Darren Jul 02 '14 at 00:08
  • @Wyzard Ok, just try to understand it this way. Say I have a small costume built framework. Now, the `public/index.php` file called the `app/boostrap.php` file, the bootstrap loads many files including config and other files before it loads controllers/view [where the header() function is found] so, architecturally it is impossible to initiate a header() before any html/php output – spartak Jul 02 '14 at 00:08
  • Try and do away with `else{ $stack_errors = 'please enter username and password to log in'; }` see if that'll make it disappear. Then instead of `else{ $stack_errors = false; ` put your header there. – Funk Forty Niner Jul 02 '14 at 00:10
  • 2
    See the paragraph I added to my answer. Just make sure you don't have any extraneous BOM/whitespace output in any of your included files and you should be OK. None of what you're including sounds like it's *meant* to produce output. – Wyzard Jul 02 '14 at 00:10
  • @IMSoP I am convinced it is impossible for me, so I would like to know how people do it. So far, I haven't gotten any answer – spartak Jul 02 '14 at 00:10
  • 6
    You've asked how to do it, and people have told you how to do it, and you've said "no, it's impossible". If you're convinced that it's impossible to avoid doing output before a `header()` call, then delete your question (since it has no possible answer) and stop wasting everyone's time. – Wyzard Jul 02 '14 at 00:11
  • 1
    @spartak You should read this [How to fix “Headers already sent” error in PHP](http://stackoverflow.com/questions/8028957/how-to-fix-headers-already-sent-error-in-php/8028987#8028987) – Emilio Gort Jul 02 '14 at 00:13
  • @Wyzard I know how to do it. That is why I provided the code *showing* how to do it. I still don't think most people got the real question. If you feel you are personally wasting your time, you are free to leave this question – spartak Jul 02 '14 at 00:14
  • 3
    "before any html/php output" - this phrase may be the key to your misunderstanding: running PHP code does not, of itself, create any output, unless it involves functions explicitly designed to do so such as `echo`. It's perfectly possible to write an application that runs thousands of lines worth of PHP code, across dozens of different files, without a single byte of output being produced. – IMSoP Jul 02 '14 at 00:15
  • 2
    "I still don't think most people got the real question." If that's the case, you might want to re-state the real question to help clarify. – showdev Jul 02 '14 at 00:17
  • @IMSoP `It's perfectly possible to write an application ... without a single byte of output being produced` So you are saying that most (reputable) frameworks out there which have thousands of lines and files are letting page redirects anywhere inside the controller without outputting a single byte of code and without using output buffering? – spartak Jul 02 '14 at 00:20
  • Well I guess I don't get it neither or am not grasping the question. I'm going to get me some popcorn. ;-) – Funk Forty Niner Jul 02 '14 at 00:20
  • 1
    ob_start(output buffering) in this case is just a work around to hide the problem, isn't the real solution. – Emilio Gort Jul 02 '14 at 00:20
  • 3
    @spartak In a word, yes. – IMSoP Jul 02 '14 at 00:22
  • @EmilioGort That is what I am saying. ob_start() would slow down my application, and is considered a hack to some level. So, that is out of the question for me. – spartak Jul 02 '14 at 00:22
  • @IMSoP I would love to read a simple answer on how that is done. Because that is what I am searching for – spartak Jul 02 '14 at 00:23
  • 1
    your problem is right here, in your own quote: " loads controllers/view [where the header() function is found]" why on earth are you doing script processing in a view? Why is this not in the controller? If you are asking how to use header() AFTER output, then you're right, it is impossible without using output buffer or you will get a warning. Otherwise, maybe you can explain why you don't have access to run this process in the proper place instead of within a view – Kai Qing Jul 02 '14 at 00:23
  • This example might be helpful, generally regarding redirects in a MVC structure: http://www.sitepoint.com/forums/showthread.php?464164-Redirects-in-MVC – showdev Jul 02 '14 at 00:25
  • @spartak I have already written an answer. It's in the section of this page labelled "answers". If there is something you don't understand about it, feel free to add a comment underneath it. – IMSoP Jul 02 '14 at 00:25
  • I think it is better that I ask another question asking, how some good full-stack frameworks manage to let users redirect inside the controller without using ob_start() or suppressing the error. After clearly having send many non-header outputs before it – spartak Jul 02 '14 at 00:27
  • 2
    @spartak "After clearly having send many non-header outputs before it" - what makes you think a well-engineered framework would have sent output before a redirect? What would the purpose of such output be? – IMSoP Jul 02 '14 at 00:29
  • 2
    It all boils down to properly structuring your framework so that there's nothing being echo'ed until it's time to do so, or giving them access to an area. Since this is a login-related APP, you're better off (and if you're not already using this) using sessions inside all pages. Proper conditional statements while not echoing messages as you're presently doing. If a criteria isn't met, redirect. Don't play around inside the gray area. *That's my take on all this.* – Funk Forty Niner Jul 02 '14 at 00:31
  • Well, I rather just get laravel and see how the redirect is done, even after the comments in the controller which should be enough to cause some problems are handled. Thanks for all the comments and answers – spartak Jul 02 '14 at 00:36
  • 2
    If I may add another suggestion. If you plan on rebuilding or using another framework, test it slowly at a smaller scale. Once you know that nothing will cause havoc, then keep going following that same convention. I fell into that trap "once", built a whole bunch of pages, only to be forced to totally rethink/rebuild the whole concept; I was not a happy camper. *Live & Learn* as they say ;-) Thinking for an hour or a day may save you a lot of time and aggravation; it has for me and that's how I work now. *Cheers* – Funk Forty Niner Jul 02 '14 at 00:39

3 Answers3

5

A well-written application should not have a problem with output being sent "too early", and causing PHP to issue HTTP headers:

Firstly, decisions which might lead to a redirect should happen during processing of input and making business decisions; this code should be entirely complete before any content is output to the page. This ensures that your classes and functions have a single responsibility, and allows you - at least in theory - to replace the output without rewriting the whole application, e.g. to create a machine-readable API version. Contrary to your comments, the importance of this principle increases when you are working on larger projects.

Secondly, PHP itself might output errors and warnings, but these should be turned off on production systems using the display_errors ini setting. You don't want users seeing the gory details of every mistake in your code - at best, they'll judge it; at worst, they'll probe it for security holes.

Thirdly, others have pointed out issues with stray whitespace outside PHP tags, and Unicode BOMs added by editors. These can be tricky to track down, but by no means impossible - a decent editor will have functions to show whitespace, and to save without a BOM. Trailing whitespace can be avoided by not using a closing ?>, since it is implied at the end of a file. A small amount of output will also be swallowed if you use the gzip "output filter"; this doesn't buffer the whole output, but will buffer a few bytes at a time so it has something to compress, so gives you a bit of a get-out.

IMSoP
  • 89,526
  • 13
  • 117
  • 169
  • Thanks for the answer, but there is not a line here that supports [your claim](http://stackoverflow.com/questions/24520823/it-is-possible-to-create-any-application-using-header-without-output-buffering#comment37966736_24520823) – spartak Jul 02 '14 at 00:30
  • 2
    @spartak I have absolutely no idea what proof you are expecting to see. I can only repeat this sentence from my answer, which is a key part of designing a good web application framework: "decisions which might lead to a redirect should happen ... before any content is output to the page". It is up to you when to output content, so it is up to you to design your application to separate logic from display. – IMSoP Jul 02 '14 at 00:34
  • I think what he wants is that some one gives him the code ready to go so he can easily use it as he is not capable of understanding it from the many open sources frameworks out there that already does that. – Prix Jul 02 '14 at 00:35
  • 3
    @Prix The problem is that that's impossible to provide, because it's an *absence* of code, not a magic function: I could write whatever code I liked, and as long as it didn't use `echo` or similar, it would be an example of code that didn't output anything. At the end of it, I could add a `header()` call, and be guaranteed not to get an error from it. – IMSoP Jul 02 '14 at 00:44
  • @IMSoP what I was not saying for you to write a code, merely that he would not rest until some one put up some code to show how its done. – Prix Jul 02 '14 at 00:53
  • @Prix Yeah, I meant "unfortunately for the OP, nobody can provide that". – IMSoP Jul 02 '14 at 01:00
  • @IMSoP Yeah, my problem is that you dismissed any doubts and held the notion that all frameworks don't use output buffering for the redirect mechanism. While, you can see [the laravel index](https://github.com/laravel/laravel/blob/master/public/index.php) file itself has comments all over even before running the whole application. Which supports my claim and suggest that a header [of comments] *IS* already sent. So, they are using buffering or similar hacks. [somewhere inside the reponse-related classes] – spartak Jul 02 '14 at 01:01
  • @Prix Well, I hope that brought you some happiness. But I am not looking for a code. – spartak Jul 02 '14 at 01:02
  • @spartak neither for answers since you didn't seem pleased with any of it even thought many of it were the right answer. – Prix Jul 02 '14 at 01:11
  • 2
    @spartak Those are PHP comments; they don't produce any output or headers. As [I suspected](http://stackoverflow.com/questions/24520823/it-is-possible-to-create-any-application-using-header-without-output-buffering/24520902?noredirect=1#comment37966639_24520823) you seem to be under the impression that just running code - or, in this case, skipping over comments - will cause PHP to produce output. That is quite simply not the case, unless that code explicitly uses `echo`, `?>`, or some other function whose explicit role is to output something to the page. – IMSoP Jul 02 '14 at 10:46
1

Headers are only sent when your PHP page produces output. If your file begins immediately with a <?php block (no whitespace, Unicode BOM, etc. before it), it won't produce any output before you get a chance to set your custom headers.

If your code is including/requiring any other PHP files before setting headers, make sure those files don't do any unwanted output either. Even if your include file is nothing but a big <?php block, check for whitespace/BOM at the beginning as well as whitespace at the end (such as a newline after the ?>).

Wyzard
  • 33,849
  • 3
  • 67
  • 87
  • Not to mention an (invisible to the naked eye) byte order mark which also counts as output, a cookie etc. Far too broad a subject and many make those common mistakes. – Funk Forty Niner Jul 01 '14 at 23:49
  • 1
    Good point, watch out for your editor putting a BOM at the beginning of the file. (Since PHP isn't Unicode-aware, PHP pages shouldn't have a Unicode BOM anyway.) – Wyzard Jul 01 '14 at 23:50
  • Exactly and I "once" was a victim of it (lol) The operative word being "once" ;-) – Funk Forty Niner Jul 01 '14 at 23:52
  • How can I check the BOM, some times when I make a copy & paste from netbean to sublime I got errors (I think BOM) and I have type the full code again, how can I avoid that? – Emilio Gort Jul 01 '14 at 23:54
  • ^--< A question within a question? – Funk Forty Niner Jul 01 '14 at 23:54
  • 1
    Make sure you're saving the file as something like ASCII, not UTF-8 or UTF-16 (which may be labeled as "Unicode"). – Wyzard Jul 01 '14 at 23:55
  • 1
    A BOM or small amount of stray whitespace can be worked around by enabling gzip compression, which buffers output until it has enough to start the compressed stream. – IMSoP Jul 01 '14 at 23:56
  • 1
    But the BOM shouldn't be there anyway. If it's output, it means it's being sent to the browser, which may be fooled into thinking that the response is Unicode when it's really something else. – Wyzard Jul 01 '14 at 23:59
  • @Wyzard Well, there's plenty of reasons why the output *would* be Unicode, although if it's UTF-8, which is pretty much standard for the web, the BOM is pretty meaningless. I definitely disagree with the advice to save as ASCII; maybe ISO8859-15 at a pinch (so you have £ and € in standard locations, and a reasonable selection of European diacritics). – IMSoP Jul 02 '14 at 00:09
  • I have for default ISO-8859-9 – Emilio Gort Jul 02 '14 at 00:11
0

Of course the header in the HTTP protocol is sent as first in the response. That's the reason it is called "header". You have to ensure in your code logic, that headers are sent before any other output. If you want to process and output any data before you make the decision which headers are to be sent, there is no other way than output buffering. PHP then does the job for you. You can flush and end output buffering as soon as you are sure that no further headers are to be sent.

Pinke Helga
  • 6,378
  • 2
  • 22
  • 42