A PHP class for parsing CLI options, text and INI files.
<?php
/**
* Command Line option exception
*
* Extend Exception class for custom exception type.
*/
class CommandLineOptionException extends Exception {}
/**
* Command Line class.
*
* A PHP class for parsing command-line options, text and INI configuration
* files.
*/
class CommandLine {
/**
* Plain-text file type const.
*
* @var const CONFIG_TYPE_PLAIN
*/
const CONFIG_TYPE_PLAIN = 1;
/**
* Ini file type const.
*
* @var const CONFIG_TYPE_INI
*/
const CONFIG_TYPE_INI = 2;
/**
*
* Parses command-line arguments and returns them as an array.
*
* @access public
* @static
* @param array $args An array of command line arguments.
* @param array $allowed Optional array of valid/whitelist options.
* @throws CommandLineOptionException Throws exception if the option is unrecognized.
* @return array The parsed command-line arguments as an array.
*
* @example
* -a is a single - character option that assumes a Boolean value (acts as a switch for turning script options on or off)
* -a -b -c are a series of single - character options, may also be condensed as -abc
* -a foo is a single - character option with an assigned argument
* -abc foo are single - character options condensed with an argument assigned to the last option (a and b would assume true while c would be assigned foo)
* --abc is an option provided as a multiple - character string
* --abc=foo is a multiple - character option with an assigned argument
*/
static public function parseOptions($args, $allowed = array()) {
$options = array();
$count = count($args);
// retrive arguments and populate $options array
for($i = 1; $i < $count; $i++) {
// retrieve arguments in form of --abc=foo
if (preg_match('/^--([-A-Z0-9]+)=(.+)$/i', $args[$i], $matches)) {
if (empty($allowed) || in_array($matches[1], $allowed)) {
$options[$matches[1]] = $matches[2];
} else {
throw new CommandLineOptionException('Unrecognized option ' . $matches[1]);
}
}
// retrieve --abc arguments
else if (substr($args[$i], 0, 2) == '--') {
$tmp = substr($args[$i], 2);
if (empty($allowed) || in_array($tmp, $allowed)) {
$options[$tmp] = true;
} else {
throw new CommandLineOptionException('Unrecognized option ' . $tmp);
}
}
// retrieve -abc foo, -abc, -a foo and -a arguments
else if ($args[$i][0] == '-' && strlen($args[$i]) > 1) {
// set all arguments to true except for last in sequence
for($j = 1; $j < strlen($args[$i]) - 1; $j++) {
if (empty($allowed) || in_array($args[$i][$j], $allowed)) {
$options[$args[$i][$j]] = true;
} else {
throw new CommandLineOptionException('Unrecognized option ' . $args[$i][$j]);
}
}
// set last argument in compressed sequence
$tmp = substr($args[$i], -1, 1);
if (empty($allowed) || in_array($tmp, $allowed)) {
// assign next $args value if is value
if ($i + 1 < $count && $args[$i + 1][0] != '-') {
$options[$tmp] = $args[$i + 1];
$i++;
} // assign option as boolean
else {
$options[$tmp] = true;
}
} else {
throw new CommandLineOptionException('Unrecognized option ' . $tmp);
}
}
// invalid option format
else {
throw new CommandLineOptionException('Invalid option format at ' . $args[$i]);
}
}
return $options;
}
/**
* Parses a configuration file and returns the options as an array.
*
* @access public
* @static
* @param string $file The file to open.
* @param const $type Plain-text file or INI file.
* @return Ambigous <multitype:, multitype:string>
*/
static public function parseConfigFile($file, $type = CONFIG_TYPE_PLAIN) {
$options = array();
// process plain configuration file
if ($type == CONFIG_TYPE_PLAIN) {
$fp = fopen($file, 'r');
while (!feof($fp)) {
$line = trim(fgets($fp));
// skip blank lines and comments
if ($line && !preg_match('^#', $line)) {
$pieces = explode('=', $line);
$opt = trim($pieces[0]);
$value = trim($pieces[1]);
$options[$opt] = $value;
}
}
fclose($fp);
}
// process ini configuration file
else if ($type == CONFIG_TYPE_INI) {
$options = parse_ini_file($file);
}
return $options;
}
/**
* Displays a prompt and reads keyboard input.
*
* Prompt for user input, accept optional maximum input length
* and callback function for validation.
*
* @access public
* @static
* @param string $label
* @param int $length Maximum allowed input length.
* @param function $callback
* @return mixed|string
*/
static public function prompt($label, $length = 255, $callback = null) {
echo $label . ': ';
$value = trim(fread(STDIN, 255));
return ($callback) ? call_user_func($callback, $value) : $value;
}
/**
* Displays a prompt with suggested response and reads keyboard input.
*
* Prompt for user input, accept optional default value, maximum
* input length and callback function for validation.
*
* @access public
* @static
* @param string $label
* @param int|string $default Optional default value. Default is null.
* @param int $length Maximum allowed input length.
* @param unknown_type $callback
* @return mixed
*
* @example
*
* do {
* $db_host = CommandLine::promptDefault('Database host', 'localhost');
* $db_schema = CommandLine::promptDefault('Database schema', 'TEST');
* $db_user = CommandLine::promptDefault('Database user', 'TESTUSR');
* $db_pass = CommandLine::prompt('Database password');
*
* echo str_repeat('-', 70) . "\n";
* echo 'Database host: ' . $db_host . "\n";
* echo 'Database schema: ' . $db_schema . "\n";
* echo 'Database user: ' . $db_user . "\n";
* echo 'Database password: ' . $db_pass . "\n";
* echo 'Database table prefix: ' . $db_tbl_prefix . "\n";
*
* $ok = CommandLine::promptDefault('Is this correct?', 'yes', 3, 'strtolower');
* }
*
* while ($ok != 'yes' && $ok != 'y');
* echo "\n";
*
*/
static public function promptDefault($label, $default = null, $length = 255, $callback = null) {
$label .= ' [' . $default . ']';
$value = self::prompt($label, $length);
if (!$value) {
$value = $default;
}
return ($callback) ? call_user_func($callback, $value) : $value;
}
}
?>