当我遇到一个导致PHP程序无限循环的错误时,我想到了这个问题。以下是一个示例情况:
假设我有一个接收图片上传的PHP网页(该页面可能是图像上传表单的响应页面)。在服务器中,脚本应该将图像存储在一个临时文件中。然后脚本应该向客户端输出一条确认消息,然后停止发送数据,这样客户端就不会等待了。然后脚本应该继续执行,在结束之前处理图像(比如调整图像大小)。
我认为这种"技术"可能很有用,这样客户就不会在耗时的过程中等待,从而防止超时。
另外,使用HTTP方法可以解决这个问题吗?
是
如果您正确地使用HTTP头,那么这可以在没有任何异步处理的情况下轻松完成。
在正常情况下,PHP会在另一端的客户端关闭连接后立即停止处理。如果您想在这个事件之后继续处理,您需要做一件事:告诉PHP忽略用户中止。怎样
ignore_user_abort()
这将允许您的脚本即使在客户端摆脱躲避后也能继续运行。但我们也面临着一个问题,即如何告诉客户他们提出的请求已经完成,以便关闭连接。通常,如果我们不指定这些头,PHP会透明地为我们处理发送这些头。不过,在这里,我们需要明确地这样做,否则客户端将不知道我们希望他们何时停止读取响应。
要做到这一点,我们必须发送适当的HTTP头来告诉客户端何时关闭:
Connection: close
Content-Length: 42
这个头的组合告诉客户端,一旦它读取了42字节的实体主体响应,消息就完成了,它们应该关闭连接。这种方法有几个后果:
- 您必须在发送任何输出之前生成响应,因为您必须确定其以字节为单位的内容长度大小,以便发送正确的标头
- 您必须在回显任何输出之前发送这些标头
所以你的脚本可能看起来像这样:
<?php
ignore_user_abort();
// do work to determine the response you want to send ($responseBody)
$contentLength = strlen($responseBody);
header('Connection: close');
header("Content-Length: $contentLength");
flush();
echo $responseBody;
// --- client will now disconnect and you can continue processing here ---
这种方法的最大"Gotchya"是,当你在web SAPI中运行PHP时,如果你在最终用户客户端关闭连接后进行耗时的处理,你可以很容易地遇到最长时间限制指令。如果这是一个问题,您可能需要考虑使用cron的异步处理选项,因为PHP在CLI环境中运行时没有时间限制。或者,您可以使用set_time_limit
docs在web环境中增加脚本的时间限制。
值得一提的是,如果你这样做,你可能还想在生成响应体时向connection_aborted()
docs添加一个检查,这样,如果用户在完成传输之前中止,你就可以避免额外的处理。
当我在twitter上上传图像时,我也遇到了同样的问题;facebook从iphone通过php的web服务。
如果图像上传的处理时间不多,那么你可以查看@Musa
的评论,这可能会对你有所帮助,但如果处理时间太长,那么试试这些步骤。
1. Image store in folder
2. Fetch image from folder using cron
3. Cron run for every 2 min in backend
这将减少您的处理时间。
希望这对你有所帮助。
建议异步执行这些操作。也就是说,制作另一个只处理先前创建的tmp文件的脚本,并使用cron运行它(甚至不涉及apache)。当php作为web服务器模块运行时,它应该专门用于快速形成响应,然后为下一个请求释放资源。
你这样想是在做正确的事情;只需在体系结构上继续前进一小步,并将请求与需要进行的繁重工作完全解耦。
你可以用几种方法#
1#
ob_start();
//output
header("Content-Length: ".ob_get_length());
header("Connection: close");
ob_end_flush();
//do other stuff
2#
使用PHP的system()或exec()关闭Process
3#
使用Shell Script 关闭进程
您可以使用ob_implicit_flush(),
它将打开或关闭隐式刷新。隐式刷新将在每次输出调用后产生刷新操作,因此不再需要显式调用flush()。
参考
如何使用PHP实现此场景?
或
您应该创建一个独立的cron,它将在特定的时间后运行,并以异步的方式执行,不让用户知道正在进行的处理,也不让用户等待。这样,您甚至可以检测到失败的案例。
您还应该尽量减少加载时间。