Source for file CommandLine.php
Documentation is available at CommandLine.php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
* This file is part of the PEAR Console_CommandLine package.
* A full featured package for managing command-line options and arguments
* hightly inspired from python optparse module, it allows the developper to
* easily build complex command line interfaces.
* LICENSE: This source file is subject to the MIT license that is available
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
* @package Console_CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @link http://pear.php.net/package/Console_CommandLine
* @since Class available since release 0.1.0
* Required unconditionally
require_once 'Console/CommandLine/Exception.php';
require_once 'Console/CommandLine/Outputter/Default.php';
require_once 'Console/CommandLine/Renderer/Default.php';
require_once 'Console/CommandLine/MessageProvider/Default.php';
* Main class for parsing command line options and arguments.
* There are three ways to create parsers with this class:
* $parser = new Console_CommandLine();
* // with an xml definition file
* $parser = Console_CommandLine::fromXmlFile('path/to/file.xml');
* // with an xml definition string
* $validXmlString = '..your xml string...';
* $parser = Console_CommandLine::fromXmlString($validXmlString);
* @package Console_CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version Release: 1.2.0
* @link http://pear.php.net/package/Console_CommandLine
* @since File available since release 0.1.0
* @example docs/examples/ex1.php
* @example docs/examples/ex2.php
* @var array $errors Error messages
* @todo move this to Console_CommandLine_MessageProvider
public static $errors = array (
'option_bad_name' => 'option name must be a valid php variable name (got: {$name})',
'argument_bad_name' => 'argument name must be a valid php variable name (got: {$name})',
'argument_no_default' => 'only optional arguments can have a default value',
'option_long_and_short_name_missing' => 'you must provide at least an option short name or long name for option "{$name}"',
'option_bad_short_name' => 'option "{$name}" short name must be a dash followed by a letter (got: "{$short_name}")',
'option_bad_long_name' => 'option "{$name}" long name must be 2 dashes followed by a word (got: "{$long_name}")',
'option_unregistered_action' => 'unregistered action "{$action}" for option "{$name}".',
'option_bad_action' => 'invalid action for option "{$name}".',
'option_invalid_callback' => 'you must provide a valid callback for option "{$name}"',
'action_class_does_not_exists' => 'action "{$name}" class "{$class}" not found, make sure that your class is available before calling Console_CommandLine::registerAction()',
'invalid_xml_file' => 'XML definition file "{$file}" does not exists or is not readable',
'invalid_rng_file' => 'RNG file "{$file}" does not exists or is not readable'
* The name of the program, if not given it defaults to argv[0].
* @var string $name Name of your program
* A description text that will be displayed in the help message.
* @var string $description Description of your program
* A string that represents the version of the program, if this property is
* not empty and property add_version_option is not set to false, the
* command line parser will add a --version option, that will display the
* Boolean that determine if the command line parser should add the help
* (-h, --help) option automatically.
* @var bool $add_help_option Whether to add a help option or not
* Boolean that determine if the command line parser should add the version
* (-v, --version) option automatically.
* Note that the version option is also generated only if the version
* property is not empty, it's up to you to provide a version string of
* @var bool $add_version_option Whether to add a version option or not
* Boolean that determine if providing a subcommand is mandatory.
* @var bool $subcommand_required Whether a subcommand is required or not
* The command line parser renderer instance.
* @var object that implements Console_CommandLine_Renderer interface
* The command line parser outputter instance.
* @var Console_CommandLine_Outputter An outputter
* The command line message provider instance.
* @var Console_CommandLine_MessageProvider A message provider instance
* Boolean that tells the parser to be POSIX compliant, POSIX demands the
* following behavior: the first non-option stops option processing.
* @var bool $force_posix Whether to force posix compliance or not
* Boolean that tells the parser to set relevant options default values,
* according to the option action.
* @see Console_CommandLine_Option::setDefaults()
* @var bool $force_options_defaults Whether to force option default values
* An array of Console_CommandLine_Option objects.
* @var array $options The options array
* An array of Console_CommandLine_Argument objects.
* @var array $args The arguments array
* An array of Console_CommandLine_Command objects (sub commands).
* @var array $commands The commands array
* Parent, only relevant in Command objects but left here for interface
* @var Console_CommandLine The parent instance
* @todo move Console_CommandLine::parent to Console_CommandLine_Command
* Array of valid actions for an option, this array will also store user
* <ActionName:string> => array(<ActionClass:string>, <builtin:bool>)
* @var array $actions List of valid actions
public static $actions = array (
'StoreTrue' => array ('Console_CommandLine_Action_StoreTrue', true ),
'StoreFalse' => array ('Console_CommandLine_Action_StoreFalse', true ),
'StoreString' => array ('Console_CommandLine_Action_StoreString', true ),
'StoreInt' => array ('Console_CommandLine_Action_StoreInt', true ),
'StoreFloat' => array ('Console_CommandLine_Action_StoreFloat', true ),
'StoreArray' => array ('Console_CommandLine_Action_StoreArray', true ),
'Callback' => array ('Console_CommandLine_Action_Callback', true ),
'Counter' => array ('Console_CommandLine_Action_Counter', true ),
'Help' => array ('Console_CommandLine_Action_Help', true ),
'Version' => array ('Console_CommandLine_Action_Version', true ),
'Password' => array ('Console_CommandLine_Action_Password', true ),
'List' => array ('Console_CommandLine_Action_List', true ),
* Custom errors messages for this command
* This array is of the form:
* $messageName => $messageText,
* $messageName => $messageText,
* If specified, these messages override the messages provided by the
* default message provider. For example:
* 'ARGUMENT_REQUIRED' => 'The argument foo is required.',
* @see Console_CommandLine_MessageProvider_Default
// {{{ Private properties
* Array of options that must be dispatched at the end.
* @var array $_dispatchLater Options to be dispatched
private $_dispatchLater = array ();
* $parser = new Console_CommandLine(array(
* 'name' => 'yourprogram', // defaults to argv[0]
* 'description' => 'Description of your program',
* 'version' => '0.0.1', // your program version
* 'add_help_option' => true, // or false to disable --help option
* 'add_version_option' => true, // or false to disable --version option
* 'force_posix' => false // or true to force posix compliance
* @param array $params An optional array of parameters
if (isset ($params['name'])) {
$this->name = $params['name'];
} else if (isset ($argv) && count($argv) > 0 ) {
} else if (isset ($_SERVER['argv']) && count($_SERVER['argv']) > 0 ) {
$this->name = $_SERVER['argv'][0 ];
} else if (isset ($_SERVER['SCRIPT_NAME'])) {
if (isset ($params['description'])) {
if (isset ($params['version'])) {
$this->version = $params['version'];
if (isset ($params['add_version_option'])) {
if (isset ($params['add_help_option'])) {
if (isset ($params['subcommand_required'])) {
if (isset ($params['force_posix'])) {
} else if (getenv('POSIXLY_CORRECT')) {
if (isset ($params['messages']) && is_array($params['messages'])) {
* Method to allow Console_CommandLine to accept either:
* + or a custom message provider
* @param mixed $instance The custom instance
* @throws Console_CommandLine_Exception if wrong argument passed
public function accept($instance)
$instance->parser = $this;
'INVALID_CUSTOM_INSTANCE',
* Returns a command line parser instance built from an xml file.
* require_once 'Console/CommandLine.php';
* $parser = Console_CommandLine::fromXmlFile('path/to/file.xml');
* $result = $parser->parse();
* @param string $file Path to the xml file
* @return Console_CommandLine The parser instance
include_once 'Console/CommandLine/XmlParser.php';
* Returns a command line parser instance built from an xml string.
* require_once 'Console/CommandLine.php';
* $xmldata = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>
* <description>Compress files</description>
* <short_name>-q</short_name>
* <long_name>--quiet</long_name>
* <description>be quiet when run</description>
* <action>StoreTrue/action>
* <argument name="files">
* <description>a list of files</description>
* <multiple>true</multiple>
* $parser = Console_CommandLine::fromXmlString($xmldata);
* $result = $parser->parse();
* @param string $string The xml data
* @return Console_CommandLine The parser instance
include_once 'Console/CommandLine/XmlParser.php';
* Adds an argument to the command line parser and returns it.
* Adds an argument with the name $name and set its attributes with the
* array $params, then return the Console_CommandLine_Argument instance
* The method accepts another form: you can directly pass a
* Console_CommandLine_Argument object as the sole argument, this allows
* you to contruct the argument separately, in order to reuse it in
* different command line parsers or commands for example.
* $parser = new Console_CommandLine();
* // add an array argument
* $parser->addArgument('input_files', array('multiple'=>true));
* // add a simple argument
* $parser->addArgument('output_file');
* $result = $parser->parse();
* print_r($result->args['input_files']);
* print_r($result->args['output_file']);
* // array('file1', 'file2')
* // if the command line was:
* // myscript.php file1 file2 file3
* In a terminal, the help will be displayed like this:
* $ myscript.php install -h
* Usage: myscript.php <input_files...> <output_file>
* @param mixed $name A string containing the argument name or an
* instance of Console_CommandLine_Argument
* @param array $params An array containing the argument attributes
* @return Console_CommandLine_Argument the added argument
* @see Console_CommandLine_Argument
include_once 'Console/CommandLine/Argument.php';
$this->args[$argument->name ] = $argument;
* Adds a sub-command to the command line parser.
* Adds a command with the given $name to the parser and returns the
* Console_CommandLine_Command instance, you can then populate the command
* with options, configure it, etc... like you would do for the main parser
* because the class Console_CommandLine_Command inherits from
* $parser = new Console_CommandLine();
* $install_cmd = $parser->addCommand('install');
* $install_cmd->addOption(
* 'long_name' => '--verbose',
* 'description' => 'be noisy when installing stuff',
* 'action' => 'StoreTrue'
* $ myscript.php install -h
* Usage: myscript.php install [options]
* -h, --help display this help message and exit
* -v, --verbose be noisy when installing stuff
* $ myscript.php install --verbose
* @param mixed $name A string containing the command name or an
* instance of Console_CommandLine_Command
* @param array $params An array containing the command attributes
* @return Console_CommandLine_Command the added subcommand
* @see Console_CommandLine_Command
public function addCommand($name, $params = array ())
include_once 'Console/CommandLine/Command.php';
// some properties must cascade to the child command if not
// passed explicitely. This is done only in this case, because if
// we have a Command object we have no way to determine if theses
// properties have already been set
foreach ($cascade as $property) {
if (!isset ($params[$property])) {
$command->$property = $this->$property;
if (!isset ($params['renderer'])) {
$renderer->parser = $command;
$command->renderer = $renderer;
$command->parent = $this;
$this->commands[$command->name ] = $command;
* Adds an option to the command line parser and returns it.
* Adds an option with the name $name and set its attributes with the
* array $params, then return the Console_CommandLine_Option instance
* The method accepts another form: you can directly pass a
* Console_CommandLine_Option object as the sole argument, this allows
* you to contruct the option separately, in order to reuse it in different
* command line parsers or commands for example.
* $parser = new Console_CommandLine();
* $parser->addOption('path', array(
* 'short_name' => '-p', // a short name
* 'long_name' => '--path', // a long name
* 'description' => 'path to the dir', // a description msg
* 'action' => 'StoreString',
* 'default' => '/tmp' // a default value
* In a terminal, the help will be displayed like this:
* Usage: myscript.php [options]
* -h, --help display this help message and exit
* -p, --path path to the dir
* Various methods to specify an option, these 3 commands are equivalent:
* $ myscript.php --path=some/path
* $ myscript.php -p some/path
* $ myscript.php -psome/path
* @param mixed $name A string containing the option name or an
* instance of Console_CommandLine_Option
* @param array $params An array containing the option attributes
* @return Console_CommandLine_Option The added option
* @see Console_CommandLine_Option
public function addOption($name, $params = array ())
include_once 'Console/CommandLine/Option.php';
if (!empty ($opt->choices ) && $opt->add_list_option ) {
$this->addOption('list_' . $opt->name , array (
'long_name' => '--list-' . $opt->name ,
array ('name' => $opt->name )
'action_params' => array ('list' => $opt->choices ),
* Displays an error to the user via stderr and exit with $exitCode if its
* value is not equals to false.
* @param string $error The error message
* @param int $exitCode The exit code number (default: 1). If set to
* false, the exit() function will not be called
if ($exitCode !== false ) {
* Displays the usage help message to the user via stdout and exit with
* $exitCode if its value is not equals to false.
* @param int $exitCode The exit code number (default: 0). If set to
* false, the exit() function will not be called
if ($exitCode !== false ) {
* Displays the program version to the user via stdout and exit with
* $exitCode if its value is not equals to false.
* @param int $exitCode The exit code number (default: 0). If set to
* false, the exit() function will not be called
if ($exitCode !== false ) {
* Finds the option that matches the given short_name (ex: -v), long_name
* (ex: --verbose) or name (ex: verbose).
* @param string $str The option identifier
* @return mixed A Console_CommandLine_Option instance or false
if ($opt->short_name == $str || $opt->long_name == $str ||
// abbreviated long option
if ($count = count($matches)) {
foreach ($matches as $opt) {
$matches_str .= $padding . $opt->long_name;
array ('name' => $str, 'matches' => $matches_str),
* Registers a custom action for the parser, an example:
* // in this example we create a "range" action:
* // the user will be able to enter something like:
* // and in the result we will have:
* // $result->options['range']: array(1, 5)
* require_once 'Console/CommandLine.php';
* require_once 'Console/CommandLine/Action.php';
* class ActionRange extends Console_CommandLine_Action
* public function execute($value=false, $params=array())
* $range = explode(',', str_replace(' ', '', $value));
* if (count($range) != 2) {
* throw new Exception(sprintf(
* 'Option "%s" must be 2 integers separated by a comma',
* $this->setResult($range);
* // then we can register our action
* Console_CommandLine::registerAction('Range', 'ActionRange');
* // and now our action is available !
* $parser = new Console_CommandLine();
* $parser->addOption('range', array(
* 'long_name' => '--range',
* 'action' => 'Range', // note our custom action
* 'description' => 'A range of two integers separated by a comma'
* @param string $name The name of the custom action
* @param string $class The class name of the custom action
if (!isset (self ::$actions[$name])) {
if (!class_exists ($class)) {
self ::triggerError ('action_class_does_not_exists',
array ('{$name}' => $name, '{$class}' => $class));
self ::$actions[$name] = array ($class, false );
* A wrapper for programming errors triggering.
* @param string $msgId Identifier of the message
* @param int $level The php error level
* @param array $params An array of search=>replaces entries
* @todo remove Console::triggerError() and use exceptions only
public static function triggerError($msgId, $level, $params=array ())
if (isset (self ::$errors[$msgId])) {
trigger_error ($msg, $level);
* Parses the command line arguments and returns a
* Console_CommandLine_Result instance.
* @param integer $userArgc Number of arguments (optional)
* @param array $userArgv Array containing arguments (optional)
* @return Console_CommandLine_Result The result instance
* @throws Exception on user errors
public function parse($userArgc=null , $userArgv=null )
if ($userArgc !== null && $userArgv !== null ) {
include_once 'Console/CommandLine/Result.php';
// remove script name if we're not in a subcommand
// will contain arguments
foreach ($this->options as $name=> $option) {
$result->options [$name] = $option->default;
// parse command line tokens
if ($cmd = $this->_getSubCommand ($token)) {
$result->command_name = $cmd->name;
$result->command = $cmd->parse ($argc, $argv);
} catch (Exception $exc) {
// Parse a null token to allow any undespatched actions to be despatched.
// Check if an invalid subcommand was specified. If there are
// subcommands and no arguments, but an argument was provided, it is
// an invalid subcommand.
array ('command' => $args[0 ]),
// if subcommand_required is set to true we must check that we have a
&& !$result->command_name
// minimum argument number check
foreach ($this->args as $name=> $arg) {
if (count($args) < $argnum) {
array ('argnum' => $argnum, 'plural' => $argnum>1 ? 's': ''),
foreach ($this->args as $name=> $arg) {
$result->args [$name] = $c ? array_splice($args, 0 , - $c) : $args;
if (!$result->args [$name] && $arg->optional && $arg->default ) {
$result->args [$name] = $arg->default;
// check value is in argument choices
if (!empty ($this->args[$name]->choices )) {
foreach ($result->args [$name] as $value) {
'ARGUMENT_VALUE_NOT_VALID',
'choices' => implode('", "', $arg->choices ),
'value' => implode(' ', $result->args [$name]),
// dispatch deferred options
foreach ($this->_dispatchLater as $optArray) {
$optArray[0 ]->dispatchAction ($optArray[1 ], $optArray[2 ], $this);
* Parses the command line token and modifies *by reference* the $options
* @param string $token The command line token to parse
* @param object $result The Console_CommandLine_Result instance
* @param array &$args The argv array
* @param int $argc Number of lasting args
* @throws Exception on user errors
protected function parseToken($token, $result, &$args, $argc)
static $stopflag = false;
if (!$stopflag && $lastopt) {
if (substr ($token, 0 , 1 ) == '-') {
if ($lastopt->argument_optional ) {
$this->_dispatchAction ($lastopt, '', $result);
if ($lastopt->action != 'StoreArray') {
} else if (isset ($result->options [$lastopt->name ])) {
// case of an option that expect a list of args
array ('name' => $lastopt->name),
// when a StoreArray option is positioned last, the behavior
// is to consider that if there's already an element in the
// array, and the commandline expects one or more args, we
// leave last tokens to arguments
if ($lastopt->action == 'StoreArray'
if (!is_null($token) || $lastopt->action == 'Password') {
$this->_dispatchAction ($lastopt, $token, $result);
if ($lastopt->action != 'StoreArray') {
if (!$stopflag && substr($token, 0 , 2 ) == '--') {
if (trim($optkv[0 ]) == '--') {
// the special argument "--" forces in all cases the end of
array ('name' => $optkv[0 ]),
$value = isset ($optkv[1 ]) ? $optkv[1 ] : false;
if (!$opt->expectsArgument () && $value !== false ) {
'OPTION_VALUE_UNEXPECTED',
array ('name' => $opt->name, 'value' => $value),
if ($opt->expectsArgument () && $value === false ) {
// maybe the long option argument is separated by a space, if
// this is the case it will be the next arg
if ($last && !$opt->argument_optional ) {
array ('name' => $opt->name),
// we will have a value next time
if ($opt->action == 'StoreArray') {
$this->_dispatchAction ($opt, $value, $result);
} else if (!$stopflag && substr($token, 0 , 1 ) == '-') {
$optname = substr($token, 0 , 2 );
// special case of "-": try to read stdin
array ('name' => $optname),
// parse other options or set the value
// in short: handle -f<value> and -f <value>
// check if we must wait for a value
if ($opt->expectsArgument ()) {
if ($last && !$opt->argument_optional ) {
array ('name' => $opt->name),
// we will have a value next time
if (!$opt->expectsArgument ()) {
$this->_dispatchAction ($opt, false , $result);
if ($opt->action == 'StoreArray') {
$this->_dispatchAction ($opt, $value, $result);
// if we are in POSIX compliant mode, we must set the stop flag to
// true in order to stop option parsing.
// addBuiltinOptions() {{{
* Adds the builtin "Help" and "Version" options if needed.
$helpOptionParams = array (
'description' => 'show this help message and exit',
if (!($option = $this->findOption('-h')) || $option->action == 'Help') {
// short name is available, take it
$helpOptionParams['short_name'] = '-h';
$versionOptionParams = array (
'long_name' => '--version',
'description' => 'show the program version and exit',
// short name is available, take it
$versionOptionParams['short_name'] = '-v';
$this->addOption('version', $versionOptionParams);
* Tries to return an array containing argc and argv, or trigger an error
* if it fails to get them.
* @return array The argc/argv array
* @throws Console_CommandLine_Exception
$argv = array ($this->name);
foreach ($_REQUEST as $key => $value) {
// match a configured option
$argv[] = $opt->short_name ?
$opt->short_name : $opt->long_name;
if ($opt->expectsArgument ()) {
$argv[] = isset ($_REQUEST[$key]) ? urldecode($v) : $v;
} else if ($v == '0' || $v == 'false') {
} else if (isset ($this->args[$key])) {
// match a configured argument
$argv[] = isset ($_REQUEST[$key]) ? urldecode($v) : $v;
return array (count($argv), $argv);
if (isset ($argc) && isset ($argv)) {
// case of register_argv_argc = 1
return array ($argc, $argv);
if (isset ($_SERVER['argc']) && isset ($_SERVER['argv'])) {
return array ($_SERVER['argc'], $_SERVER['argv']);
return array (0 , array ());
* Dispatches the given option or store the option to dispatch it later.
* @param Console_CommandLine_Option $option The option instance
* @param string $token Command line token to parse
* @param Console_CommandLine_Result $result The result instance
private function _dispatchAction ($option, $token, $result)
if ($option->action == 'Password') {
$this->_dispatchLater [] = array ($option, $token, $result);
$option->dispatchAction ($token, $result, $this);
* Tries to return the subcommand that matches the given token or returns
* false if no subcommand was found.
* @param string $token Current command line token
* @return mixed An instance of Console_CommandLine_Command or false
private function _getSubCommand ($token)
if ($cmd->name == $token || in_array($token, $cmd->aliases )) {
Documentation generated on Mon, 11 Mar 2019 15:51:31 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|