3

I'm getting input from an html form. There are a bunch of text inputs, thus a bunch of key-value pairs. You see my current method is excruciatingly tedious when one has more than three pairs.

I'd like to know, is there a more efficient method of turning the hash into a series of scalar variables? I want the key to be the variable name, set to the value of the key.

I'm relatively new to perl, sorry if this is a stupid question.

#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use CGI qw(:standard Vars);

print "Content-type: text/html\n\n";

my %form = Vars();

$hourly = $form{hourly};
$hours_w = $form{hours_w};
$rent_m = $form{rent_m};
#...
djeikyb
  • 4,470
  • 3
  • 35
  • 42
  • 6
    Why convert - why not just leave in the hash? – mmmmmm Mar 24 '11 at 12:13
  • Because I don't want to. Admittedly, leaving it is simpler. But I'm still curious if there is a way to do what I ask. I may need it in the future? – djeikyb Mar 24 '11 at 12:18
  • 3
    It's enough to `use` CGI once. Also, the OO style of programming with CGI.pm is better: `my $cgi = CGI->new; my $hourly = $cgi->param('hourly');` – Eugene Yarmash Mar 24 '11 at 12:33
  • 6
    A Perl hash **already is** a Perl variable. – tchrist Mar 24 '11 at 14:22
  • @eugene y to use Vars you have to `use` it twice. @tchrist good point. I think I mean convert to a bunch of scalars. – djeikyb Mar 26 '11 at 23:56
  • Does this answer your question? [How to set a list of scalars from a perl hash ref?](https://stackoverflow.com/questions/13657103/how-to-set-a-list-of-scalars-from-a-perl-hash-ref) – ggorlen Apr 24 '21 at 01:45
  • @ggorlen It does not. I edited the title so it's a little easier at a glance to tell them apart. Check out the great answers I got, and how they differ significantly from what you mistakenly suggest as a dupe. – djeikyb Apr 28 '21 at 00:43
  • @djeikyb Thanks for the edit. The reason I suggested the dupe is that the top answer in the dupe and the most-upvoted answer in this thread are virtually identical, except the top answer in the dupe offers a better explanation and shows how to destructure the hash both as a hash ref and as a hash, so it's more comprehensive. I wound up at this thread hunting for that and I suspect most other visitors are looking for that as well, judging by the votes. – ggorlen Apr 28 '21 at 00:55
  • @ggorlen Back in 2011, I was definitely trying to generalize the formation of my question. Thankfully I failed, and got an early lesson in web security : D And the excellent tip on the name of what I (should not have) wanted: symbolic references! – djeikyb Apr 28 '21 at 01:11
  • @ggorlen Do you think the title of the other question could be improved? It might be that using floundering unsure language like "how to turn a hash into, uh, normal variables? scalars?" is what catches the traffic. I was having a lot of trouble understanding perl names like hash and scalar, even though I understood key-value collections and that most variables I use represent a single value. Personally I'd never google something like "how to set x from y", it'd always be like "how to turn x into y" or "convert x to y" – djeikyb Apr 28 '21 at 01:25
  • @djeikyb Maybe -- hard to say what the search engines are doing or how people phrase it. I landed at this question first and solution #2 with +15 answered my question, then I later found the other one with 99 views and thought it was more appropriate. But I'm not really sure how to search-engine optimize it. Feel free if you want, but I think by making this title more specific and offering a link to the other one, I'm satisfied that that's sufficient. – ggorlen Apr 28 '21 at 01:28

4 Answers4

15

You can use a hash slice to assign to multiple variables at once:

my ($hourly, $hours_w, $rent_m) = @{$form}{qw(hourly hours_w rent_m)};

Creating variables dynamically would require eval().

Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
5

Use CGI's OO interface.

my $q = CGI->new();
$q->import_names('Q');
print $Q::hourly; # hourly param, if any

Do not import_names into global namespace (main::) though, or you'll get in trouble sooner or later.

Dallaylaen
  • 5,268
  • 20
  • 34
2

What you're trying to do is called symbolic references (see perldoc perlref and search for /Symbolic references/). It is not considered to be best practice.

Try:

for my $key ( keys %form ){
  no strict;
  $$key = $form{$key};
}
shawnhcorey
  • 3,545
  • 1
  • 15
  • 17
  • 2
    I would restrict the for() list to a fixed set of keys. Who knows what key/value pairs come from the net?.. – Dallaylaen Mar 24 '11 at 14:14
  • That's why it's not considered to be best practice. For some reason people think writing `$hourly` is easier than `$form{hourly}` but it can get you into all sorts of hot water. – shawnhcorey Mar 24 '11 at 14:50
  • there is "normal" level "not considered to be best practice" and then there's "could allow a cleaver hacker to rape your web server and pillage your customer's data" level "not considered to be best practice". Blindly allowing a remote user to overwrite any value in your symbol table is definitely in the second set. – Ven'Tatsu Mar 24 '11 at 18:28
  • @Dallaylaen @Ven'Tatsu Oh. Now I see why this is a bad idea. I still like the question, because mayhaps it'll be useful, and at the least extend my perl knowledge. But I'll not use it with my form. And Thanks shawn for the term for what I'm trying to do. Off to read the manual.. – djeikyb Mar 24 '11 at 23:24
2
my $cgi;
BEGIN {
    $cgi = CGI->new();
}

BEGIN {
    # Only create variables we expect for security
    # and maintenance reasons.
    my @cgi_vars = qw( hourly hours_w rent_m );

    for (@cgi_vars) {
        no strict 'refs';
        ${$_} = $cgi->param($_);
    }

    # Declare the variables so they can be used
    # in the rest of the program with strict on.
    require vars;
    vars->import(map "\$$_", @cgi_vars);
}
ikegami
  • 367,544
  • 15
  • 269
  • 518