這會一次顯示一行,並暫停 2 秒。
(在 IEx 和 Firefox 下測試)
<?php
if (ob_get_level() == 0) ob_start();
for ($i = 0; $i<10; $i++){
echo "<br> Line to show.";
echo str_pad('',4096)."\n";
ob_flush();
flush();
sleep(2);
}
echo "Done.";
ob_end_flush();
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
flush — 沖刷系統輸出緩衝區
沖刷 PHP 的系統寫入緩衝區和 PHP 使用的後端(例如:CGI、Web 伺服器)。在命令列環境中,flush() 將嘗試僅沖刷緩衝區的內容,而在 Web 環境中,標頭和緩衝區的內容都會被沖刷。
注意: flush() 可能無法覆寫 Web 伺服器的緩衝配置,並且對瀏覽器中的任何客戶端緩衝沒有影響。
注意: 此函式對使用者層級輸出處理器(例如由 ob_start() 或 output_add_rewrite_var() 啟動的處理器)沒有任何影響。
flush() 可能會干擾在 Web 環境中設定和傳送標頭的輸出處理器(例如 ob_gzhandler()),因為它會在這些處理器執行之前傳送標頭。
此函式沒有參數。
沒有傳回值。
版本 | 描述 |
---|---|
8.4.0 | 現在在 FastCGI 中,沖刷沒有主體的標頭將會成功。 |
這會一次顯示一行,並暫停 2 秒。
(在 IEx 和 Firefox 下測試)
<?php
if (ob_get_level() == 0) ob_start();
for ($i = 0; $i<10; $i++){
echo "<br> Line to show.";
echo str_pad('',4096)."\n";
ob_flush();
flush();
sleep(2);
}
echo "Done.";
ob_end_flush();
?>
這是我用來關閉幾乎所有可能導致不必要輸出緩衝,並開啟隱含沖刷的方式
<?php
@apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);
?>
如果仍然失敗,請記住 Internet Explorer 和 Safari 在開始增量渲染之前有一個 1k 的緩衝區,因此您也需要輸出一些填充。
如果您想在使用來自 Apache httpd 和 mod_proxy_fcgi 的 php-fpm 時讓 flush 生效,從 2.4.31 開始,您可以附加 flushpackets=on 以啟用沖刷,預設情況下是立即的,以及 flushwait=n,其中 n 是以毫秒為單位的延遲沖刷時間,以提高效能。
這些值可以附加到 <Proxy> 指令中,例如 <Proxy "fcgi://127.0.0.1/" flushpackets=on flushwait=500> 或在 ProxyPass 和 ProxyPassMatch 行中。
2.4 的 mod_proxy_fcgi 文件中沒有記載這一點,但在 2.5 或 trunk 文件中是可用的。
我想指出有一個函式可以取代 ob_flush 和 flush。如果您在頁面頂部設定 ob_implicit_flush(true);,它會自動沖刷您在腳本其餘部分中執行的任何 echo 或 print。
請注意,您仍然需要通過瀏覽器篩選器傳送最少量的資料。我建議使用 str_pad($text,4096);,因為這會自動用空格將文字延長至 4 KB,這是使用 FireFox 和 Linux 時的最小限制。
我希望這對大家有所幫助。
關於瀏覽器的緩衝,您可以使用
$out=str_pad($yourMessage.'<br/>',1024);
print($out);
ob_flush();
flush();
這對我在 Firefox 60 ESR 中有效。
對於使用 IIS 的 Windows 系統,ResponseBufferLimit 優先於 PHP 的 output_buffering 設定。因此,您還必須將 ResponseBufferLimit 設定為低於其預設值的值。
對於舊於 7 的 IIS 版本,可以在 %windir%\System32\inetsrv\fcgiext.ini 檔案(FastCGI 設定檔)中找到此設定。您可以將適當的行設定為
ResponseBufferLimit=0
對於 IIS 7+,設定儲存在 %windir%\System32\inetsrv\config 中。編輯 applicationHost.config 檔案並搜尋 PHP_via_FastCGI(假設您已按照安裝說明,使用名稱 PHP_via_FastCGI 將 PHP 安裝為 FastCGI 模組)。在 add 標籤內,將以下設定放在最後
responseBufferLimit="0"
因此,整行看起來會像這樣
<add name="PHP_via_FastCGI" path="*.php" verb="*" modules="FastCgiModule" scriptProcessor="C:\PHP\php-cgi.exe" resourceType="Either" responseBufferLimit="0" />
或者,您可以使用以下命令插入設定
%windir%\system32\inetsrv\appcmd.exe set config /section:handlers "/[name='PHP_via_FastCGI'].ResponseBufferLimit:0"
當將 PHP 與 CGI/FastCGI 模式一起使用時,會有一個新的緩衝區(由 mod_fcgid 啟動,預設大小為 65536 位元組)。這會導致 `flush()` 和 `ob_flush()` 無法如預期般使用 implicit_flush(true) 運作。
在 mod_fcgid 設定中設定 "OutputBufferSize 0" 可以解決此問題。
希望這有幫助!
大家好。
一直為資料無法沖刷到 IE (6) 而困擾,即使我嘗試了 strpad 4096 個字元、所有標頭都正常、TABLE 和 no TABLE、flush 和 ob_flush - 仍然是空白頁面。嘗試在沖刷前新增 sleep(1) - 一切都像施了魔法般地奏效了。
/Mikael
在搜尋過 PHP 網站、Google 和各種論壇後,找不到解決我的腳本在呼叫 flush 和 ob_flush 時沒有任何輸出的問題,我想到嘗試告訴 PHP 在開始 echo 之前呼叫
session_write_close();
它就像魔法一樣地奏效了。我找不到任何關於這方面的參考資料,所以我希望這個筆記能在未來幫助到其他人。
就像 IE 一樣,Safari 在顯示任何內容之前需要相當多的資料,實際上比 Explorer 還要多。以下程式碼在 Firefox 和 Safari 中對我來說是有效的,也應該在 IE 中正常運作。
<?php
for($i = 0; $i < 40000; $i++)
{
echo ' '; // 額外空格
}
// 保持資料流向瀏覽器?
flush();
// 50000 微秒可保持資料在 Safari、IE、Firefox 等瀏覽器中流動
usleep(50000);
?>
這段程式碼來自一個討論瀏覽器與 flush() 功能的部落格上的評論。
如果 flush() 函式不起作用,您必須在 php.ini 中設定以下選項:
--[程式碼]--
output_buffering = Off
;output_handler =
zlib.output_compression = Off
;zlib.output_handler =
--[^程式碼^]--
如果問題仍然存在,您必須查看伺服器的標頭並檢查 `Server` 字串。
在我的情況下,前端是 Nginx 網頁伺服器,而 Apache 作為後端。
因此,必須在 Nginx 設定檔中停用緩衝。
要停止緩衝,您必須將以下字串添加到設定檔中:
--[程式碼]--
proxy_buffering off;
--[^程式碼^]--
然後重新啟動 Nginx 常駐程式。有關設定的更多資訊,您可以在 Nginx 網站上的文件中找到。
結合一些想法,我終於讓一個長時間運行的腳本可以即時回饋它正在做的事情。這是一個以 cgi 運行 PHP 的 WAMP 設定。我相當確定 Apache 只是沒有發送任何緩衝的輸出,因為它試圖提供幫助。為了幫助大家,我希望這個範例解決方案能對某些人有所幫助。
<?php
// 感謝 mandor at mandor
ini_set('max_execution_time', 0);
ini_set('implicit_flush', 1);
ob_implicit_flush(1);
echo '正在執行某些操作'; my_flush();
sleep(5);
echo '正在執行其他操作'; my_flush();
sleep(5);
echo '終於完成了 - 太棒了';
function my_flush() {
// 遵循 matt at hevanet 的方法
for ($i=0;$i<10000;$i++) echo ' ';
ob_flush();
flush();
}
我嘗試在我的 Windows 機器上讓 flush 工作時遇到了一堆問題,在閱讀了這裡所有人的內容但仍然無效後,我終於找到了一個解決方案。
1) 設定 output_buffering = 0
2) 設定 zlib.output_compression = 0
然後我使用 Wireshark 來監控網路封包,事實上,伺服器正在推送資料,但瀏覽器沒有顯示它... 所以這是瀏覽器的緩衝問題 (我使用的是 Firefox 13)。
對我來說,我需要發送約 1k 的資料,它才會顯示資料。為了做到這一點,我添加了更多標頭資訊..
在 php.ini 中,我設定 default_charset = "utf-8"
這就足以解決緩衝區的問題了。
您也可以嘗試執行
echo str_repeat(" ", 1024), "\n";
在腳本的開頭。
希望這對您有幫助
這是 Rusty 在下方評論的延伸
在這裡坐了幾個小時,試圖讓 IE6 在頁面中間刷新資料 (在 Firefox 中它運作完美),我終於搞清楚了問題。除非包含它的表格是完整的,否則 IE 不會顯示刷新後的資料 (即使它已經有了)。
您希望 IE 顯示的每個新元素都不能在任何類型的表格中。您必須結束所有表格。
使用函式 flush() 有點複雜,您必須多做實驗。
因此,如果您設計一個網站在最後有一個時間迴圈,該迴圈透過表單資料輸入 (資料提交) 呼叫另一個網站,則您必須
給緩衝區一些東西,以便快速載入新網站。
例如
<?php
$instant=gettimeofday();
$timenow=$instant["sec"];//開始時間
//時間迴圈(例如,30 分鐘後的安全性儲存)
while (1) { echo "<b></b>";//無用 (僅為了快速載入下一個
//或切換時的相同網站)
flush(); //輸出緩衝區
$instant=gettimeofday();
$timeactual=$instant["sec"]; //以秒為單位取得實際時間
$flag=(($timeactual>$timenow+$diff)? 1:0);//$diff=切換時間
if ($flag) { what_do_at_switch_Time();//Sec.Save 等等
$timenow=$timeactual; } //設定新的開始時間
sleep(5); //或者其他...(重要)
} //while 迴圈結束
?>
因此,您可以在您的網站中編寫安全性儲存或其他功能的程式碼,如果您進行切換,則新網站或相同網站 (呼叫的網站) 的上傳會正常運作...
我花了幾天的時間試圖弄清楚為什麼 flush 突然不能工作了,雖然它以前運作得很好。顯然,是 McAfee Spamkiller 引起了問題。停用它沒有用,我必須完全移除它。希望這對某些人有幫助。
如果您沒有明確使用緩衝功能,那麼只有當輸出緩衝在您的 php.ini 檔案中開啟時,才需要 ob_flush()。
只有當 implicit_flush 在您的 php.ini 檔案中關閉時,才需要 flush()。將 implicit_flush 設定為開啟將會移除所有這些 flush() 呼叫的需要,但它通常只在極度受控的環境中才有用。在生產環境中開啟 implicit_flush 可能會很糟糕。
這幫助我讓刷新功能正常運作。
使用帶有 deflate 的 Apache。
關閉此腳本的壓縮:(將其添加到腳本頂部的某個位置)
apache_setenv('no-gzip', '1');
但是,這只有在 PHP 作為模組而不是 cgi 擴充功能執行時才有效,並且必須停用安全模式。
您也可以透過建立 .htaccess 檔案並新增以下條目來關閉目錄的壓縮:
mod_gzip_on Off
但是這會影響整個目錄。
希望我能幫上忙。
在 php8.3-fpm 和 apache 2.4.57 上
為了讓 flush 在瀏覽器中正常運作,您需要發送更多資料 (至少 4096 個位元組/flush),並且您需要為該網站將設定新增到您的 apache2 設定的虛擬主機中
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://127.0.0.1"
</FilesMatch>
<Proxy fcgi://127.0.0.1/">
ProxySet enablereuse=on flushpackets=on
</Proxy>
您好,
我在將 javascript 發送到 <body></body> 內容已發送到瀏覽器後,遇到了相同的問題 (該腳本會更新 iframe 的內容)。
兩個解決方案對我有效
- 新增足夠的資料 (即:額外的虛擬文字,例如空格),或者,
- 在頁面結尾 echo '</body>' 標籤
請注意,要使後者起作用,應該
- 在 php.ini 中關閉 output_buffering,並執行以下操作之一
* 在 php.ini 中開啟 implicit_flush,或者,
* 在腳本開頭呼叫 ob_implicit_flush();
我偏好在結尾 echo '</body>' 標籤,因為它不需要透過網路發送任何額外資料,而且是一種更簡潔的編碼技術。
注意事項
- 使用 perl 和 cgi 時不需要這些變通方法,... 。
- 您可以保持 php.ini 中的 zlib.output_compression 處於開啟狀態
誠摯問候,並希望這對您有所幫助。
Maurits
我找到了一種建立簡單進度列的方法,該進度列在大多數情況下是跨平台的。由於我的想法來自這個網站,因此只有分享才能回饋給社群。
注意:關於瀏覽器緩衝的一些有趣事項... 你必須要有 <html><body> 標籤,Firefox 和其他一些瀏覽器才能在 Javascript 中透過 id 識別項目。因此,我建議在呼叫此函數之前使用某種 header 函數。
<?php
function fn_progress_bar($intCurrentCount = 100, $intTotalCount = 100)
{
static $intNumberRuns = 0;
static $intDisplayedCurrentPercent = 0;
$strProgressBar = '';
$dblPercentIncrease = (100 / $intTotalCount);
$intCurrentPercent = intval($intCurrentCount * $dblPercentIncrease);
$intNumberRuns++;
if(1 == $intNumberRuns)
{
$strProgressBar = <<< BAR
<table width='50%' id='progress_bar' summary='progress_bar' align='center'><tbody><tr>
<td id='progress_bar_complete' width='0%' align='center' style='background:#CCFFCC;'> </td>
<td style='background:#FFCCCC;'> </td>
</tr></tbody></table>
<script type='text/javascript' language='javascript'>
function dhd_fn_progress_bar_update(intCurrentPercent)
{
document.getElementById('progress_bar_complete').style.width = intCurrentPercent+'%';
document.getElementById('progress_bar_complete').innerHTML = intCurrentPercent+'%';
}
</script>
BAR;
}
else if($intDisplayedCurrentPercent <> $intCurrentPercent)
{
$intDisplayedCurrentPercent = $intCurrentPercent;
$strProgressBar = <<< BAR
<script type='text/javascript' language='javascript'>
dhd_fn_progress_bar_update($intCurrentPercent);
</script>
BAR;
}
if(100 <= $intCurrentPercent)
{
$intNumberRuns = $intDisplayedCurrentPercent = 0;
$strProgressBar = <<< BAR
<script type='text/javascript' language='javascript'>
document.getElementById('progress_bar').style.visibility='hidden';
</script>
BAR;
}
echo $strProgressBar;
flush();
ob_flush();
}
?>