2011-07-14 96 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