PHP Headers Already Sent

How to fix Headers already sent error in PHP

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:

  • header / header_remove
  • session_start / session_regenerate_id
  • setcookie / setrawcookie

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:

  • What is output buffering?
  • Why use output buffering in PHP?
  • Is using output buffering considered a bad practice?
  • Use case for output buffering as the correct solution to "headers already sent"

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

  • Google provides a lengthy list of similar discussions.
  • And of course many specific cases have been covered on Stack Overflow as well.
  • The WordPress FAQ explains How do I solve the Headers already sent warning problem? in a generic manner.
  • Adobe Community: PHP development: why redirects don't work (headers already sent)
  • Nucleus FAQ: What does "page headers already sent" mean?
  • One of the more thorough explanations is HTTP Headers and the PHP header() Function - A tutorial by NicholasSolutions (Internet Archive link).
    It covers HTTP in detail and gives a few guidelines for rewriting scripts.

Cannot modify Header Information - headers already sent

Headers already sent is an issue where you try to redirect an user with header() or when you try to start a session session_start() when the browser already rendered content (for example html, but can also be a PHP echo statement for example).

To fix the issue, check if you have any echo() statements or raw HTML before sending headers, and check if you do not have whitespaces in front of <?php.

A more detailed answer to help you fix this issue can be found here: https://stackoverflow.com/a/8028987/4274852

I suspect you did not provide us with all your code, as I cannot find any specific problems in yours at the moment. I hope the link above helps you to debug your code, if not: Make sure to post everything above your PHP code.

Just a note: I see you are still using mysql_query statements, which are deprecated. Use msqli or PDO instead.

Edit

I see you posted your code, try replacing all your PHP code at the top of your page instead of in the middle and it should work. In your current code, you have raw HTML before the PHP code (<h1> and <p> elements in this case), which makes it impossible to send more header data using header(), as all headers were already sent before rendering the page.

I editted your code to fix the issue hopefully, you can find it here (instead of posting it here, which would make an awkward long answer):

http://pastebin.com/0JfBdjU5

Warning: Cannot modify header information - headers already sent by

The error message is triggering because of the HTML that appears before your first <?php tag. You cannot output anything before header() is called. To fix this error start your document with the <?php tag and only start outputting HTML after you are done handling the condition that outputs XML for flash.

A cleaner solution would be to separate out the XML generation for flash and the HTML output into different files.

