請注意,如果您在 ob_start 和 ob_end_clean 或 ob_end_flush 之間更改 zlib 輸出壓縮設定,您將會收到錯誤:ob_end_flush() 無法刪除緩衝區 zlib 輸出壓縮
範例
<?php
ob_start();
$output = ob_get_contents();
ini_set('zlib.output_compression', '1');
ob_end_clean();
?>
此範例中的 ob_end_clean(); 將會拋出錯誤。
(PHP 4, PHP 5, PHP 7, PHP 8)
ob_end_clean — 清除(擦除)作用中輸出緩衝區的內容並關閉它
此函式會呼叫輸出處理程式(使用 PHP_OUTPUT_HANDLER_CLEAN
和 PHP_OUTPUT_HANDLER_FINAL
旗標),捨棄其傳回值,捨棄作用中輸出緩衝區的內容,並關閉作用中輸出緩衝區。
如果沒有使用 PHP_OUTPUT_HANDLER_REMOVABLE
旗標啟動的作用中輸出緩衝區,ob_end_clean() 將會失敗。
即使作用中輸出緩衝區是在沒有 PHP_OUTPUT_HANDLER_CLEANABLE
旗標的情況下啟動的,ob_end_clean() 也會捨棄其內容。
此函式沒有參數。
如果函式失敗,它會產生一個 E_NOTICE
。
以下範例顯示了一個清除作用中輸出緩衝區內容的簡單方法
範例 #1 ob_end_clean() 範例
<?php
ob_start();
echo '不會顯示的文字。';
ob_end_clean();
?>
請注意,如果您在 ob_start 和 ob_end_clean 或 ob_end_flush 之間更改 zlib 輸出壓縮設定,您將會收到錯誤:ob_end_flush() 無法刪除緩衝區 zlib 輸出壓縮
範例
<?php
ob_start();
$output = ob_get_contents();
ini_set('zlib.output_compression', '1');
ob_end_clean();
?>
此範例中的 ob_end_clean(); 將會拋出錯誤。
請注意,如果您使用回呼函式呼叫 ob_start,即使您使用 ob_end_clean 捨棄輸出緩衝區,該回呼函式仍然會被呼叫。
因為一旦設定了回呼函式,就無法將其從輸出緩衝區中移除,阻止回呼函式產生任何作用的唯一方法是執行以下操作
<?php
$ignore_callback = false;
ob_start('my_callback');
...
if($need_to_abort) {
$ignore_callback = true;
ob_end_clean();
...
}
function my_callback(&$buffer) {
if($GLOBALS['ignore_callback']) {
return "";
}
...
}
?>
如果對輸出緩衝沒有把握(已啟用或未啟用),
您可以嘗試這些防護措施
<?php
while (ob_get_level() !== 0) {
ob_end_clean();
}
// 或
while (ob_get_length() !== false) {
ob_end_clean();
}
?>
如果您希望在客戶端已經擁有最新版本時阻止腳本執行,您可以這樣做:
您可以這樣做:
ob_start();
$mtime=filemtime($_SERVER["SCRIPT_FILENAME"])-date("Z");
$gmt_mtime = date('D, d M Y H:i:s', $mtime) . ' GMT';
$headers = getallheaders();
if(isset($headers["If-Modified-Since"])) {
if ($headers["If-Modified-Since"] == $gmt_mtime) {
header("HTTP/1.1 304 Not Modified");
ob_end_clean();
exit;
}
}
$size=ob_get_length();
header("Last-Modified: ".$gmt_mtime);
header("Content-Length: $size");
ob_end_flush();
當然,您可以查詢資料庫或採用任何與腳本結果修改相關的日期,而不是將 If-Modified-Since 標頭與腳本上次修改日期進行比較。
例如,您可以使用此技術動態生成圖像。如果使用者透過 If-Modified-Since 標頭指示他已經擁有圖像的版本,則無需生成圖像,並讓伺服器最終將其捨棄,因為伺服器僅在之後才會解釋 If-Modified-Since 標頭。
這樣可以節省伺服器負載並縮短響應時間。
關於先前的評論
您也可以依賴 ETag 並簡單地使用 time()
<?php
$time = time();
$mins = 1;
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) and str_replace('"', '', $_SERVER['HTTP_IF_NONE_MATCH'])+($mins*60) > $time)
{
header('HTTP/1.1 304 Not Modified');
exit();
}
else
{
header('ETag: "'.$time.'"');
}
echo '快取 ', $mins*60, ' 秒<br/>', date('G:i:s');
?>
請注意,ob_end_clean() 會捨棄標頭。
如果您想清除輸出緩衝區,但不清除標頭(例如,因為您使用 firephp...),那麼這就是解決方案
<?php
...
$headers = array();
if ( !headers_sent() ) {
$headers = apache_response_headers();
}
ob_end_clean();
ob_start();
if ( !empty( $headers ) ) {
foreach ( $headers as $name => $value ) {
header( "$name: $value" );
}
}
...
?>
我在網頁應用程式的通用例外處理器中使用它,它會清除緩衝區(但不清除包含除錯資訊的標頭),並使用 readfile() 傳送 500 錯誤頁面。
祝 PHP 使用愉快,
Tamas.
請記住,mrfritz379 的範例 (#49800) 只是一個範例。您可以用更有效率的方式達成該範例的結果,而無需使用輸出緩衝函式
echo "<p>搜尋執行中。請耐心等候。。。";
$output = "<p>檔案列表:</p>\n";
if (is_dir($dir)) {
$dh = opendir($dir);
while (($fd = readdir($dh)) != false) {
echo " .";
$output .= $fd;
}
}
echo "</br>搜尋完成!</p>\n";
echo $output;
除了 John Smith 的評論 (#42939) 之外,即使您呼叫 ob_end_clean(),ob_gzhandler() 仍可能會將 HTTP 標頭「Content-Encoding」設定為「gzip」或「deflate」。這會在以下情況下造成問題
1. 呼叫 ob_gzhandler()。
2. 顯示「一些內容」;
3. 呼叫 ob_end_clean()。
4. 顯示「新內容」;
在上述情況下,瀏覽器可能會收到「Content-Encoding: gzip」HTTP 標頭,並嘗試解壓縮未壓縮的「新內容」。瀏覽器將會失敗。
在以下情況下,此行為將不會被注意到
1. 呼叫 ob_gzhandler()。
2. 顯示「一些內容」;
3. 呼叫 ob_end_clean()。
4. 呼叫 ob_gzhandler()。
5. 顯示「新內容」;
這是因為第二個 ob_gzhandler() 將會掩蓋第一個 ob_gzhandler() 的缺失。
解決方案是像 John Smith 那樣為 ob_gzhandler() 編寫一個包裝器。
如果您在以「register_shutdown_function」註冊的函式中呼叫 ob_end_clean,那就太遲了,任何緩衝區都已經發送到用戶端。
關於 <geoff at spacevs dot com> 所說的「如果您在以 'register_shutdown_function' 註冊的函式中呼叫 ob_end_clean,那就太遲了,任何緩衝區都已經發送到用戶端。」,以下是我想出的解決方法。
<?php
function ClearBuffer($Buffer) {
return "";
}
function Shutdown() {
ob_start("ClearBuffer");
}
register_shutdown_function("Shutdown");
?>
這會清除所有輸入到輸出緩衝區的內容。基本上它與 "STDOUT > /dev/null" 相同。
這可能在其他地方貼過,但我沒看過。
要在程式執行時顯示進度指示器,但不輸出輸出緩衝區的內容,可以使用以下方法:
echo "<p>搜尋執行中。請耐心等候。。。";
$output = "<p>檔案列表:</p>\n";
if (is_dir($dir)) {
$dh = opendir($dir);
while (($fd = readdir($dh)) != false) {
echo " .";
ob_start();
echo $fd;
$output .= ob_get_contents();
ob_end_clean();
}
}
echo "</br>搜尋完成!</p>\n";
echo $output;
程式將繼續印出「.」,而不印出檔案列表。然後會印出「搜尋完成」訊息,接著是緩衝的檔案列表。