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

My CGI code needs to do this:

  1. Retrieve parameters from a flat file
  2. Insert them as values into an HTML form
  3. Allow the user to modify the values in the form
  4. Preview the modified values
  5. Save the modified values again into a flat file

So there are two sources for name/value pairs: the flat file and the HTML posts. These two sources have the same variables consistently throughout the application. I created two CGI objects, one for each source. And in my naiveté called them both $q, to save myself having to figure out how to pass the variables from one object into another inside of the code. Samples:

Getting the name/value pairs from the HTML form post:

$q = new CGI; { my $q = shift; my %query_hash; foreach ( $q->param() ) { $query_hash{$_} = $q->param($_); } return %query_hash; }

Getting the name/value pairs from the flat file:

{ open (REVIEW, "<review.txt") or die "can't open review.txt!"; $q = new CGI("REVIEW"); close (REVIEW); }

Saving the name/value pairs to the flat file:   $q->save("NEWREVIEW");

I ran this by TGI and he's not sure how kosher it is to have 2 CGI objects with the same name, and he's not sure if using $q->save is a good idea. He told me to put the question before y'all.

Any advice? I'll take anything you can give-

Thanks,

LadyD

Replies are listed 'Best First'.
Re: Multiple CGI Objects w/ Same Name
by voyager (Friar) on Jul 11, 2001 at 02:30 UTC
    Take a longer look at the CGI.pm documentation. It is designed to have a query object (your $q) get values from get/post, from a file, or manually set. And since you can set it manually, you can use it to collect values from more than one of these source types. It seems like it should be what you need.

    Note, you would be doing all this on one such query object.

Re: Multiple CGI Objects w/ Same Name
by TGI (Parson) on Jul 11, 2001 at 03:12 UTC

    Let me try to clarify what LadyD is talking about. The script is a state machine style CGI. In some states she needs to get data in and out of a text file.

    Simple, I thought, just use Data::Dumper to get strings to write out and then read and eval them to get them back. LadyD decided to read the CGI docs and found the CGI::save method which saves form input to a filehandle. The data can be retrieved when you create a new CGI object by saying $q = new CGI (FILEHANDLE). The problem is that by the time she knows which file to open, she has already had to use info from the CGI object.

    I suggested she do something like this:

    use CGI; use strict; my $q = new CGI; if ($q->param('state') eq 'foo') { DoFoo($q); } else { ErrorOut('Say what?') } sub DoFoo { my $q = shift; # do some magic to pick filehandle open (FILEHANDLE, "<the_file") or die "Sadness: $!\n"; my $p = new CGI ('FILEHANDLE'); foreach ($p->param()) { # $q->param($_) = $p->param($_) Bad old code # I sure whish I could do that sort of thing, I make this erro +r too often. $q->param( -name=>$_, -values=>$p->param($_) ); } # do more stuff } sub ErrorOut { die shift; }

    Please note that this code is totally untested off the top of my head type material. The important bit is in the DoFoo subroutine, especially the for loop.

    So, is it bad to have two CGI objects in one script? Should she just use Data::Dumper like everyone else? Should I just butt out?

    Updated I fix my bad code. $q->param($_) = $p->param($_) should be $q->param( -name=>$_, -values=>$p->param($_) );


    TGI says moo

Re: Multiple CGI Objects w/ Same Name
by synapse0 (Pilgrim) on Jul 11, 2001 at 13:12 UTC
    You don't want to use the multiple cgi thing.. It really doesn't serve a purpose in this case.
    Ok, so to get this straight, you are saving parameters across sessions and need to re-access those paramaters, keeping intact any new paramaters that come along?
    Looking at save() from CGI, it basically writes a file of key=value pairs, one per line.. also, throwing other info at param() will add those key=value pairs to the list.
    With that info, this might help:
    #!/usr/bin/perl -Tw use CGI; my $cgi = new CGI; # show current list print "\n\n"; print join(" ",$cgi->Vars()); print "\n"; if (open(FILE, "<./saved_params.txt")) { # add saved parameters while(<FILE>) { chomp; # CGI's save() ends the file # with = alone on the last line last if $_ =~ /^=$/; # split out the key=value pair my($key, $val) = split(/=/,$_,2); # and add them to the current list $cgi->param($key=>$val); } } # show final list print "--\n"; print join(" ",$cgi->Vars()); print "\n\n"; # save final list if (open(FILE, ">./params")) { $cgi->save(FILE); close(FILE); }
    I ran this from the cmd line, so it won't work as is in a web environment (no print $cgi->header in there). Also, it doesn't do any checking for a parameter that's already existing, so if the original list had like foo=bar and there was a saved foo=baz, the baz would overwrite bar (i would imagine), but that should be easy enough to check against.
    Hopefully that'll help you with what you're trying to do.
    -Syn0
Re: Multiple CGI Objects w/ Same Name
by adzap (Initiate) on Jul 11, 2001 at 15:29 UTC
    I had a similar problem recently

    I wrote somthing like:-

    my $gender = 'M';
    print $gender;
    $gender = 'F';
    print $gender;

    But then I was asked to compare the two values, and set
    them equal if they were different

    my $gender1 = 'F';
    my $gender2 = 'M';

    print $gender1;
    print $gender2;

    if $gender1 eq $gender2
    {print "same gender"}
    else
    { $gender1 = $gender2 }

    So is it ok to have a variable take two diffrent values or should i create a separate variable for each value, as in the second example?
      It depends on what you need to do with the values. Basic assignment to a scalar ( $var ) will lose anything that was in there before, so if you had $var = "first" and then did $var = "second" you just lost the "first" info. In your example, there's no way to conmpare the two. So if you need to keep the info, use another variable for other info.. If you don't care what was in the variable before, then overwriting it is fine... -Syn0
Re: Multiple CGI Objects w/ Same Name
by sierrathedog04 (Hermit) on Jul 11, 2001 at 05:27 UTC
    The following code runs without error in ActiveState 5.6/WinMe when warnings is turned off:
    use strict; my $test = 123; my $test = 456; print $test;
    On the other hand, it produces a "masks earlier declaration in same scope" warning when run with -w turned on.

    In the code you describe your second declaration of a reference named $q masks your first declaration. The answer is, yes, you are allowed to do it.

    However, the prophet Dylan said "to live outside the Law you must be honest." It says in the Talmud that "he who will not take upon himself the yoke of the Law must take upon himself the yoke of the world."

    Well, it's like that in Perl also. You can live outside the Law and intentionally write programs that do not run with strict and warnings turned on. But in that case you lose the protection of the Perl gods. Then you must be honest as Dylan said, meaning that the dubious practices that -w guards against must not confuse you and induce coding errors. And you take upon yourself the yoke of the real world as the Talmudic fathers said, which means that in the real world the Perl Porters may have forgotten to test what happens to those programmers who live outside the Law, and the perl interpreter itself might have an undiscovered bug that kills your program.

    It is a big world out there. There are endless opportunities to get into trouble. Why ask for trouble by living outside the Law and writing code that fails when run under the -w flag?

    Consider what would have happened if Moses's mother had decided to name her son "Abraham" instead of "Moses." Then there would have been two Abrahams in the Bible, just as you have two CGI objects named 'q'. People might have become confused. "Follow Abraham out of Egypt? Abraham's dead!" The Jews might never have entered the Promised Land.

    Please stop. Ask not whether thou shalt declare two references with the same variable name, for such a question is not conducive to Perl enlightenment.