831

When running my script, I am getting several errors like this:

Warning: Cannot modify header information - headers already sent by (output started at /some/file.php:12) in /some/file.php on line 23

The lines mentioned in the error messages contain header() and setcookie() calls.

What could be the reason for this? And how to fix it?

Amal Murali
  • 70,371
  • 17
  • 120
  • 139
Moses89
  • 4,367
  • 3
  • 13
  • 6
  • read: http://stackoverflow.com/questions/1912029/warning-cannot-modify-header-information-headers-already-sent-by-error – Book Of Zeus Nov 06 '11 at 17:44
  • Make sure no text is outputted (`ob_start` and `ob_end_clean() ` may prove useful here). You could then set a cookie or session equal to `ob_get_contents()` and then use `ob_end_clean()` to clear the buffer. – Jack Apr 03 '14 at 20:16
  • Use the `safeRedirect` function in my PHP Library: https://github.com/heinkasner/PHP-Library/blob/master/extra.php – heinkasner Jul 24 '14 at 13:29
  • 5
    ~~~~~~~~~~ Your file ENCODING should not be `UTF-8`, but `UTF-8 (Without BOM)`~~~~~~~~~~~ – T.Todua Sep 19 '14 at 08:00

11 Answers11

3129

No output before sending headers!

Functions that send/modify HTTP headers must be invoked before any output is made. summary ⇊ Otherwise the call fails:

Warning: Cannot modify header information - headers already sent (output started at script:line)

Some functions modifying the HTTP header are:

Output can be:

  • Unintentional:

    • Whitespace before <?php or after ?>
    • The UTF-8 Byte Order Mark specifically
    • Previous error messages or notices
  • Intentional:

    • print, echo and other functions producing output
    • Raw <html> sections prior <?php code.

Why does it happen?

To understand why headers must be sent before output it's necessary to look at a typical HTTP response. PHP scripts mainly generate HTML content, but also pass a set of HTTP/CGI headers to the webserver:

HTTP/1.1 200 OK
Powered-By: PHP/5.3.7
Vary: Accept-Encoding
Content-Type: text/html; charset=utf-8

<html><head><title>PHP page output page</title></head>
<body><h1>Content</h1> <p>Some more output follows...</p>
and <a href="/"> <img src=internal-icon-delayed> </a>

The page/output always follows the headers. PHP has to pass the headers to the webserver first. It can only do that once. After the double linebreak it can nevermore amend them.

When PHP receives the first output (print, echo, <html>) it will flush all collected headers. Afterward it can send all the output it wants. But sending further HTTP headers is impossible then.

How can you find out where the premature output occurred?

The header() warning contains all relevant information to locate the problem cause:

Warning: Cannot modify header information - headers already sent by (output started at /www/usr2345/htdocs/auth.php:52) in /www/usr2345/htdocs/index.php on line 100

Here "line 100" refers to the script where the header() invocation failed.

The "output started at" note within the parenthesis is more significant. It denominates the source of previous output. In this example, it's auth.php and line 52. That's where you had to look for premature output.

