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".
getopt
(PHP 4 >= 4.3.0, PHP 5)
getopt — コマンドライン引数のリストからオプションを取得する
説明
スクリプトに渡されたオプションをパースします。
パラメータ
- options
- この文字列の各文字をオプション文字として使用し、 スクリプトにハイフンひとつ (-) で始まるオプションとして渡された内容とマッチさせます。 たとえば、オプション文字列 "x" は -x というオプションを認識します。
- longopts
-
オプションの配列。
この配列の各要素をオプション文字列として使用し、
スクリプトにハイフンふたつ (--)
で始まるオプションとして渡された内容とマッチさせます。
たとえば、longopts の要素 "opt" は
--opt というオプションを認識します。
注意: PHP5.3.0 より前のバージョンでは、 このパラメータは一部のシステムでしか使用できません。
options パラメータに含まれる要素には次のようなものがあります。
- 単一の文字 (値を受け付けない)
- 文字の後にコロンをひとつ続けたもの (値が必須であるパラメータ)
- 文字の後にコロンをふたつ続けたもの (値がオプションであるパラメータ)
注意: オプションの値で、" " (空白) を区切り文字として使用することはできません。
注意: options と longopts の書式はほぼ同じです。唯一の違いは、 longopts はオプションの配列 (その各要素がオプションとなる) を受け取るけれども options は文字列 (その各文字がオプションとなる) を受け取るということです。
返り値
この関数はオプション/引数のペアを連想配列で返します。 失敗した場合は FALSE を返します。
変更履歴
| バージョン | 説明 |
|---|---|
| 5.3.0 | "=" を引数/値の区切り文字として使用できるようになりました。 |
| 5.3.0 | オプションの値 ("::" で指定します) に対応しました。 |
| 5.3.0 | この関数はシステムに依存しなくなり、 Windows でも動作するようになりました。 |
例
例1 getopt() の例
<?php
$options = getopt("f:hp:");
var_dump($options);
?>
上のスクリプトを php script.php -fvalue -h として実行すると、次のようになります。
array(2) { ["f"]=> string(5) "value" ["h"]=> bool(false) }
例2 getopt() の例 その2
<?php
$shortopts = "";
$shortopts .= "f:"; // 値が必須
$shortopts .= "v::"; // 値がオプション
$shortopts .= "abc"; // これらのオプションは値を受け取りません
$longopts = array(
"required:", // 値が必須
"optional::", // 値がオプション
"option", // 値なし
"opt", // 値なし
);
$options = getopt($shortopts, $longopts);
var_dump($options);
?>
上のスクリプトを php script.php -f "value for f" -v -a --required value --optional="optional value" --option として実行すると、次のようになります。
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) }
例3 getopt() の例 その3
複数のオプションを一度に渡す例
<?php
$options = getopt("abc");
var_dump($options);
?>
上のスクリプトを php script.php -aaac として実行すると、次のようになります。
array(2) { ["a"]=> array(3) { [0]=> bool(false) [1]=> bool(false) [2]=> bool(false) } ["c"]=> bool(false) }
注意
注意: register_argc_argv オプションを有効にしないと、この館数は動作しません。
getopt
25-May-2008 05:41
26-Apr-2008 05: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:
<?
$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
)
)
17-Feb-2008 05:42
It was not obvious to me how to check for the presence of options which do not accept values, but this will do it:
<?php
$options = getopt('a');
if ( is_null($options['a']) )
echo "-a not present\n";
else
echo "-a present\n";
?>
20-Nov-2007 05: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 03: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";
?>
24-Apr-2007 03: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 05: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 11: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
)
06-Jun-2006 06:55
I have written another function to parse command line variables. The source can be found at http://afe.cc/getopt.txt and the include file generic.h is at http://afe.cc/generic.h .
What you need to do is to put required variables to an array in a specific order and call parse_args. All variables that must be read from command line are set automatically. I've tried to imitate the output of GNU's getopt library.
Hope it helps.
AFE
01-May-2006 01: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).
09-Dec-2005 09:59
After having problems with the getopt() function I developed this to handle parameters in a smilar way to 'nix shell script. Hope this is of some us to someone.
#!/usr/bin/php4
<?php
#
# Purpose: Parse parameters passed to script in way comaparable to shell script
# Usage: include_once("/some/path/getArgs.php"); OR
# require_once("/some/path/getArgs.php"); depending on context of parent script
# Post: Generate an associative array $params
#
# Author: A.Waite
# Date: 09/12/05
# Version: V1.0
$i = 1;
$params = array();
for ($i=1; $i < $argc; $i++){
if ( isParam($argv[$i]) ){
if (strlen($argv[$i]) == 1){
//do nothing
// single -
}elseif ( strlen($argv[$i]) == 2){
//seperated (ie -H www.google.com) or no value parameter (ie. -h)
$paramName = $argv[$i];
$paramVal = ( !isParam( $argv[ $i + 1 ] ) ) ? $argv[$i + 1] : null;
}elseif ( strlen($argv[$i]) > 2){
//joined parameters ie -Hwww.google.com
$paramName = substr($argv[$i],0,2);
$paramVal = substr($argv[$i],2);
}
$params[ $paramName ] = $paramVal;
}
}
#determines whether string is a parameter
function isParam($string){
return ($string{0} == "-") ? 1: 0;
}
?>
07-Sep-2005 03:40
The code snippet that daevid at daevid dot com gives works, however is not a perfect getopt replacement since you cannot use the "default" switch statement.
Usage: prog [OPTIONS] <req'd argument> <req'd argument>
The switch() call will eventually run on those 2 required arguments. If you use the "default" statement, it will catch the argument and chances are you use the default statement as your --help trap, thus it will exit the script (if that's what you do).
So, if you use that example below, you may want to check each "argv" variable, and if it doesn't match --*, then you may want to skip past it and store it in another array for retrieval as a required argument if your script uses those.
I will be writing a getopt class that will do everything properly possibly, if/when I do, I'll post it up here so you can all use it rather than the built in getopt code (seems a bit limiting compared to the actual C library getopt_long()).
01-Jun-2005 05: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);
?>
31-Jan-2005 01:44
i didn't like the way getopt worked, exactly, so i wrote a new variant, that other people would possibly like to see. (works more like perl's function)
it reads an array of options like:
$opAr = array ("-a|--append","-l|--list","-i|--input:");
$op = bgetop($opAr);
and parses the command line, returning an array like
$op['cmdline'] = $param; ...
it has a small bug that can easily be avoided ... haven't yet determined how to work around the particular case where the bug exists, but otherwise is very robust.
it also accepts wildwards as the last option, or the output from another program like 'find' :
./getop.php `find /etc -name *.conf`
populates the $op array with the filenames returned from find. it's pretty nifty.
the source is at : http://higginsforpresident.net/projects/source/getopt-0.1.phps
i didn't want to post it here until i fixed that one condition, but the function works nicely (as expected) if you don't use duplicate beginnings for different option array strings:
$opAr = array("-f:","--foo");
bgetopt() sees --foo needs no 'next input', but -f exists in '--foo', so ./getop.php -f foobar set's f to 'true', which is the
expected result of array("-f","--foo") or array("-f|--foo"), but not ("-f:","--foo");
enjoy. (my first submission here ... be kind.)
12-May-2004 06:36
A sample use :
#!/usr/bin/php
<?php
$opt = getopt("s:f:r:u:");
$help="***Error :url_mailer.php -s <subject> -f <sender_email> -r <receipient_email> -u <url_to_mail>";
if($opt[s]=='' || $opt[r]=='' || $opt[u]=='' || $opt[f]=='' ){ echo "$help\n";exit(); }
# prepare the mail message from the url
$url=trim($opt[u]);
$message=file_get_contents($url);
# prepare mail headers
$headers = "MIME-Version: 1.0\r\n";
$headers.= "Content-type: text/html; charset=iso-8859-1\r\n";
$headers.= "From: $opt[f] \r\n";
# send the mail
mail($opt[r],$opt[s],$message,$headers);
?>
24-Apr-2004 11: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
)
$
20-Dec-2003 01:00
For all buddies outside who dont get getopt to work :)
here is a php variant with just standard function calls
<?
//Set Defaults
$options["a"]="valA";
$options["b"]="valB";
parseArgs($argv,&$options);
//options will be $options["FLAG"] (if not argument is given like -h the $options["h"] will be set to bolean true
if($options["h"] == true) {
print_usage();
exit(1);
}
var_dump($options);
function parseArgs($a = array(), $r) {
$f=NULL;
for($x = 0; $x < count($a); $x++) {
if($a[$x]{0} == "-") {
$f=$a[$x];
$r[substr($f,1,strlen($f))]=true;
}
if ($f != NULL) {
if (($a[$x+1] != NULL) && ($a[$x+1] != "") && ($a[$x+1] != "") && ($a[$x+1]{0} != "-")) {
$r[substr($f,1,strlen($f))]=$a[$x+1];
} else {
$f=$a[x+1];
}
}
}
}
function print_usage() {
echo "-a bla bla\n";
echo "-b bla bla\n";
echo "-h display this help\n";
}
?>
17-Jul-2003 11:07
Unlike POSIX.2 getopt(), this function does not modify argv, so it's
only useful if you have no non-option arguments. More often than
not, you're probably better off examining $argv yourself.