一尘不染

PHP为系统调用的脚本设置超时,set_time_limit不起作用

linux

我有一个命令行PHP脚本,该脚本使用带有foreach的数组的每个成员运行wget请求。这个wget请求有时可能会花费很长时间,因此,例如,如果它超过15秒,我希望能够设置超时以终止脚本。我禁用了PHP安全模式,并在脚本的早期尝试了set_time_limit(15),但是它会无限期地继续。
更新: 感谢Dor指出这是因为set_time_limit()不尊重system()调用。

因此,我试图找到其他方法来在执行15秒后杀死脚本。但是,我不确定是否可以同时在wget请求中间检查脚本运行的时间(do
while循环不起作用)。也许用一个计时器派生一个进程,并将其设置为在一定时间后杀死父进程?

感谢您的提示!

更新: 以下是我的相关代码。$ url是从命令行传递的,它是多个URL的数组(很抱歉,最初没有发布此URL):

foreach( $url as $key => $value){
    $wget = "wget -r -H -nd -l 999 $value";
    system($wget);
    }

阅读 999

收藏
2020-06-03

共1个答案

一尘不染

您可以结合使用“ –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);
  }
}

注意:如果不使用-t,wget将尝试20次,每次等待–timeout秒。

这是使用proc_open / proc_terminate(@Josh的建议)的一些示例代码:

$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");
  }
}
2020-06-03