Typical causes:

  1. Print, echo

    Intentional output from print and echo statements will terminate the opportunity to send HTTP headers. The application flow must be restructured to avoid that. Use functions and templating schemes. Ensure header() calls occur before messages are written out.

    Functions that produce output include

    • print, echo, printf, vprintf
    • trigger_error, ob_flush, ob_end_flush, var_dump, print_r
    • readfile, passthru, flush, imagepng, imagejpeg


    among others and user-defined functions.

  2. Raw HTML areas

    Unparsed HTML sections in a .php file are direct output as well. Script conditions that will trigger a header() call must be noted before any raw <html> blocks.

    <!DOCTYPE html>
    <?php
        // Too late for headers already.
    

    Use a templating scheme to separate processing from output logic.

    • Place form processing code atop scripts.
    • Use temporary string variables to defer messages.
    • The actual output logic and intermixed HTML output should follow last.

  3. Whitespace before <?php for "script.php line 1" warnings

    If the warning refers to output inline 1, then it's mostly leading whitespace, text or HTML before the opening <?php token.

     <?php
    # There's a SINGLE space/newline before <? - Which already seals it.
    

    Similarly it can occur for appended scripts or script sections:

    ?>
    
    <?php
    

    PHP actually eats up a single linebreak after close tags. But it won't compensate multiple newlines or tabs or spaces shifted into such gaps.

  4. UTF-8 BOM

    Linebreaks and spaces alone can be a problem. But there are also "invisible" character sequences that can cause this. Most famously the UTF-8 BOM (Byte-Order-Mark) which isn't displayed by most text editors. It's the byte sequence EF BB BF, which is optional and redundant for UTF-8 encoded documents. PHP however has to treat it as raw output. It may show up as the characters  in the output (if the client interprets the document as Latin-1) or similar "garbage".

    In particular graphical editors and Java-based IDEs are oblivious to its presence. They don't visualize it (obliged by the Unicode standard). Most programmer and console editors however do:

    joes editor showing UTF-8 BOM placeholder, and MC editor a dot

    There it's easy to recognize the problem early on. Other editors may identify its presence in a file/settings menu (Notepad++ on Windows can identify and remedy the problem), Another option to inspect the BOMs presence is resorting to an hexeditor. On *nix systems hexdump is usually available, if not a graphical variant which simplifies auditing these and other issues:

    beav hexeditor showing utf-8 bom

    An easy fix is to set the text editor to save files as "UTF-8 (no BOM)" or similar to such nomenclature. Often newcomers otherwise resort to creating new files and just copy&pasting the previous code back in.

    Correction utilities

    There are also automated tools to examine and rewrite text files (sed/awk or recode). For PHP specifically there's the phptags tag tidier. It rewrites close and open tags into long and short forms, but also easily fixes leading and trailing whitespace, Unicode and UTF-x BOM issues:

    phptags  --whitespace  *.php
    

    It's safe to use on a whole include or project directory.

  5. Whitespace after ?>

    If the error source is mentioned as behind the closing ?> then this is where some whitespace or the raw text got written out. The PHP end marker does not terminate script execution at this point. Any text/space characters after it will be written out as page content still.

    It's commonly advised, in particular to newcomers, that trailing ?> PHP close tags should be omitted. This eschews a small portion of these cases. (Quite commonly include()d scripts are the culprit.)

  6. Error source mentioned as "Unknown on line 0"

    It's typically a PHP extension or php.ini setting if no error source is concretized.

    • It's occasionally the gzip stream encoding setting or the ob_gzhandler.
    • But it could also be any doubly loaded extension= module generating an implicit PHP startup/warning message.

  7. Preceding error messages

    If another PHP statement or expression causes a warning message or notice being printed out, that also counts as premature output.

    In this case you need to eschew the error, delay the statement execution, or suppress the message with e.g. isset() or @() - when either doesn't obstruct debugging later on.

No error message

If you have error_reporting or display_errors disabled per php.ini, then no warning will show up. But ignoring errors won't make the problem go away. Headers still can't be sent after premature output.

So when header("Location: ...") redirects silently fail it's very advisable to probe for warnings. Reenable them with two simple commands atop the invocation script:

error_reporting(E_ALL);
ini_set("display_errors", 1);

Or set_error_handler("var_dump"); if all else fails.

Speaking of redirect headers, you should often use an idiom like this for final code paths:

exit(header("Location: /finished.html"));

Preferably even a utility function, which prints a user message in case of header() failures.

Output buffering as a workaround

PHPs output buffering is a workaround to alleviate this issue. It often works reliably, but shouldn't substitute for proper application structuring and separating output from control logic. Its actual purpose is minimizing chunked transfers to the webserver.

  1. The output_buffering= setting nevertheless can help. Configure it in the php.ini or via .htaccess or even .user.ini on modern FPM/FastCGI setups.
    Enabling it will allow PHP to buffer output instead of passing it to the webserver instantly. PHP thus can aggregate HTTP headers.

  2. It can likewise be engaged with a call to ob_start(); atop the invocation script. Which however is less reliable for multiple reasons:

    • Even if <?php ob_start(); ?> starts the first script, whitespace or a BOM might get shuffled before, rendering it ineffective.

    • It can conceal whitespace for HTML output. But as soon as the application logic attempts to send binary content (a generated image for example), the buffered extraneous output becomes a problem. (Necessitating ob_clean() as a further workaround.)

    • The buffer is limited in size, and can easily overrun when left to defaults. And that's not a rare occurrence either, difficult to track down when it happens.

