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

Let's say I have three .pl files (rpt1, rpt2, rpt3). I'm using HTML::Template and CGI.pm to generate the main menu. Clicking on the submit button will launch the rpt1.pl/rpt1.tmpl combo (via the POST method). From rpt1, I want to launch rpt2 depending on which cell is clicked. However, I'm having trouble snagging all the info I want. I also want to eventually create a link to each data cell that snatches the appropriate params and passes those to the next script. Note: not all the CGI params I want are in a form.

I have a "header section" in rpt1 that contains a bunch of info about the report. This header section is a separate H::T file that has been populated using various TMPL_VARs and CGI params. I'd like to snag that entire header section and have it repeat on the subsequent rpt 2 and rpt3 pages. I also need the various items in this header section to help determine what parameters to use in subsequent database calls for rpt2 and rpt3.

Now, I know I can put at the beginning of rpt2.pl the following type of statements for every variable I think I'll need in the subsequent pages, but this seems to be the "hard" way to do it (I'm thinking there should be an easier "get it all at once" way):

my $rpt_name = $CGI->param('rpt_name'); my $rpt_descr = $CGI->param('rpt_descr'); #etc., etc.
I've tried the following at various times trying to figure this out. I think I've managed to completely confuse myself. (Note: I didn't try these all at once; I tried them separately).

I can print out my variables like this, but I'm not sure how to then import them into the next script:

foreach my $name ( $CGI->param() ) { my $value = $CGI->param($name); print "The value of $name is $value<br>"; }
I tried to use CGI.pm's import_names in rpt2.pl, but nothing populates in the header template section as I would have expected (well, at least the CGI params, not necessarily the TMPL_VAR params):
$CGI->import_names('R'); #other stuff my $tmpl_main2 = HTML::Template->new( filename => "rpt2.tmpl", associate => $CGI, global_vars => 1, ); #other stuff print $tmpl_main2->output();
I've also tried this in rpt2.pl (that was launched from rpt1) but nothing prints out:
#!/usr/bin/perl use CGI ':standard'; print header(); print param('key');
And, from the CGI.pm docs, I've tried this in rpt1.pl, hoping that the "associate=>$CGI" in rpt2.pl would pull them in:
@names = $CGI->param;
I also (in desperation) tried passing the @names to the template like this but (as expected) I then get a complaint about 'passCGI' is not in my template. Even putting 'passCGI' in my template only led to further complaints about it should be a TMPL_LOOP, etc.
$tmpl_main1->param(passCGI => \@names);

I have searched quite a bit out in Google-land, and it seems like a lot of suggestions point to using the GET method, reading the ENV{QUERY_STRING}, parsing the stuff out, etc. However, my forms are using the POST method (but I'm not particular emotionally attached to that method... I just thought it was safer). Also, I wasn't thrilled about using hidden fields since that'll let someone view my source and see exactly what fields I'm passing around. And lastly, not all my variables are in forms.

So, since I know TIMTOWTDI, I thought I'd ask those folks who play with HTML::Template, CGI and Perl for ideas. Also, please feel free to dumb it down for me as I'm still learning this stuff. Thanks!

Lori

Replies are listed 'Best First'.
Re: HTML::Template, CGI, pass template params to next script
by borisz (Canon) on Feb 02, 2004 at 16:20 UTC
    To transport some data from one page to another you can use sessions, put the data into the url or put the data into the request.
    Boris
      Thanks, Boris! I had not heard of sessions before, so I did a little(okay, a lot of) reading on it. I like CGI::Session (meaning I actually understood how to use it). It also gives a nice overview of the various methods used to keep data along for the "ride" as a user moves around, and the pros and cons of each method.

      We don't have CGI::Session loaded on our Unix server, but I can (and will) load it on my Windows ActiveState variety so I can play with it. Then, I will make some fudge, carry it to the dba, bat my eyelashes, and beg him to load CGI::Session on the Unix box. ;-)

      Lori

Re: HTML::Template, CGI, pass template params to next script
by jdtoronto (Prior) on Feb 02, 2004 at 19:33 UTC
    Lori713

    You have several choices.

    1. If I recall correctly CGI has a 'sticky mode' so it can allow you to populate a second form based on the response to the first form. This is suitable for very simple situations.
    2. You can't pass just @names to HTML::Template - you have to pass it a reference to the entire HASH, in fact you can even pass it the object and it will use the param method to extract the HASH!
    3. A session system is good too, as you say TIMTOWTDI. If you need the capability of a session managed application, CGI::Session makes it very easy. Fortuantely most of the time my apps are session managed so the I can tuck things in a session and get them back as has already been described to you.
    4. Data::FormaValidator and its close cousin HTML::FillInForm can be used to implement the same sort of thing with very flexible validation along the way.
    5. POST method is safer than GET, in only a very minor way. But the sue of a sessioning system will allow the variables never to leave your server, so you don't have so much to worry about. It also means you can store other incidental information along the way as well and you can expire not only the entire session, but a part of the session.
      For example, my users have to log-in, but after 30 minutes of no usage they are automatically logged-out. By using the expire method of CGI::Session you can have a session which persists (as mine do) but the user needs to log back in again after a period of inactivity.
    6. Our very good frinds, in teh form of Lincoln Stein and otehrs have been so gracious and generous as to bless us with CGI.pm and its related modules. Please do not make the mistake of trying to do it yourself.

    jdtoronto

      First, thanks for your responses and explanations. I admit I burst into laughter when I read #6... the idea that I might roll my own when I can barely read and understand any POD... <giggle> I just wish it were even possible to roll my own at this stage! ;-)

      I've been trying to play with CGI::Session, but I can't get it to work for me. I don't know if it's because I'm trying to save ALL my CGI form variables PLUS my TMPL_VAR variables... Is that even possible?

      As for CGI.pm, wouldn't CGI.pm's "stickyness" be the default behavior? I see where there's a pragma called "-nosticky". I can't seem to pass the variables to the second script, even though I successfully passed them to the first script (and I suspect it's because the variables were in a form and CGI.pm likes that). So, am I correct in my understanding that CGI.pm won't pass the form variables a second time because there's no form?

      edited: left the following question out...

      Now, on to item #2... that's intriguing. I'd like to make sure I understand what you're saying. I can save all my template variables in an array, then pass that array over to the template and somehow (don't know how yet) I can then "extract" them into individual items I can use? Did I get that right?

      Thanks!

      Lori

        I just wish it were even possible to roll my own at this stage! ;-)
        I was jokingly referring to the 'googling' you did when you came up with all sorts of references to getting the $ENV variable and parsing it! Just don't do it please :)
        As for CGI.pm, wouldn't CGI.pm's "stickyness" be the default behavior? I see where there's a pragma called "-nosticky". I can't seem to pass the variables to the second script, even though I successfully passed them to the first script (and I suspect it's because the variables were in a form and CGI.pm likes that). So, am I correct in my understanding that CGI.pm won't pass the form variables a second time because there's no form?
        I am going to pass on comeenting here. Yes, as I recall, CGI.pm's default is sticky, but it is a LONG time since I used it that way.
        I've been trying to play with CGI::Session, but I can't get it to work for me. I don't know if it's because I'm trying to save ALL my CGI form variables PLUS my TMPL_VAR variables... Is that even possible?
        Sheesh! Why does everybody have trouble getting CGI::Session to work! It's easy. OK, here we go:
        1. Create you database table, make sure that you have the required two fields. e.g.
          SET FOREIGN_KEY_CHECKS=0; #---------------------------- # Table structure for sessions #---------------------------- CREATE TABLE `sessions` ( `id` varchar(32) NOT NULL default '', `a_session` text NOT NULL, UNIQUE KEY `id` (`id`) ) TYPE=MyISAM;
          and make sure that the 'a_session' is at least a BLOB size field.
        2. Set up the database and get a DBH object back.
          my $config = { DSN => 'DBI:mysql:session', MySQLunm => 'ipsofalco', MySQLpwd => 'ipsoquango', }; my $dbh = &createDBconnection( $config->{DSN}, $config->{MySQLunm}, $c +onfig->{MySQLpwd} ); # Get a CGI object, it will be filled if a form was #submitted and will have a cookie in teh header #if one had been set. my $q = new CGI; #Initialize the session, if their is a cookie in the #CGI object then the CGISESSID will be the value of an #existing session, otherwise it creates a new session my $session = new CGI::Session("driver:MySQL", $q, {Handle=>$dbh}); #$rdcookie is the value of the cookie that was already # in the header read=past tense in this case. my $rdcookie = $q->cookie("CGISESSID"); #$id is the session id (an MD5 hash) of the session. my $id = $session->id(); # Set cookie with new expire time my $cookie = $q->cookie(-name=>'CGISESSID', -value=>$session->id, -exp +ires=>'+1d');
        3. Now we can write to the session, read from it, clear it and expire things, like this in a crude shopping cart:
          sub addItemCart { my ($cgi, $session, $orderitem) = @_; my $orderitem = &getItemForCart($cgi, $session); # get current cart contents my $cart = $session->param("CART") || []; # add selected item push @{$cart}, $orderitem; # update the CART in the session $session->param( "CART", $cart ); $session->flush(); return displayCart($cgi, $session); }
          Does nothing more than get a hash of an item and adds it to the CART value(a list of hashes) which is saved in the session parameters.
        4. To clear the cart we clear the session value that was saved:
          sub clrCart { my ($cgi, $session) = @_; $session->clear(["CART"]); $session->flush(); return &displayCart($cgi, $session); }
          and in this case display the updated cart.
        Save what you like int he session parameters. Save an entire HASH, darn it, save an array of hashes just like my silly little cart.

        To see some more code - much more complete, have a look at jdtoronto's scratchpad The full working version is posted there.

        jdtoronto

        I missed part of your questions:
        I can save all my template variables in an array, then pass that array over to the template and somehow (don't know how yet) I can then "extract" them into individual items I can use? Did I get that right?
        Not quite, you can pass it a hash reference, if you want to fill in several TMPL_VAR's you can do this:
        $template->param( 'username' => 'john', 'userstatus' => 'paid' );
        So you can build a HASH and pass in a reference. Oh. lets not forget, in CGI the Vars method will return either a HASH of a HASHREF of all the parameters, instead of iterating over them using the param method you can get then in one bite. If you use
        $hashref = $q->Vars;
        then you get a tied HASHREF which you can pass to H::T.
        $template->param( $hashref );
        will set all the variables for which a hash key exists. In this case <TMPL_VAR name="username"> and <TMPL_VAR name="userstatus">.

        Interestingly, H::T can also accept an object with a param method, similar to CGI. Well, this then means that you should be able to pass the query object to H::T, I havn't tried it, but it should work.

        $template->param( associate => $q );

        HTML::Template is immensely flexible and can be used in many ways, and it can be fed in many and various ways too!

        jdtoronto