2012-05-14 35 views
19

我有ob_start()和相應的ob_flush()。我想刷新一部分數據並繼續執行其餘部分。使用ob_flush()沒有幫助。如果可能的話,還需要在瀏覽器中顯示加載而不顯示。如何刷新數據到瀏覽器,但繼續執行

編輯:

我不想用ajax

+0

做完第一個ob_flush後,是否需要顯示其他輸出?或者您希望客戶完全瞭解請求,然後在後臺繼續進行某些處理? – Corbin

+0

繼續在後臺 – aWebDeveloper

+0

好的,已經更新了我的答案。 – Corbin

回答

15

ob_flush寫入緩衝區。換句話說,ob_flush告訴PHP給Apache(或nginx/lighttpd/whatever)輸出,然後讓PHP忘記它。一旦Apache有輸出,它就可以隨心所欲地執行任何操作。 (換句話說,在ob_flush之後,不管它是否立即寫入瀏覽器,都無法控制)。

所以,簡短的回答:沒有保證的方式來做到這一點。

只是猜測,你可能正在尋找AJAX。每當有人在頁面內容加載時嘗試操作,AJAX幾乎總是正確的路徑。

如果您想在後臺繼續執行任務,則可以使用ignore_user_abort,但詳細的here,但這通常不是最佳方法。你基本上失去了對該線程的控制,並且在我看來,Web服務器線程並不是重處理所屬的地方。

我會嘗試從面向網絡的東西中提取出來。這可能意味着一個cron條目或者只是從PHP內部產生一個後臺進程(一個從腳本執行內部啓動的進程不會因爲腳本而死亡,並且腳本不會在死前完成)。

如果你確實走了那條路,這意味着你甚至可以根據需要製作某種狀態系統。然後,您可以監視執行情況,併爲用戶定期更新進度。 (從技術上講,你也可以使用ignore_user_abort -ed腳本製作狀態系統,但它對我來說似乎並不那麼幹淨。)

+1

當新用戶登錄時,我想節省很多數據。這些數據應該立即保存,但不會中斷用戶,即在瀏覽器上顯示加載 – aWebDeveloper

1

我有一篇文章解釋瞭如何在我的博客上使用apache/mod_php來實現這一點:http://codehackit.blogspot.com/2011/07/how-to-kill-http-connection-and.html希望這有助於歡呼

+7

如果您在此處添加了一小段代碼,這將對您有所幫助,因此如果您的網站出現故障,我們仍然可以在此處找到答案。你在你的博文中寫的代碼有效。但是,如果您之前告訴apache gzip您的內容,它將不再有效(因爲長度將不再正確) – Zombaya

-1

用途:

header("Content-Length: $len"); 

..where $len是數據的長度刷新到客戶端。

我沒有背景,知道何時何這是去工作,但我想在幾個瀏覽器,並且所有立刻回到:

<?PHP 
    header("Content-length:5"); 
    echo "this is more than 5"; 
    sleep(5); 
?> 

編輯:瀏覽器,IE瀏覽器,並Opera顯示this,而FireFox顯示this is more than 5。儘管如此,他們都關閉了請求。

+0

這就是爲什麼內容長度需要與實際內容長度相同的原因。謹防gzip,因爲這會改變你的回覆的長度。 – Zombaya

+0

@ Zombaya,我不明白這是如何相關的。只要他沒有試圖在一定量之後切斷他的輸出,就應該在發送必要的數據後結束請求。 – mowwwalker

+0

那麼,當我嘗試這樣做,並且長度與實際長度不匹配時,連接不會總是關閉並繼續加載。 – Zombaya

15

我在過去做到了這一點,這是我如何解決它:

ob_start(); 

/* 
* Generate your output here 
*/ 

// Ignore connection-closing by the client/user 
ignore_user_abort(true); 

// Set your timelimit to a length long enough for your script to run, 
// but not so long it will bog down your server in case multiple versions run 
// or this script get's in an endless loop. 
if ( 
    !ini_get('safe_mode') 
    && strpos(ini_get('disable_functions'), 'set_time_limit') === FALSE 
){ 
    set_time_limit(60); 
} 

// Get your output and send it to the client 
$content = ob_get_contents();   // Get the content of the output buffer 
ob_end_clean();      // Close current output buffer 
$len = strlen($content);    // Get the length 
header('Connection: close');   // Tell the client to close connection 
header("Content-Length: $len");  // Close connection after $len characters 
echo $content;      // Output content 
flush();        // Force php-output-cache to flush to browser. 
            // See caveats below. 

// Optional: kill all other output buffering 
while (ob_get_level() > 0) { 
    ob_end_clean(); 
} 

正如我在一對夫婦的意見之前說的,你應該注意使用gzip壓縮您的內容,因爲這將改變你的內容的長度,但不改變它的標題。它也可以緩衝你的輸出,所以它不會立即發送給客戶端。
你可以試着讓apache知道不使用apache_setenv('no-gzip', '1');來gzip你的內容。但是如果你使用rewrite-rules進入你的頁面,這將不起作用,因爲那樣它也會修改這些環境變量。至少,它是爲我做的。

查看更多關於將您的內容刷新到manual中的用戶的警告。

+0

只是一個FYI的PHP函數是ob_get_content ** S ** –

+1

發現故意的錯誤。 $ len!= $ size; –

+1

@LukeOliff,謝謝你的提醒,改變了它。 – Zombaya

4

這是我的功能

function bg_process($fn, $arr) { 
    $call = function($fn, $arr){ 
     header('Connection: close'); 
     header('Content-length: '.ob_get_length()); 
     ob_flush(); 
     flush(); 
     call_user_func_array($fn, $arr); 
     }; 
    register_shutdown_function($call, $fn, $arr); 
    } 

包到底要執行的功能,PHP後關閉連接。當然瀏覽器會停止緩衝。

function test() { 
    while (true) { 
     echo 'this text will never seen by user'; 
     } 
    } 

這是如何調用該函數

bg_process('test'); 

第一個參數是callable, 第二個參數是一個數組要傳遞給「測試」功能與索引數組

注:在腳本開始處我不使用ob_start()