I wrote a library some time ago to counter some of the missing features of the rather limited 'getopt' function. The library as well documentation can be found on my website at http://hash-bang.net/2008/12/missing-php-functions-getopts/
It provides functionality for long switches (e.g. '--delete'), incrementing switches (e.g. '-v -v -v' or '-vvv' for very, very verbose), long values (e.g. '--exclude this.file') and lots more.
getopt
(PHP 4 >= 4.3.0, PHP 5)
getopt — Lit des options passées dans la ligne de commande
Description
getopt() lit les options passées dans la ligne de commande.
Liste de paramètres
- options
- Chaque caractère dans cette chaîne sera utilisé en tant que caractères optionnels et devra correspondre aux options passées, commençant par un tiret simple (-). Par exemple, une chaîne optionnelle "x" correspondra à l'option -x.
- longopts
-
Un tableau d'options. Chaque élément de ce tableau sera utilisé comme
option et devra correspondre aux options passées, commençant par un
tiret double (--).
Par exemple, un élément longopts "opt"
correspondra à l'option --opt.
Note: Avant PHP 5.3.0, ce paramètre n'était disponible que sous peu de systèmes.
Le paramètre options peut contenir les éléments suivants :
- Caractères individuels (n'accepte pas de valeur)
- Caractères suivis par un deux-points (le paramètre nécessite une valeur)
- Caractères suivis par deux deux-points (valeur optionnelle)
Les valeurs optionnelles sont les premiers arguments après la chaîne. Peut importe que la valeur soit suivie d'un espace ou non.
Note: Les valeurs optionnelles n'acceptent pas l'espace comme séparateur.
Note: Le format des paramètres options et longopts est identique ; la seule différence est que longopts prend un tableau en option (où chaque élément est une option) alors que options prend une chaîne (où chaque caractère est une option).
Valeurs de retour
Cette fonction retourne un tableau d'options/arguments, ou FALSE si une erreur survient.
Historique
| Version | Description |
|---|---|
| 5.3.0 | Ajout du support de "=" comme séparateur argument/valeur. |
| 5.3.0 | Ajout du support des valeurs optionnelles (spécifié par "::"). |
| 5.3.0 | Cette fonction n'est plus dépendante du système et fonctionne maintenant également sous Windows. |
Exemples
Exemple #1 Exemple avec getopt()
<?php
$options = getopt("f:hp:");
var_dump($options);
?>
L'exécution du script ci-dessus avec la commande php script.php -fvalue -h affichera :
array(2) {
["f"]=>
string(5) "value"
["h"]=>
bool(false)
}
Exemple #2 Second exemple avec getopt()
<?php
$shortopts = "";
$shortopts .= "f:"; // Valeur requise
$shortopts .= "v::"; // Valeur optionnelle
$shortopts .= "abc"; // Ces options n'acceptent pas de valeur
$longopts = array(
"required:", // Valeur requise
"optional::", // Valeur optionnelle
"option", // Aucune valeur
"opt", // Aucune valeur
);
$options = getopt($shortopts, $longopts);
var_dump($options);
?>
L'exécution du script ci-dessus avec la commande php script.php -f "value for f" -v -a --required value --optional="optional value" --option affichera :
array(6) {
["f"]=>
string(11) "value for f"
["v"]=>
bool(false)
["a"]=>
bool(false)
["required"]=>
string(5) "value"
["optional"]=>
string(14) "optional value"
["option"]=>
bool(false)
}
Exemple #3 Troisième exemple avec getopt()
Passage de plusieurs options
<?php
$options = getopt("abc");
var_dump($options);
?>
L'exécution du script ci-dessus avec la commande php script.php -aaac affichera :
array(2) {
["a"]=>
array(3) {
[0]=>
bool(false)
[1]=>
bool(false)
[2]=>
bool(false)
}
["c"]=>
bool(false)
}
getopt
15-Mar-2009 11:36
16-Aug-2008 05:28
I really need long options but it's not supported in 5.2.6 on my Solaris box so I wrote an _getopt() to simulate getopt().
An example
======== a.php ========
#!/usr/local/bin/php
<?php
include "getopt.inc";
$shortopts = "f:v::abc:hp";
$longopts = array(
"required:", // Required value
"optional::", // Optional value
"option", // No value
"opt", // No value
);
$options = _getopt( $shortopts, $longopts);
var_dump($options);
?>
====== end of a.php ======
then run the file a.php,
# ./a.php -f "test 2" -ab --required "test 1" --optional="test 3" --option -v "test 4" -k
array(7) {
["f"]=>
string(6) "test 2"
["a"]=>
bool(false)
["b"]=>
bool(false)
["required"]=>
string(6) "test 1"
["optional"]=>
string(6) "test 3"
["option"]=>
bool(false)
["v"]=>
string(6) "test 4"
}
Source code is a bit longer and not allowed by this site. Please go to my page http://www.ntu.beautifulworldco.com/weblog/?p=526 for it.
24-May-2008 08:41
After getopt() of PHP5.3.0 (on Windows) ignored some parameters if there was a syntactical problem, I decided to code my own generic parameter parser.
<?php
/**
* Parses $GLOBALS['argv'] for parameters and assigns them to an array.
*
* Supports:
* -e
* -e <value>
* --long-param
* --long-param=<value>
* --long-param <value>
* <value>
*
* @param array $noopt List of parameters without values
*/
function parseParameters($noopt = array()) {
$result = array();
$params = $GLOBALS['argv'];
// could use getopt() here (since PHP 5.3.0), but it doesn't work relyingly
reset($params);
while (list($tmp, $p) = each($params)) {
if ($p{0} == '-') {
$pname = substr($p, 1);
$value = true;
if ($pname{0} == '-') {
// long-opt (--<param>)
$pname = substr($pname, 1);
if (strpos($p, '=') !== false) {
// value specified inline (--<param>=<value>)
list($pname, $value) = explode('=', substr($p, 2), 2);
}
}
// check if next parameter is a descriptor or a value
$nextparm = current($params);
if (!in_array($pname, $noopt) && $value === true && $nextparm !== false && $nextparm{0} != '-') list($tmp, $value) = each($params);
$result[$pname] = $value;
} else {
// param doesn't belong to any option
$result[] = $p;
}
}
return $result;
}
?>
A call like: php.exe -f test.php -- alfons -a 1 -b2 -c --d 2 --e=3=4 --f "alber t" hans wurst
and an in-program call parseParameters(array('f')); would yield in a resulting array:
Array
(
[0] => alfons
[a] => 1
[b2] => 1
[c] => 1
[d] => 2
[e] => 3=4
[f] => 1
[1] => alber t
[2] => hans
[3] => wurst
)
As you can see, values without an identifier are stored with numeric indexes. Existing identifiers without values get "true".
25-Apr-2008 08:26
One thing of important note would be that getopt() actually respects the '--' option to end an option list. Thus given the code:
test.php:
<?php
$options = getopt("m:g:h:");
if (!is_array($options) ) {
print "There was a problem reading in the options.\n\n";
exit(1);
}
$errors = array();
print_r($options);
?>
And running:
# ./test.php ./run_vfs -h test1 -g test2 -m test3 -- this is a test -m green
Will return:
Array
(
[h] => test1
[g] => test2
[m] => test3
)
Whereas running:
# /test.php ./run_vfs -h test1 -g test2 -m test3 this is a test -m green
Will return:
Array
(
[h] => test1
[g] => test2
[m] => Array
(
[0] => test3
[1] => green
)
)
19-Nov-2007 08:44
Although very interesting, koenbollen at gnospamail dot com's update of the argv array fails when option values follow the option with no space :
Indeed
php MyScript.php5 -t5
and
php MyScript.php5 -t 5
with $options="t:" are treated as the same by getopt.
This upgraded function should take care of it :
File : shift_test.php5
<?php
function shift($options_array)
{
foreach( $options_array as $o => $a )
{
// Look for all occurrences of option in argv and remove if found :
// ----------------------------------------------------------------
// Look for occurrences of -o (simple option with no value) or -o<val> (no space in between):
while($k=array_search("-".$o.$a,$GLOBALS['argv']))
{ // If found remove from argv:
if($k)
unset($GLOBALS['argv'][$k]);
}
// Look for remaining occurrences of -o <val> (space in between):
while($k=array_search("-".$o,$GLOBALS['argv']))
{ // If found remove both option and value from argv:
if($k)
{ unset($GLOBALS['argv'][$k]);
unset($GLOBALS['argv'][$k+1]);
}
}
}
// Reindex :
$GLOBALS['argv']=array_merge($GLOBALS['argv']);
}
print_r($argv);
$options_array=getopt('t:h');
shift($options_array);
print_r($argv);
?>
>php shift_test.php5 -h -t4 param1 param2
will ouptut :
Array
(
[0] => test.php5
[1] => -h
[2] => -t4
[3] => param1
[4] => param2
)
Array
(
[0] => test.php5
[1] => param1
[2] => param2
)
>php shift_test.php5 -h -t 4 param1 param2
will ouptut :
Array
(
[0] => test.php5
[1] => -h
[2] => -t
[3] => 4
[4] => param1
[5] => param2
)
Array
(
[0] => test.php5
[1] => param1
[2] => param2
)
08-Nov-2007 06:47
This is how I handle arguments with getopt: I use switch within a foreach at the beginning of a program.
<?php
$opts = getopt('hs:');
// Handle command line arguments
foreach (array_keys($opts) as $opt) switch ($opt) {
case 's':
// Do something with s parameter
$something = $opts['s'];
break;
case 'h':
print_help_message();
exit(1);
}
print "$something\n";
?>
23-Apr-2007 06:40
<?php
function getopt_($opts, $argv) {
$opts_array = explode(':', $opts);
foreach($opts_array as $opt) {
$key = array_search($opt, $argv);
if($key && !in_array($argv[$key+1], $opts_array)) {
$result[$opt] = trim($argv[$key+1]);
} elseif($key) {
$result[$opt] = '';
}
}
return $result;
}
$result = getopt('-h:-o:--help', $argv);
?>
29-Mar-2007 08:51
After you use the getopt function you can use the following script to update the $argv array:
<?php
$options = "c:ho:s:t:uvV";
$opts = getopt( $options );
foreach( $opts as $o => $a )
{
while( $k = array_search( "-" . $o, $argv ) )
{
if( $k )
unset( $argv[$k] );
if( preg_match( "/^.*".$o.":.*$/i", $options ) )
unset( $argv[$k+1] );
}
}
$argv = array_merge( $argv );
?>
Note: I used the array_merge function to reindex the array's keys.
Cheers, Koen Bollen
About getopt(String):
Parses the command-line arguments into an associative array, using the function's String parameter to specify arguments and options, thus:
* arguments are specified as any letter followed by a colon, e.g. "h:".
* arguments are returned as "h" => "value".
* options are specified as any letter not followed by a colon, e.g. "r".
* options are returned as "r" => (boolean) false.
Also note that:
1) Options or arguments not passed in the command-line parameters are not set in the returned associative array.
2) Options or arguments present in the command-line arguments multiple times are returned as an enumerated array within the returned associative array.
25-Oct-2006 02:08
You cant use this function twice or more.
For example:
<?php
print_r(getopt('a:b:c:'));
print_r(getopt('d:e:f:'));
?>
You would be confused by the result.
[yarco@localhost ~]$ php test3.php -a love -b love -d love
Array
(
[a] => love
[b] => love
)
Array
(
[e] => love
[d] => love
)
30-Apr-2006 04:57
There are 2 simpler (and much faster) methods for getting good getopt() operation without creating your own handler.
1. Use the Console_Getopt PEAR class (should be standard in most PHP installations) which lets you specify both short and long form options as well as whether or not arguments supplied to an option are themselves 'optional'. Very simple to use and requires very little code to operate compaired to writing own handler.
2. If you cannot load external PEAR objects, use your shell's getopt() functions (which in BASHs case work very well) to process options and have your shell script then call your PHP script with a rigid argument structure that is very easy for PHP to digest such as:
% myfile.php -a TRUE -b FALSE -c ARGUMENT ...
If the initial arguments are invalid you can have the shell script return an error without calling the PHP script. Sounds convoluted but is a very simple solution and in fact PHP's own % pear command uses this method. /usr/bin/pear is a shell script that does some simle checking before calling pearcmd.php and repassing the arguments on to it.
The second method is by far the best for portability because it allows a single shell script to check a few things like your PHP version and respond acordingly e.g. does it call your PHP4 or PHP5 compatible script? Also, because getopt() is not available on Windows, The second solution allows you to do Windows specific testing as a BAT file (as oposed to BASH, ZSH or Korn on UNIX).
31-May-2005 08:11
This is how I parse command line options:
<?php
$OPTION['debug'] = false;
$OPTION['test'] = false;
$OPTION['force'] = "";
//loop through our arguments and see what the user selected
for ($i = 1; $i < $_SERVER["argc"]; $i++)
{
switch($_SERVER["argv"][$i])
{
case "-v":
case "--version":
echo $_SERVER['argv'][0]." v07.19.04 06:10 PM\n";
exit;
break;
case "--debug":
$OPTION['debug'] = true;
break;
case "--force":
$OPTION['force'] = " --force";
break;
case "--db":
case "--database":
case "--id":
if ( is_numeric($_SERVER['argv'][$i+1]) )
$OPTION['CompanyID'] = intval($_SERVER['argv'][++$i]);
else //it must be a database name
$OPTION['CompanyDB'] = $_SERVER['argv'][++$i];
break;
case "--base":
case "--basedir":
case "--dir":
$OPTION['basedir'] = $_SERVER["argv"][++$i];
break;
case "--test":
$OPTION['test'] = true;
break;
case "-?":
case "-h":
case "--help":
?>
This will print any .txt files, process any .sql files and
execute any .php files found starting from the base directory
'<?=$OPTION['basedir']?>' in alphabetical order.
Usage: <?php echo $_SERVER['argv'][0]; ?> <option>
--help, -help, -h, or -? to get this help.
--version to return the version of this file.
--debug to turn on output debugging.
--test to fake the SQL and PHP commands.
--force to ignore SQL errors and keep on going.
--db [CompanyDB] to apply to only this [CompanyDB].
--id [CompanyID] to apply to only this [CompanyID].
--basedir [directory] to change base directory from <?=$OPTION['basedir']?>.
Omitting the CompanyID or CompanyDB will cause ALL Company DB's to be updated.
There are global files and per-company files. Global files are applied to global
databases (see list below). Their filename contains a tag that reflects the database
to apply them against. Per-company files are applied against databases. Their
filename contains a tag that reads 'COMPANY'. Files should be in <?=$OPTION['basedir']?>;
Global files that are understood:
<?=$OPTION['basedir']?>
<?php foreach ($GLOBAL_SQL_FILES as $sqlFile) echo $sqlFile." "; ?>
<?php
exit;
break;
}
} //parse arguments
// print_r($OPTION);
?>
24-Apr-2004 02:17
"phpnotes at kipu dot co dot uk" and "tim at digicol dot de" are both wrong or misleading. Sean was correct. Quoted space-containing strings on the command line are one argument. It has to do with how the shell handles the command line, more than PHP. PHP's getopt() is modeled on and probably built upon the Unix/POSIX/C library getopt(3) which treats strings as strings, and does not break them apart on white space.
Here's proof:
$ cat opt.php
#! /usr/local/bin/php
<?php
$options = getopt("f:");
print_r($options);
?>
$ opt.php -f a b c
Array
(
[f] => a
)
$ opt.php -f 'a b c'
Array
(
[f] => a b c
)
$ opt.php -f "a b c"
Array
(
[f] => a b c
)
$ opt.php -f a\ b\ c
Array
(
[f] => a b c
)
$
