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

I am working on finishing up a CGI application and I have run into a roadblock. I have a mail form that collects visitor information and then sends it to a separate script for processing. If there is a problem, the user is redirected to the original form, otherwise they are sent to a thank you page.

Now, the problem I am running into is that the query object's values are not being passed along when there is an error and the user is redirected back to the original form through $q->redirect( "form.cgi" )

Is there a way, apart from tacking data on to the URL, that I can save the form information?

Thanks,
Jeremiah

Replies are listed 'Best First'.
Re: Keeping Form Values
by tcf22 (Priest) on Oct 22, 2003 at 00:14 UTC
    If you are redirecting you need to do $q->redirect("form.cgi?key1=val1&key2=val2");
    You also combine them into 1 script and do something like this
    if(defined $q->param('form_submitted')){ if(&errors){ #Error occured &display_form($q); }else{ &thank_you; } }else{ &display_form; } sub display_form(){ ##Do form stuff }
    Also in display_form(), you might want to consider using HTML::Template and doing
    $temp = HTML::Template->new( file => 'file.tmpl', associate => $q );
    which will put all the submitted values into the template as long as the associated <TMPL_VAR NAME=".."> tags are there.

    - Tom

Re: Keeping Form Values
by matthewb (Curate) on Oct 22, 2003 at 00:23 UTC
    You are describing the default behaviour of CGI.pm within a single program.

    If you need to access session data across multiple scripts you need either to consider the use of CGI::Session, Apache::Session or roll your own equivalent functionality.

    MB
Re: Keeping Form Values
by hanenkamp (Pilgrim) on Oct 22, 2003 at 00:29 UTC

    Lots of ways. You've already stumbled upon the most obvious, which is to tack the values onto the end of the redirect URI. However, this is by no means the only way.

    You can remember session information via cookies on the user's browser (or place a session identifier at the end of your link URLs or as <input type="hidden" .../> fields in forms). You can then have a temporary file on the local machine keyed to that session value storing the information, which may be restored. In fact, CGI contains a rather nice facility to help with this via the save method.

    You could also save the data to something like a database. If you use cookies and the amount of data to be stored is relatively small, you could store the data in the cookie itself. (Won't work well for you, though, if you get many paranoid folks such as myself who mostly turn off cookies.)

    Another solution I can think of would be to execute form.cgi directly within your processor script. This would replace $q->redirect("form.cgi") with a do, eval, or require to compile and execute the other form script's code. This way it could inherit the state directly, rather than be executed on its own via a second user request. Of course, this means that the form would appear at the processor URL, but it's another possibility.

Re: Keeping Form Values
by injunjoel (Priest) on Oct 22, 2003 at 01:41 UTC
    Greetings all,
    I do an aweful lot of CGI scripting and have run into this very problem. I would suggest relegating the mail form to a sub within your processing script then you can prepopulate it programatically.
    Here is a prepopulation script I wrote early on.
    pass it a string containing your form and a reference to a hash containing your data keyed by the values you would find in the corresponding form.
    it will return you a string contianing your form prepopulated.
    I am positive this can be rewritten more efficiently but I hope this helps.
    sub prepopulate_form{ my ($frm_str, $hashref) = @_; my %values = %$hashref; my @val_keys = keys(%values); for(my $i=0;$i<(scalar(@val_keys));$i++){ my $name = $val_keys[$i]; my $frm_elm; if( $frm_str =~ m/(<(input|textarea)[^>]*name="$name"[^>]*>)/) +{ $frm_elm = $1; }elsif( $frm_str =~ m%(<select name="$name".*?/select>)%s ){ $frm_elm = $1; } my $new_elm = $frm_elm; if($frm_elm =~ m/<input/){ my $type = $1 if($frm_elm =~ m/type="([^"]*)"/); my $value = $1 if($frm_elm =~ m/value="([^"]*)"/); if($type eq "radio"){ $frm_elm = $1 if($frm_str =~ /(<input[^>]*name="$name" +[^>]*value="$values{$name}"[^>]*>)/); $new_elm = $frm_elm; $new_elm =~ s/>/ checked="true">/; }elsif($type eq "checkbox"){ if($values{$name} == 1){ $new_elm =~ s/>/ checked>/; } }elsif($type =~ m/text/){ if($new_elm =~ /value=/){ $new_elm =~ s/value="[^"]*"/value="$values{$name}" +/; }else{ $new_elm =~ s/>/ value="$values{$name}">/; } } }elsif($frm_elm =~ /<textarea/){ $new_elm =~ s/(<textarea[^>]*>)/$1 $values{$name}/; }elsif($frm_elm =~ /<select/){ $new_elm =~ s/(value="$values{$name}")/$1 selected/s; } $frm_elm =~ s/([\-\?\)\(\/])/\\$1/g; $frm_str =~ s/$frm_elm/$new_elm/s; } return $frm_str; }#end prepopulate_form sub

      If you need something like this in the future, have a look at HTML::FillInForm which does the exact same thing, except it uses HTML::Parser instead of a load of regexps.

      Whenever I come up with a cool new idea for a module, I find out someone has already put it up on CPAN.