Both approaches therefore may become unreliable - in particular when switching between development setups and/or production servers. This is why output buffering is widely considered just a crutch / strictly a workaround.

See also the basic usage example in the manual, and for more pros and cons:

But it worked on the other server!?

If you didn't get the headers warning before, then the output buffering php.ini setting has changed. It's likely unconfigured on the current/new server.

Checking with headers_sent()

You can always use headers_sent() to probe if it's still possible to... send headers. Which is useful to conditionally print info or apply other fallback logic.

if (headers_sent()) {
    die("Redirect failed. Please click on this link: <a href=...>");
}
else{
    exit(header("Location: /user.php"));
}

Useful fallback workarounds are:

  • HTML <meta> tag

    If your application is structurally hard to fix, then an easy (but somewhat unprofessional) way to allow redirects is injecting a HTML <meta> tag. A redirect can be achieved with:

     <meta http-equiv="Location" content="http://example.com/">
    

    Or with a short delay:

     <meta http-equiv="Refresh" content="2; url=../target.html">
    

    This leads to non-valid HTML when utilized past the <head> section. Most browsers still accept it.

  • JavaScript redirect

    As alternative a JavaScript redirect can be used for page redirects:

     <script> location.replace("target.html"); </script>
    

    While this is often more HTML compliant than the <meta> workaround, it incurs a reliance on JavaScript-capable clients.

Both approaches however make acceptable fallbacks when genuine HTTP header() calls fail. Ideally you'd always combine this with a user-friendly message and clickable link as last resort. (Which for instance is what the http_redirect() PECL extension does.)

Why setcookie() and session_start() are also affected

Both setcookie() and session_start() need to send a Set-Cookie: HTTP header. The same conditions therefore apply, and similar error messages will be generated for premature output situations.

