Last active
March 24, 2022 10:58
-
-
Save swichers/027d5ae903350cbd4af8 to your computer and use it in GitHub Desktop.
Capturing STDERR from interactive proc_open call
This file contains hidden or 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
{ | |
"name": "swichers/passthru_with_errors", | |
"description": "An enhanced passthru() command that includes error capturing.", | |
"license": "Apache-2.0", | |
"authors": [ { "name": "Steven Wichers", "role": "Developer" } ], | |
"require": { | |
"php": ">=5.3.0" | |
}, | |
"autoload": { | |
"files": ["passthru_with_errors.php"] | |
} | |
} |
This file contains hidden or 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 | |
/** | |
* @file | |
* Demonstrates how to execute an interactive process using proc_open while | |
* also grabbing STDERR for your own use. | |
* | |
* I did not like the other options that redirected output to a file on disk, or | |
* used some other more complex way to grab STDERR. | |
* | |
* I would like to eliminate the loop in favor of a stream capture of some sort, | |
* but came up short. | |
*/ | |
// Prevent defining the function multiple times. | |
if (!function_exists('passthru_with_errors')) { | |
/** | |
* Executes an interactive command while capturing STDERR and the return code. | |
* | |
* @param string $command | |
* The command that will be executed. | |
* | |
* @param int &$return_var | |
* If the return_var argument is present, the return status of the Unix | |
* command will be placed here. | |
* | |
* @param array &$stderr_ouput | |
* If the stderr_ouput argument is present, the output sent to STDERR. | |
* | |
* @return | |
* No value is returned. | |
*/ | |
function passthru_with_errors($command, &$return_var = null, array &$stderr_ouput = null) { | |
$return_var = null; | |
$stderr_ouput = array(); | |
$descriptorspec = array( | |
// Must use php://stdin(out) in order to allow display of command output | |
// and the user to interact with the process. | |
0 => array('file', 'php://stdin', 'r'), | |
1 => array('file', 'php://stdout', 'w'), | |
2 => array('pipe', 'w'), | |
); | |
$pipes = array(); | |
$process = @proc_open($command, $descriptorspec, $pipes); | |
if (is_resource($process)) { | |
// Loop on process until it exits normally. | |
do { | |
$status = proc_get_status($process); | |
// If our stderr pipe has data, grab it for use later. | |
if (!feof($pipes[2])) { | |
// We're acting like passthru would and displaying errors as they come in. | |
$error_line = fgets($pipes[2]); | |
echo $error_line; | |
$stderr_ouput[] = $error_line; | |
} | |
} while ($status['running']); | |
// According to documentation, the exit code is only valid the first call | |
// after a process is finished. We can't rely on the return value of | |
// proc_close because proc_get_status will read the exit code first. | |
$return_var = $status['exitcode']; | |
proc_close($process); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is genius! I've been fighting with
proc_open()
for a while and just hit a mental block on how to allow the process to keep running sinceget_stream_contents()
blocks until there's content. Didn't even think aboutfgets()
. Good work!