2013-05-13 169 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