Skip to content

Instantly share code, notes, and snippets.

@vijinho
Last active October 1, 2018 21:07
Show Gist options
  • Save vijinho/89a0f458bcdc0dd6dab402af1bc7e6a1 to your computer and use it in GitHub Desktop.
Save vijinho/89a0f458bcdc0dd6dab402af1bc7e6a1 to your computer and use it in GitHub Desktop.
execute a command in php and return the captured output and streams stdin, stdout, stderr
<?php
define('VERBOSE', 1);
define('DEBUG', 1);
//-----------------------------------------------------------------------------
// required commands check
$commands = get_commands([
'find' => 'System command: find',
'curl' => 'https://curl.haxx.se',
'wget' => 'https://www.gnu.org/software/wget/'
]);
if (empty($commands)) {
exit;
}
//-----------------------------------------------------------------------------
// main program
debug('Commands:' $commands);
debug('Memory used:');
echo get_memory_used();
verbose('Finished.');
//-----------------------------------------------------------------------------
/**
* Dump debug data if DEBUG constant is set
*
* @param optional string $string string to output
* @param optional mixed $data to dump
* @return boolean true if string output, false if not
*/
function debug($string = '', $data = '')
{
if (DEBUG) {
echo trim('[D ' . get_memory_used() . '] ' . $string) . "\n";
if (!empty($data)) {
print_r($data);
}
return true;
}
return false;
}
/**
* Output string if VERBOSE constant is set
*
* @param string $string string to output
* @param optional mixed $data to dump
* @return boolean true if string output, false if not
*/
function verbose($string, $data = '')
{
if (VERBOSE && !empty($string)) {
echo trim('[V' .((DEBUG) ? ' ' . get_memory_used() : '') . '] ' . $string) . "\n";
if (!empty($data)) {
print_r($data);
}
return true;
}
return false;
}
/**
* Get memory used MB
*
* @return string memory used in MB
*/
function get_memory_used()
{
return(
ceil(memory_get_usage() / 1024 / 1024) . '/' .
ceil(memory_get_peak_usage() / 1024 / 1024));
}
function get_commands($requirements = [])
{
static $commands = []; // cli command paths
$found = true;
foreach ($requirements as $tool => $description) {
if (!array_key_exists($tool, $commands)) {
$found = false;
break;
}
}
if ($found) {
return $commands;
}
$errors = [];
foreach ($requirements as $tool => $description) {
$cmd = cmd_execute("which $tool");
if (empty($cmd)) {
$errors[] = "Error: Missing requirement: $tool - " . $description;
} else {
$commands[$tool] = $cmd[0];
}
}
if (!empty($errors)) {
echo join("\n", $errors) . "\n";
}
return $commands;
}
/**
* Execute a command and return streams as an array of
* stdin, stdout, stderr
*
* @param string $cmd command to execute
* @return mixed array $streams | boolean false if failure
* @see https://secure.php.net/manual/en/function.proc-open.php
*/
function shell_execute($cmd)
{
$process = proc_open(
$cmd,
[
['pipe', 'r'],
['pipe', 'w'],
['pipe', 'w']
], $pipes
);
if (is_resource($process)) {
$streams = [];
foreach ($pipes as $p => $v) {
$streams[] = stream_get_contents($pipes[$p]);
}
proc_close($process);
return [
'stdin' => $streams[0],
'stdout' => $streams[1],
'stderr' => $streams[2]
];
}
return false;
}
/**
* Execute a command and return output of stdout or throw exception of stderr
*
* @param string $cmd command to execute
* @param boolean $split split returned results? default on newline
* @param string $exp regular expression to preg_split to split on
* @return mixed string $stdout | Exception if failure
* @see shell_execute($cmd)
*/
function cmd_execute($cmd, $split = true, $exp = "/\n/")
{
$result = shell_execute($cmd);
if (!empty($result['stderr'])) {
throw new Exception($result['stderr']);
}
$data = $result['stdout'];
if (empty($split) || empty($exp) || empty($data)) {
return $data;
}
return preg_split($exp, $data);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment