View Full Version : Enumerating dynamically generated form variables
Opally
03-21-2007, 10:22 PM
Hi!
I have an HTML group registration form which calls a CGI form processor script, which calls a setup file that contains configuration info specific to that form. The HTML form generates additional registrant fields dynamically. This is new for me; I used to just write the list of form field names in the setup file.
I'm wondering if it's possible to code in the additional fields into the setup file without writing 50+ lines of form variables for 50 potential registrants. The current setup form looks like this:
@form_variables = (
"name",
"institution",
"street",
"city",
"state",
"zip",
[...and so on]);
It presents a verification screen to the submitter, blocking the CC number before submitting data:
foreach $variable (@form_variables)
{
$form_data{$variable} =~ s/"/"/g;
$form_data{$variable} =~ s/\</</g;
$form_data{$variable} =~ s/\>/>/g;
$form_data{$variable} =~ s/\n/\<P\>/g;
print qq~
<INPUT TYPE = "hidden" NAME = "$variable"
VALUE = "$form_data{$variable}">~;
}
print qq~
<INPUT TYPE = "hidden" NAME = "setup_file"
VALUE = "$location_of_setup_file">
<font face="Arial" size="3">You submitted the following information:</font><br><br>
<TABLE border="0" cellpadding="4" cellspacing="4">~;
foreach $variable (@form_variables)
{
if (($form_data{$variable})&&($variable ne "Cardnumber")) {
print qq~
<TR VALIGN ="top" bgcolor="#F3FFD9">
<TH ALIGN = "left" VALIGN = "top">$form_variable_name_map{$variable}</TH>
<TD>$form_data{$variable}</TD>
</TR>~;
}
[...and so on]
The CGI form processor calls the setup file and other supporting libraries.
It emails results to the admin and form submitter:
foreach $variable (@form_variables)
{
$form_data{$variable} =~ s/"/"/g;
$form_data{$variable} =~ s/</\</g;
$form_data{$variable} =~ s/>/\>/g;
$form_data{$variable} =~ s/\<P\>/\n/g;
if (($form_data{$variable})&&($variable ne "Cardnumber")){
$email_body .= &format_text_field($form_variable_name_map{$variable});
$email_body .= "$form_data{$variable}\n";
}
It writes data to a file:
foreach $variable (@form_variables)
{
$form_data{$variable} =~ s/\n/~nl~/g;
if (($variable eq "subtotal")||($variable eq "name")||($variable eq
"card")||($variable eq "Name_on_Card")||($variable eq
"Cardnumber")||($variable eq "Expdate")) {
$database_row .= "$form_variable_name_map{$variable}";
$database_row .= "$database_field_delimiter";
$database_row .= "$form_data{$variable}";
# $database_row .= "$database_delimiter";
$database_row .= "\n";
}
} # End of foreach $variable (@form_variables)
You can see the form here, but the processor scripts are not visible:
https://www.coreknowledge.org/secure/html_forms/confregform.htm
Thanks for your suggestions on how I can handle this intelligently!
---Opally
KevinADC
03-22-2007, 04:32 AM
I think your looking at the answer to your dilema:
if (($form_data{$variable})&&($variable ne "Cardnumber")) {
use a hash of names to skip:
if (($form_data{$variable}) && (! exists $skip_these{$variable})) {
FishMonger
03-22-2007, 05:49 AM
It might be because it's been a long day for me, in fact it's been a long 2 weeks, but I'm not 100% sure I know what you're asking, but if Kevin is on the right track, then using a hash would be the way to go.
Here are a couple comments/suggestions that are not directly related to your question, but will help to improve your script.
Don't use the hidden fields for maintaining state, especially if you're passing c/c data. Instead, use server side session variables.
http://search.cpan.org/~markstos/CGI-Session-4.20/lib/CGI/Session.pm
http://search.cpan.org/~chorny/Apache-Session-1.82/Session.pm
I can't tell from the code you posted if you're using it or not, but you should take advantage of the CGI module. In your code sample, you can use the escapeHTML() function instead of multiple regexs and the html tags should be in lowercase.
http://search.cpan.org/~lds/CGI.pm-3.27/CGI.pm
The font tag is depreciated; you should use css formatting, like you're using throughout the rest of your script.
When you're writing your data to the database file, you're looping through all 50+ form variables, but are only outputting 5 of them. It would be more efficient to use join() on those 5 variables.
Instead of using the flat file for the database, it would be much better to use a Mysql database, especially since it contains credit card info. I hope you're storing the c/c numbers encrypted as required and the server is in a secure NOC.
FishMonger
03-22-2007, 06:05 AM
Here are a couple other modules that would come in handy.
http://search.cpan.org/~nwiger/CGI-FormBuilder-3.0501/lib/CGI/FormBuilder.pod
http://search.cpan.org/~markle/CGI-FormBuilder-Mail-FormatMultiPart-1.0.4/lib/CGI/FormBuilder/Mail/FormatMultiPart.pm
Opally
03-22-2007, 05:09 PM
Thanks for the replies!
But I fear I have failed to make my question clear. I want to send all the form data in email (the CC stuff is handled fine, I want to see the rest of it.) Let me try this.
Can I interrupt this list of variables with a For loop to establish a lot of additional field names that must be enumerated for this form processor to work correctly?
@form_variables = (
"name",
"institution",
"street",
"city",
"state",
"zip",
...and interrupt here with a FOR loop to establish a whole lot more field names that are of the format "fieldname[i]"?
);
I don't really want to remake the entire underpinnings of the form unless I have to. But thanks for the links to FormBuilder, very interesting. My question is very basic, as I have little familiarity with Perl. If you think this is doable as I describe, I'll write the FOR loop. I thought I'd ask for an opinion from you smart Perl guys on what is doable within this script, that's why I supplied examples of how the fields are processed.
---Opally
Opally
03-22-2007, 05:48 PM
What's with the FormBuilder website? The tutorials don't work and neither does the subscriber list.
FishMonger
03-22-2007, 08:01 PM
Ok, I have a better, but not complete, understanding of what you want.
No, you can't insert a for loop inside the assignment of an array.
Instead of using an array, it would be easier/better to use a hash. Each field name would be assigned a value of 1 or 0 (true or false) to indicate that the form value needs to be included or excluded in the email.
Here's a short example.
Note: a hash (associative array) is an unordered list. If you need it ordered, you'd use the use Tie::IxHash module which I have commented out in this example. http://search.cpan.org/~gsar/Tie-IxHash-1.21/lib/Tie/IxHash.pm
#!/usr/bin/perl
use strict;
use warnings;
my %form_variables;
#use Tie::IxHash;
#tie %form_variables, 'Tie::IxHash';
%form_variables = (
name => 0,
institution => 1,
street => 0,
city => 1,
state => 0,
zip => 1,
);
foreach my $fieldname (keys %form_variables) {
print "$fieldname\n" if $form_variables{$fieldname};
}
If you want more than a true/fase test, then test for a specific value instead of the true value that my example uses.
Opally
03-22-2007, 09:15 PM
Thank you, FishMonger. See, I didn't even know that was an array.
I'll see about adapting the scripts to use a hash instead of an array to deal with field data and field names.
---Opally
KevinADC
03-22-2007, 09:35 PM
Fishmonger,
I see no reason to do that, just include the names you want to use in the hash, theres no need to be a true or false value for the hash key unless it can be changed during the life of the program. Essentially you just have this again:
@form_variables = (
"name",
"institution",
"street",
"city",
"state",
"zip",
but now in a hash. Or maybe I just am not understanding the question at all.
FishMonger
03-23-2007, 12:01 AM
Kevin,
Using the hash as I described is not required, but overall I think it's a better, cleaner and more versatile approach. The approach you suggest would require using the complete array as well as a hash that duplicates some or a good portion of that array.
Right now the script is making a choice between “A or B”. What happens when requirements change and additional choices need to be added? Do you add more hashes that duplicate the array elements to accommodate each decision? The hash simplifies the process since all you need to do is change the value of the hash key (either statically in the config file or dynamically in the script) and adjust the logic to test for that new condition.
Opally
03-23-2007, 04:43 PM
Thanks again all for your input.
I recalled that I have a friend who is a Perl whiz, so I asked him for his help. You may be interested in the very simple solution. Yes, I know these scripts have deprecated CSS and other antiquities, but really, I'd rather redo the forms in PHP if I am going to put any significant amount of energy into it. I was looking for a simple solution if one was available, and here it is.
### beginning of array ###
@form_variables = (
"name",
"institution",
"street",
"city",
"state",
"zip",
[. . .]
"Comments",);
### end of array ###
for ($i = 0; $i < 50; $i++) {
$rname = "regisname" . $i;
$remail = "regisemail" . $i;
$rtour = "registour" . $i;
push @form_variables, $rname, $remail, $rtour;
}
There is also a field names section which applies better descriptions to the report:
%form_variable_name_map = (
"name", "Name",
"institution", "School/Institution",
"street", "Street",
"city", "City",
"state", "State",
"zip", "Zip Code",
[. . .]
"Comments", "Comments",
);
for ($i = 0; $i < 50; $i++) {
$rname = "regisname" . $i;
$rnameText = "Registrant ".($i + 1)." Name";
$form_variable_name_map{$rname} = $rnameText;
$remail = "regisemail" . $i;
$remailText = "Registrant ".($i + 1)." E-mail";
$form_variable_name_map{$remail} = $remailText;
$rtour = "registour" . $i;
$rtourText = "Registrant ".($i + 1)." Tour";
$form_variable_name_map{$rtour} = $rtourText;
}
---Opally
KevinADC
03-23-2007, 06:43 PM
hehehe... well I missed the clue in your previous post about what you really wanted to do:
"fieldname[i]"?
you friend the perl whiz either picked up on that or had a better understanding of what you were attempting.
FishMonger
03-23-2007, 07:15 PM
Ya, I also missed that clue.
By any chance did you have a more detailed discussion of your needs with your friend and provide him with a more complete sample of your code before comming up with the solution?
Opally
03-23-2007, 09:47 PM
I am sorry that I wasn't clear. You know, they say that the most important part of programming is clear communication and figuring out what questions to ask, and not jumping to conclusions, heh. "Customers" are rarely good at making their needs known, to themselves or others!
Yes, I talked to my friend on the phone and mailed him the entire batch of code, and he checked with me his understanding of what I was asking for, before trying to code anything. Once he understood it, it probably took him less than five minutes.
I probably included too many code snippets in my original post, that confused more than it clarified.
To boil it down, it was a question about how to add a lot of new field names to the array by using a FOR loop, because I was generating so many more fields on the fly with the group registration form. But I know so little Perl that I didn't even realize that was an array of field names.
Thank you all again for your time and help!
vBulletin® v3.8.2, Copyright ©2000-2012, Jelsoft Enterprises Ltd.