ZF-11133: Zend_Console_Getopt: Missing required parameter consumes next option as its parameter value
Description
Given a rules declaration like:
$rules = array('user|u=s' => 'Username (required)',
'case|c=i' => 'Case number (required)');
$options = new Zend_Console_Getopt($rules);
calling this with the first option missing its parameter, e.g.:
php test.php -u -c 12345
will result in the user option being assigned the value -c and the case option not being set at all. The same would not occur if the parameter were optional.
The problem arises in the _parseSingleOption function of Zend/Console/Getopt.php (line numbers refer to the version included in release 1.11.3). For options with required parameters the next argument (if one exists) is always processed as the parameter (line 791/792),
case 'required':
if (count($argv) > 0) {
whereas for optional parameters, the next argument is checked for a leading '-' (line 802/803):
case 'optional':
if (count($argv) > 0 && substr($argv[0], 0, 1) != '-') {
The simple solution is to add the check for the leading '-' to the required parameter processing too (make line 792 identical to line 803). The downside is that required parameters with a genuine leading '-' would no longer be possible, but since optional parameters already cannot have it, and allowing it is a potential source of confusion, this should not be an issue.
If it is desired to allow parameter values with leading '-', it should be possible to do something either by checking whether the next argument matches a valid option, or by insisting on using the --user="-Fred" syntax with an extra processing to indicate that the next argument (created from the string after the =) is definitely a parameter.
Comments
Posted by Chris de Kok (mech7) on 2011-09-28T07:10:53.000+0000
Yes this is confusing the docs still mention you can make it required!
Posted by Andras Gyomrey (andras) on 2012-08-15T16:00:12.000+0000
Where's the error: docs or implementation? Would a patch be useful?
Posted by Simon Yates (yatessc) on 2012-08-16T09:30:57.000+0000
Probably only implementation, depending on the decision as to required behaviour.
According to the documentation at present, in the example I gave above an exception should be thrown for the missing parameter to the username option, but in fact it consumes the -c as the parameter value, and the casenumber option is not set. This results in incorrect errors - the calling script thinks that the casenumber option has not been set (or passed at all), whereas in fact it is the username that is missing.
As I said, the simple solution would be to check the next argument for a leading '-' in the required parameter case as well, just as the optional parameter case already does. This would enable the code to function as documented. (It is possible, though I would hope unlikely, that this would break some existing code relying on the undocumented behaviour.)