2011-07-14 154 views
6

爲什麼如果客戶端關閉瀏覽器(因此連接到服務器),此虛擬腳本會繼續運行事件?PHP腳本不會在瀏覽器退出時退出

 
while (true) 
{ 
    sleep(1); 
    file_put_contents('/tmp/foo' , "I'm alive ".getmypid()."\n" , FILE_APPEND); 
} 

根據this,我感到意外。另外this示例似乎不起作用。

而且帶有非零參數的set_time_limit根本什麼都不做。

我想澄清一下。

+0

您忽略了用戶中止,而沒有向客戶端做任何輸出。 – hakre

回答

9

如果您嘗試在該循環中將一些輸出寫入瀏覽器,您應該發現如果連接已終止,腳本將中止。這種行爲是在文檔中暗示了ignore_user_abort

當運行PHP命令行腳本,腳本的TTY去 遠沒有腳本被終止,則該腳本將嘗試寫 下一次死亡任何東西,除非值設置爲TRUE

我嘗試了一些自己的實驗,結果發現,即使你嘗試一些瀏覽器輸出,該腳本將繼續運行,如果輸出緩衝區還沒有滿。如果關閉輸出緩衝,則在嘗試輸出時腳本將中止。這是有道理的 - 當SAPI層嘗試傳輸輸出時,應該注意到請求已被終止。

下面是一個例子...

//ensure we're not ignoring aborts.. 
ignore_user_abort(false); 

//find out how big the output buffer is 
$buffersize=max(1, ini_get('output_buffering')); 


while (true) 
{ 
    sleep(1); 

    //ensure we fill the output buffer - if the user has aborted, then the script 
    //will get aborted here 
    echo str_repeat('*', $buffersize)."\n"; 

    file_put_contents('/tmp/foo' , "I'm alive ".getmypid()."\n" , FILE_APPEND); 
} 

演示什麼觸發中止。如果你有一個腳本很容易進入一個沒有輸出的無限循環,你可以使用connection_aborted()來測試連接是否仍然打開。

+0

試過,同樣的行爲。 – cYrus

+0

@cYrus:你試過了什麼。請在你的問題代碼中反映出來。您需要禁用忽略用戶中止。默認設置是在IIRC上。 – hakre

+0

@Paul:你能提供工作代碼嗎? – cYrus

1

set_time_limit只限制花費在php代碼上的時間。大部分時間(我猜測> 99.9%)在您的程序中花費在系統調用中,將數據寫入文件並進行睡眠。

ignore_user_abort只有當你(而不是在本地文件)寫的東西到客戶端中止 - 有根本沒有辦法可以在TCP區分未使用和終止的連接,否則,除非客戶excplicitely終止連接與RST數據包。

+0

這解釋了'set_time_limit',寫一些東西沒有做任何改變。 – cYrus

+0

需要寫入*輸出*來觸發用戶中止傳感IIRC。 - http://www.php。net/manual/en/features.connection-handling.php – hakre

+0

@hakre是的,當然隨機本地文件對TCP連接沒有影響。更新。 – phihag