PHP headers_sent() Function: Everything You Need to Know
As a PHP developer, you may need to check whether HTTP headers have already been sent to the client. The headers_sent() function is a built-in function in PHP
Every HTTP response is split into two parts: a block of headers (status code, Content-Type, cookies, redirects) followed by the response body. The catch is that headers must be sent before any body output. The moment PHP echoes a single byte of body, it flushes the headers and locks them — any later call to header(), setcookie(), or session_start() then triggers the infamous Cannot modify header information - headers already sent warning.
headers_sent() is the built-in that lets you ask, before you try to send a header, whether it is already too late. This guide covers its syntax, its by-reference parameters, what causes premature output, and how to fix it.
What headers_sent() Does
headers_sent() returns a boolean:
true— headers have already been sent (output started). Any furtherheader()/setcookie()call will fail.false— no output has started yet, so it is still safe to set headers.
Guarding header logic with headers_sent() lets you avoid the warning and degrade gracefully (for example, log the problem or fall back to a JavaScript redirect) instead of crashing the page.
Syntax
headers_sent(string &$filename = null, int &$line = null): boolBoth parameters are optional and passed by reference. When headers have been sent, PHP fills them with the location of the output that started it:
$filename— the name of the source file where output first began.$line— the line number within that file.
This is what makes headers_sent() so useful for debugging: it points you straight at the culprit.
Basic Usage
Check the return value before sending a header:
<?php
if (!headers_sent()) {
header('Location: /dashboard');
exit;
}
echo 'Headers were already sent, cannot redirect via HTTP.';If output has not started, the redirect header is sent. Otherwise the script avoids the fatal warning and prints a fallback message.
Finding Where Output Started
Pass the two reference variables to learn exactly what sent the headers — invaluable when a stray space or echo is buried in an included file:
<?php
if (headers_sent($file, $line)) {
echo "Headers already sent in $file on line $line";
} else {
setcookie('theme', 'dark');
echo 'Cookie set successfully.';
}If the condition is true, you get a message like Headers already sent in /var/www/header.php on line 12, telling you precisely where to look.
What Triggers "Headers Already Sent"
Anything that produces body output before your header call flushes the headers. Common causes:
- Whitespace or a blank line before
<?php— even one space or newline counts as output. - A newline after the closing
?>of an included file. (Best practice: omit the closing?>in pure-PHP files entirely.) echo,print,printf, orvar_dumprunning before the header.- A UTF-8 file saved with a BOM (byte-order mark) — those invisible leading bytes are output.
- PHP warnings/notices printed to the page (when
display_errorsis on) before headers.
Fixing It with Output Buffering
If you cannot reorder your code so all headers come first, wrap the script in an output buffer. ob_start() holds the body in memory instead of sending it immediately, so headers stay modifiable until the buffer is flushed:
<?php
ob_start(); // start buffering — nothing is sent yet
echo 'Some early output';
// Still safe: the echo above is held in the buffer, headers are not sent
setcookie('user', 'jane');
header('X-App-Version: 2.0');
ob_end_flush(); // now send headers, then the buffered bodyBecause output is buffered, headers_sent() would still return false after the echo, and the later setcookie() and header() calls succeed.
Related Functions
header()— send a raw HTTP header.headers_list()— list headers queued or already sent.setcookie()— set a cookie (sends aSet-Cookieheader).ob_start()— start output buffering to delay sending headers.- PHP Sessions —
session_start()also sends headers and is a frequent trigger.
Conclusion
headers_sent() is a small but essential guard: call it before any header(), setcookie(), or session_start() to check whether output has already begun. When it returns true, the by-reference $filename and $line arguments pinpoint the offending output so you can fix it — or wrap your script in ob_start() to keep headers modifiable until you are ready to flush.