我正在尝试制作一个 PHP 脚本,我已经完成了脚本,但它需要 10 分钟才能完成它设计的过程。这不是问题,但是我认为我必须一直保持页面加载,这很烦人。我可以拥有它以便我开始该过程,然后在 10 分钟后返回并查看它生成的日志文件吗?
10 回答
好吧,你可以使用“ ignore_user_abort (true)”
所以脚本将继续工作(密切关注脚本持续时间,也许添加“ set_time_limit(0)”)
但是这里有一个警告:您将无法使用以下两行停止脚本:
ignore_user_abort(true);
set_time_limit(0);
除了你可以直接访问服务器并杀死那里的进程!(去过那里,做了一个无限循环,一遍又一遍地调用自己,让服务器尖叫着停下来,被大喊大叫......)
听起来您应该有一个队列和一个用于处理队列的外部脚本。
例如,您的 PHP 脚本应该将一个条目放入数据库表并立即返回。然后,每分钟运行的 cron 会检查队列并为每个作业派生一个进程。
这里的优点是您不会将 apache 线程锁定 10 分钟。
在 Windows 下,我对这种过程有很多问题;我的情况有点不同,因为我不关心“脚本”的响应——我希望脚本启动并允许其他页面请求在它忙于工作时通过。
由于某些原因; 我遇到了问题,要么挂起其他请求,要么在大约 60 秒后超时(apache 和 php 都设置为在大约 20 分钟后超时);事实证明,firefox 无论如何都会在 5 分钟后超时(默认情况下),所以在那之后,如果不更改 firefox 中的设置,您将无法知道浏览器发生了什么。
我最终使用进程打开和进程关闭方法在 cli 模式下打开一个 php,如下所示:
pclose(popen("start php myscript.php", "r"));
这将(使用 start )打开 php 进程,然后终止启动进程,让 php 运行所需的时间 - 同样,您需要终止该进程以手动将其关闭。它不需要您设置任何超时,您可以让调用它的当前页面继续并输出更多详细信息。
唯一的问题是,如果您需要向脚本发送任何数据,您要么通过另一个来源进行,要么将其作为参数传递给“命令行”;这不是那么安全。
很好地满足了我们的需要,并确保脚本始终启动并允许运行而不会中断。
我认为 shell_exec 命令是您正在寻找的。
但是,它在安全模式下被禁用。
关于它的 PHP 手册文章在这里: http: //php.net/shell_exec
这里有一篇关于它的文章:http: //nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/
您可以使用另一个选项,运行脚本 CLI...它将在后台运行,您甚至可以根据需要将其作为 cronjob 运行。
例如
> #!/usr/bin/php -q
<?php
//process logs
?>
这可以设置为 cronjob 并且将不受时间限制地执行....虽然这个示例适用于基于 unix 的操作系统。
仅供参考,我有一个运行无限循环的 php 脚本,该脚本执行一些处理,并且在过去 3 个月中一直在不停地运行。
您可以使用ignore_user_abort()
- 即使您关闭浏览器或转到其他页面,脚本也将继续运行。
除了 bastiandoeen 的回答,您还可以结合ignore_user_abort(true);
cUrl request。
将请求中止设置为低CURLOPT_TIMEOUT_MS
并在连接关闭后继续处理:
function async_curl($background_process=''){
//-------------get curl contents----------------
$ch = curl_init($background_process);
curl_setopt_array($ch, array(
CURLOPT_HEADER => 0,
CURLOPT_RETURNTRANSFER =>true,
CURLOPT_NOSIGNAL => 1, //to timeout immediately if the value is < 1000 ms
CURLOPT_TIMEOUT_MS => 50, //The maximum number of mseconds to allow cURL functions to execute
CURLOPT_VERBOSE => 1,
CURLOPT_HEADER => 1
));
$out = curl_exec($ch);
//-------------parse curl contents----------------
//$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
//$header = substr($out, 0, $header_size);
//$body = substr($out, $header_size);
curl_close($ch);
return true;
}
async_curl('http://example.com/background_process_1.php');
注意
如果您希望 cURL 在不到一秒的时间内超时,您可以使用 CURLOPT_TIMEOUT_MS,尽管“类 Unix 系统”上存在一个错误/“功能”,如果该值小于 1000 毫秒,则会导致 libcurl 立即超时并出现错误“ cURL 错误 (28): 已超时”。这种行为的解释是:
[...]
解决方案是使用 CURLOPT_NOSIGNAL 禁用信号
优点
- 无需切换方法(兼容windows & linux)
- 无需通过 headers 和 buffer 实现连接处理(独立于浏览器和 PHP 版本)
缺点
- 需要卷曲扩展
资源
祖克。
我很确定这会起作用:
<?php
pclose(popen('php /path/to/file/server.php &'));
echo "Server started. [OK]";
?>
'&' 很重要。它告诉外壳程序不要等待进程退出。
您也可以在您的 php 中使用此代码(如“bastiandoeen”所说)
ignore_user_abort(true);
set_time_limit(0);
在您的服务器停止命令中:
<?php
$output;
exec('ps aux | grep -ie /path/to/file/server.php | awk \'{print $2}\' | xargs kill -9 ', $output);
echo "Server stopped. [OK]";
?>
只需在任何输出之前调用 StartBuffer(),当您希望客户端关闭连接时调用 EndBuffer()。调用 EndBuffer() 后的代码将在没有客户端连接的服务器上执行。
私有函数 StartBuffer(){ @ini_set('zlib.output_compression',0); @ini_set('implicit_flush',1); @ob_end_clean(); @set_time_limit(0); @ob_implicit_flush(1); @ob_start(); } 私有函数 EndBuffer(){ $size = ob_get_length(); header("内容长度:$size"); header('连接:关闭'); ob_flush();ob_implicit_flush(1); }