PHP为带有系统调用的脚本设置超时,设置时间限制不工作
我有一个命令行PHP脚本,它使用foreach数组的每个成员运行wget请求。这个wget请求有时可能需要很长时间,因此我希望能够设置一个超时,以便在超过15秒时终止脚本。我已经禁用了PHP安全模式,并尝试在脚本的早期设置时间限制(15),但是它会无限期地继续更新:感谢Dor指出这是因为set_time_limit()不尊重system()调用 因此,我试图找到其他方法在执行15秒后杀死脚本。但是,我不确定是否可以检查脚本运行的时间,同时它在WGET请求的中间(Do-while循环不工作)。也许用一个计时器分叉一个进程,并将其设置为在一段时间后杀死父进程 谢谢你的提示 更新: 下面是我的相关代码$url是从命令行传递的,是多个url的数组(很抱歉最初没有发布此内容):PHP为带有系统调用的脚本设置超时,设置时间限制不工作,php,windows,linux,command-line,Php,Windows,Linux,Command Line,我有一个命令行PHP脚本,它使用foreach数组的每个成员运行wget请求。这个wget请求有时可能需要很长时间,因此我希望能够设置一个超时,以便在超过15秒时终止脚本。我已经禁用了PHP安全模式,并尝试在脚本的早期设置时间限制(15),但是它会无限期地继续更新:感谢Dor指出这是因为set_time_limit()不尊重system()调用 因此,我试图找到其他方法在执行15秒后杀死脚本。但是,我不确定是否可以检查脚本运行的时间,同时它在WGET请求的中间(Do-while循环不工作)。也许
您可以将wget程序的输出定向到一个文件,然后该文件立即返回。
另见: 注意:set_time_limit()函数 和配置指令 最大执行时间仅影响 脚本本身的执行时间。 任何花在这方面的时间 在执行 脚本,例如使用 system()、流操作、数据库 在以下情况下不包括查询等: 确定 脚本已经运行。这不是 在测量到 时间是真实的
来源:@php.net除了
设置时间限制()
之外,还可以尝试使用wget命令行参数--timeout
请记住set\u time\u limit(15)
从零开始重新启动超时计数器,因此不要在循环内调用它(出于您的目的)
从man wget
:
--超时=秒
设置网络
超时至秒。这是
相当于指定
--dns超时、-连接超时和-读取超时,所有这些都在同一时间
与网络互动时,,
Wget可以检查超时和中止
如果需要太长时间,请停止操作。
这可以防止像挂起这样的异常情况
读取和无限连接。唯一的
默认情况下启用的超时是
900秒读取超时。设定
超时到0将完全禁用它。
除非你知道你在做什么,否则它会
最好不要更改默认值
超时设置
所有与超时相关的选项都接受
十进制值以及次秒
价值观例如,0.1秒是一个
合法(尽管不明智)的选择
超时。亚秒超时为
用于检查服务器响应
用于测试网络延迟的时间或
编辑:确定。我知道你现在在做什么。您可能应该做的是使用而不是
system
,并使用time()
函数检查时间,如果wget tskes太长,则调用该函数。您可以使用“-timeout”和time()的组合。首先计算您总共有多少时间,然后在脚本运行时降低--timeout
例如:
$endtime = time()+15;
foreach( $url as $key => $value){
$timeleft = $endtime - time();
if($timeleft > 0) {
$wget = "wget -t 1 --timeout $timeleft $otherwgetflags $value";
print "running $wget<br>";
system($wget);
} else {
print("timed out!");
exit(0);
}
}
$endtime=time()+15;
foreach($url作为$key=>$value){
$timeleft=$endtime-time();
如果($timeleft>0){
$wget=“wget-t1——超时$timeleft$otherwgetflags$value”;
打印“运行$wget
”;
系统(wget);
}否则{
打印(“超时!”);
出口(0);
}
}
注意:如果您不使用-t,wget将尝试20次,每次等待--timeout秒
下面是一些使用proc_open/proc_terminate(@Josh的建议)的示例代码:
$descriptorspec=数组(
0=>数组(“管道”、“r”),
1=>数组(“管道”,“w”),
2=>阵列(“管道”,“w”)
);
$pipes=array();
$endtime=time()+15;
foreach($url作为$key=>$value){
$wget=“wget$otherwgetflags$value”;
打印“正在运行$wget\n”;
$process=proc_open($wget,$descriptorspec,$pipes);
如果(是_资源($process)){
做{
$timeleft=$endtime-time();
$read=数组($pipes[1]);
stream_select($read,$write=NULL,$exeptions=NULL,$timeleft,NULL);
如果(!空($read)){
$stdout=fread($pipes[1],8192);
打印(“wget said--$stdout--\n”);
}
}而(!feof($pipes[1])&&$timeleft>0);
如果($timeleft我认为最好的方法是在命令本身中处理杀戮,至少在Linux(Ubuntu 17.10)上是这样。没有其他方法对我有效…proc_terminate
来自另一个答案的方法有效,但不会给出输出
在下面的示例中,我添加了一个神奇的字符串来检查您的进程是否仍在运行。如果运行时间超过$sec
,它会立即终止进程,并留下一个注释“Timeout!”
这样,我确信命令不会超过超时时间,并且我会收到我需要的所有stdout/stderr
$wget = "wget -r -H -nd -l 999 $value"; // your command
$sec = 5; // timeout in seconds
$cmd = $wget . " & ii=0 && while [ \"2\" -eq \"`ps -p $! | wc -l \" ]; do ii=$((ii+1)); if [ \$ii -gt ".($sec)."0 ]; then echo 'Timeout!';kill $!; break;fi; sleep 0.1; done"
system($cmd); // system call
+1.他还需要限制wget的执行时间,请参见我的answer@Josh:我想他指的是PHP脚本:“因此,我希望能够设置一个超时,以便在脚本超过15秒时终止该脚本”。但注意wget超时也是值得赞赏和有益的:)是的,但正如您所说,set_time_limit对wget这样的外部命令没有影响——因此要限制脚本的总时间(包括wget,因为它是从脚本调用的),wget也必须是有限的。无论如何,这是我对问题的理解…感谢您的帮助,但不幸的是,这不符合我的目的。我很抱歉没有发布相关代码,这会使问题更加清楚(请参阅上面更新的问题代码)。因此,wget的timeout参数只是为每个wget请求设置超时,而不是为整个脚本设置超时。因此,当我向脚本传递5个URL时,每个URL的超时时间为20秒,这至少总共是100秒,通常由于递归选项的缘故。Dor high
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w")
);
$pipes = array();
$endtime = time()+15;
foreach( $url as $key => $value){
$wget = "wget $otherwgetflags $value";
print "running $wget\n";
$process = proc_open($wget, $descriptorspec, $pipes);
if (is_resource($process)) {
do {
$timeleft = $endtime - time();
$read = array($pipes[1]);
stream_select($read, $write = NULL, $exeptions = NULL, $timeleft, NULL);
if(!empty($read)) {
$stdout = fread($pipes[1], 8192);
print("wget said--$stdout--\n");
}
} while(!feof($pipes[1]) && $timeleft > 0);
if($timeleft <= 0) {
print("timed out\n");
proc_terminate($process);
exit(0);
}
} else {
print("proc_open failed\n");
}
}
$wget = "wget -r -H -nd -l 999 $value"; // your command
$sec = 5; // timeout in seconds
$cmd = $wget . " & ii=0 && while [ \"2\" -eq \"`ps -p $! | wc -l \" ]; do ii=$((ii+1)); if [ \$ii -gt ".($sec)."0 ]; then echo 'Timeout!';kill $!; break;fi; sleep 0.1; done"
system($cmd); // system call