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

ref*_*xiv 3 php linux windows command-line

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

所以我试图在执行15秒后找到其他方法来杀死脚本.但是,我不确定是否可以检查脚本在同时处于wget请求中间时运行的时间(while循环不起作用).也许用一个定时器分叉一个进程并设置它在一段时间后杀死父进程?

谢谢你的任何提示!

更新: 以下是我的相关代码.$ url是从命令行传递的,是一个包含多个URL的数组(对不起,最初不发布):

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

Jos*_*osh 6

--timeout除了之外,请尝试使用wget命令行参数set_time_limit().

请记住set_time_limit(15) 从零开始重新启动超时计数器,所以不要在循环内调用它(为了您的目的)

来自man wget:

--timeout =秒

将网络超时设置为秒秒.这相当于同时指定--dns-timeout, - connect-timeout和--read-timeout.

在与网络交互时,Wget可以检查超时并在操作时间过长时中止操作.这可以防止像挂起读取和无限连接之类的异常.默认情况下启用的唯一超时是900秒读取超时.将超时设置为0会完全禁用它.除非您知道自己在做什么,否则最好不要更改默认的超时设置.

所有与超时相关的选项都接受十进制值以及亚秒值.例如,0.1秒是超时的合法(虽然不明智)选择.亚秒超时对于检查服务器响应时间或测试网络延迟非常有用.

编辑:好的.我明白你现在在做什么.您应该做的是使用proc_open代替system,并使用time()函数检查时间,如果wget tskes太长则调用proc_terminate.


ddr*_*own 5

您可以结合使用“--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);
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:如果不使用 -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");
  }
}
Run Code Online (Sandbox Code Playgroud)