Monolith-0 has asked for the wisdom of the Perl Monks concerning the following question:

Lately I've been making some scripts simmilar to the following example:
When somepage.pl is accessed, it gives the user a form to fill out. The data in the form is sumbitted to somepage.pl?submit. The 'submit' arg. runs a different function to process the data from the form.
This process seems ineficiant and error prone. I was wondering if anybody knows of a better way of getting data from a form.

- Monolith

Replies are listed 'Best First'.
Re: Retrieving Form Data
by Hero Zzyzzx (Curate) on Jul 15, 2001 at 02:42 UTC

    Well, there's nothing wrong with this way of doing things, in theory, but the devil's in the details. I'm not entirely sure what the deal with "submit" is in your query string. Submit buttons, <input type="submit" name="submit"> will send thier values along in a form, so I don't think I'd use "submit" as the value to determine the state of my application.

    Can you post some code to show how you're doing this? It's kind of hard to help you out with such a general question and no code. . .

      Here's a sample of what sompage.pl might be like:
      use strict; if ($ARGV[0] eq "submit") { &submit_data; } else { $view_form; } #################### sub view_form { print "<HTML>\n"; print " <BODY>\n\n"; print " <FORM METHOD= \"POST\" ACTION= \"somepage.pl?submit\">\n" +; print " <B>Pass:</B> <INPUT TYPE= \"PASSWORD\" NAME= \"Pass\"><B +R>\n"; print " <BR>\n"; print " <B>Name:</B> <INPUT TYPE= \"TEXT\" NAME= \"Name\"><BR>\n +"; print " <B>URL:</B> <INPUT TYPE= \"TEXT\" NAME= \"URL\" SIZE=40> +<BR>\n"; print " <INPUT TYPE= \"SUBMIT\" VALUE= \"Submit\">\n"; print " </FORM>\n"; print " </BODY>\n"; print "</HTML>\n"; } #################### sub submit_data { # Get the data submitted from the form read(STDIN, my $buffer, $ENV{'CONTENT_LENGTH'}); # Split the name-value pairs my @pairs = split(/&/, $buffer); my %FORM; foreach my $pair (@pairs) { my ($name, $value) = split(/=/, $pair); # Remove plus signs and decode %-encoding $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ s/<!--(.|\n)*-->//g; $FORM{$name} = $value; } ## Do something with the data }

      - Monolith

        Oh my. I'd probably do that differently, especially by using CGI.pm for my form decoding. There's a million different reasons to CGI, the best is that it makes your job much easier!

        Here's your code, using CGI.pm:

        #!/usr/bin/perl -wT use strict; use CGI; my $q= CGI->new(); if (!$q->param('pass'){ print_form($q); } else { submit_data($q) } sub print_form{ my $q =shift; print $q->header(). $q->start_html(). $start_form(-method=>'POST', -action=>'/cgi-bin/somepage.pl'). $q->b('Pass:'). $q->textfield(-name=>'pass'). $q->br(). $q->b('Name:'). $q->textfield(-name=>'name'). $q->br(). $q->b('URL:'). $q->textfield(-name=>'url'). $q->submit(). $q->end_form(). $q->end_html(); } sub submit_data{ my $q=shift; # No need to go through all that form decoding stuff here. # It's done automatically, and in the Right Way by CGI.pm. #do stuff with data. }

        Why is this better? Less typing, for one. Easier to read, too. Plus CGI.pm is very, very good for creating forms and simple HTML (it does a lot more than what I used it for here, obviously!). CGI.pm is also very good for creating tables programatically, e.g. from a database. You can even use CGI to auto-fill your forms, when you validate data from users.

        If you're going to be doing more complex HTML in your code, you should look into a templating system that lets you separate your perl scripts from your HTML. A really good one to learn is HTML::Template. It'll seem like a pain at first, but it's worth it in the long run.

        Some links:
        Use CGI or Die! from Ovid. Really good reading.
        Ovid's CGI tutorial.
        The CGI.pm docs from Lincoln Stein.
        HTML::Template Tutorial at PerlMonth.

        Update:The way I REALLY would have done this is with CGI::Application, which I think is like a state machine, and is HTML::Template's (non-)evil twin.

Re: Retrieving Form Data
by Cubes (Pilgrim) on Jul 15, 2001 at 02:56 UTC
    If you use CGI.pm, you can use the param() function to find out whether your script has been handed any input or not. Test for a return value from param(), process the form data if there is any, or output the blank form if there is none. See Lincoln Stein's CGI.pm page for more information.
Re: Retrieving Form Data
by ralphch (Sexton) on Jul 15, 2001 at 03:14 UTC
    There should be no problem when doing this, but an alternative would to check the availability of a form field. For example:

    if(!$form) { &display_form(); }
    else { &process_form(); }

    Ralph.
      So I wouldn't have to use the extra argument? That makes sense.
Re: Retrieving Form Data - Statefulness on the Web
by meonkeys (Chaplain) on Jul 15, 2001 at 05:00 UTC
    This topic always piques my interest, particularly becuase everyone encounters it at some time in their CGI life. The question is, really: what is the user trying to do during this particular request? One hint is the request type itself: GET, POST, HEAD, etc. Here's what I do (similar to your method, I think):
    1. post to the same page with a unique variable, like go=1
    2. check for go=1, then do form processing

    You could also post to a different CGI or a different subroutine in the same CGI, and simply posting to that CGI or sub indicates that form processing is to take place.

    I really enjoy the speed and freedom of mod_perl for this reason... you could probably implement a pretty complex state machine to know at what point a user is in a particular process (logging on, posting a message, etc.).

    "This process seems ineficiant and error prone."
    I guess this depends on the programmer, right?

    If anyone knows more about state machines (links, info, whatever) please post!
Re: Retrieving Form Data
by princepawn (Parson) on Jul 15, 2001 at 06:21 UTC
    I really enjoy the speed and freedom of mod_perl for this reason... you could probably implement a pretty complex state machine to know at what point a user is in a particular process (logging on, posting a message, etc.).
    A powerful well-crafted one is already part of CGI::MxScreen. this web framework was developed by the same person who developed Storable, Log::Agent and Carp::Datum.