【问题标题】:PHP script doesn't exit on browser exitPHP脚本不会在浏览器退出时退出
【发布时间】:2011-07-14 19:24:45
【问题描述】:

如果客户端关闭浏览器(因此连接到服务器),为什么这个虚拟脚本会继续运行事件?

而(真) { 睡眠(1); file_put_contents( '/tmp/foo' , "我还活着 ".getmypid()."\n" , FILE_APPEND ); }

根据this,这出乎我的意料。 this 的例子似乎也不起作用。

而带有非零参数的set_time_limit 根本什么都不做。

我想澄清一下。

【问题讨论】:

  • 您忽略了用户中止,而没有向客户端执行任何类型的输出。

标签: php termination


【解决方案1】:

如果您尝试在该循环中向浏览器写入一些输出,您应该会发现如果连接已终止,脚本将中止。 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() 测试连接是否仍然打开。

【讨论】:

  • @cYrus:你试过什么。请在您的问题代码中反映这一点。您需要禁用忽略用户中止。默认设置是在 IIRC 上。
  • @Paul:谢谢它有效!但是有些数据实际上是通过这种方式从服务器发送到客户端的吗?
  • 不,因为连接已中止!我在上面演示的只是脚本在 SAPI 层尝试刷新缓冲区之前不会中止。如果您有特定原因要检查客户端中止,请检查 connection_aborted()
  • 我的意思是在中止之前(客户端关闭浏览器)。好吧,根据wireshark,数据实际上是发送的:*...。无论如何,这解决了我的问题,谢谢!
【解决方案2】:

set_time_limit 只限制花在 php 代码上的时间。程序中的大部分时间(我猜 >99.9%)都花在系统调用、将数据写入文件和休眠中。

ignore_user_abort 仅在您向客户端写入内容时中止(不在本地文件中) - 在 TCP 中,您根本无法区分未使用和终止的连接,除非客户端使用 RST 数据包明确终止连接。

【讨论】:

  • 这就解释了set_time_limit,写东西不会做任何改变。
  • 需要写入 输出 以触发用户中止感应 IIRC。 -- php.net/manual/en/features.connection-handling.php
  • @hakre 是的,当然随机本地文件对 TCP 连接没有影响。已更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 2018-08-21
  • 2023-03-08
  • 2011-12-04
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多