Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP为带有系统调用的脚本设置超时,设置时间限制不工作_Php_Windows_Linux_Command Line - Fatal编程技术网

PHP为带有系统调用的脚本设置超时,设置时间限制不工作

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循环不工作)。也许

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

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

谢谢你的提示

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


您可以将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