(CGI::Vars) Re: Variable Variables
by mwp (Hermit) on Dec 05, 2000 at 07:41 UTC
|
Doing something like this is bad practice, for a variety of
reasons. Mostly because if someone adds a form field that
you did not prepare for, it might affect a different part
of the script. For example, if someone added a form field
called "key" your script would die because it would try to
set $key to the form value, which is also the
loop iterator.
If you want to avoid calling $query->param()
each and every time you want to access the form values,
and I sympathize, you should try something like this:
use strict;
use CGI;
my $query = new CGI; # this will import the form values
my %vars = $query->Vars(); # this will "export" the form values
print "Name: ", $vars{name}, "\n";
...et cetera. See the CGI.pm manpage for more info
about the Vars syntax.
HTH
'kaboo | [reply] [Watch: Dir/Any] [d/l] [select] |
|
There's also import_names(), which takes an argument of a namespace (anything but main:: ;) to import parameters into, so that you can say $namespace::var instead of param('var') or $cgi->param('var').
use CGI qw/import_names/;
import_names('X');
print $X::hello;
Another case of TMTOWTDI. :)))
--k.
(Although you could always override CGI.pm's import_names() if you really, really, really wanted $hello, but the reasons its disabled by default are sound -- see the docs for more.) | [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
Thanks. Vars() is relatively new, around CGI.pm 2.50
if I remember correctly.
I understand what you're saying... he only creates the
variables in the list he defines for the foreach loop. I
guess what I was trying to imply was that whomever edits
the form and adds a field is going to have to come into
the CGI script and modify that too, creating the situation
I described. =) You would hope the programmer in question
would realize their folly and change the formfield name so
that it wouldn't break the script, but never forget
O'Toole's postulate: Murphy was an optimist.
| [reply] [Watch: Dir/Any] |
|
I recall seeing a link to a PHP(?) bug report because the automatic action in that language is to create variables in main namespace named after the form elements. However people could write over package globals that people didn't want changed, compromising security.
| [reply] [Watch: Dir/Any] |
|
This is OK unless a parameter is specified more than once as
in '?ar=3&ar=2' - in this case Vars loses a value. The
following is what I use:
my %args = ();
# get cgi parameters into a hash. preserve multi-valued
# parms
for my $p ( $cg->param() )
{
my @tmp = $cg->param($p);
if ( scalar @tmp == 1 ) { $args{$p} = $tmp[0] }
else { $args{$p} = [ @tmp ] }
}
Now %args has your params, w/ multi-valued
ones as references to arrays.
- Bob Niederman | [reply] [Watch: Dir/Any] [d/l] |
|
That's a good point. (Neat routine, too.) But consider this:
Before coming here, and before CGI.pm matured, I was a
notorious advocate of
cgi-lib.pl. As a matter of fact, part of the reason that the Vars method in CGI.pm was added was to facilitate the transition of cgi-lib.pl users over to CGI.pm. In cgi-lib.pl you would do something like this:
require "cgi-lib.pl";
&ReadParse(*input); # store form values in the glob "input"
print &PrintHeader; # print HTML header
print "Name: ", $input{name}, "<br>\n";
This was very nice syntax and worked well for me for many moons. =) When the form parser would encounter multiple values for a single field name, it would string them together with the NUL character (by default), so you could do this:
print "First value: ", $input{valueList}, "<br>\n";
print "All values: ",
join("<br>\n", split(/\0/, $input{valueList}));
And it would do exactly what you'd expect it to do. Neat, huh? Well, conveniently enough, CGI.pm inherited this behaviour. But don't take my word for it:
#!/usr/bin/perl -w
# /~alakaboo/cgi-perl/multi.pl
use strict;
use CGI;
my $q = new CGI;
my %v = $q->Vars();
print $q->header('text/plain');
{
local $" = "\n";
my @tmp = split /\0/, $v{ar};
print "@tmp";
}
Voila. | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Variable Variables
by Adam (Vicar) on Dec 05, 2000 at 07:33 UTC
|
Your problems are many. First off, the my inside the foreach loop means your variables vanish right after you declare them. Not what you intended. Second, you are violating strict (${$key} is an unstrict ref). Third there are many better ways to do this, but I'm left wondering why you would want to. Why not just use $query->param("whatever") when you need it? Why duplicate it like that? To make your code more legible? Well then that loop isn't going to help. If you really want to get a copy of the params while shaking the $query then use a hash:
use strict;
my $q = CGI->new();
my %p;
$p{$_} = $q->param($_) for qw( name
email
website
andSoOn
);
| [reply] [Watch: Dir/Any] [d/l] |
Re: Variable Variables
by merlyn (Sage) on Dec 05, 2000 at 07:34 UTC
|
| [reply] [Watch: Dir/Any] |
Re: Variable Variables
by marius (Hermit) on Dec 05, 2000 at 11:03 UTC
|
thanks for the insight, all.. ++'s all around. Valuable lessones when learning perl: hashes can be used for "darn near everything". I hadn't even thought of using hashes for the project, but it's obviously the superior approach.
I think I'm gonna end up using alakaboo's $query->Vars() method. Didn't know about that, and ended up going from CGI.pm 2.46 to 2.76 anyway. I guess that needed an update anyhoo.
| [reply] [Watch: Dir/Any] |
|
use strict;
use CGI qw(header param); print header;
print "The variable is: ", param('variable_name'), "\n";
This will cut off a line, and you just have to reference param() everywhere.
The other option requires that you don't use strict, but it's fairly nifty:
use CGI qw(header param); print header;
foreach (param) { $$_ = param($_); }
With this, you'll end up with all the variables translated into Perl variables. For example, a form with item named item will become $item in your script. Someone somewhere said this could potentially be a security risk, but I'm not sure how yet.
Hope this helps. BTW, if anyone knows why the above is bad, please let me know. Thanks. | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Variable Variables
by chipmunk (Parson) on Dec 05, 2000 at 22:38 UTC
|
I just want to point out, since multiple people have suggested using
foreach ($query->param()) { $$_ = $query->param($_) }
that the CGI module provides a method for importing names:
$query->import_names('Q');
imports all the parameters into the Q namespace. CGI warns against importing into the main package, for good reason: it's a huge security flaw! Someone could replace the value of any scalar variable in your code just by faking the form data.
Also note that using the above 'roll-your-own' approach to importing fails for multi-valued parameters, assigning them to scalars instead of to arrays. Using CGI's built-in method handles multi-valued parameters correctly. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
Using CGI's built-in method handles multi-valued
parameters correctly.
Actually I tried it ($cg->import_names('Q'))
and it still loses values on muti-valued params.
- Bob Niederman
| [reply] [Watch: Dir/Any] [d/l] |
|
I just tried it too. It turns out that import_names() does this in an interesting fashion; it imports all parameters as both scalars and arrays.
#!/usr/local/bin/perl
use CGI;
my $query = new CGI ( { single => 'one',
multi => ['two', 'three'],
}
);
$query->import_names('Q');
1;
Now, using the debugger to examine the results:
Loading DB routines from perl5db.pl version 1.0402
Emacs support available.
Enter h or `h h' for help.
main::(tmp.cgi:5): my $query = new CGI ( { single => 'one',
main::(tmp.cgi:6): multi => ['two', 'thr
+ee'],
DB<1> n
main::(tmp.cgi:10): $query->import_names('Q');
DB<1> n
main::(tmp.cgi:12): 1;
DB<1> V Q
$single = 'one'
@single = (
0 'one'
)
$multi = 'two'
@multi = (
0 'two'
1 'three'
)
DB<2>
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Variable Variables
by Anonymous Monk on Dec 05, 2000 at 21:55 UTC
|
I always do something like this when using CGI.pm:
foreach ($query->param) {
$$_ = $query->param($_);
}
Saves plenty of typing ;) Of course, you could always just
select a few variables to use:
foreach (qw(alpha bravo charlie)) {
$$_ = $query->param($_);
}
Which gives you $alpha, $bravo and $charlie with the values returned from the form.
HTH :-) | [reply] [Watch: Dir/Any] |
|
When I try this using mod_perl I'm told:
Can't use string ("some_variable") as a SCALAR ref while "strict refs" in use.
Is there another way to do this in mod_perl?
Thanks
| [reply] [Watch: Dir/Any] |