Last active
September 16, 2020 07:48
-
-
Save fordnox/f79c90c100ccea07880c to your computer and use it in GitHub Desktop.
Execute shell command with timeout and converting stderr to Exception if any
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @param int $timeout - max process execution time in seconds until it is terminated | |
**/ | |
function execute($cmd, $stdin = null, $timeout = 600) | |
{ | |
$this->log->debug("executing: " . $cmd . " ". $stdin); | |
$cmd = str_replace("\n", "", $cmd); | |
$cmd = str_replace("\r", "", $cmd); | |
$descriptorspec = array( | |
0 => array("pipe", "r"), // stdin is a pipe that the child will read from | |
1 => array("pipe", "w"), // stdout is a pipe that the child will write to | |
2 => array("pipe", "w"), // stderr is a pipe that the child will write to | |
); | |
$pipes = array(); | |
$timeout += time(); | |
$process = proc_open($cmd, $descriptorspec, $pipes); | |
if (!is_resource($process)) { | |
throw new Exception('Invalid resource', 1011); | |
} | |
$output = ''; | |
$error = ''; | |
if($stdin) { | |
// 0 => writeable handle connected to child stdin | |
fwrite($pipes[0], $stdin); | |
} | |
fclose($pipes[0]); | |
do { | |
$write = null; | |
$exceptions = null; | |
$timeleft = $timeout - time(); | |
if ($timeleft <= 0) { | |
proc_terminate($process); | |
throw new Exception("command timeout", 1012); | |
} | |
$read = array($pipes[1],$pipes[2]); | |
stream_select($read, $write, $exceptions, $timeleft); | |
if (!empty($read)) { | |
$output .= fread($pipes[1], 1024); | |
$error .= fread($pipes[2], 1024); | |
} | |
$output_exists = (!feof($pipes[1]) || !feof($pipes[2])); | |
} while ($output_exists && $timeleft > 0); | |
if ($timeleft <= 0) { | |
proc_terminate($process); | |
throw new Exception("command timeout", 1013); | |
} | |
fclose($pipes[1]); | |
fclose($pipes[2]); | |
proc_close($process); | |
if($error) { | |
throw new Exception($error, 1012); | |
} | |
return $output; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment