http://qs321.pair.com?node_id=149454

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

I'm trying to learn the limitations of CGI's using cookies and hidden fields through the use of CGI::Session. My main goal is to create a CGI that will call itself through multiple invocations of a form, getting further along each time. I'm having incredible difficulty with the main project, so I've created this simple script to test what I do (and don't) understand about session state.

This script simply asks for the user's name and age. It should loop each time the user submits, incrementing $age by one each time. Could someone please explain to me why this doesn't work past the 2nd invocation?

-fuzzyping
#!/usr/bin/perl use strict; use CGI; use CGI::Session::DB_File; my $title = "Test Hidden Fields"; my $cgi = CGI->new; my $sid = $cgi->cookie('session_id') || undef; my $Session = new CGI::Session::DB_File($sid, {FileName=>'/var/www/cgi +-bin/nobody/sessions.db', LockDirectory=>'/var/www/cgi-bin/nobody'}); if ($sid) { $Session->load_param($cgi) } $sid ||=$Session->id; my $cookie = $cgi->cookie(-name=>'session_id', -value=>$sid, -expires= +>"+5m"); print $cgi->header( -cookie=>$cookie, -start_html=>$title); print "<center>", $cgi->h1($title), "</center>"; if ($cgi->param('name')) { $Session->param(-name=>'name', -value=>$cgi->param('name')); $Session->param(-name=>'age', -value=>$cgi->param('age')); $Session->save_param($cgi); &add_age; } elsif ($cgi->param('test')) { &add_age; } else { print $cgi->start_form, "Name: ", $cgi->textfield('name'), "Age: ", $cgi->textfield('age'), $cgi->p, $cgi->submit('Next'), " ", $cgi->defaults("Clear"), $cgi->end_form; } print $cgi->end_html; sub add_age { my $age = $Session->param('age'); ++$age; print $Session->param('name'), "\'s new age is $age"; $Session->param(-name=>'age', -value=>$age); $Session->save_param($cgi); print $cgi->start_form, $cgi->hidden(-name=>'test', -value=>'test'), $cgi->submit('Next'), $cgi->end_form; }

Replies are listed 'Best First'.
Re: CGI::Session problems
by ropey (Hermit) on Mar 05, 2002 at 18:33 UTC
    I may be wrong, but I once had a similar problem. When creating your hidden field such as
    $Session->param(-name=>'age', -value=>$age);
    it won't actually change the value as it is already initialised. try
    $Session->param(-name=>'age', -value=>$age, -force => 1);
    which now updates the value. HTH
      Thanks, but that didn't seem to help as much as I'd hoped. I tried to force the save to $Session->param('age'), but now it loses 'name', forcing it to default to ++0, or 1. The result would be to return the correct name and ++$age after the first submit, but "'s new age is 1" and "'s new age is 2" for the subsequent submits. Anything after that continues to repeat the last result.

      Sensing that my hidden data isn't being passed after the 2nd invocation (isn't that what CGI::Session is for???), I made the following changes to &add_age to try and get it to force 'name' as well...
      sub add_age { my $age = $Session->param('age'); my $name = $Session->param('name'); ++$age; print $Session->param('name'), "\'s new age is $age"; $Session->param(-name=>'age', -value=>$age, -force=>1); $Session->param(-name=>'name', -value=>$name, -force=>1); $Session->save_param($cgi); print $cgi->start_form, $cgi->hidden(-name=>'test', -value=>'test'), $cgi->submit('Next'), $cgi->end_form; }
      While it now saves the name correctly, it doesn't increment at all past the first good invocation. How do the CGI gods handle this type of ongoing, looping CGI type? Am I assuming incorrectly in that CGI::Session stores full session state information in the db file? As long as it knows my $sid, and I load it correctly, shouldn't the hidden data always be available to me?

      *sigh*

      -fuzzyping