(Of course, they're furthermore affected by disabled cookies in the browser or even proxy issues. The session functionality obviously also depends on free disk space and other php.ini settings, etc.)

Further links

Paresh Mangukiya
  • 14,668
  • 7
  • 90
  • 90
mario
  • 138,064
  • 18
  • 223
  • 277
  • Also regular notepad.exe is tricky. I use NetBeans normally that doesn't add BOM, even if file is encoded so. Editing a file later in notepad messes things up, especially towards IIS as webserver. It seems as apache discards the (unitentionally added) BOM. – Teson Dec 03 '15 at 09:17
  • 4
    Removing the closing `?>` from the end of a php files is usually a good practice which helps minimizing these errors as well. Unwanted whitespace will not occur at the end of files, and you will still be able to add headers to the response later. It is also handy if you use output buffering, and would not like to see added unwanted whitespace at the end of the parts generated by the included files. – Nikita 웃 Feb 08 '16 at 19:34
  • Strange thing, I moved my file from cPanel Linux Hosting to VPS. Before it was working properly but here it showed this error.(I had some html code before header). Why? – Pablo Escobar Apr 30 '17 at 19:36
  • @Purushotamrawat Did you read the part about "**But it worked on the other server!?**" – mario Apr 30 '17 at 19:52
  • @mario but I didn't change the Output Buffering – Pablo Escobar Apr 30 '17 at 20:32
  • @TheCrazyProfessor because it waits before sending anything to the client until the complete output is rendered/buffered server-side. Without output buffering, the server starts sending out the data as it gets generated (streaming), in which case it needs to send out headers first which cannot be manipulated later on. – huysentruitw May 16 '17 at 11:42
  • and sometimes its just about php version! its so difficult to edit all complicated codes and its better to change your server php version to most compatible with your cods – Solivan Jul 12 '17 at 04:28
  • When the page loads I already have a Content-Type: header loaded and sent. What setting made this happen? – Peter S McIntyre Aug 01 '17 at 17:37
  • 1
    @PeterSMcIntyre The UTF8 BOM presumably (fix that) / no output buffering enabled (don't rely on that). – mario Aug 01 '17 at 22:05
  • I just want to mention that using `curl` and not setting `CURLOPT_RETURNTRANSFER` to `TRUE` can also produce output and therefore trigger 'headers already sent'-error – kask Mar 19 '18 at 16:25
  • Thanks for adding the unintentional causes in the beginning. I had one, tiny, little space before a ` – AnalogWeapon May 19 '18 at 23:08
  • If you really need to display content before forwarding. You can use replace in JavaScript: window.location.replace("http://newUrl.com");. You can set up a recursive JS function with setTimeout() that looks for information on the page that signals that it's time to forward and then calls replace. – Bob Ray Jun 05 '18 at 05:29
  • For the "But it worked on the other server!?" part -- it was my case, in case of running your own local server, try to edit the php.ini file and set output_buffering to output_buffering=4096. IF THIS STILL DOES NOT WORK - try to increase it. That was my problem. I had to increase buffer to 64kb because some pages were just that big. Oh and also do not forget to restart server, just in case. – hocikto Jun 24 '18 at 17:29
  • If you are using UltraEdit, Save-As (Select Encoding option bottom right) UTF-8 No boM (this fixed it for me) – hamish Jul 14 '19 at 12:20
  • Nothing worked for me, except this `ob_start();` solved the issue. Thanks – Jodyshop Aug 16 '19 at 10:03
  • Whitespace before – Immran Mohammed Mar 16 '20 at 06:24
  • Beautifully well crafted answer. – Hillel Apr 19 '21 at 13:37
204

This error message gets triggered when anything is sent before you send HTTP headers (with setcookie or header). Common reasons for outputting something before the HTTP headers are:

  • Accidental whitespace, often at the beginning or end of files, like this:

     <?php
    // Note the space before "<?php"
    ?>
    

       To avoid this, simply leave out the closing ?> - it's not required anyways.

  • Byte order marks at the beginning of a php file. Examine your php files with a hex editor to find out whether that's the case. They should start with the bytes 3F 3C. You can safely remove the BOM EF BB BF from the start of files.
  • Explicit output, such as calls to echo, printf, readfile, passthru, code before <? etc.
  • A warning outputted by php, if the display_errors php.ini property is set. Instead of crashing on a programmer mistake, php silently fixes the error and emits a warning. While you can modify the display_errors or error_reporting configurations, you should rather fix the problem.
    Common reasons are accesses to undefined elements of an array (such as $_POST['input'] without using empty or isset to test whether the input is set), or using an undefined constant instead of a string literal (as in $_POST[input], note the missing quotes).

Turning on output buffering should make the problem go away; all output after the call to ob_start is buffered in memory until you release the buffer, e.g. with ob_end_flush.

However, while output buffering avoids the issues, you should really determine why your application outputs an HTTP body before the HTTP header. That'd be like taking a phone call and discussing your day and the weather before telling the caller that he's got the wrong number.

NikiC
  • 95,987
  • 31
  • 182
  • 219
phihag
  • 245,801
  • 63
  • 407
  • 443
126

I got this error many times before, and I am certain all PHP programmer got this error at least once before.

Possible Solution 1

This error may have been caused by the blank spaces before the start of the file or after the end of the file.These blank spaces should not be here.

ex) THERE SHOULD BE NO BLANK SPACES HERE

   echo "your code here";

?>
THERE SHOULD BE NO BLANK SPACES HERE

Check all files associated with file that causes this error.

Note: Sometimes EDITOR(IDE) like gedit (a default linux editor) add one blank line on save file. This should not happen. If you are using Linux. you can use VI editor to remove space/lines after ?> at the end of the page.

Possible Solution 2: If this is not your case, then use ob_start to output buffering:

<?php
  ob_start();

  // code 

 ob_end_flush();
?> 

This will turn output buffering on and your headers will be created after the page is buffered.

SK98
  • 25
  • 6
Manish Shrivastava
  • 26,075
  • 13
  • 88
  • 100
  • 20
    `ob_start()` just hides the problem; don't use it to solve this particular problem. – Ja͢ck May 15 '13 at 10:21
  • @Ja͢ck If I don't use of `ob_start()`, then what should I do for solving this problem: `Headers already sent` – Shafizadeh Jul 14 '15 at 17:08
  • @Sajad if you're getting the error specifically because of the editor you're using, you should fiddle with the settings to make it stop causing the problem, or switch editors. If you're getting the error for any other reason, you should read through the replies in this question (specifically the accepted answer) to figure out what the problem actually is, and the solve it. – Samsquanch Jul 14 '15 at 19:42
  • 4
    `ob_start()` doesn't *"hide"* the problem, it **solves** the problem. – Tomas Oct 22 '15 at 20:51
  • 1
    I had such a problem when I upload my files to server, which supported even PHP5.3 Use server with PHP 5.6 or more – GGSoft Dec 09 '15 at 11:19
  • 1
    @jack true, I agree with you. Ideal way is to remove spaces before starting php tag `` – Manish Shrivastava May 06 '17 at 09:37
  • Many people asks where to add `ob_start();`. because after adding the `ob_start();` they still get the error. You have to add to the page that triggered the current page. Ex: page1 (button clicked) -> page2.(header redirect) -> page0 (home). You have to add it to the page1. Many people got confused and add in page2. – Dexter Aug 07 '18 at 16:46
  • 1
    Solved my issue. – NickDimou Jan 26 '21 at 05:03
94

Instead of the below line

//header("Location:".ADMIN_URL."/index.php");

write

echo("<script>location.href = '".ADMIN_URL."/index.php?msg=$msg';</script>");

or

?><script><?php echo("location.href = '".ADMIN_URL."/index.php?msg=$msg';");?></script><?php

It'll definitely solve your problem. I faced the same problem but I solved through writing header location in the above way.

Yogesh Suthar
  • 29,554
  • 17
  • 66
  • 96
Ipsita Rout
  • 4,149
  • 3
  • 33
  • 37
42

You do

printf ("Hi %s,</br />", $name);

before setting the cookies, which isn't allowed. You can't send any output before the headers, not even a blank line.

Seth Carnegie
  • 70,115
  • 19
  • 169
  • 239
35

COMMON PROBLEMS:

(copied from: source)

====================

1) there should not be any output (i.e. echo.. or HTML codes) before the header(.......); command.

2) remove any white-space(or newline) before <?php and after ?> tags.

3) GOLDEN RULE! - check if that php file (and also, if you include other files) have UTF8 without BOM encoding (and not just UTF-8). That is problem in many cases (because UTF8 encoded file has something special character in the start of php file, which your text-editor doesnt show)!!!!!!!!!!!

4) After header(...); you must use exit;

5) always use 301 or 302 reference:

header("location: http://example.com",  true,  301 );  exit;

6) Turn on error reporting, and find the error. Your error may be caused by a function that is not working. When you turn on error reporting, you should always fix top-most error first. For example, it might be "Warning: date_default_timezone_get(): It is not safe to rely on the system's timezone settings." - then farther on down you may see "headers not sent" error. After fixing top-most (1st) error, re-load your page. If you still have errors, then again fix the top-most error.

7) If none of above helps, use JAVSCRIPT redirection(however, strongly non-recommended method), may be the last chance in custom cases...:

echo "<script type='text/javascript'>window.top.location='http://website.com/';</script>"; exit;
Jorn
  • 458
  • 7
  • 11
33

It is because of this line:

printf ("Hi %s,</br />", $name);

You should not print/echo anything before sending the headers.

Sarfraz
  • 355,543
  • 70
  • 511
  • 562
26

A simple tip: A simple space (or invisible special char) in your script, right before the very first <?php tag, can cause this ! Especially when you are working in a team and somebody is using a "weak" IDE or has messed around in the files with strange text editors.

I have seen these things ;)

PeeHaa
  • 66,697
  • 53
  • 182
  • 254
Sliq
  • 14,005
  • 24
  • 99
  • 137
23

Another bad practice can invoke this problem which is not stated yet.

See this code snippet:

<?php
include('a_important_file.php'); //really really really bad practise
header("Location:A location");
?>

Things are okay,right?

What if "a_important_file.php" is this:

<?php
//some php code 
//another line of php code
//no line above is generating any output
?>

 ----------This is the end of the an_important_file-------------------

This will not work? Why?Because already a new line is generated.

Now,though this is not a common scenario what if you are using a MVC framework which loads a lots of file before handover things to your controller? This is not an uncommon scenario. Be prepare for this.

From PSR-2 2.2 :


  • All PHP files MUST use the Unix LF (linefeed) line ending.
  • All PHP files MUST end with a single blank line.
  • The closing ?> tag MUST be omitted from files containing only php

Believe me , following thse standards can save you a hell lot of hours from your life :)

MD. Sahib Bin Mahboob
  • 18,208
  • 2
  • 20
  • 45
  • 3
    According to several standards (Zend for example), you shouldn't put the closing `?>` tag in any file in any case any way – Daniel W. Apr 04 '14 at 11:31
  • I cannot reproduce this in Windows environment since it works using any combination (adding closing tags, blanks, pressing enter key, etc). It seems that this issue happens mostly in Linux environments. – Junior Mayhé Jun 10 '15 at 12:11
  • @JuniorM It should be reproducible. Can you share the code you were experimenting in a gist or something alike? – MD. Sahib Bin Mahboob Jun 11 '15 at 04:59
  • I am on Windows 7, with latest Wamp installed. I think this bug is related to hidden characters for end of line. My Wordpress' shortcodes.php was the causing the issue. I added to this file a simple function and it started to fire this "headers sent" error. I have compared my shortcodes.php with wordpress' and it was ok, except the `CR LF` (typical Windows end of line). I solve it by downloading the original file from Wordpress repo that has `LF` (Linux end of line) instead of `CR LF` and I also moved my function to theme's functions.php. Based on: http://bit.ly/1Gh6mzN – Junior Mayhé Jun 11 '15 at 14:11
  • @Sahib, notice that still I cannot reproduce what is stated in this answer. The answer is totally fine for Linux environment. I have tested things such a blank between `?>` ``. In Windows+ Wamp all those combinations work fine. Wierd... – Junior Mayhé Jun 11 '15 at 14:13
  • :+1: I had the same problem, but the other way round: The important file, I included had the `header()` command in it and the main script (which had a very similar name) produced output before the include. – rubo77 Mar 26 '21 at 05:40
16

Sometimes when the dev process has both WIN work stations and LINUX systems (hosting) and in the code you do not see any output before the related line, it could be the formatting of the file and the lack of Unix LF (linefeed) line ending.

What we usually do in order to quickly fix this, is rename the file and on the LINUX system create a new file instead of the renamed one, and then copy the content into that. Many times this solve the issue as some of the files that were created in WIN once moved to the hosting cause this issue.

This fix is an easy fix for sites we manage by FTP and sometimes can save our new team members some time.

zok
  • 3,053
  • 7
  • 33
  • 55
Lupin
  • 1,185
  • 10
  • 16
3

Generally this error arise when we send header after echoing or printing. If this error arise on a specific page then make sure that page is not echoing anything before calling to start_session().

Example of Unpredictable Error:

 <?php //a white-space before <?php also send for output and arise error
session_start();
session_regenerate_id();

//your page content

One more example:

<?php
includes 'functions.php';
?> <!-- This new line will also arise error -->
<?php
session_start();
session_regenerate_id();

//your page content

Conclusion: Do not output any character before calling session_start() or header() functions not even a white-space or new-line

Ram Sharma
  • 8,368
  • 7
  • 38
  • 53
Biswadeep Sarkar
  • 682
  • 8
  • 16