簡體   English   中英

如何在 PHP 中禁用輸出緩沖

[英]How to disable output buffering in PHP

我編寫了一個簡單的中繼腳本,它連接到網絡攝像頭並從套接字讀取,並使用打印功能輸出這些數據。 數據是已設置邊界的 MJPG 數據。 我只是輸出讀取的數據。

問題是 PHP 似乎正在緩沖這些數據。 當我將相機設置為 1 FPS 時,Feed 會凍結 7-8 秒,然后快速顯示 8 幀。 如果我將分辨率設置為很大,相機會以每秒 1 幀的速度移動。 我假設然后發生了一些緩沖(因為大尺寸會快速填充緩沖區,而小尺寸不會),我不知道如何禁用這種緩沖。 有誰知道怎么做?

代碼:

ignore_user_abort(false);

$boundary = "myboundary";

//Set this so PHP doesn't timeout during a long stream
set_time_limit(0);

$socketConn = @fsockopen ("192.168.1.6", 1989, $errno, $errstr, 2);
if (!$socketConn)
exit();
stream_set_timeout($socketConn, 10);
fputs ($socketConn, "GET /mjpeg HTTP/1.0\r\n\r\n");

//Setup Header Information
header("Cache-Control: no-cache");
header("Cache-Control: private");
header("Pragma: no-cache");
header("Content-type: multipart/x-mixed-replace; boundary=$boundary");

@ini_set('implicit_flush', 1);
for ($i = 0; $i < ob_get_level(); $i++)
ob_end_flush();
ob_implicit_flush(1);

stream_set_blocking($f2, false);

//Send data to client
while (connection_status() == CONNECTION_NORMAL)
{
    $chunk = fread($socketConn, 128);
    print $chunk;   
}

fclose($socketConn);

tl;博士版本

做兩件事:

  1. 禁用用戶空間輸出緩沖區,或者...

    • 在全球范圍內,無論是...

      • 在 php.ini 中關閉output_buffering ,或
      • 使用以下命令關閉 Apache 配置中的output_buffering

         php_flag "output_buffering" Off
    • 或僅針對您關心的腳本,通過...

      • 調用ob_end_flush() ,或
      • 調用ob_end_clean()
  2. 此外,通過以下任一方式,盡可能多地禁用服務器級輸出緩沖區:

    • 在腳本開始時調用ob_implicit_flush() ,或
    • 在每個echo語句或其他將輸出添加到響應正文的語句之后調用flush()

更長的版本

令人困惑的是,有兩層緩沖可能是相關的,PHP 文檔在區分這兩者方面做得很差。

輸出緩沖器

PHP 文檔通常將第一層稱為“輸出緩沖區”。 這層緩沖只影響輸出到 HTTP 響應的正文,而不影響標頭。 您可以使用ob_start()打開輸出緩沖,並使用ob_end_flush()ob_end_clean()將其關閉。 您還可以使用 php.ini 中的output_buffering選項讓所有腳本自動啟動輸出緩沖。

php.ini 的生產版本的這個選項的默認值是 4096,這意味着輸出的前 4096 個字節將緩沖在輸出緩沖區中,此時它將被刷新並關閉輸出緩沖。

您可以通過在 php.ini 文件中將output_buffering設置為Off (或使用

php_flag "output_buffering" Off

在您的 Apache 配置中,如果您使用的是 Apache)。 或者,您可以通過在腳本開始時調用ob_end_clean()ob_end_flush()來為單個腳本禁用它。

寫緩沖區和網絡服務器緩沖區

除了輸出緩沖區之外,還有 PHP 手冊中稱為“寫入緩沖區”的內容,以及您的 Web 服務器擁有的任何緩沖系統。 如果您通過mod_php將 PHP 與 Apache 一起使用,並且沒有使用mod_gzip ,則可以調用flush()來刷新這些; 對於其他后端,它也可能有效,盡管手冊對提供保證持謹慎態度:

描述

void flush ( void )

刷新 PHP 的寫入緩沖區以及 PHP 正在使用的任何后端(CGI、Web 服務器等)。 這會嘗試將當前輸出一直推送到瀏覽器,但有一些警告。

flush()可能無法覆蓋您的 Web 服務器的緩沖方案,並且它對瀏覽器中的任何客戶端緩沖都沒有影響。 它也不影響 PHP 的用戶空間輸出緩沖機制。 這意味着如果您正在使用它們,您將必須同時調用ob_flush()flush()來刷新 ob 輸出緩沖區。

還有幾種方法可以讓 PHP 在每次echo任何內容時自動調用flush() (或執行任何其他將輸出回顯到響應主體的操作)。

第一個是調用ob_implicit_flush() 請注意,此函數的名稱具有欺騙性; 給定它的ob_前綴,任何有理智的人都會期望它會影響“輸出緩沖區”,就像ob_startob_flushob_flush 。但是,情況並非如此; ob_implicit_flush()flush() ,影響服務器級輸出緩沖區,並且不會以任何方式與其他ob_函數控制的輸出緩沖區ob_

第二個是通過在 php.ini 中將implicit_flush標志設置為On來全局啟用隱式刷新。 這相當於在每個腳本開始時調用ob_implicit_flush() 請注意,手冊建議不要這樣做,隱晦地引用了“嚴重的性能影響” ,其中一些我在這個切線相關的答案中進行了探討。

您可以在每次讀取操作后調用flush() ,而不是禁用輸出緩沖。 這避免了必須弄亂服務器配置並使您的腳本更具可移植性。

輸出緩沖可以分層,我也遇到過早期代碼已經創建多個級別的情況。 這將清除它們。

while (ob_get_level()) ob_end_clean(); 
// or ob_end_flush() if you want the contents of the buffer.

我們可以在 .htaccess 文件中給出以下代碼來禁用 PHP 中的輸出緩沖

php_flag "output_buffering" off

我知道這個問題有點老了,但是回到這個問題,您可以在腳本到腳本的基礎上關閉輸出緩沖,如下所示:

if (ob_get_level())
   ob_end_clean();

這應該關閉它后面的任何腳本的所有輸出緩沖。

對於 Windows IIS 服務器,上述解決方案都不起作用,因為 IIS 管理自己的緩沖區,也應該禁用它。

只需使用 PHP 腳本將以下web.config添加到您的文件夾中即可禁用緩沖。 在下面的示例中使用了 PHP v7.3.7,但您可以將名稱替換為其他版本。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <clear />
            <add name="php-7.3.7" path="*.php" verb="GET,HEAD,POST" modules="FastCgiModule" scriptProcessor="C:\Program Files\PHP\v7.3\php-cgi.exe" resourceType="Either" requireAccess="Script" responseBufferLimit="0" />
        </handlers>
    </system.webServer>
</configuration>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM