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

My first post here, so please be gentle. I have a very basic CGI script (and I have stripped it out here even more just to illustrate the problem). The problem is thus -- the first time I load the web page (that is, no form is submitted), "template," the first field in the form, automatically gets the value "minscale". If I actually enter something in the "template" and "minscale" fields, the entered values are correctly passed and reflected back in the preformatted output at the bottom of the page. Its just that first time... it seems the hash definition at the top is causing the problem... the "template" key is getting nothing from param('template') and is using the name of the next key as its value. Any advice will be much appreciated. Code follows
#!/usr/bin/perl -w use strict; use CGI::Pretty qw(:standard); use CGI::Carp qw(fatalsToBrowser); my %webobj = ( 'template' => param('template'), 'minscale' => param('minscale') ); print header, start_html; print<<WEBOBJ; <form method='get' action='webobj.cgi'> <b>Web Object</b> <table border='0'> <tr> <td align='right'>Template</td> <td><input type='text' name='template' value="$webobj{'templat +e'}"></td> </tr> <tr> <td align='right'>Minscale</td> <td><input type='text' name='minscale' value="$webobj{'minscal +e'}"></td> </tr> <tr><td></td><td colspan='2'><input type='Submit' value='submit'> +<input type='reset'></td></tr> </table> </form> <pre> # ## start web object WEB TEMPLATE "$webobj{'template'}" MINSCALE $webobj{'minscale'} END # end web object # </pre> WEBOBJ print end_html;

Replies are listed 'Best First'.
•Re: Puzzling CGI behavior
by merlyn (Sage) on Jan 30, 2003 at 03:14 UTC
    my %webobj = ( 'template' => param('template'), 'minscale' => param('minscale') );
    That's always dangerous code. param in a list context (or any subroutine in a list context, for that matter) might return a variable number of arguments. You'll want to add scalar in front of each of those param calls.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

      You get exactly the same result if you do this:
      my %webobj = ( 'template' => , 'minscale' => 2 );
      because there is no param(template), so it's like you said 'template' => nothing, comma, minscale, I guess.

      I suppose this is somehow different to doing it with an undefined variable -- that way you'd get undef as the value for 'template'.

      I know it's daggy and old-fashioned, but if I'm in a hurry, I just do this:

      CGI::ReadParse();
      which puts everything into a hash called %in. That was only included in CGI.pm for backward, perl 4/cgi-lib compatibility, but I like it. It does what you're trying to do here, right?
      --
      “Every bit of code is either naturally related to the problem at hand, or else it's an accidental side effect of the fact that you happened to solve the problem using a digital computer.”
      M-J D
        I often do:

        use CGI qw(:cgi-lib); my $form = Vars;

        Gives you a tied hash-reference to all parameters, also allowing you to change the submitted parameters...

      thanks, that also works... so my choices are
      my %webobj = ( 'template' => param('template') || '', 'minscale' => param('minscale') || '' );
      or
      my %webobj = ( 'template' => scalar(param('template')), 'minscale' => scalar(param('minscale')) );
      From Randal's comment it seems the latter would be the wiser choice.

      I am assuming 'minscale' is being assigned as a value to the 'template' key because there is nothing in param('template') and the comma is causing minscale to appear as part of a list.
Re: Puzzling CGI behavior
by BrowserUk (Patriarch) on Jan 30, 2003 at 03:06 UTC

    The quick (and possibly dirty, depending on your POV) is to ensure that your hash has a default value the first-time through.

    my %webobj = ( 'template' => param('template')||'', 'minscale' => param('minscale')||'0' );

    A quick test shows this seems to work ok for your example.


    Examine what is said, not who speaks.

    The 7th Rule of perl club is -- pearl clubs are easily damaged. Use a diamond club instead.

      thanks for the suggestion. I will take it. However, here's my question. Why does this happen? I mean, I can also do something like
      my $template = param('template'); my $minscale = param('minscale'); my %webobj = ( 'template' => $template, 'minscale' => $minscale );
      and then I get acceptable behavior. But, this shouldn't be necessary. In fact, even if I get something strange, why the heck does 'template' => param('template') end up grabbing 'minscale' as its value... that comma after param('template') should tell it to lay off of 'minscale'. Would love to find out why? Many thanks
        that comma after param('template') should tell it to lay off of 'minscale'.

        It doesn't, though. merlyn has the right of it, as usual. There are no parameters. Calling param() in list context (as happens in the hash assignment) produces an empty list in this case. Since there has to be a value, Perl grabs the next one in a list.

        Your snippet is equivalent to:

        my %webobj = ( 'template', param( 'template' ), 'minscale', param( 'minscale' ), );

        Consider what happens if you assign an empty list:

        use strict; use Data::Dumper; my %hash = ( foo => ,,, bar => 1 => 'baz' ); print Dumper \%hash;
Re: Puzzling CGI behavior
by Coruscate (Sexton) on Jan 30, 2003 at 07:41 UTC

    Your question has been answered in a sufficient manner, but I'd just like to show you something else as well. It's nice if a person picks either the CGI routine or the hand-done routine. What I mean is that you use CGI for outputting headers and even the opening html tag, but then you do the actual page by hand, not using the tools provided by CGI.pm. The one thing I noticed on a once-through through your script is the the row with the submit button is invalid html -> you have a total of 3 columns in this row, while the two preceeding rows have only 2 :) So here's the program, quickly redone to completely use CGI. Untested, but I think I matched all those parentheses and curly braces :)

    #!/usr/bin/perl -w use strict; use CGI qw/:standard :cgi-lib/; my $I = Vars; print header(), start_html('Example Page'), start_form(), strong('Web Object'), table( Tr( td( {align=>'right'}, 'Template' ), td( textfield({ name => 'template' }) ) ), Tr( td( {align=>'right'}, 'Minscale' ), td( textfield({ name => 'minscale' }) ) ), Tr( td( {colspan=>2}, submit({ value => 'submit' }) ) ) ), end_form(), pre( qq{TEMPLATE "$I->{'template'}"\nMINSCALE "$I->{'minscale'}"} +), end_html();


          C:\>shutdown -s
          >> Could not shut down computer:
          >> Microsoft is logged in remotely.
        

(jeffa) Re: Puzzling CGI behavior
by jeffa (Bishop) on Jan 30, 2003 at 14:29 UTC
    Your question has already been answered, but i felt inclined to query why one would use a variable named %webobj without blessing it. You don't need to do this - you could simply do something like:
    my %webojb; $webobj{template} = param('template'); $webobj{minscale} = param('minscale');
    without having to resort to transitory variables. But, here is some code that uses Class::MethodMaker:
    use strict; use warnings; use CGI qw(param); my $webobj = WebObj->new(); $webobj->template(param('template')); $webobj->minscale(param('minscale')); print $webobj->template,$/; print $webobj->minscale,$/; package WebObj; use strict; use warnings; use Class::MethodMaker new => 'new', get_set => [qw(template minscale)], ;
    Try running this code with the following args
    ./webobj.cgi 'template=foo'
    ./webobj.cgi 'template=foo&minscale=bar'
    ./webobj.cgi 'template=foo&minscale=bar&minscale=baz'
    
    Personally, i wouldn't even bother with using %webobj unless i knew that it would need to be passed around a lot. I generally use HTML::Template as my 'object container', if you will. ;)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)