You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by Brian Gaber <Br...@PWGSC.GC.CA> on 2008/06/13 20:39:13 UTC

CGI.pm param and mod_perl

I have converted a CGI.pm cgi-bin script to run in mod_perl as a
Registry.  On multiple runs I seem to get old values of a param('var').
I have read the documents and understand I need to be careful with
global variables.  Is there something I need to be aware of when I use
CGI.pm params?  One thought, my code is written to use the CGI.pm
default object so that I do not have something like $q = new CGI;  Could
this be the cuase?

Thanks.

Brian

Re: CGI.pm param and mod_perl

Posted by Michael Peters <mp...@plusthree.com>.
Brian Gaber wrote:

> When I read the mod_perl docs they suggest that use vars was one
> approach to fix the "Variable X will not stay shared at" error.

This makes me think that maybe your problem is something else... but try below.

> What is the recommended approach?  Pass a reference to $q?

Not a reference, but $q itself (objects are already references, so passing a
reference to a reference doesn't gain anything). It's a good idea in just about
all programming languages to avoid globals and pass things around to subroutines
that need them.

-- 
Michael Peters
Plus Three, LP


RE: CGI.pm param and mod_perl

Posted by Brian Gaber <Br...@PWGSC.GC.CA>.
I just did as you suggested.

Now in the log I get a

Variable "$q" will not stay shared at ...

error from the $q->param('deptLtr') in the subroutine.

When I read the mod_perl docs they suggest that use vars was one
approach to fix the "Variable X will not stay shared at" error.

What is the recommended approach?  Pass a reference to $q?

Thanks

-----Original Message-----
From: Michael Peters [mailto:mpeters@plusthree.com] 
Sent: Friday, June 13, 2008 3:21 PM
To: Brian Gaber
Cc: modperl@perl.apache.org
Subject: Re: CGI.pm param and mod_perl

Brian Gaber wrote:
> Using $q was not successful. 

That's because you ignored my advice :)

> Here is what I have done:
> 
> use vars qw($q);

That makes $q a global. Bad, bad, very bad. Slap yourself on the wrist.
Remove that "use vars" line.

> $q = CGI->new();

Now replace that with

  my $q = CGI->new();

> sub print_form {
>    my $dept2show = 'A';
>    
>    if ( $q->param('deptLtr') ) {
>       ($dept2show) = $q->param('deptLtr') =~ /^([a-zA-Z]{1})$/;
>    }
> 
> 
> 	I am running this script simultaneously on two PCs.  Sometimes 
> $dept2show has the expected value, but often is has the an old value.

This is because Apache is using multiple processes to handle things.
Sometimes you're hitting a process for the first time, so it creates an
new CGI object and all is well. But sometimes your request goes back to
a process that has already loaded and executed this code before, so $q
is not a new CGI object.

--
Michael Peters
Plus Three, LP


RE: CGI.pm param and mod_perl

Posted by Brian Gaber <Br...@PWGSC.GC.CA>.
Here are relevant parts of code:

use CGI '-autoload';
use DBI();
use warnings;
use strict;

# Initial declaration and/or population of global script variables

use vars qw($q);

$q = CGI->new();

open(DEBUGLOG, ">> /tmp/mod_perl_debug.txt");
foreach my $name ( $q->param() ) {
   my $value = $q->param($name);
   print DEBUGLOG "The value of $name is $value for PID: $$\n";
} 

&print_form();

sub print_form {
   my $region = $q->param('region');
   my $dept2show = 'A';

   if ( $q->param('deptLtr') ) {
      ($dept2show) = $q->param('deptLtr') =~ /^([a-zA-Z]{1})$/;
   }

-----Original Message-----
From: Dondi Stroma [mailto:dstroma@verizon.net] 
Sent: Friday, June 13, 2008 4:38 PM
To: Brian Gaber
Cc: modperl@perl.apache.org
Subject: Re: CGI.pm param and mod_perl

Brian Gaber wrote:

> The HTML code that I am selecting looks like this:

That's not necessary. What does your perl code look like now? Also, try
printing/warning the value of $$, which is the process ID. I think
you'll find that the value of your variable stays the same for each
process. 


RE: CGI.pm param and mod_perl

Posted by Brian Gaber <Br...@PWGSC.GC.CA>.
Dondi,

        Thanks for the advice.  Here is the log output now:

The value of region is Atlantic for PID: 44538
The value of set is 0 for PID: 44538
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400

The value of region is Atlantic for PID: 60132
The value of deptLtr is G for PID: 60132
The value of set is 0 for PID: 60132 <- GOOD
SELECT * FROM atlantic_rr WHERE dept REGEXP '^G' ORDER BY dept, pay_list

The value of region is Atlantic for PID: 48600
The value of set is 0 for PID: 48600 <- GOOD
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400

The value of region is Atlantic for PID: 53446
The value of deptLtr is F for PID: 53446 <- GOOD
The value of set is 0 for PID: 53446
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list

The value of region is Atlantic for PID: 53446
The value of deptLtr is F for PID: 53446 <- ERROR I clicked on G
The value of set is 0 for PID: 53446
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list

	This last entry for PID 53446 confirms my suspicion that for
some reason the CGI.pm query object and thus param('var') is not new on
every run.  Why, I have no idea.

	BTW, when you and Michael talk about logging via [warn] are you
reffering to a syslog change or some Perl function?

	Thanks.

Brian

-----Original Message-----
From: Dondi Stroma [mailto:dstroma@verizon.net]
Sent: Friday, June 13, 2008 4:38 PM
To: Brian Gaber
Cc: modperl@perl.apache.org
Subject: Re: CGI.pm param and mod_perl

Brian Gaber wrote:

> The HTML code that I am selecting looks like this:

That's not necessary. What does your perl code look like now? Also, try
printing/warning the value of $$, which is the process ID. I think
you'll find that the value of your variable stays the same for each
process.






Re: CGI.pm param and mod_perl

Posted by Dondi Stroma <ds...@verizon.net>.
Brian Gaber wrote:

> The HTML code that I am selecting looks like this:

That's not necessary. What does your perl code look like now? Also, try 
printing/warning the value of $$, which is the process ID. I think you'll 
find that the value of your variable stays the same for each process. 


RE: CGI.pm param and mod_perl

Posted by Brian Gaber <Br...@PWGSC.GC.CA>.
Michael,

	The fatal errors from yesterday are fixed.  When I run this as a
cgi-bin it runs fine.

	The HTML code that I am selecting looks like this:

<th><form name='A' method='post'>
<input type=hidden name=region value='Atlantic'>
<input type=hidden name=deptLtr value='A'>
<input type=hidden name=set value='0'>
<a href="javascript: document.A.submit()">A</a>
</form>
</th>
<th><form name='B' method='post'>
<input type=hidden name=region value='Atlantic'>
<input type=hidden name=deptLtr value='B'>
<input type=hidden name=set value='0'>
<a href="javascript: document.B.submit()">B</a>
</form>
... Etc (for each letter of the alphabet)

The value of region is Atlantic  <- GOOD
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400

The value of region is Atlantic
The value of deptLtr is I  <- GOOD
The value of set is 0 SELECT * FROM atlantic_rr WHERE dept REGEXP '^I'
ORDER BY dept, pay_list

The value of region is Atlantic
The value of deptLtr is O  <- GOOD
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^O' ORDER BY dept, pay_list

The value of region is Atlantic  <- GOOD
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400

The value of region is Atlantic
The value of deptLtr is K  <- GOOD
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^K' ORDER BY dept, pay_list

The value of region is Atlantic
The value of deptLtr is F  <- GOOD
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list

The value of region is Atlantic
The value of deptLtr is F <- ERROR I selected C
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list

The value of region is Atlantic
The value of deptLtr is O <- ERROR I selected C
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^O' ORDER BY dept, pay_list


-----Original Message-----
From: Michael Peters [mailto:mpeters@plusthree.com] 
Sent: Friday, June 13, 2008 4:21 PM
To: Brian Gaber
Cc: Dondi Stroma; modperl@perl.apache.org
Subject: Re: CGI.pm param and mod_perl

Brian Gaber wrote:

> 	Here is the log you asked for:

We need a little more context than that. For instance I don't see where
it actually has the fatal error you mentioned from the earlier posts.
Also, if you could annotate it with what the values of those params
"should" be.

But the most important thing you can do is to reduce the problem down to
the smallest possible code that still has the fatal error. Not only will
it help us help you, but 90% of the time when I do that I figure out
what the problem was on my own.

--
Michael Peters
Plus Three, LP


Re: CGI.pm param and mod_perl

Posted by Michael Peters <mp...@plusthree.com>.
Brian Gaber wrote:

> 	Here is the log you asked for:

We need a little more context than that. For instance I don't see where it
actually has the fatal error you mentioned from the earlier posts. Also, if you
could annotate it with what the values of those params "should" be.

But the most important thing you can do is to reduce the problem down to the
smallest possible code that still has the fatal error. Not only will it help us
help you, but 90% of the time when I do that I figure out what the problem was
on my own.

-- 
Michael Peters
Plus Three, LP


RE: CGI.pm param and mod_perl

Posted by Brian Gaber <Br...@PWGSC.GC.CA>.
Michael,

	Here is the log you asked for:

The value of region is Atlantic
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400
The value of region is Atlantic
The value of deptLtr is I
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^I' ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is O
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^O' ORDER BY dept, pay_list
The value of region is Atlantic
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400
The value of region is Atlantic
The value of deptLtr is K
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^K' ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is F
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is F <- ERROR I selected C
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is O <- ERROR I selected C
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^O' ORDER BY dept, pay_list

	Thanks.
-----Original Message-----
From: Michael Peters [mailto:mpeters@plusthree.com] 
Sent: Friday, June 13, 2008 3:47 PM
To: Dondi Stroma
Cc: modperl@perl.apache.org
Subject: Re: CGI.pm param and mod_perl

Dondi Stroma wrote:

> I don't see what is so bad about this:
> 
> use vars qw($q);
> $q = CGI->new();
> 
> Even though it's a global variable, you are assigning it a new value,
> CGI->new, each time.

You're right. I don't normally think about registry scripts since I
almost never use them. I was thinking he was doing that at the top of a
module such that it was happening at compile time. But even then my
advice wasn't that helpful since the assignment would still only happen
at compile time.

> I suspect the problem is something else, possibly part of the script 
> that we haven't seen.

Yeah, I'm starting to think the same thing. Brian, why don't you print
the value of the param to the log ("warn" is good for this) for the
request (along with the SQL that you're generating) so you/we can see
what the actual value being pulled it.

--
Michael Peters
Plus Three, LP


RE: CGI.pm param and mod_perl

Posted by Brian Gaber <Br...@PWGSC.GC.CA>.
Sorry, my e-mail client didn't like the line endings of the log.  Here
is the log agin in a more readable format:

The value of region is Atlantic
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400
The value of region is Atlantic
The value of deptLtr is I
The value of set is 0 SELECT * FROM atlantic_rr WHERE dept REGEXP '^I'
ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is O
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^O' ORDER BY dept, pay_list
The value of region is Atlantic
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^A' ORDER BY dept, pay_list
LIMIT 0, 400
The value of region is Atlantic
The value of deptLtr is K
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^K' ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is F
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is F <- ERROR I selected C
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^F' ORDER BY dept, pay_list
The value of region is Atlantic
The value of deptLtr is O <- ERROR I selected C
The value of set is 0
SELECT * FROM atlantic_rr WHERE dept REGEXP '^O' ORDER BY dept, pay_list

	Thanks. 

-----Original Message-----
From: Michael Peters [mailto:mpeters@plusthree.com] 
Sent: Friday, June 13, 2008 3:47 PM
To: Dondi Stroma
Cc: modperl@perl.apache.org
Subject: Re: CGI.pm param and mod_perl

Dondi Stroma wrote:

> I don't see what is so bad about this:
> 
> use vars qw($q);
> $q = CGI->new();
> 
> Even though it's a global variable, you are assigning it a new value,
> CGI->new, each time.

You're right. I don't normally think about registry scripts since I
almost never use them. I was thinking he was doing that at the top of a
module such that it was happening at compile time. But even then my
advice wasn't that helpful since the assignment would still only happen
at compile time.

> I suspect the problem is something else, possibly part of the script 
> that we haven't seen.

Yeah, I'm starting to think the same thing. Brian, why don't you print
the value of the param to the log ("warn" is good for this) for the
request (along with the SQL that you're generating) so you/we can see
what the actual value being pulled it.

--
Michael Peters
Plus Three, LP


Re: CGI.pm param and mod_perl

Posted by Michael Peters <mp...@plusthree.com>.
Dondi Stroma wrote:

> I don't see what is so bad about this:
> 
> use vars qw($q);
> $q = CGI->new();
> 
> Even though it's a global variable, you are assigning it a new value,
> CGI->new, each time.

You're right. I don't normally think about registry scripts since I almost never
use them. I was thinking he was doing that at the top of a module such that it
was happening at compile time. But even then my advice wasn't that helpful since
the assignment would still only happen at compile time.

> I suspect the problem is something else, possibly part of the script
> that we haven't seen.

Yeah, I'm starting to think the same thing. Brian, why don't you print the value
of the param to the log ("warn" is good for this) for the request (along with
the SQL that you're generating) so you/we can see what the actual value being
pulled it.

-- 
Michael Peters
Plus Three, LP


Re: CGI.pm param and mod_perl

Posted by Dondi Stroma <ds...@verizon.net>.
Michael Peters wrote:
> Brian Gaber wrote:
>> Using $q was not successful.
>
> That's because you ignored my advice :)
>
>> Here is what I have done:
>>
>> use vars qw($q);
>
> That makes $q a global. Bad, bad, very bad. Slap yourself on the wrist. 
> Remove
> that "use vars" line.

I don't see what is so bad about this:

use vars qw($q);
$q = CGI->new();

Even though it's a global variable, you are assigning it a new value, 
CGI->new, each time.

On the other hand, a subroutine should never use a lexical variable that was 
declared outside of it, at least not in a Registry type script because of 
the nested subroutines. So this is very bad and should trigger a "variable 
will not stay shared" warning:

my $q = CGI->new;
sub dostuff {
  print $q->param('foobar');
}

I suspect the problem is something else, possibly part of the script that we 
haven't seen. 


Re: CGI.pm param and mod_perl

Posted by Michael Peters <mp...@plusthree.com>.
Brian Gaber wrote:
> Using $q was not successful. 

That's because you ignored my advice :)

> Here is what I have done:
> 
> use vars qw($q);

That makes $q a global. Bad, bad, very bad. Slap yourself on the wrist. Remove
that "use vars" line.

> $q = CGI->new();

Now replace that with

  my $q = CGI->new();

> sub print_form {
>    my $dept2show = 'A';
>    
>    if ( $q->param('deptLtr') ) {
>       ($dept2show) = $q->param('deptLtr') =~ /^([a-zA-Z]{1})$/;
>    } 
> 
> 
> 	I am running this script simultaneously on two PCs.  Sometimes
> $dept2show has the expected value, but often is has the an old value.

This is because Apache is using multiple processes to handle things. Sometimes
you're hitting a process for the first time, so it creates an new CGI object and
all is well. But sometimes your request goes back to a process that has already
loaded and executed this code before, so $q is not a new CGI object.

-- 
Michael Peters
Plus Three, LP


RE: CGI.pm param and mod_perl

Posted by Brian Gaber <Br...@PWGSC.GC.CA>.
Michael,

	Using $q was not successful.  Here is what I have done:

use vars qw($q);

$q = CGI->new();

sub print_form {
   my $dept2show = 'A';
   
   if ( $q->param('deptLtr') ) {
      ($dept2show) = $q->param('deptLtr') =~ /^([a-zA-Z]{1})$/;
   } 


	I am running this script simultaneously on two PCs.  Sometimes
$dept2show has the expected value, but often is has the an old value.

-----Original Message-----
From: Michael Peters [mailto:mpeters@plusthree.com] 
Sent: Friday, June 13, 2008 2:54 PM
To: Brian Gaber
Cc: modperl@perl.apache.org
Subject: Re: CGI.pm param and mod_perl

Brian Gaber wrote:
>  One thought, my code is written to use the CGI.pm default object so 
> that I do not have something like $q = new CGI;  Could this be the 
> cuase?

Very well could be.

Doing a "$q = new CGI" means that you will get a new CGI object on every
request, which is what you want. I've never used the function interface
of CGI.pm like you did in your example so I don't know how CGI.pm
handles it behind the scenes (whether it creates a new object on each
request or not). But if I were you, that's probably the first place I'd
look.

Also, just a couple of minor nits to help you out. Instead of "$q = new
CGI" do "my $q = CGI->new()". First off the "my" means it's a local
(lexical) variable.
Always good to have your vars be local unless you know you'll need
something else. And "new CGI" is the indirect object syntax for method
calls which is generally frowned upon since it can lead to problems that
are hard to track down. "CGI->new()" is alway unambiguous.

--
Michael Peters
Plus Three, LP


Re: CGI.pm param and mod_perl

Posted by Perrin Harkins <pe...@elem.com>.
On Fri, Jun 13, 2008 at 2:53 PM, Michael Peters <mp...@plusthree.com> wrote:
> Doing a "$q = new CGI" means that you will get a new CGI object on every
> request, which is what you want. I've never used the function interface of
> CGI.pm like you did in your example so I don't know how CGI.pm handles it behind
> the scenes (whether it creates a new object on each request or not).

Sad to say, CGI->new is mostly just lipstick on a pig.  Behind the
scenes, it still puts everything in globals.  CGI.pm is just not an OO
module.

However, it is safe to use with mod_perl because it reinitializes the
globals on each request.  The only problems I've run into with this
are from internal redirects, when it doesn't realize there's a fresh
request.

- Perrin

Re: CGI.pm param and mod_perl

Posted by Michael Peters <mp...@plusthree.com>.
Brian Gaber wrote:
>  One thought, my code is written to use the CGI.pm
> default object so that I do not have something like $q = new CGI;  Could
> this be the cuase?

Very well could be.

Doing a "$q = new CGI" means that you will get a new CGI object on every
request, which is what you want. I've never used the function interface of
CGI.pm like you did in your example so I don't know how CGI.pm handles it behind
the scenes (whether it creates a new object on each request or not). But if I
were you, that's probably the first place I'd look.

Also, just a couple of minor nits to help you out. Instead of "$q = new CGI" do
"my $q = CGI->new()". First off the "my" means it's a local (lexical) variable.
Always good to have your vars be local unless you know you'll need something
else. And "new CGI" is the indirect object syntax for method calls which is
generally frowned upon since it can lead to problems that are hard to track
down. "CGI->new()" is alway unambiguous.

-- 
Michael Peters
Plus Three, LP