PHP - cannot modify header information - headers already sent by (output started at

From php documentation:

Remember that header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP.

So move header('Location: reset.php?username='.$username); before any other kind of output.

By the way, this question was already answered:

  • How to fix "Headers already sent" error in PHP
  • PHP Header redirect not working

Cannot modify header information - headers already sent by

This is a common error caused by BOM (Byte Order Mark). The indicator for this is the fact that the output started on line 1.

See the duplicate thread How to fix "Headers already sent" error for the resolution.

Cannot modify header information - headers already sent by

goto config.php file and just add ob_start(); method it will work...please try this..

go to application/config/config.php anf my config file is --

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
ob_start();

/*

|--------------------------------------------------------------------------

| Base Site URL

|--------------------------------------------------------------------------

|

| URL to your CodeIgniter root. Typically this will be your base URL,

| WITH a trailing slash:

|

| http://example.com/

|

| If this is not set then CodeIgniter will guess the protocol, domain and

| path to your installation.

|

*/

$config['base_url'] = 'http://localhost/smspanel/';

/*

|--------------------------------------------------------------------------

| Index File

|--------------------------------------------------------------------------

|

| Typically this will be your index.php file, unless you've renamed it to

| something else. If you are using mod_rewrite to remove the page set this

| variable so that it is blank.

|

*/

$config['index_page'] = '';

/*

|--------------------------------------------------------------------------

| URI PROTOCOL

|--------------------------------------------------------------------------

|

| This item determines which server global should be used to retrieve the

| URI string. The default setting of 'AUTO' works for most servers.

| If your links do not seem to work, try one of the other delicious flavors:

|

| 'AUTO' Default - auto detects

| 'PATH_INFO' Uses the PATH_INFO

| 'QUERY_STRING' Uses the QUERY_STRING

| 'REQUEST_URI' Uses the REQUEST_URI

| 'ORIG_PATH_INFO' Uses the ORIG_PATH_INFO

|

*/

$config['uri_protocol'] = 'AUTO';

/*

|--------------------------------------------------------------------------

| URL suffix

|--------------------------------------------------------------------------

|

| This option allows you to add a suffix to all URLs generated by CodeIgniter.

| For more information please see the user guide:

|

| http://codeigniter.com/user_guide/general/urls.html

*/

$config['url_suffix'] = '';

/*

|--------------------------------------------------------------------------

| Default Language

|--------------------------------------------------------------------------

|

| This determines which set of language files should be used. Make sure

| there is an available translation if you intend to use something other

| than english.

|

*/

$config['language'] = 'english';

/*

|--------------------------------------------------------------------------

| Default Character Set

|--------------------------------------------------------------------------

|

| This determines which character set is used by default in various methods

| that require a character set to be provided.

|

*/

$config['charset'] = 'UTF-8';

/*

|--------------------------------------------------------------------------

| Enable/Disable System Hooks

|--------------------------------------------------------------------------

|

| If you would like to use the 'hooks' feature you must enable it by

| setting this variable to TRUE (boolean). See the user guide for details.

|

*/

$config['enable_hooks'] = false;

/*

|--------------------------------------------------------------------------

| Class Extension Prefix

|--------------------------------------------------------------------------

|

| This item allows you to set the filename/classname prefix when extending

| native libraries. For more information please see the user guide:

|

| http://codeigniter.com/user_guide/general/core_classes.html

| http://codeigniter.com/user_guide/general/creating_libraries.html

|

*/

$config['subclass_prefix'] = 'MY_';

/*

|--------------------------------------------------------------------------

| Allowed URL Characters

|--------------------------------------------------------------------------

|

| This lets you specify with a regular expression which characters are permitted

| within your URLs. When someone tries to submit a URL with disallowed

| characters they will get a warning message.

|

| As a security measure you are STRONGLY encouraged to restrict URLs to

| as few characters as possible. By default only these are allowed: a-z 0-9~%.:_-

|

| Leave blank to allow all characters -- but only if you are insane.

|

| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!

|

*/

$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';

/*

|--------------------------------------------------------------------------

| Enable Query Strings

|--------------------------------------------------------------------------

|

| By default CodeIgniter uses search-engine friendly segment based URLs:

| example.com/who/what/where/

|

| By default CodeIgniter enables access to the $_GET array. If for some

| reason you would like to disable it, set 'allow_get_array' to FALSE.

|

| You can optionally enable standard query string based URLs:

| example.com?who=me&what=something&where=here

|

| Options are: TRUE or FALSE (boolean)

|

| The other items let you set the query string 'words' that will

| invoke your controllers and its functions:

| example.com/index.php?c=controller&m=function

|

| Please note that some of the helpers won't work as expected when

| this feature is enabled, since CodeIgniter is designed primarily to

| use segment based URLs.

|

*/

$config['allow_get_array'] = TRUE;

$config['enable_query_strings'] = FALSE;

$config['controller_trigger'] = 'c';

$config['function_trigger'] = 'm';

$config['directory_trigger'] = 'd'; // experimental not currently in use

/*

|--------------------------------------------------------------------------

| Error Logging Threshold

|--------------------------------------------------------------------------

|

| If you have enabled error logging, you can set an error threshold to

| determine what gets logged. Threshold options are:

| You can enable error logging by setting a threshold over zero. The

| threshold determines what gets logged. Threshold options are:

|

| 0 = Disables logging, Error logging TURNED OFF

| 1 = Error Messages (including PHP errors)

| 2 = Debug Messages

| 3 = Informational Messages

| 4 = All Messages

|

| For a live site you'll usually only enable Errors (1) to be logged otherwise

| your log files will fill up very fast.

|

*/

$config['log_threshold'] = 1;

/*

|--------------------------------------------------------------------------

| Error Logging Directory Path

|--------------------------------------------------------------------------

|

| Leave this BLANK unless you would like to set something other than the default

| application/logs/ folder. Use a full server path with trailing slash.

|

*/

$config['log_path'] = '';

/*

|--------------------------------------------------------------------------

| Date Format for Logs

|--------------------------------------------------------------------------

|

| Each item that is logged has an associated date. You can use PHP date

| codes to set your own date formatting

|

*/

$config['log_date_format'] = 'Y-m-d H:i:s';

/*

|--------------------------------------------------------------------------

| Cache Directory Path

|--------------------------------------------------------------------------

|

| Leave this BLANK unless you would like to set something other than the default

| system/cache/ folder. Use a full server path with trailing slash.

|

*/

$config['cache_path'] = '';

/*

|--------------------------------------------------------------------------

| Encryption Key

|--------------------------------------------------------------------------

|

| If you use the Encryption class or the Session class you

| MUST set an encryption key. See the user guide for info.

|

*/

$config['encryption_key'] = '100F72504334360FDEEB3A699E';

/*

|--------------------------------------------------------------------------

| Session Variables

|--------------------------------------------------------------------------

|

| 'sess_cookie_name' = the name you want for the cookie

| 'sess_expiration' = the number of SECONDS you want the session to last.

| by default sessions last 7200 seconds (two hours). Set to zero for no expiration.

| 'sess_expire_on_close' = Whether to cause the session to expire automatically

| when the browser window is closed

| 'sess_encrypt_cookie' = Whether to encrypt the cookie

| 'sess_use_database' = Whether to save the session data to a database

| 'sess_table_name' = The name of the session database table

| 'sess_match_ip' = Whether to match the user's IP address when reading the session data

| 'sess_match_useragent' = Whether to match the User Agent when reading the session data

| 'sess_time_to_update' = how many seconds between CI refreshing Session Information

|

*/

$config['sess_cookie_name'] = 'ci_session';

$config['sess_expiration'] = 7200;

$config['sess_expire_on_close'] = FALSE;

$config['sess_encrypt_cookie'] = FALSE;

$config['sess_use_database'] = FALSE;

$config['sess_table_name'] = 'ci_sessions';

$config['sess_match_ip'] = FALSE;

$config['sess_match_useragent'] = TRUE;

$config['sess_time_to_update'] = 300;

/*

|--------------------------------------------------------------------------

| Cookie Related Variables

|--------------------------------------------------------------------------

|

| 'cookie_prefix' = Set a prefix if you need to avoid collisions

| 'cookie_domain' = Set to .your-domain.com for site-wide cookies

| 'cookie_path' = Typically will be a forward slash

| 'cookie_secure' = Cookies will only be set if a secure HTTPS connection exists.

|

*/

$config['cookie_prefix'] = "";

$config['cookie_domain'] = "";

$config['cookie_path'] = "/";

$config['cookie_secure'] = FALSE;

/*

|--------------------------------------------------------------------------

| Global XSS Filtering

|--------------------------------------------------------------------------

|

| Determines whether the XSS filter is always active when GET, POST or

| COOKIE data is encountered

|

*/

$config['global_xss_filtering'] = FALSE;

/*

|--------------------------------------------------------------------------

| Cross Site Request Forgery

|--------------------------------------------------------------------------

| Enables a CSRF cookie token to be set. When set to TRUE, token will be

| checked on a submitted form. If you are accepting user data, it is strongly

| recommended CSRF protection be enabled.

|

| 'csrf_token_name' = The token name

| 'csrf_cookie_name' = The cookie name

| 'csrf_expire' = The number in seconds the token should expire.

*/

$config['csrf_protection'] = FALSE;

$config['csrf_token_name'] = 'csrf_test_name';

$config['csrf_cookie_name'] = 'csrf_cookie_name';

$config['csrf_expire'] = 7200;

/*

|--------------------------------------------------------------------------

| Output Compression

|--------------------------------------------------------------------------

|

| Enables Gzip output compression for faster page loads. When enabled,

| the output class will test whether your server supports Gzip.

| Even if it does, however, not all browsers support compression

| so enable only if you are reasonably sure your visitors can handle it.

|

| VERY IMPORTANT: If you are getting a blank page when compression is enabled it

| means you are prematurely outputting something to your browser. It could

| even be a line of whitespace at the end of one of your scripts. For

| compression to work, nothing can be sent before the output buffer is called

| by the output class. Do not 'echo' any values with compression enabled.

|

*/

$config['compress_output'] = FALSE;
/*


Related Topics



Leave a reply



Submit