Today, I decided to build a simple, but highly parametrable script that takes a bunch of images and resizes them with a given method. My first problem was : how to make a good command line arguments parser, so that I don’t have to write each argument in a specific order, or not putting some arguments at all, using a default value…
In bash, this is quite simple, but I wanted to use PHP for the script, so that I could use the GD library that I know well.

Then I found this class, made by Diego Feitosa, that looked nice, but wasn’t exactly what I wanted : I was forced to use an option (i.e. “-something <param>”) for each argument in the command line. It is nice for defining the behaviour of the script, but if you want to script something that process files, you just can’t – or only one file at a time.

In fact, this is exactly what I was doing : processing a lot of files. But with this parser, I couldn’t. So I decided to hack it a bit…

This code is an extended version of the CLI Parser of Diego Feitosa, which allows the user to pass arguments that are not options. I also made other modifications to the script :

  • added a method to check if an argument is valid as a non option (by default, everything that doesn’t start with ‘-’ can be a non-option)
  • improved usage description : the type awaited by an option is shown, better indentation
  • improved error messages : if the type in the command line doesn’t match with an option, the error is shown. In the version of Diego, only the usage message was shown.
  • auto-inclusion of the option types
  • new option types : Positive Numeric, Negative Numeric, Integers, Enum

You can find the code here.

Here is an example of the usage of this parser. This example is also located in the source code provided above :

require_once('CliParser.inc');
$clistring = new CliTokenString("-c");
$clistring->setDescription("It requires a string");

$clihelp = new CliTokenBoolean("--help");
$clihelp->setDescription("Token that shows a help message");

$clisingleton = new CliTokenBoolean("-e");
$clisingleton->setDescription("It don't require any value. The existence of this argument is enough");

$clibool = new CliTokenBoolean("-b");
$clibool->setDescription("Boolean token");

$clidir = new CliTokenDirectory("-d");
$clidir->setDescription("This token require a directory path as argument. If the argument isn't a directory path, an error message will appear.");

$clifile = new CliTokenDirectory("-f");
$clifile->setDescription("This token require a file path as argument. If the argument isn't a file path, an error message will appear.");

$cliint = new CliTokenInteger("-i");
$cliint->setDescription("This token require an integer path as argument. If the argument isn't an integer, an error message will appear.");

$clienum = new CliTokenEnum("-enum", array('the', 'different', 'values', 'accepted'));
$clienum->setDescription("This token requires its argument to be one of the values specified");

class MyCliParser extends CliParser
{
  public function getHelpMessage()
  {
    global $argv;
    echo sprintf("Usage: %s [options] <file(s)>\nOptions :\n", $argv[0]);
    $this->getDescriptions();
    echo "\n";
    exit;
  }
}

//Building the parser and parsing the arguments
$cli = new MyCliParser($_SERVER["argv"]);
$cli->register($clihelp, false); // false because it not require an argument
$cli->register($clistring);
$cli->register($clisingleton, false); // false because it not require an argument
$cli->register($clibool);
$cli->register($clidir);
$cli->register($clifile);
$cli->register($cliint);
$cli->register($clienum);
$cli->parse();

//Showing the help message if asked
if ($clihelp->getValue())
{
  $cli->getHelpMessage();
  exit;
}

//Showing the options
var_dump($clistring->getValue());
var_dump($clisingleton->getValue());
var_dump($clibool->getValue());
var_dump($clidir->getValue());
var_dump($clifile->getValue());
var_dump($cliint->getValue());

//Showing the non options
var_dump($cli->getNonOptions());

/* Some commands :
php example.php --help
=> will show the help message

php example.php -c foo
=> the $clistring token will be set

php example.php -e -c foo
=> the $clisingleton token will be set

php example.php nonoption1 -i 42
=> one non-option argument : nonoption1

php example.php -i 42 nonoption1
=> same thing, different order

php example.php -i 42.5
=> shows an error : 42.5 is not an integer
*/