PHP中控制proc_open的执行时间

来源:互联网 发布:java判断文件类型 编辑:程序博客网 时间:2024/04/29 21:02

目前想到有两个办法。

一个是fork方式。
发现直接通过进程的alarm信号方式无法控制proc_open的执行。所以用fork方式,通过fork让子进程执行proc_open,父进程则通过alarm的方式控制时间。但是这么做会造成如果有输出值的话会很麻烦,要让子进程一直执行下去,因为没找到好的办法让父进程能获取子进程的输出。当然通过进程间通信能解决,但是太麻烦了。。。

另外个stream_select方式

  1. //cmd为要执行的程序, timeout是超时时间
  2.        $descriptorspec = array(
  3.     0 => array("pipe""r"),
  4.     1 => array("pipe""w"),
  5.     2 => array("pipe""w")
  6.     );
  7.         $process = proc_open($cmd$descriptorspec$pipes);
  8.     $stdout_str = $stderr_str = "";
  9.  
  10.     if (is_resource($process)) {
  11.         //执行成功
  12.         stream_set_blocking($pipes[1]0);
  13.         stream_set_blocking($pipes[2]0);  //不阻塞
  14.         fwrite($pipes[0]$stdin_str);
  15.         fclose($pipes[0]);
  16.  
  17.         //设置超时时钟
  18.         $endtime = time() + $timeout;
  19.  
  20.         do {
  21.             $timeleft = $endtime - time();
  22.             $ret = stream_select(
  23.                 $read = array($pipes[1],$pipes[2]),
  24.                 $write = null,
  25.                 $except = null,
  26.                 $timeleft
  27.             );
  28.  
  29.             if ($ret === false) {
  30.                 $err = true;
  31.                 break;
  32.             } else if ($ret === 0) {
  33.                 $timeleft = 0;
  34.                 break;
  35.             } else {
  36.                 foreach ($read as $sock) {
  37.                     if ($sock === $pipes[1]) {
  38.                         $stdout_str .= fread($sock4096);
  39.                     } else if ($sock === $pipes[2]) {
  40.                         $stderr_str .= fread($sock4096);
  41.                     }
  42.                 }
  43.             }
  44.         }while((feof($pipes[1]) === false || feof($pipes[2]) === false) &&$timeleft > 0);
  45.  
  46.         fclose($pipes[1]);
  47.         fclose($pipes[2]);
  48.         if($timeleft <= 0) {
  49.             proc_terminate($process);
  50.             $stderr_str = "操作已超时(".$timeout."秒)";
  51.         }
  52.  
  53.         if (isset($err) && $err === true){  //这种情况的出现是通过信号发送中断时产生
  54.             proc_terminate($process);
  55.             $stderr_str = "操作被用户取消";
  56.         }
  57.         proc_close($process);
  58.         return true;
  59.     }
  60.     else {
  61.         return false;
  62.     }

stream_select 果然很强大…异步的读取输出,解决执行超时的问题。另外这种方式还可以防止输出堵死缓存。例如如果将上述获取输出的代码改成

  1. // stdout
  2. $stdout = stream_get_contents($pipes[1]);
  3. fclose($pipes[1]);
  4.  
  5. // stderr
  6. $stderr = stream_get_contents($pipes[2]);
  7. fclose($pipes[2]);

有就可能造成缓存堵死,当然对这种情况的处理也可以通过fork子进程解决。

原创粉丝点击