如何在服务器中运行PHP代码的同时阻止PHP向客户端发送数据?

Mar*_*cia 4 php http

当我遇到一个导致我的PHP程序无限循环的错误时,这个问题就出现了.以下是一个示例情况:

假设我有一个接收图片上传的PHP网页(该页面可能是图片上传表单的响应页面).在服务器中,脚本应将图像存储在临时文件中.然后,脚本应该向客户端输出确认消息,然后停止发送数据,以便客户端不会等待.然后脚本应该继续执行,在结束之前处理图像(如调整大小).

我认为这种"技术"可能是有用的,这样客户就不会在耗时的过程中等待,从而防止超时.

此外,这可以使用HTTP方法解决吗?

rdl*_*rey 11

是.

如果您正确使用HTTP标头,则无需任何异步处理即可轻松完成此操作.

在正常情况下,只要另一端的客户端关闭连接,PHP就会停止处理.如果你想在这个事件之后继续处理,你需要做一件事:告诉PHP忽略用户中止.怎么样?

ignore_user_abort()

这将允许您的脚本即使在客户端躲闪后也能继续运行.但我们也面临着如何告诉客户他们所做的请求已完成以便关闭连接的问题.通常,如果我们不指定它们,PHP会透明地处理为我们发送这些标头.但是,我们需要明确地执行此操作,否则客户端将不知道我们何时希望它们停止读取响应.

为此,我们必须发送适当的HTTP标头以告知客户端何时关闭:

Connection: close
Content-Length: 42
Run Code Online (Sandbox Code Playgroud)

这种标头组合告诉客户端,一旦它读取42字节的实体主体响应,消息就完成了,并且它们应该关闭连接.这种方法有几个后果:

  1. 您必须发送任何输出之前生成响应,因为您必须确定其内容长度大小(以字节为单位),以便您可以发送正确的标头.
  2. 回显任何输出之前,您必须实际发送这些标题.

所以你的脚本看起来像这样:

<?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 ---
Run Code Online (Sandbox Code Playgroud)

使用此方法的大"Gotchya"是,当您在Web SAPI中运行PHP时,如果在最终用户客户端关闭连接后执行耗时的处理,则可以轻松地针对最大时间限制指令运行.如果这是一个问题,您可能需要考虑使用cron的异步处理选项,因为PHP在CLI环境中运行时没有时间限制.或者,您可以使用set_time_limitdocs在Web环境中提高脚本的时间限制.

值得一提的是,如果您执行此类操作,您可能还需要在生成响应正文时向connection_aborted()文档添加检查,以便在完成传输之前用户中止时可以避免其他处理.

  • 这个答案需要更多的牛铃. (5认同)