2011-03-15 3 views
2

나는 다음과 같은 코드를 가지고 :PHP 프로세스 실행 시간 초과

/** 
* Executes a program and waits for it to finish, taking pipes into account. 
* @param string $cmd Command line to execute, including any arguments. 
* @param string $input Data for standard input. 
* @param integer $timeout How much to wait from program in msecs (-1 to wait indefinitely). 
* @return array Array of "stdout", "stderr" and "return". 
*/ 
function execute($cmd,$stdin=null,$timeout=-1){ 
    $proc=proc_open(
     $cmd, 
     array(array('pipe','r'),array('pipe','w'),array('pipe','w')), 
     $pipes=null 
    ); 
    fwrite($pipes[0],$stdin);     fclose($pipes[0]); 
    $stdout=stream_get_contents($pipes[1]); fclose($pipes[1]); 
    $stderr=stream_get_contents($pipes[2]); fclose($pipes[2]); 
    $return=proc_close($proc); 
    return array(
     'stdout' => $stdout, 
     'stderr' => $stderr, 
     'return' => $return 
    ); 
} 

그것은 두 개의 "문제"가 있습니다.

  • 코드는 동기식입니다. 대상 프로세스가 닫힐 때까지 고정됩니다.
  • 지금까지, 나는 "일시 정지 상관 없어

(예 : Windows에서 리눅스에 $cmd > /dev/null &start /B $cmd로) 명령의 다른 종류를 발행하지 않고"동결 "에서 할 수 없었습니다 ", 전혀. 난 단지 그 타임 아웃을 구현할 필요가있다.

참고 : 솔루션은 플랫폼 간 호환이 가능해야합니다. $cmd을 변경하지 않아도된다는 점도 중요합니다. 복잡한 명령을 실행하고 있지만 문제가있을 수 있습니다. 그러나 수정 방법에 따라 다릅니다. , 나는 다른 대안을 선호한다.

은 내가 도울 수있는 몇 가지 자원을 발견했습니다

답변

1

보다는 stream_get_contents을, 당신은 더 많은 미세 그레인 얻을 수 fread를 사용하여 볼 수 있었다 코드가하는 일을 제어 할 수 있습니다. stream_set_timeout과 결합하면 원하는 것을 제공 할 수 있습니다.

내가 생각한 것의 데모로 뭔가를 던져 버렸습니다.이 코드는 완전히 테스트되지 않았으므로 보증이 없지만 올바른 방향으로 보낼 수 있습니다. ;)

function execute($cmd,$stdin=null,$timeout=-1){ 
    $proc=proc_open(
     $cmd, 
     array(array('pipe','r'),array('pipe','w'),array('pipe','w')), 
     $pipes=null 
    ); 
    fwrite($pipes[0],$stdin);     fclose($pipes[0]); 

    stream_set_timeout($pipes[1], 0); 
    stream_set_timeout($pipes[2], 0); 

    $stdout = ''; 

    $start = microtime(); 

    while ($data = fread($pipes[1], 4096)) 
    { 
     $meta = stream_get_meta_data($pipes[1]); 
     if (microtime()-$start>$timeout) break; 
     if ($meta['timed_out']) continue; 
     $stdout .= $data; 
    } 

    $return = proc_close($proc); 
    $stdout .= stream_get_contents($pipes[1]); 
    $stderr = stream_get_contents($pipes[2]); 

    return array(
     'stdout' => $stdout, 
     'stderr' => $stderr, 
     'return' => $return 
    ); 
} 
2

코드에 몇 가지 실수가 있습니다.

실제로 작동하는지 :

이 나를 위해 일하게 될 것으로 보인다
function execute($cmd, $stdin = null, $timeout = -1) 
{ 
    $proc=proc_open(
     $cmd, 
     array(array('pipe','r'), array('pipe','w'), array('pipe','w')), 
     $pipes 
    ); 
    var_dump($pipes); 
    if (isset($stdin)) 
    { 
     fwrite($pipes[0],$stdin); 
    } 
    fclose($pipes[0]); 

    stream_set_timeout($pipes[1], 0); 
    stream_set_timeout($pipes[2], 0); 

    $stdout = ''; 

    $start = microtime(); 

    while ($data = fread($pipes[1], 4096)) 
    { 
     $meta = stream_get_meta_data($pipes[1]); 
     if (microtime()-$start>$timeout) break; 
     if ($meta['timed_out']) continue; 
     $stdout .= $data; 
    } 

    $stdout .= stream_get_contents($pipes[1]); 
    $stderr = stream_get_contents($pipes[2]); 
    $return = proc_close($proc); 

    return array(
     'stdout' => $stdout, 
     'stderr' => $stderr, 
     'return' => $return 
    ); 
} 
0

:

public function toPDF() { 
    $doc = $this->getDocument(); 

    $descriptor = [ 
     ['pipe','r'], 
     ['pipe','w'], 
     ['file','/dev/null','w'], // STDERR 
    ]; 
    $proc = proc_open('/usr/local/project/scripts/dompdf_cli.php',$descriptor,$pipes,sys_get_temp_dir()); 
    fwrite($pipes[0],"$doc[paper]\n$doc[html]"); 
    fclose($pipes[0]); 

    $timeout = 30; 

    stream_set_blocking($pipes[1], false); 

    $pdf = ''; 

    $now = microtime(true); 

    try { 
     do { 
      $elapsed = microtime(true) - $now; 

      if($elapsed > $timeout) { 
       throw new \Exception("PDF generation timed out after $timeout seconds"); 
      } 
      $data = fread($pipes[1], 4096); 
      if($data === false) { 
       throw new \Exception("Read failed"); 
      } 
      if(strlen($data) === 0) { 
       usleep(50); 
       continue; 
      } 
      $pdf .= $data; 
     } while(!feof($pipes[1])); 

     fclose($pipes[1]); 
     $ret = proc_close($proc); 
    } catch(\Exception $ex) { 
     fclose($pipes[1]); 
     proc_terminate($proc); // proc_close tends to hang if the process is timing out 
     throw $ex; 
    } 


    if($ret !== 0) { 
     throw new \Exception("dompdf_cli returned non-zero exit status: $ret"); 
    } 

    // dump('returning pdf'); 
    return $pdf; 
} 

내가 stream_set_timeout의 목적이 무엇인지 확실하지 않다 - 단지 잡음 환경을 설정하는 것을 시간 제한을 읽지 만 전체 시간을 제한하려면 스트림을 비 차단 모드로 설정 한 다음 소요 시간을 설정해야합니다.