ayurkowski has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to use Getopt::Long to parse CLI args. When run from the command line, this works nicely; however, when I post to my ISP's site, then attempt to execute the script by passing the parameters in the browser, e.g.:

http://...script.cgi?--extract&--file=welcome

- boolean ("extract!" => \$extract) options work ok;
- STRING options ("file=s" => \$file) return as undefined
- if multiple options are used, EVERYTHING is undefined

Same results occur when I attempt to execute via SSI...
Is this a browser-specific thing, or what? I've just spent 6 hours perusing every (muttered cuss word deleted) FAQ I can find without gaining enlightenment. When I consider how long I've diddled around with this, I'd have been better off using CGI.pm and doing the extra type checking... <sigh>

  • Comment on Why does Getopt::Long ignore browser and SSI-based parameters?

Replies are listed 'Best First'.
Re: Why does Getopt::Long ignore browser and SSI-based parameters?
by Kanji (Parson) on Apr 16, 2002 at 12:34 UTC

    CGIs derive their parameters from either $ENV{'QUERY_STRING'} or <STDIN> (or both!), while Getopt::Long expects everything to be in @ARGV.

    Converting one to the other is trivial ...

    my $extract; my $file; { local @ARGV = split /&/, $ENV{'QUERY_STRING'}; GetOptions( 'file=s' => \$file, 'extract!' => \$extract, ); }

    That'll break if you have URI-escaped characters (ie, %7E instead of ~), so a more robust solution would be to iteratively build @ARGV using CGI's param funcs.

    my $extract; my $file; { local @ARGV; foreach my $key ( param ) { if ( param($key) ) { foreach my $value ( param($key) ) { push @ARGV, $key, $value; } } else { # arg-less booleans push @ARGV, $key; } } GetOptions( 'file=s' => \$file, 'extract!' => \$extract, ); }
Re: Why does Getopt::Long ignore browser and SSI-based parameters?
by ayurkowski (Initiate) on Apr 16, 2002 at 21:18 UTC
    Thanks for a succinct answer. Obviously, I would need to ensure that the appropriate parameters are prefixed ("--") to support GetOptions.

    Your answer raises two further questions if you'll indulge me:

    -why the different handling of arguments re: command line vs CGI -- and where, if anyplace, is that documented? I read and looked up references for 'parameters' and 'arguments' for a full day before I posted the question, and didn't see anything that hinted at the issue;

    -could you possibly explain the REALLY bizarre CGI response when I test-run your logic on Win32 and my ISPs SUN server?

    use CGI; my $qry = new CGI; my $argCt = @ARGV; for ($i=0; $i < $argCt; $i++) { print "Arg $i = [$ARGV[$i]]\n"; } print "No args found\n" if $argCt == 0; foreach my $key ( $qry->param ) { if ( $qry->param($key) ) { foreach my $value ( $qry->param($key) ) { print "key, value are $key, $value\n"; } } else { # arg-less booleans print "key-only is $key\n"; } } print "Arg(0) is [$ARGV[0]], param list is [", $qry->param(),"]\n";
    which given the following command lines, produces the given output:
    perl stuff.pl a b c Arg[0] = a Arg[1] = b Arg[2] = c key, value are keywords, a key, value are keywords, b key, value are keywords, c Arg(0) is [a], param list is [keywords]
    but
    perl stuff.pl a b= Arg[0] = a Arg[1] = b= key-only is a key-only is b Arg(0) is [a], param list is [ab]
    Note that the "arg-less" booleans appear to have values until ONE value is either specified, OR an "=" trails the value??? (As you noted, on the SUN/OS webserver, the arguments are undefined; the wierd "keywords" 'parameter' happens both on the Win32 command line AND when I run this on the website via the browser with
    http:...stuff.cgi?a&b

    Thanks!

      why the different handling of arguments re: command line vs CGI -- and where, if anyplace, is that documented?

      A good place to start is the CGI spec, but to answer your Perl isn't a CGI-centric language, so there's no reason why command-line and CGI arguments to be handle the same way.

      Heck, if you happened to write a Perl based webserver, handling them the same way could be detrimental; after all, how would you pass arguments to the webserver and process CGIs?

      could you possibly explain the REALLY bizarre CGI response

      An oversight on my part:

      If CGI.pm thinks it's being called ISINDEX-style (see the spec again and the CGI.pm's keyword section) it behaves a little differently, making arguments available via keywords or param('keywords').

      Something like the below may get things working as you expect, but my testing was inconsistent across different versions of CGI.pm.

      if ( param($key) ) { foreach my $value ( param($key) ) { if ( $key eq 'keywords' && keywords ) { # We ONLY have booleans push @ARGV, param('keywords'); next; } push @ARGV, $key, $value; } } else { # ...

          --k.