Source for file Command.php
Documentation is available at Command.php
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.02 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Anders Johannsen <anders@johannsen.com> |
// | Author: Dan Allen <dan@mojavelinux.com>
// +----------------------------------------------------------------------+
require_once 'System.php';
define('SYSTEM_COMMAND_OK', 1 );
define('SYSTEM_COMMAND_ERROR', -1 );
define('SYSTEM_COMMAND_NO_SHELL', -2 );
define('SYSTEM_COMMAND_INVALID_SHELL', -3 );
define('SYSTEM_COMMAND_TMPDIR_ERROR', -4 );
define('SYSTEM_COMMAND_INVALID_OPERATOR', -5 );
define('SYSTEM_COMMAND_INVALID_COMMAND', -6 );
define('SYSTEM_COMMAND_OPERATOR_PLACEMENT',-7 );
define('SYSTEM_COMMAND_COMMAND_PLACEMENT', -8 );
define('SYSTEM_COMMAND_NOHUP_MISSING', -9 );
define('SYSTEM_COMMAND_NO_OUTPUT', -10 );
define('SYSTEM_COMMAND_STDERR', -11 );
define('SYSTEM_COMMAND_NONZERO_EXIT', -12 );
// {{{ class System_Command
* The System_Command:: class implements an abstraction for various ways
* of executing commands (directly using the backtick operator,
* as a background task after the script has terminated using
* register_shutdown_function() or as a detached process using nohup).
* @author Anders Johannsen <anders@johannsen.com>
* @author Dan Allen <dan@mojavelinux.com>
* Array of settings used when creating the shell command
* Array of available shells to use to execute the command
* Array of available control operators used between commands
var $controlOperators = array ();
* The system command to be executed
var $systemCommand = null;
* Previously added part to the command string
var $previousElement = null;
* Directory for writing stderr output
* To allow the pear error object to accumulate when building
* the command, we use the command status to keep track when
* Hold initialization PEAR_Error
* Defines all necessary constants and sets defaults
function System_Command ($in_shell = null )
'SHELL' => $this->which ($in_shell),
// prepare the available control operators
$this->controlOperators = array (
// List of allowed/available shells
// Find the first available shell
if (empty ($this->options['SHELL'])) {
foreach ($this->shells as $shell) {
if ($this->options['SHELL'] = $this->which ($shell)) {
// see if we still have no shell
if (empty ($this->options['SHELL'])) {
$this->_initError = & PEAR ::raiseError (null , SYSTEM_COMMAND_NO_SHELL, null , E_USER_WARNING , null , 'System_Command_Error', true );
// Caputre a temporary directory for capturing stderr from commands
$this->tmpDir = System ::tmpdir ();
if (!System ::mkDir (" -p {$this->tmpDir}" )) {
$this->_initError = & PEAR ::raiseError (null , SYSTEM_COMMAND_TMPDIR_ERROR , null , E_USER_WARNING , null , 'System_Command_Error', true );
* Sets the value for an option. Each option should be set to true
* or false; except the 'SHELL' option which should be a string
* naming a shell. The options are:
* 'SEQUENCE' Allow a sequence command or not (right now this is always on);
* 'SHUTDOWN' Execute commands via a shutdown function;
* 'OUTPUT' Output stdout from process;
* 'NOHUP' Use nohup to detach process;
* 'BACKGROUND' Run as a background process with &;
* 'STDERR' Output on stderr will raise an error, even if
* the command's exit value is zero. The output from
* stderr can be retrieved using the getDebugInfo()
* method of the Pear_ERROR object returned by
* 'AUTORESET' Automatically call reset() after a successful
* @param string $in_option is a case-sensitive string,
* corresponding to the option
* @param mixed $in_setting is the new value for the option
* @return bool true if succes, else false
function setOption($in_option, $in_setting)
return $this->_initError;
$option = strtoupper($in_option);
if (!isset($this->options[$option])) {
PEAR::raiseError(null, SYSTEM_COMMAND_ERROR, null, E_USER_NOTICE, null, 'System_Command_Error', true);
$this->options[$option] = !empty ($in_setting);
if (($shell = $this->which ($in_setting)) !== false ) {
$this->options[$option] = $shell;
PEAR::raiseError(null, SYSTEM_COMMAND_NO_SHELL, null, E_USER_NOTICE, $in_setting, 'System_Command_Error', true);
if (empty($in_setting)) {
$this->options[$option] = false;
else if ($location = $this->which ('nohup')) {
$this->options[$option] = $location;
PEAR::raiseError(null, SYSTEM_COMMAND_NOHUP_MISSING, null, E_USER_NOTICE, null, 'System_Command_Error', true);
* Used to push a command onto the running command to be executed
* @param string $in_command binary to be run
* @param string $in_argument either an option or argument value, to be handled appropriately
* @param string $in_argument
* @return boolean true on success {or System_Command_Error Exception}
function pushCommand($in_command)
return $this->_initError;
if (!is_null($this->previousElement) && !in_array ($this->previousElement, $this->controlOperators)) {
$this->commandStatus = -1;
$error = PEAR ::raiseError (null , SYSTEM_COMMAND_COMMAND_PLACEMENT , null , E_USER_WARNING , null , 'System_Command_Error', true );
$command = escapeshellcmd($this->which ($in_command));
if ($command === false ) {
$error = PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_COMMAND, null, E_USER_WARNING, null, 'System_Command_Error', true);
if (strpos($arg, '-') === 0) {
$command .= ' ' . escapeshellarg($arg);
$this->previousElement = $command;
$this->systemCommand .= $command;
return isset ($error) ? $error : true;
* Used to push an operator onto the running command to be executed
* @param string $in_operator Either string reprentation of operator or system character
* @return boolean true on success {or System_Command_Error Exception}
function pushOperator($in_operator)
return $this->_initError;
$operator = isset($this->controlOperators[$in_operator]) ? $this->controlOperators[$in_operator] : $in_operator;
if (is_null ($this->previousElement) || in_array ($this->previousElement, $this->controlOperators)) {
$this->commandStatus = -1;
$error = PEAR ::raiseError (null , SYSTEM_COMMAND_OPERATOR_PLACEMENT , null , E_USER_WARNING , null , 'System_Command_Error', true );
elseif (!in_array($operator, $this->controlOperators)) {
$this->commandStatus = -1;
$error = PEAR ::raiseError (null , SYSTEM_COMMAND_INVALID_OPERATOR , null , E_USER_WARNING , $operator, 'System_Command_Error', true );
$this->previousElement = $operator;
$this->systemCommand .= ' ' . $operator . ' ';
return isset ($error) ? $error : true;
* Executes the code according to given options
* @return bool true if success {or System_Command_Exception}
return $this->_initError;
// if the command is empty or if the last element was a control operator, we can't continue
if (is_null($this->previousElement) || $this->commandStatus == -1 || in_array ($this->previousElement, $this->controlOperators)) {
return PEAR::raiseError(null, SYSTEM_COMMAND_INVALID_COMMAND, null, E_USER_WARNING, $this->systemCommand, 'System_Command_Error', true );
// Warning about impossible mix of options
if (!empty($this->options['OUTPUT'])) {
if (!empty($this->options['SHUTDOWN']) || !empty ($this->options['NOHUP'])) {
return PEAR::raiseError(null, SYSTEM_COMMAND_NO_OUTPUT, null, E_USER_WARNING, null, 'System_Command_Error', true);
// if this is not going to stdout, then redirect to /dev/null
if (empty($this->options['OUTPUT'])) {
$this->systemCommand .= ' >/dev/null';
// run a command immune to hangups, with output to a non-tty
if (!empty($this->options['NOHUP'])) {
$this->systemCommand = $this->options['NOHUP'] . $this->systemCommand;
// run a background process (only if not nohup)
elseif (!empty($this->options['BACKGROUND'])) {
// Register to be run on shutdown
if (!empty($this->options['SHUTDOWN'])) {
$line = "system(\"{ $this->systemCommand}$suffix\"); ";
$function = create_function('', $line);
register_shutdown_function($function);
if ($this->options['AUTORESET']) {
// send stderr to a file so that we can reap the error message
$tmpFile = tempnam($this->tmpDir, 'System_Command-');
$this->systemCommand .= ' 2>' . $tmpFile . $suffix;
$shellPipe = $this->which ('echo') . ' ' . escapeshellarg ($this->systemCommand) . ' | ' . $this->options['SHELL'];
exec ($shellPipe, $result, $returnVal);
// command returned nonzero; that's always an error
$return = PEAR::raiseError(null, SYSTEM_COMMAND_NONZERO_EXIT, null, E_USER_WARNING, null, 'System_Command_Error', true);
else if (!$this->options['STDERR']) {
// caller does not care about stderr; return success
$return = implode("\n", $result);
// our caller cares about stderr; check stderr output
if (filesize($tmpFile) > 0) {
// the command actually wrote to stderr
$stderr_output = file_get_contents($tmpFile);
$return = PEAR::raiseError(null, SYSTEM_COMMAND_STDERR, null, E_USER_WARNING, $stderr_output, 'System_Command_Error', true);
// total success; return stdout gathered by exec()
$return = implode("\n", $result);
if ((!PEAR::isError($return)) && ($this->options['AUTORESET'])) {
* Functionality similiar to unix 'which'. Searches the path
* for the specified program.
* @param $cmd name of the executable to search for
* @return string returns the full path if found, false if not
// only pass non-empty strings to System::which()
if (!is_string($in_cmd) || '' === $in_cmd) {
// explicitly pass false as fallback value
return System::which($in_cmd, false);
* Prepare for a new command to be built
$this->previousElement = null;
$this->systemCommand = null;
$this->commandStatus = 0;
* Return a textual error message for a System_Command error code
* @param integer error code
* @return string error message, or false if the error code was
function errorMessage($in_value)
if (!isset($errorMessages)) {
SYSTEM_COMMAND_OK => 'no error',
SYSTEM_COMMAND_ERROR => 'unknown error',
SYSTEM_COMMAND_NO_SHELL => 'no shell found',
SYSTEM_COMMAND_INVALID_SHELL => 'invalid shell',
SYSTEM_COMMAND_TMPDIR_ERROR => 'could not create temporary directory',
SYSTEM_COMMAND_INVALID_OPERATOR => 'control operator invalid',
SYSTEM_COMMAND_INVALID_COMMAND => 'invalid system command',
SYSTEM_COMMAND_OPERATOR_PLACEMENT => 'invalid placement of control operator',
SYSTEM_COMMAND_COMMAND_PLACEMENT => 'invalid placement of command',
SYSTEM_COMMAND_NOHUP_MISSING => 'nohup not found on system',
SYSTEM_COMMAND_NO_OUTPUT => 'output not allowed',
SYSTEM_COMMAND_STDERR => 'command wrote to stderr',
SYSTEM_COMMAND_NONZERO_EXIT => 'non-zero exit value from command',
if (System_Command::isError($in_value)) {
$in_value = $in_value->getCode ();
return isset($errorMessages[$in_value]) ? $errorMessages[$in_value] : $errorMessages[SYSTEM_COMMAND_ERROR];
* Tell whether a result code from a System_Command method is an error
* @return bool whether $in_value is an error
function isError($in_value)
return (is_object($in_value) &&
(strtolower(get_class($in_value)) == 'system_command_error' ||
is_subclass_of($in_value, 'system_command_error')));
// {{{ class System_Command_Error
* System_Command_Error constructor.
* @param mixed System_Command error code, or string with error message.
* @param integer what "error mode" to operate in
* @param integer what error level to use for $mode & PEAR_ERROR_TRIGGER
* @param mixed additional debug info, such as the last query
class System_Command_Error extends PEAR_Error
* Message in front of the error message
* @var string $error_message_prefix
var $error_message_prefix = 'System_Command Error: ';
function System_Command_Error($code = SYSTEM_COMMAND_ERROR, $mode = PEAR_ERROR_RETURN,
$level = E_USER_NOTICE, $debuginfo = null)
$this->PEAR_Error (System_Command ::errorMessage ($code), $code, $mode, $level, $debuginfo);
$this->PEAR_Error ("Invalid error code: $code" , SYSTEM_COMMAND_ERROR , $mode, $level, $debuginfo);
Documentation generated on Mon, 11 Mar 2019 15:47:25 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|