Output Buffering (ob_start / ob_flush)
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]);
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
15 Mar 2026
Edited
22 Mar 2026
Views
16
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
No pings yesterday
Amazonbot 6
Google 2
ChatGPT 2
Perplexity 1
Ahrefs 1
Also referenced
How they use it
crawler 10
crawler_json 2
Related categories
⚡
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