$
Command not allowed by whitelist.";
return;
}
}
// Dangerous commands filter
$dangerous = ['rm -rf', 'mkfs', 'dd', ':(){ :|:& };:', 'chmod 777', '> /dev/sda'];
foreach ($dangerous as $danger) {
if (strpos($cmd, $danger) !== false) {
echo "Dangerous command detected and blocked.";
return;
}
}
$shell = '/bin/bash';
if (!is_executable($shell)) $shell = '/bin/sh';
$safe_cd = 'cd ' . escapeshellarg($path) . ' 2>/dev/null && ';
$run_cmd = $safe_cd . escapeshellcmd($shell) . ' -lc ' . escapeshellarg($cmd) . ' 2>&1';
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
];
$process = @proc_open($run_cmd, $descriptors, $pipes, null, null);
if (!is_resource($process)) {
echo "Failed to open process. Ensure exec/proc_open is allowed.";
} else {
stream_set_blocking($pipes[1], false);
stream_set_blocking($pipes[2], false);
fclose($pipes[0]);
$output = '';
$start = time();
$timed_out = false;
while (true) {
$read = [$pipes[1], $pipes[2]];
$write = null;
$except = null;
$num = stream_select($read, $write, $except, 1, 0);
if ($num !== false && $num > 0) {
foreach ($read as $r) {
$chunk = stream_get_contents($r);
if ($chunk !== false && $chunk !== '') {
$output .= $chunk;
if (strlen($output) > $TERMINAL_MAX_OUTPUT) {
$output = substr($output, 0, $TERMINAL_MAX_OUTPUT) . "\n\n[Output truncated (too large)]";
break 2;
}
}
}
}
$status = proc_get_status($process);
if (!$status['running']) {
$output .= stream_get_contents($pipes[1]);
$output .= stream_get_contents($pipes[2]);
break;
}
if ((time() - $start) > $TERMINAL_TIMEOUT) {
$timed_out = true;
proc_terminate($process, 9);
$output .= "\n\n[Command terminated due to timeout after {$TERMINAL_TIMEOUT} seconds]";
break;
}
usleep(100000);
}
@fclose($pipes[1]);
@fclose($pipes[2]);
@proc_close($process);
if ($output === '') {
$output = "[No output]";
}
// Highlight output
$output = htmlspecialchars($output);
$output = preg_replace('/\b(error|fail|failed|denied|permission)\b/i', '$0', $output);
$output = preg_replace('/\b(success|ok|done|completed)\b/i', '$0', $output);
$output = preg_replace('/\b(warning|notice)\b/i', '$0', $output);
echo nl2br($output);
}
?>