PHP脚本能否在用户关闭浏览器后继续运行?

26
例如,有一个非常简单的PHP脚本用于更新数据库上的一些表格,但该过程需要很长时间(可能需要10分钟)。因此,即使用户关闭了浏览器,我也希望这个脚本能够继续处理,因为有时候用户不想等待并关闭了浏览器或者跳转到另一个网页。

如果我想要将浏览器请求与作业执行解耦,那么我该如何请求另一个 PHP 脚本,同时让用户的当前请求正常继续呢?因此,当用户请求任何 URL 时,该请求将启动另一个脚本(该脚本独立于用户浏览器和其他请求之外运行)。而用户将继续正常浏览该网站。 - Oguz Bilgic
7个回答

22
如果任务需要花费10分钟,不要直接使用浏览器执行它。你有很多其他选择:
  • 使用cronjob定期执行任务。
  • 让浏览器请求插入一行新数据到数据库表中,这样定期的cronjob可以处理新数据行并使用适当的参数执行PHP脚本。
  • 让浏览器请求将消息写入队列系统,该系统具有侦听此类事件的订阅者(然后执行脚本)。
虽然这些建议可能对您的情况来说有些过头了,但关键的联合特征是将浏览器请求与作业执行分离,以便可以异步地完成任务。
如果您需要更新浏览器窗口的进度,您需要使用定期执行的AJAX请求来检索作业状态。

如果我想将浏览器请求与作业执行解耦,那么我该如何在用户当前请求正常进行的情况下请求另一个PHP脚本呢?因此,当用户请求任何URL时,该请求将启动另一个脚本(该脚本独立于用户浏览器和其他请求之外运行)。而用户将继续正常地浏览网站。我该如何做到这一点? - Oguz Bilgic
看到那些项目符号了吗?这些都是实现此操作的方法。在大多数情况下,设置一个小型数据库表来保存后台进程的输入就可以了。然后,您可以启动一些 PHP 脚本来执行作业,可以通过 cron 或其他方法来执行。 - timdev
你需要将一个工作记录放在数据库的队列中。该记录可以包含用户提供给你的任何数据。定时任务会查看队列,获取下一个工作记录,读取用户提供的参数,然后使用这些输入来完成它的工作。仔细阅读David的第二个要点,这正是你想要做的。 - timdev
我该如何执行数据库中新行记录的 PHP URL(而不是脚本),因为我使用框架。因此,常规的定时作业可以处理。 - Oguz Bilgic

19
为了直接回答您的问题,请查看ignore_user_abort
更广泛地说,您可能在这里面临一个架构问题。
如果有许多用户可以启动此操作,您将希望网页应用程序将作业添加到某种队列中,并拥有一组处理所有工作的后台进程。

6

这个 PHP 脚本会在客户端断开连接后继续运行(不这样做将是一种安全风险),但只能在 max_execution_time 之内保持运行状态(通常默认为30秒,可以在 php.ini 或 PHP 脚本中设置)。

例如:

<?php
    $fh = fopen("bluh.txt", 'w');
    for($i=0; $i<20; $i++) {
        echo $i."<br/>";
        fwrite($fh,$i."\n");
        sleep(1);
    }
    fclose($fh);
?>

在浏览器中运行此代码,并在代码执行完成前关闭浏览器。你会发现,20秒后,该文件包含了所有$i的值。

将for循环的上限改为100而不是20,你会发现它只运行了0到29。由于PHP的max_execution_time,脚本超时并停止运行。


不错的答案。但是,如果脚本尝试将输出刷新到浏览器而不是写入文件,例如使用 echo "..."; flush(); ob_flush();,会怎样呢?我认为脚本将终止,因为输出流将不再可用。 - ban-geoengineering
@ban-geoengineering,一开始我也认为你是正确的,但我测试了你的建议(上面的代码已经每秒使用´echo´),但在我的系统上,当标签关闭时脚本并没有中止。很奇怪。 - Max

2
如果脚本完全基于服务器(没有向用户提供反馈),即使客户端关闭,也会执行该操作。
PHP的一般架构是,客户端发送请求到脚本,脚本向用户返回回复。如果没有向用户返回任何内容,即使用户不在另一端,脚本仍将执行。简单来说,常规脚本中服务器和客户端之间没有恒定的连接。

1

您可以使用包含时间和要运行的命令的crontab文件,使PHP脚本每20分钟运行一次,在这种情况下,它将是php脚本。


0

是的。服务器不知道用户是否关闭了浏览器。至少它不会立即注意到。

不会:服务器可能(取决于其配置方式)不允许php脚本运行10分钟。在廉价共享主机上,我不会依赖脚本运行超过合理的响应时间。


-1
一个服务器端的脚本将会继续执行它正在做的事情,不管客户端在做什么。
编辑:顺便问一下,您确定要打开需要10分钟的页面吗?我建议您使用任务队列(其项目会按时执行)并将用户重定向到“好的,我正在处理”页面。

并不完全正确:通常会有守卫来“杀死”运行时间较长的 PHP 脚本,这些守卫采用 crontab 条目的形式。 - jldupont
@jldupont:我不是 PHP 方面的专家,但是这些脚本与客户端有关吗? - shanyu
1
@shanyu - 不确定jldupont在说什么。PHP有一些配置变量可以终止长时间运行的脚本,但它们与cron没有任何关系。 - timdev
这并不是真的,服务器端脚本并不总是不管客户端而继续执行... - rmorse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接