Re: CGI::Session problems
by Speedy (Monk) on Mar 06, 2002 at 03:55 UTC
    I haven't actually used CGI::Session, so I may be off-base here. But from reading the description, it appears that statements like:

    $Session->param(-name=>'age', -value=>$age, -force=>1);
    and
    $Session->param(-name=>'name', -value=>$name, -force=>1);

    won't do what you expect.

    I'm basing this on the descriptiong of save_param($cgi) at the CPAN site:

    This method is the opposite of load_param(). It saves all the parameters in your CGI environment to your Session's parameters. For example, you might want all the information that user supplied in a form in your website to be saved into the session object. Again, remember to pass CGI object as the first and the only argument. Example:

    $Session->save_param($cgi);


    So I think first you have to get your CGI.pm variables right. Rather than the "$Session" statements you were using, you could try:

    print $cgi->hidden(-name=>'name', -value=>"$name");
    print $cgi->hidden(-name=>'age', -value=>"$age", -force=>'1');

    immediately before the end_form and submit statements. This saves the name and age variables (with the force='1' making the incremented age variable replace the old "sticky" parameter).

    Then at the top of the script, which you will now be re-entering after executing the "submit" statement, but this time with the CGI parameters "right" and actually available to the script, put the

    $Session->save_param($cgi);

    statement. (If you don't get the CGI parameter variable saved, in this case as hidden variable, as you found they will be lost. I suspect the $Session statements didn't save them either.)

    Often in this case you might go away, using the cookie value for reentry later. Or you can recall it as your code now works. But until the values are saved in the CGI.pm space, you apparently can't save them one at a time into the CGI::Session database.

    Live in the moment.

Re: CGI::Session problems
by oubiwann (Sexton) on Mar 06, 2002 at 04:06 UTC
    I tried testing your code, but I couldn't for the life me get CGI::Session working - however, I did get CGI::kSession working, and I pasted some code below. From what I can tell, your logic works and is good, and I would therefore assume that the issue lies in the module's usage. You might want to check this one out - it's clean an simple... (haven't looked at the actual .pm code, though...)
    #!/usr/local/bin/perl
    
    use strict;
    use CGI;
    use CGI::kSession;
    
    my $cgi = new CGI;
    print $cgi->header;
    print $cgi->start_html();
    
    my $s = new CGI::kSession(lifetime=>10,path=>"/tmp/",id=>'test');
    $s->start();
    $s->register("name") unless $s->is_registered("name");
    $s->register("age") unless $s->is_registered("age");
    
    if ($cgi->param("name")) {
            $s->set("name", $cgi->param("name"));
            $s->set("age", $cgi->param("age"));
            &add_age();
    } elsif ($cgi->param('test')) {
            &add_age();
    } else {
            print $cgi->start_form,
                    "Name: ",
                    $cgi->textfield("name"),
                    "Age: ",
                    $cgi->textfield("age"),
                    $cgi->p,
                    $cgi->submit('Next'), " ",
                    $cgi->defaults("Clear"),
                    $cgi->end_form;
    }
    
    print $cgi->end_html();
    
    sub add_age {
            my $age = $s->get("age");
            my $name = $s->get("name");
            $age++;
            print $name, "\'s new age is $age";
            $s->set("age", $age);
            #$s->set("name", $name);
            print $cgi->start_form,
                    $cgi->hidden(-name=>'test', -value=>'test'),
                    $cgi->submit('Next'),
                    $cgi->end_form;
    }
    
    1;
    
Re: CGI::Session problems
by scottstef (Curate) on Mar 06, 2002 at 13:47 UTC
    I am not sure, but there may be a problem with CGI::Session. When I did a query on it, it said to contact the author. When I tried to install it through CPAN, I got this:
    cpan> install CGI::Session Running install for module CGI::Session The module CGI::Session isn't available on CPAN. Either the module has not yet been uploaded to CPAN, or it is temporary unavailable. Please contact the author to find out more about the status. Try 'i CGI::Session'.

    You may want to contact the modules author.

    "The social dynamics of the net are a direct consequence of the fact that nobody has yet developed a Remote Strangulation Protocol." -- Larry Wall