Jump to content

Strange/Inconsistent "Header Already Sent" message


doubledee

Recommended Posts

I am getting a strange "Header already sent" error message.

 

This is happening when I go from my "articles_index.php" page - which lists a summary of each article -  to my article template file "article.php" which is where I swap in and out the relevant article from my database.

 

Here is my abridged code from "article.php"

 

if (isset($_GET['category']) && isset($_GET['title'])){
// Category and Title exist.

$category = $_GET['category'];
$title = $_GET['title'];

// Build query.
// Prepare statement.

}else{
	// No Title exists.

	// Take user to Home Page.
	header("Location: " . WEB_ROOT . "index.php");
}

 

Below is what happens when you click on different article pictures and different article links.  (Admittedly, some of these links are from when I was just using an "id" to identify articles, but the point is that I do not believe that an invalid query string or an old-style link to a physical file should cause the error I'm getting?!)

 

 

Scenarios:

 

Scenario #1: <a href="<?php echo WEB_ROOT ?>article.php?category=articles&title=all-about-creating-dynamic-content">

Outcome:  Works.  Article is displayed.

 

Scenario #2: <a href="point_to_some_file.php">(Read Full Story)</a>

Outcome: File Not Fund

 

Scenario #3: <a href="<?php echo WEB_ROOT ?>article.php?category=articles&title=some_other_name">

Outcome: Works.  "Sorry! The article you were looking for could not be found."

 

Scenario #4: <a href="some_other_file_name.php">(Read Full Story)</a>

Outcome: File Not Found

 

Scenario #5: <a href="<?php echo WEB_ROOT ?>article.php?category=articles&title=guide-to-quickbooks">

Outcome: Works.  Article is displayed

 

Scenario #6: <a href="<?php echo WEB_ROOT ?>article.php?id=1">(Read Full Story)</a>

Outcome: Warning: Cannot modify header information - headers already sent by (output started at /Users/user1/Documents/DEV/++htdocs/01_MyProject/article.php:14) in /Users/user1/Documents/DEV/++htdocs/01_MyProject/article.php on line 68

 

If I add this code at the beginning of my file...

 

// Start Output Buffering.
ob_start();

 

...and this code in my ELSE branch...

 

// Send and turn off output buffering.
ob_end_flush();

// End script.
exit();

 

...then the error goes away, but I have no clue what is causing this error?!

 

I thought this error was caused when you send characters to the screen before you try to send Header data?

 

How is sending an improperly formatted query string or an invalid file or path related?!

 

Thanks,

 

 

Debbie

 

 

Link to comment
Share on other sites

If an error is being generated, output will be sent because you have display errors on.  You would not have this setting turned on for a production server.  Don't turn on output buffering unless you completely understand what it is for, and have a good reason to use it. 

Link to comment
Share on other sites

If an error is being generated, output will be sent because you have display errors on.  You would not have this setting turned on for a production server.

 

Isn't an error also being sent with a "Page Not Found"?

 

Since I don't plan on having incorrectly formatted query strings, can I just ignore this error?

 

 

Don't turn on output buffering unless you completely understand what it is for, and have a good reason to use it.

 

Can you elaborate?

 

I read a book that says to turn it on when you are doing things that could send output to the screen and thus cause such an error.

 

 

 

Debbie

 

 

Link to comment
Share on other sites

The book was describing a hack that should not be used IMO.

 

The simple answer is, don't try and send content before sending headers.

 

I understand this, however, it really doesn't answer my question...

 

Why is it that Scenario #6 behaves the way it does?

 

I don't see why that scenario with that particular invalid query string sends data and blows things up?

 

(Sorry for not getting this.)

 

Also, since I will presumably have the *correct* query string, do I need to worry about error-handling in case this did happen, or is it assumed if it works it will always work?!

 

 

Debbie

 

 

Link to comment
Share on other sites

output started at /Users/user1/Documents/DEV/++htdocs/01_MyProject/article.php:14

 

Read the error message, it tells you exactly what file and what line in that file sent output to the screen. You need to look at line 14 (and the surrounding lines) of article.php. It is sending some output to the browser. If there are other error messages, they are likely causing this error. Fix the other errors first. I would suspect that you are referencing the "category" or "title" element of $_GET without first checking to see if they exist.

 

Never assume it will always work. If a user types your query string into the address bar, and spells "category" wrong, you will get the same error. Always check to see if the query string contains what you are expecting and act accordingly if it does not.

 

Link to comment
Share on other sites

output started at /Users/user1/Documents/DEV/++htdocs/01_MyProject/article.php:14

 

Read the error message, it tells you exactly what file and what line in that file sent output to the screen. You need to look at line 14 (and the surrounding lines) of article.php. It is sending some output to the browser. If there are other error messages, they are likely causing this error. Fix the other errors first. I would suspect that you are referencing the "category" or "title" element of $_GET without first checking to see if they exist.

 

Never assume it will always work. If a user types your query string into the address bar, and spells "category" wrong, you will get the same error. Always check to see if the query string contains what you are expecting and act accordingly if it does not.

 

 

Here is my code starting at Line 14...

 

<?php
// Access Constants
require_once('config/config.inc.php');

// Connect to the database.
require_once('private/mysqli_connect.php');

// Initialize variables.
$articleExists = FALSE;
$id = $metaDescription = $metaKeywords = $title = '';
$pageTitle = $pageSubtitle = $writtenOn = $author = $body = $endNotes = '';

//	$id = 1;

if (isset($_GET['title'])){
	// Title exists.

	$title = $_GET['title'];

	// Build query.
	$q = 'SELECT meta_description, meta_keywords, page_title, page_subtitle, written_on, author, body, end_notes
					FROM article
					WHERE title=?';

	// Prepare statement.
	$stmt = mysqli_prepare($dbc, $q);

 

 

Last night I took out "Category" for other reasons, but the logic of the code above is the same.

 

And you'll see I am using ISSET() so that should take care of the one issue you mentioned above.

 

Any ideas?

 

Thanks,

 

 

Debbie

 

 

Link to comment
Share on other sites

Here is my code starting at Line 14...

 

Are you saying that line 14 is <?php? If so, what are the 13 lines above that? Anything outside of the opening tag is sent to the browser as content. Post everything from the beginning of the file through line 20 or so (preferably through the header() call that is producing the error).

 

Is this "line 14" from the code that produced the error message that said the output started at line 14? In other words, you said you changed the code, is the error message still indicating line 14 as the start of output?

 

If you use View Source in your browser, what do you see? Anything before the error message is output you need to eliminate. If the header error is the only thing you see, then something might be sending whitespace (a space, tab, or newline) to the browser.

 

Link to comment
Share on other sites

Here is my code starting at Line 14...

 

Are you saying that line 14 is <?php?

 

Yes, I gave you lines 14 onward...

 

 

If so, what are the 13 lines above that? Anything outside of the opening tag is sent to the browser as content. Post everything from the beginning of the file through line 20 or so (preferably through the header() call that is producing the error).

 

Is this "line 14" from the code that produced the error message that said the output started at line 14? In other words, you said you changed the code, is the error message still indicating line 14 as the start of output?

 

If you use View Source in your browser, what do you see? Anything before the error message is output you need to eliminate. If the header error is the only thing you see, then something might be sending whitespace (a space, tab, or newline) to the browser.

 

Here are lines 1 - 14...

 

<?php
//
// Start Output Buffering.
//	ob_start();

// Initialize a session.
session_start();

// From article at:  http://shiflett.org/articles/the-truth-about-sessions
$fingerprint = 'SHIFLETT' . $_SERVER['HTTP_USER_AGENT'];
$_SESSION['fingerprint'] = md5($fingerprint . session_id());
?>

<?php

 

Could the blank line on Line 13 cause an issue?

 

 

Debbie

 

 

Link to comment
Share on other sites

Could the blank line on Line 13 cause an issue?

 

Yes, that line is outside of php any tags and is sent as is to the browser.

 

FYI - The php tokens generated (which must all be executed when your code runs) by putting a closing php tag, some in-line html (a new-line) and an opening php tag is -

T_CLOSE_TAG
T_INLINE_HTML
T_OPEN_TAG

 

 

Link to comment
Share on other sites

Yes, it will. That blank line is being sent to the browser. The documentation indicates that the newline "immediately following" the closing tag will not be sent. But the blank line has another newline, and I'm sure that one will be sent.

 

There really is no reason to break out of PHP there, you could just remove the closing tag and the following opening tag; PHP loves blank lines, it will just eat them up!

 

<?php
//
// Start Output Buffering.
//	ob_start();

// Initialize a session.
session_start();

// From article at:  http://shiflett.org/articles/the-truth-about-sessions
$fingerprint = 'SHIFLETT' . $_SERVER['HTTP_USER_AGENT'];
$_SESSION['fingerprint'] = md5($fingerprint . session_id());

// Access Constants
require_once('config/config.inc.php');

// Connect to the database.

 

You may also want to watch out for HTTP_USER_AGENT. There is no guarantee that every user agent will send this value. And if it is not there, that line of code will produce a notice, which, if display_errors is on, will be sent to the browser and will cause the header call to fail again. You might try:

 

$fingerprint = 'SHIFLETT' . (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');

Link to comment
Share on other sites

FYI - The php tokens generated (which must all be executed when your code runs) by putting a closing php tag, some in-line html (a new-line) and an opening php tag is -

T_CLOSE_TAG
T_INLINE_HTML
T_OPEN_TAG

 

That went over my head.

 

Two things...

 

1.) People keep talking to me about "tokens" lately and I totally don't understand what they mean?!

 

2.) I have no clue of what you are giving me above...  :o

 

 

Debbie

 

 

Link to comment
Share on other sites

You may also want to watch out for HTTP_USER_AGENT. There is no guarantee that every user agent will send this value. And if it is not there, that line of code will produce a notice, which, if display_errors is on, will be sent to the browser and will cause the header call to fail again. You might try:

 

$fingerprint = 'SHIFLETT' . (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '');

 

Thanks for the suggestion.  (I know I'm bad sanitizing my data when it comes to ISSET.)

 

If I do that will that handle any and all issues?

 

I got that code offline to help with my Comments module.  (Honestly, I forgot what that even does?!)

 

 

 

Debbie

 

 

Link to comment
Share on other sites

That will handle cases where the user-agent string is not provided. I don't know what the "fingerprint" is used for, so I can't say it is the perfect solution; but it will prevent that line of code from throwing an error. And since user-agent strings are not unique, it will probably provide the same functionality.

 

As for tokens: computer languages have to be executed by a computer. So there is usually a parsing process that converts the source code we write into "tokens" that the computer can process. Usually, tokens are represented (internally) as integers. This makes it much easier for the computer to read and execute the code -- since all integers are the same size, they can use jump tables and offsets to determine what the instruction is. Otherwise, they would have to determine the length of the string (i.e. "print") and then determine the address of the (internal) function to call, and then figure out where the parameters are, and so forth. Yes, the computer still has to do this, but it does it in the parsing phase. If it did not do it up front, whenever it executed a loop, it would have to interpret the same source code over and over -- source code that DOES NOT CHANGE during the loop -- that is a waste of time. How it all works is advanced, internals stuff, and in general programmers rarely need to worry about tokens and jump tables.

 

In this case, PFMaBiSmAd was showing the tokens that were generated by your code (actually, the human representation of the tokens, not the actual integers). As you can see, there is HTML in there, which is what was being sent to the browser and causing your error. I had never considered using the tokenizer as a debugging tool, ... but, there ya go.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.