2013-05-13 168 views
7

問題是,對於一個漫長的過程,無論客戶端瀏覽器當前是否連接,PHP腳本都會繼續執行。有沒有可能,如果客戶端已經終止了對腳本的Ajax調用,那麼腳本也會在服務器上終止?我發現這是處理這個超時問題最簡單的辦法如果HTTP請求被取消/關閉,PHP會自動終止腳本

+0

其中的困難是,一個新的AJAX調用必須到服務器上,這涉及到運行第二個PHP腳本來進行。第二個PHP腳本需要訪問由第一個PHP腳本生成的線程。我可以想到多種方式來做到這一點 - 但它不會是自動的。您需要確保編寫您的PHP代碼,以便通過新的獨立創建的線程以某種方式訪問​​或控制原始線程。 – 2013-05-13 14:17:54

+0

實際上,PHP的默認行爲是在客戶端斷開連接時中止進程。 – Jon 2013-05-16 16:39:10

+0

@jon在我的Windows服務器的情況下,它斷開連接後繼續運行。不過,我也不希望PHP僅僅關閉這個過程。我需要ROLLBACK數據庫事務並安全地關閉它。 – 2013-05-16 16:43:46

回答

8

正如指出的@metadings PHP確實有一個函數來檢查是否存在名爲connection_aborted連接中止()。它將返回1,如果連接否則爲0

終止在一個長長的服務器端程序,用戶可能需要知道,如果客戶端 從服務器斷開或者他已經關閉了瀏覽器,則 服務器可以安全地關閉該過程。

尤其是在應用程序使用php會話的情況下,如果我們在客戶端斷開連接後仍然運行長進程,那麼服務器將無法響應此會話。並且來自同一客戶端的任何其他請求將等到先前的進程完全執行。造成這種情況的原因是會話文件在進程運行時被鎖定。然而,你可以通過調用session_write_close()方法來解鎖它。但是這在所有情況下都不可行,可能需要在流程結束時寫入會話。

現在,如果我們只在一個循環中調用connection_aborted(),那麼它總是會返回0,無論連接是否關閉。

0意味着連接不中止。這是誤導。但是,經過重新搜索和實驗後,如果發現輸出緩衝區中的是php的原因。

首先,爲了檢查中止,循環中的開發人員必須通過回顯一些文本向客戶端發送一些輸出。例如:

print " "; 

由於進程仍在運行,輸出將不會發送到客戶端。現在發送輸出,然後我們需要刷新輸出緩衝區。

flush(); 
ob_flush(); 

然後,如果我們檢查中止,那麼它會給出正確的結果。

if (connection_aborted() != 0) { 
    die(); 
} 

以下是工作的例子,這會即使您正在使用PHP會議的工作:

session_start(); 
ignore_user_abort (TRUE); 

file_put_contents ("con-status.txt", "Process started..\n\n"); 

for($i = 1; $i <= 15; $i ++) { 

    print " "; 

    file_put_contents ("con-status.txt", "Running process unit $i \n", FILE_APPEND); 
    sleep (1); 

    // Send output to client 
    flush(); 
    ob_flush(); 

    // Check for connection abort 
    if (connection_aborted() != 0) { 
     file_put_contents ("con-status.txt", "\nUser terminated the process", FILE_APPEND); 
     die(); 
    } 

} 

file_put_contents ("con-status.txt", "\nAll units completed.", FILE_APPEND); 

EDIT 07-APR-2017

如果有人使用快速-Cgi在Windows上,然後他實際上可以終止 CGI線程從內存中斷連接時使用以下代碼:

if (connection_aborted() != 0) { apache_child_terminate(); exit; }

+0

請注意,'ob_flush'應該在'flush'前調用,如果輸出緩衝正在使用中(甚至可能是ob_end_flush?)http://stackoverflow.com/questions/4191385/php-buffer-ob-flush-vs-flush – metadings 2013-07-24 04:04:48

1

一種方法是這樣:

1:服務器爲「處理」上設置的值。開始一個獨立的線程來處理。
2:初始ajax調用返回成功
3:頁面上的javascript進入'等待模式',每10或30或60秒或5或10分鐘或其他任何事情發送新的ajax請求(取決於您的情況)來確定服務器上的值是否仍然設置爲'處理'。
4:獨立線程完成。它將服務器上的值設置爲「完成」。
5:頁面上的javascript進行下一個等待模式查詢,並返回'完成'和相應的數據。

4B:如果時間淫穢量的推移沒有「完成」時,它註冊爲失敗。多少時間是淫穢取決於你的情況。發送ajax調用,將值從'處理'更新爲'取消'。 5b:獨立線程定期檢查狀態以確保它仍然被設置爲'正在處理'。如果它看到模式轉換爲「取消」,它將自行取消。

4

退房PHP connection_aborted()函數。在進行處理時,您可以檢查中止的連接以正常取消進度,就像人們在交互式線程模型中所做的那樣。

+0

哇。我甚至不知道這是在那裏。謝謝! – 2013-05-13 14:52:37

+0

@metadings這似乎不適用於Ajax請求。 ajax請求被終止,並且connection_aborted()仍然返回0.即使我已經通過關閉網頁仍嘗試執行腳本。可能是什麼原因? – 2013-05-13 19:15:06

+0

@metadings函數connection_aborted()有一個錯誤,它會一直返回0看到這個bug:https://bugs.php.net/bug.php?id=54062 ...有沒有其他的選擇? – 2013-05-13 19:34:12