← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Output Buffering (ob_start / ob_flush)

PHP PHP 4.0+ Intermediate
debt(d7/e3/b3/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated=no and phpstan as the only listed tool, but phpstan does not natively catch missing ob_start() or unmatched ob_end_clean() calls reliably. The 'headers already sent' error is a runtime signal only seen when the code executes, and the memory-leak from nested buffers is silent in production until the script degrades — matching d7.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix describes adding ob_start() at the top of templates and pairing it with ob_end_clean()/ob_end_flush(). This is a small, localised fix in one file or component, not a one-liner swap (e1) but not a multi-file refactor either — e3 is accurate.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to covers web and CLI contexts broadly, but the actual buffering calls are typically confined to specific entry points or template layers. The choice doesn't reshape the whole codebase, but it does impose a persistent maintenance awareness in those zones (ensure buffers are flushed/cleaned), making b3 the best fit.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap / documented gotcha' (t5). The misconception field explicitly states developers think output buffering is only for capturing template output, missing its header-deferral, compression, and response-interception roles. The SAPI-dependent implicit buffering behaviour (PHP-FPM vs others) is an additional documented gotcha that many developers learn the hard way — solidly t5.

About DEBT scoring →

Also Known As

ob_start PHP output buffering ob_get_clean

TL;DR

Capturing PHP output into a buffer rather than sending it immediately, enabling manipulation before delivery or header modification.

Explanation

PHP's output buffering (ob_start(), ob_get_clean(), ob_flush()) intercepts all echo/print output into an internal buffer. This enables: modifying output after generation (adding compression, injecting content), sending headers after output has started (workaround for 'headers already sent' errors — though proper code shouldn't need this), capturing template output as a string, and implementing full-page caching. Nested buffers are supported. ob_gzhandler compresses output — but prefer server-level compression. Forgetting to flush or clean a buffer on exceptions is a common source of partially-delivered or corrupted responses.

Common Misconception

Output buffering is only useful for capturing template output. It also allows headers to be sent after output has started (by buffering the output), enables response compression, and is used by frameworks to implement response interception and modification.

Why It Matters

Output buffering captures output before sending it — enabling headers to be set after content begins, reducing network round-trips, and allowing content to be modified or discarded before delivery.

Common Mistakes

  • Calling header() after output has been sent — 'headers already sent' error caused by missing ob_start().
  • Not calling ob_end_clean() or ob_end_flush() — nested buffers cause memory leaks in long-running scripts.
  • Relying on output buffering to fix poorly structured code instead of fixing the output order.
  • Not knowing that PHP-FPM and some SAPIs have implicit output buffering — behaviour differs across environments.

Code Examples

✗ Vulnerable
// Headers already sent — ob_start() would fix this:
echo 'Some content'; // Output sent
header('Location: /dashboard'); // Warning: headers already sent

// Fix:
ob_start();
echo 'Some content';
header('Location: /dashboard');
ob_end_clean();
exit;
✓ Fixed
// ob_start() captures all output until ob_end_flush()/ob_get_clean()
ob_start();
require 'template.php'; // outputs HTML
$html = ob_get_clean(); // capture and stop buffering

// Send custom headers before any output — ob_start() buys time
ob_start();
// ... lots of processing that might echo ...
header('X-Processing-Time: ' . $elapsed); // still works — nothing sent yet
ob_end_flush();

// Template rendering pattern
function render(string $template, array $vars): string {
    extract($vars, EXTR_SKIP);
    ob_start();
    require "views/{$template}.php";
    return ob_get_clean();
}
$html = render('email/welcome', ['user' => $user]);

Added 15 Mar 2026
Edited 22 Mar 2026
Views 38
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 0 pings F 0 pings S 1 ping S 2 pings M 1 ping T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 1 ping T 1 ping W
Bing 1
SEMrush 1
Amazonbot 7 Scrapy 5 ChatGPT 4 Google 3 Ahrefs 3 Claude 2 Bing 2 Perplexity 1 Meta AI 1 Majestic 1 Sogou 1 SEMrush 1
crawler 26 crawler_json 5
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Use ob_start() at the top of templates to capture output and manipulate it before sending — but avoid buffering entire large responses in memory; send chunked with flush() for streaming
📦 Applies To
PHP 4.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
headers already sent errors from output before header(); large response built entirely in memory before sending; no output buffering in templates
Auto-detectable: ✗ No phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Low Context: Function


✓ schema.org compliant