如何使长时间运行的PHP脚本立即显示成功消息?



目标

我试图创建一个PHP脚本,其中电子邮件一个相当大的(6MB) PDF文件的用户在一个网站上请求它。用户在表单中输入他们的电子邮件地址,提交表单,然后通过PHP Mailer实例将文件发送给他们。用户提交表单时显示一个成功页面。

问题

通过POST方法提交数据后,会有很长的暂停,服务器最终返回404。然而,几分钟后,电子邮件和PDF附件都收到了。

故障诊断/尝试解决方案

我把这个问题归结为PHP Mailer只是花了太长时间来发送电子邮件,因为大的附件。服务器超时并返回404。同时,脚本最终完成处理,然后接收电子邮件。

如果我删除附件,只是发送一个空白的电子邮件,脚本加载得非常快,并显示成功/确认页面。

我考虑过创建一个重定向,但是我发现在PHP中如何实现重定向的解释,据说你应该杀死原始脚本(我不想这样做)。

的问题

我如何允许电子邮件脚本花时间运行,同时立即向用户显示成功消息,使他们不会感到困惑?

这是一个消息队列的任务。将发送邮件所需的所有信息存储在队列中,并让后台任务获取这些信息并发送邮件。如果消息队列插入成功,则向用户显示插入成功消息。

如果你没有访问后台脚本(例如共享主机),你仍然可以有一个直接的响应。只需使用ignore_user_abort(true)并发送正确的Content-Length标头。浏览器将信任该标头并显示响应,而脚本可以继续运行并发送邮件。

另一个解决方案:做一个小技巧,而不是立即在电子邮件中附加一个大文件。给他们PDF文件的下载链接。因此,内容变得太短了。但没有附件

您可以努力创建唯一的URL以供不同的用户下载相同的PDF文件。

不要立即通过电子邮件发送文件,而是将请求存储在数据库中,其中包含发送请求所需的所有详细信息。然后,您可以使用cronjob/计划任务定期(如果您愿意,每分钟一次)检查数据库中是否有未完成的请求,并在后台发送电子邮件。

由于没有提供任何代码,因此可以使用AJAX调用脚本并在任何需要的地方显示成功消息。脚本将被调用,用户将获得消息,并且一旦脚本完成,用户将收到电子邮件。

当然,成功消息不应该在AJAX处理程序中实现,否则消息也会被延迟。

对于异步作业队列(如Gearman或Beanstalk)来说,这是一个很好的用例。

你必须运行一个外部工作进程来等待来自作业服务器的任务。
在web服务器端,只需创建任务,将其发送到作业服务器,并将其分发给工作进程,然后退出PHP脚本。
工作进程将继续发送邮件,而web服务器可以继续处理HTTP请求。

最新更新