如何在Unix服务器上后台运行PHP代码

4
在我的网站上,我有一些功能允许用户上传数据源。这些数据源通常有超过30,000条记录。并且每个记录需要经过复杂的验证过程。因此,简单地处理这些数据源将需要超过1小时的时间才能完成任务。这个长时间运行的过程是不可避免的。
这些数据源由公共用户上传。而数据源大小小于5MB的文本文件。所以我们不想给FTP访问权限,也不想给这些用户命令行访问权限。我们只想通过Web访问来上传数据源。并且我们必须在他们上传后立即处理这些数据源。一旦处理完成,我们还必须发送邮件报告给他们。
现在的问题是长时间运行的网页会在许多网络上抛出一些代理超时问题(因为它需要1小时才能响应)。这是大多数客户端网络配置的问题。
我需要一种方法来触发一个PHP脚本一旦上传了数据源。并且该脚本应该在后台运行,同时完整地完成页面加载而不延迟客户端。
一旦处理完成,我将使后台处理数据并向客户端发送电子邮件。由于客户端可能只在几个月内使用这些功能,并且在意外的时间范围内使用,因此无法使用Cron表。
如果有任何方法可以通过网络访问来触发PHP脚本在后台运行,请告诉我。
一个简化需求的样例脚本
假设这个例子并帮助我修改这个脚本以实现结果。我有两个PHP脚本"thread.php和createfile.php"。名为"thread.php"的文件将由客户端通过Web浏览器打开。此脚本需要执行脚本"createfile.php"。但它将花费20秒来响应。但我们希望允许它在后台运行。并立即在浏览器中显示输出。
以下是示例脚本的代码。
createfile.php(http://sugunan.net/demo/createfile.php
<?php
sleep(20);
@unlink("phpfile.txt");
$myfile = fopen("phpfile.txt", "w") or die("Unable to open file!");
$txt = date("h:i:s")."\n";
fwrite($myfile, $txt);
fclose($myfile);
mail("someone@example.com","Background process","Process completed");
?>

创建的文件可以通过网址访问:http://sugunan.net/demo/phpfile.txt

thread.php (http://sugunan.net/demo/thread.php)

<pre>
<?php
echo "Script start at: " . date('h:i:s') . "\n";
include("createfile.php"); //give a method to execute this script but in background without delay
echo "Script end at: " . date('h:i:s');
?>

这将使用sleep()函数延迟,给出以下输出结果。

脚本开始时间:02:53:27

脚本结束时间:02:53:47

有没有办法在不使用include()方法的情况下执行"createfile.php"?并且避免在后台处理"createfile.php"时等待20秒的sleep延迟?
请注意,我想避免客户端等待时间,并立即在浏览器上输出结果。

请查看此处:https://dev59.com/U2Yr5IYBdhLWcg3wOX26#13872965 - Donal
1
可能是PHP线程调用PHP函数异步的重复问题。 - Marcin Orlowski
感谢您的评论和答案。我已经放置了带有可访问的网址的示例代码。您能否提供建议,如何修改这些脚本以避免延迟但在后台处理? - sugunan
@ Marcin Orlowski:我尝试了与类似问题中提出的并行处理建议。它可以很好地进行并行处理。但是,这又会等待在浏览器中输出结果。如果延迟发生在浏览器上,那么客户端将再次遇到代理超时问题。以下示例是我尝试过的一个示例。http://www.mullie.eu/parallel-processing-multi-tasking-php/ - sugunan
@Marcin Orlowski:我从另一个堆栈溢出的答案中找到了可行的解决方案:https://dev59.com/Xm865IYBdhLWcg3wa-A0#3819422 。相关问题和所选答案符合我的要求。如果你愿意,你可以把我的问题标记为那个问题的副本。 - sugunan
3个回答

1

使用exec()

http://php.net/manual/en/function.exec.php

这将允许你在另一个线程中运行长时间的进程。我已经使用它来转换wav到mp3,视频转换或解析大型XML文件的所有其他PHP、Python或C应用程序...请确保在完成时通过电子邮件通知你或用户,如果成功则通知。

编辑后的纯人类信息网站演示中提供了可工作的代码...现在它实际上会写入文件。 thread.php应该看起来像这样:

<?php 
    echo "Script start at: " . date('h:i:s') . "\n"; 
    exec("php -f  createfile.php /dev/null &"); 
    echo "Script end at: " . date('h:i:s'); 
?> 

如果您正在使用Windows:
<?php 
    echo "Script start at: " . date('h:i:s') . "\n"; 
    exec("start /B php createfile.php"); //obviously change the paths etc where needed..
    echo "Script end at: " . date('h:i:s'); 
?> 

需要给Windows部分提供信用:如何使用EXEC()和CMD在后台执行PHP脚本


我把您最后编辑的代码放在这里:http://sugunan.net/demo/thread1.php,但仍有延迟。请单击并查看需要多长时间。 - sugunan
我正在使用Godaddy的Linux托管服务。感谢您的帮助。但是,无论如何,我从以下帖子中得到了答案:https://dev59.com/Xm865IYBdhLWcg3wa-A0#3819422 这是相同的问题和可行的解决方案。 - sugunan
我最初放了 nohup 代码,但它并不需要。你介意从这里删除 -1 吗?我的意思是,它已经能正常工作了 :-) - Chemdream
我在不使用扩展的bash代码的情况下可以正常工作。 - Chemdream
实际上,如果您查看Cristian以下的答案,它几乎与我的相同,并且适用于其他人。它可能取决于您的配置... - Chemdream
显示剩余3条评论

0

PHP并不是为这种工作而设计的。但有一些技巧可以尝试做到。

如果您的源有超过30,000条记录,使用PHP FPM会出现超时问题。因此,您的脚本必须使用PHP CLI运行(检查PHP CLI超时的服务器参数)。

您应该查看Rabbit MQ并编写一个每分钟消费队列中的消息的cron作业。这里有一个使用PHP的示例http://www.rabbitmq.com/tutorials/tutorial-two-php.html

希望这能帮助到您


CLI很好。但如果它是每月几次活动,就没有理由每分钟运行cron。而且我们需要在客户完成上传后立即处理此脚本。 - sugunan

0

最终我从以下帖子中得到了一个可行的答案:php exec命令(或类似命令)以不等待结果的方式

所以我编辑了代码,使其按照以下方式工作。但我不知道它是如何工作的解释。我只是从那个答案中复制了语法,并在此处进行了修改。

<?php 
echo "Script start at: " . date('h:i:s') . "\n"; 
exec('bash -c "exec nohup php createfile.php > /dev/null 2>&1 &"');
echo "Script end at: " . date('h:i:s'); 
?>

这里php createfile.php将是执行PHP脚本并继续而不等待输出的命令。

感谢Cristian


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