0

I am going crazy with this error: Cannot modify header information - headers already sent by...

Please note that I know about the gazillion results on google and on stack overflow. My problem is the way I've constructed my pages. To keep html separate from php, I use include files. So, for example, my pages look something like this:

<?php 
require_once('web.config.php'); 
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Login</title>
<link rel="shortcut icon" href="images/favicon.gif"/>
<link rel="shortcut icon" href="images/favicon.ico"/>
<link rel="stylesheet" type="text/css" href="<?php echo SITE_STYLE; ?>"/>
</head>
<body>
<div id="page_effect" style="display:none;">
<?php require_once('./controls/login/login.control.php'); ?>
</div>
</body>
</html>

So, by the time my php file is included, the header is already sent.

Part of the include file looks like this:

// redirect to destination
if($user_redirect != 'default')
{
    header('Location:'.$user_redirect);
}
elseif($user_redirect == 'default' && isset($_GET['ReturnURL']))
{
    $destination_url = $_GET['ReturnURL'];
    header('Location:'.$destination_url);
}
else
{
    header('Location:'.SITE_URL.'login.php');
}

But I can't figure out how to work around this. I can't have the header redirect before the output so having output buffering on is the only thing I can do. Naturally it works fine that way - but having to rely on that just stinks.

It would be nice if PHP had an alternative way to redirect or had additional parameters to tell it to clear the buffer.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 3
    Why do you output anything if you don't want it to be shown to user? – zerkms Dec 24 '10 at 06:50
  • @Scott W.: I mean, if you perform redirect - why do you need to output anything? User will never see anything because it is redirect. Any reason to output text that will never be seen by onyone? Any reason to do in this way? – zerkms Dec 24 '10 at 07:02

3 Answers3

2

The key is not to separate PHP from HTML, but to separate Presentation from Processing. Redirecting based on the state of the application is part of the processing. Do that first.

Oswald
  • 31,254
  • 3
  • 43
  • 68
  • 1
    Honestly, I'm not sure what you mean by that. Is HTML not presentation and PHP not processing???? –  Dec 24 '10 at 07:10
  • 1
    @Scott W. HTML is presentation, but not all PHP is processing. E.g. is part of the presentation, while is processing. – Oswald Dec 24 '10 at 07:34
1

Like you said, the problem is how you have structured your pages.

You should be handling authentication logic (and others) before you output your pages. That makes for much better security anyway.

As you also probably know by now, you shouldn't rely on output buffering, as the size of that buffer can change, and what you have before your login will change with your template, causing unreliable behavior even with output buffering enabled.

Brad
  • 159,648
  • 54
  • 349
  • 530
  • Authentication happens on button click when the user submits the login form - not before. After authentication the user is redirected based on a conditional statement. So, I haven't a clue as to what you were trying to say. –  Dec 24 '10 at 07:06
  • @Scott W., PHP is server side... it doesn't execute on the client. Your code checking the username and password could very well be the first lines of the whole program and they would work well. Can you paste your controls/login/login.control.php somewhere so I can help you? Typically, you have something like includes/application.php which has the base of all the code that runs on every page. In there should be your authentication code. What you are effectively doing now (I think) is outputting half the login page twice and then throwing a redirect header. – Brad Dec 24 '10 at 15:57
1

Is there any echo/print statement before the header statements? That could cause this error.