RE: can't properly append to file from mod_perl script

2000-07-05 Thread Geoffrey Young

Are you setting PerlWarn On and checking for errors?

I get these when compiling your script under RegistryLoader:

Variable "$results_file" will not stay shared at
/usr/local/apache/perl-bin/test.cgi line 29.
Variable "$entry" will not stay shared at
/usr/local/apache/perl-bin/test.cgi line 31.
Variable "$display_file" will not stay shared at
/usr/local/apache/perl-bin/test.cgi line 38.
Useless use of concatenation in void context at
/usr/local/apache/perl-bin/test.cgi line 56.

see
http://perl.apache.org/guide/perl.html#my_Scoped_Variable_in_Nested_S 

the mod_perl guide is full of lots of goodies that are worth reading...

HTH

--Geoff

> -Original Message-
> From: Rob Egan [mailto:[EMAIL PROTECTED]]
> Sent: Friday, June 30, 2000 8:01 PM
> To: [EMAIL PROTECTED]
> Subject: RE: can't properly append to file from mod_perl script
> 
> 
> Hi,
> 
> I sent an earlier post with a script that was appending 
> garbage along with
> user email addresses that were submitted through a form. 
> After seeing all
> the suggestions about improvement, I went ahead and rewrote 
> the script from
> scratch (it's much shorter now!). My version actually 
> prevents garbage from
> being placed into the output file, but it still has a 
> problem. If I open up
> two browsers on separate machines, go to the page containing 
> the form, and
> simultaneously submit addresses from both machines, after maybe 8 or 9
> entries the output becomes incorrect. For example, if I enter 
> the following
> e-mail addresses one at a time from the form:
> 
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> 
> Then I view the output file and see this output:
> 
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> [EMAIL PROTECTED]
> 
> It's as though the parameters I'm pulling from the form get 
> stuck somewhere,
> but I can't figure out where. I tried autoflushing buffers 
> for both STDOUT
> and the output channel I use to write the output (called 
> RESULTS in the
> script), but that doesn't help. Some of you guys had 
> mentioned writing some
> cleanup code after I close my file, but I don't quite 
> understand what I need
> to clean up (sorry, I'm kind of new at this). Any ideas? (the 
> code is below)
> 
> -Rob
> 
> begin script text
> #!/usr/local/bin/perl -w
> 
> # call strict, CGI, and Fcntl modules
> use strict;
> use CGI;
> use Fcntl qw(:flock);
> use FileHandle;
> 
> # autoflush buffers
> $| = 1;
> 
> # Variable definitions
> my $results_file = "./beastie.results.csv";
> my $display_file = "./email_thankyou.html";
> my $entry;
> 
> Sub routine definitionsDon't change anything 
> below here
> 
> # General error routine (takes 3 string arguments, displays 
> results in HTML)
> sub bail {
>   my ($status, $keyword, $message) = "@_";
>   print h1("$status $keyword"), p($message), end_html();
>   die $message;
> }
> 
> # Open results file, lock it, write entry, close/unlock it.
> sub write_entry {
>   RESULTS->autoflush(1);
>   open(RESULTS, ">>$results_file") || bail(500, "Results 
> Error", "$!");
>   flock(RESULTS, LOCK_EX);
>   print RESULTS $entry;
>   close(RESULTS);
> }
> 
> # Display thank you page with link back to main site.
> sub say_thanks {
>   print CGI::header();
>   open(DISPLAYFILE, "<$display_file") || bail(500, "Error", "$!");
> while() {
> print;
>   }
>   close(DISPLAYFILE);
> }
> 
> Begin main program
> 
> # Create CGI object, and gather email addresses into array
> my $query = CGI->new();
> my $address = $query->param('email');
> 
> # Format URL encoded email address into ascii, append date 
> stamp to it.
>   $address =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack("C", hex($1))/eg;
>   $entry = "$address, " . localtime() . "\n";
> 
> # Write the email and timestamp to results file, display 
> thank you page,
> exit.
> write_entry();
> say_thanks();
> exit(0);
> 
> End of script
> 



RE: can't properly append to file from mod_perl script

2000-06-30 Thread Rob Egan

Hi,

I sent an earlier post with a script that was appending garbage along with
user email addresses that were submitted through a form. After seeing all
the suggestions about improvement, I went ahead and rewrote the script from
scratch (it's much shorter now!). My version actually prevents garbage from
being placed into the output file, but it still has a problem. If I open up
two browsers on separate machines, go to the page containing the form, and
simultaneously submit addresses from both machines, after maybe 8 or 9
entries the output becomes incorrect. For example, if I enter the following
e-mail addresses one at a time from the form:

[EMAIL PROTECTED]
[EMAIL PROTECTED]
[EMAIL PROTECTED]
[EMAIL PROTECTED]
[EMAIL PROTECTED]

Then I view the output file and see this output:

[EMAIL PROTECTED]
[EMAIL PROTECTED]
[EMAIL PROTECTED]
[EMAIL PROTECTED]
[EMAIL PROTECTED]

It's as though the parameters I'm pulling from the form get stuck somewhere,
but I can't figure out where. I tried autoflushing buffers for both STDOUT
and the output channel I use to write the output (called RESULTS in the
script), but that doesn't help. Some of you guys had mentioned writing some
cleanup code after I close my file, but I don't quite understand what I need
to clean up (sorry, I'm kind of new at this). Any ideas? (the code is below)

-Rob

begin script text
#!/usr/local/bin/perl -w

# call strict, CGI, and Fcntl modules
use strict;
use CGI;
use Fcntl qw(:flock);
use FileHandle;

# autoflush buffers
$| = 1;

# Variable definitions
my $results_file = "./beastie.results.csv";
my $display_file = "./email_thankyou.html";
my $entry;

Sub routine definitionsDon't change anything below here

# General error routine (takes 3 string arguments, displays results in HTML)
sub bail {
  my ($status, $keyword, $message) = "@_";
  print h1("$status $keyword"), p($message), end_html();
  die $message;
}

# Open results file, lock it, write entry, close/unlock it.
sub write_entry {
  RESULTS->autoflush(1);
  open(RESULTS, ">>$results_file") || bail(500, "Results Error", "$!");
  flock(RESULTS, LOCK_EX);
  print RESULTS $entry;
  close(RESULTS);
}

# Display thank you page with link back to main site.
sub say_thanks {
  print CGI::header();
  open(DISPLAYFILE, "<$display_file") || bail(500, "Error", "$!");
while() {
print;
  }
  close(DISPLAYFILE);
}

Begin main program

# Create CGI object, and gather email addresses into array
my $query = CGI->new();
my $address = $query->param('email');

# Format URL encoded email address into ascii, append date stamp to it.
  $address =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack("C", hex($1))/eg;
  $entry = "$address, " . localtime() . "\n";

# Write the email and timestamp to results file, display thank you page,
exit.
write_entry();
say_thanks();
exit(0);

End of script




Re: can't properly append to file from mod_perl script

2000-06-29 Thread Stas Bekman

> On Thu, 29 Jun 2000, Stas Bekman wrote:
> 
> > When using file locking one must make sure, that if the script has been
> > stopped before the close() was called, to use an END block under Registry
> > or $r->register_cleanup() anywhere. See:
> > http://perl.apache.org/guide/debug.html#Handling_the_User_pressed_Stop_
> > http://perl.apache.org/guide/debug.html#Cleanup_Code
> > 
> > Otherwise you might get stuck with a stale lock, which will be never
> > removed unless the same process will call open() on the same filehandler.
> > And it'd be the same filehandler only if you use "open, IN ..." style, if
> > you use Symbol module or perl5.6 filehandler autovivification a new unique
> > filehandler will be created when the same code will run again.
> > 
> > So close() under mod_perl is not enough when locking is used.
> 
> Are you suggesting that more has to be done even if you use my $fh type
> opening? I'm not sure I believe you, if thats what you're suggesting - the
> second paragraph there seems to confuse things. If you use my $fh style
> opening (either the Symbol or 5.6 way) you need worry not about unlocking
> files or cleanup code for unlocking/closing files - it's all done by the
> garbage collector. (you should close your filehandles anyway though for
> the sake of cleanliness and not leaving around locks, but my point was
> merely the necessity of it).

Frank were talking about using globals. I forgot to stress this point. My
post is correct only when assuming that one uses globals.

so if you use 

  use vars ($fh)
  $fh = Symbol::gensym; # or Apache::Symbol
  open $fh, "foo" ...

it holds. Now thinking again about 5.6, I'm not sure about this:

  use vars ($fh)
  open $fh, "foo"...

is the auto-vivication of a unique filehandler works in this case? Or
only when one uses:

  open my $fh, "foo"...

if the latter is correct, my statement is incorrect regrading the perl5.6
autovivication, and only these two cases hold:

  # 1
  open IN, "foo" 

  # 2
  use vars ($fh)
  $fh = Symbol::gensym; # or Apache::Symbol
  open $fh, "foo" ...

In both you should worry to add a cleanup code.

_
Stas Bekman  JAm_pH --   Just Another mod_perl Hacker
http://stason.org/   mod_perl Guide  http://perl.apache.org/guide 
mailto:[EMAIL PROTECTED]   http://perl.org http://stason.org/TULARC
http://singlesheaven.com http://perlmonth.com http://sourcegarden.org






Re: can't properly append to file from mod_perl script

2000-06-29 Thread Matt Sergeant

On Thu, 29 Jun 2000, Stas Bekman wrote:

> When using file locking one must make sure, that if the script has been
> stopped before the close() was called, to use an END block under Registry
> or $r->register_cleanup() anywhere. See:
> http://perl.apache.org/guide/debug.html#Handling_the_User_pressed_Stop_
> http://perl.apache.org/guide/debug.html#Cleanup_Code
> 
> Otherwise you might get stuck with a stale lock, which will be never
> removed unless the same process will call open() on the same filehandler.
> And it'd be the same filehandler only if you use "open, IN ..." style, if
> you use Symbol module or perl5.6 filehandler autovivification a new unique
> filehandler will be created when the same code will run again.
> 
> So close() under mod_perl is not enough when locking is used.

Are you suggesting that more has to be done even if you use my $fh type
opening? I'm not sure I believe you, if thats what you're suggesting - the
second paragraph there seems to confuse things. If you use my $fh style
opening (either the Symbol or 5.6 way) you need worry not about unlocking
files or cleanup code for unlocking/closing files - it's all done by the
garbage collector. (you should close your filehandles anyway though for
the sake of cleanliness and not leaving around locks, but my point was
merely the necessity of it).

-- 


Fastnet Software Ltd. High Performance Web Specialists
Providing mod_perl, XML, Sybase and Oracle solutions
Email for training and consultancy availability.
http://sergeant.org | AxKit: http://axkit.org




Re: can't properly append to file from mod_perl script

2000-06-29 Thread Stas Bekman

On 29 Jun 2000, Frank D. Cringle wrote:

> Vivek Khera <[EMAIL PROTECTED]> writes:
> > > "RE" == Rob Egan <[EMAIL PROTECTED]> writes:
> > 
> > RE> CGI scripts to behave in mod_perl. All it does is capture e-mail addresses,
> > RE> and place them in a text file so we can gather them up later and drop them
> > RE> into a database. If you run the script as a regular CGI (without mod_perl
> > RE> enabled) it works great. But on the mod_perl enabled server, the script
> > RE> throws garbage into the file and overwrites previous entries if a user
> > RE> submits more than one e-mail address in a single session (i.e. they enter
> > 
> > It has nothing to do with the person quitting the browser.  It has to
> > do with your script using global variables.  Turn on "use strict" and
> > perl warnings and see what your error log says.
> > 
> > Then go to the mod perl guide and search for "sticky variables".
> 
> But since they are all global (no use of my), they won't be sticky.
> 
> There is plenty wrong with the script, although I can't specifically
> correlate the symptoms with the mistakes.  Sometimes the file is
> referred to as $results_file and in other places by its literal name.
> The 'if (-e $results_file) open ">..." else open ">>..."' code is
> unnecessary and will break if 2 processes hit the first if
> concurrently.  Just open it in append mode.  If it isn't there it will
> be created.  If you don't have write permission the open will fail.
> The locking is classically broken "# Unlock before you close" No!
> Wrong!.  Just close the file.  That has the desired side-effects of
> first flushing the buffered data and then unlocking the file.

When using file locking one must make sure, that if the script has been
stopped before the close() was called, to use an END block under Registry
or $r->register_cleanup() anywhere. See:
http://perl.apache.org/guide/debug.html#Handling_the_User_pressed_Stop_
http://perl.apache.org/guide/debug.html#Cleanup_Code

Otherwise you might get stuck with a stale lock, which will be never
removed unless the same process will call open() on the same filehandler.
And it'd be the same filehandler only if you use "open, IN ..." style, if
you use Symbol module or perl5.6 filehandler autovivification a new unique
filehandler will be created when the same code will run again.

So close() under mod_perl is not enough when locking is used.

_
Stas Bekman  JAm_pH --   Just Another mod_perl Hacker
http://stason.org/   mod_perl Guide  http://perl.apache.org/guide 
mailto:[EMAIL PROTECTED]   http://perl.org http://stason.org/TULARC
http://singlesheaven.com http://perlmonth.com http://sourcegarden.org





Re: can't properly append to file from mod_perl script

2000-06-29 Thread Frank D. Cringle

Vivek Khera <[EMAIL PROTECTED]> writes:
> > "RE" == Rob Egan <[EMAIL PROTECTED]> writes:
> 
> RE> CGI scripts to behave in mod_perl. All it does is capture e-mail addresses,
> RE> and place them in a text file so we can gather them up later and drop them
> RE> into a database. If you run the script as a regular CGI (without mod_perl
> RE> enabled) it works great. But on the mod_perl enabled server, the script
> RE> throws garbage into the file and overwrites previous entries if a user
> RE> submits more than one e-mail address in a single session (i.e. they enter
> 
> It has nothing to do with the person quitting the browser.  It has to
> do with your script using global variables.  Turn on "use strict" and
> perl warnings and see what your error log says.
> 
> Then go to the mod perl guide and search for "sticky variables".

But since they are all global (no use of my), they won't be sticky.

There is plenty wrong with the script, although I can't specifically
correlate the symptoms with the mistakes.  Sometimes the file is
referred to as $results_file and in other places by its literal name.
The 'if (-e $results_file) open ">..." else open ">>..."' code is
unnecessary and will break if 2 processes hit the first if
concurrently.  Just open it in append mode.  If it isn't there it will
be created.  If you don't have write permission the open will fail.
The locking is classically broken "# Unlock before you close" No!
Wrong!.  Just close the file.  That has the desired side-effects of
first flushing the buffered data and then unlocking the file.

-- 
Frank Cringle,  [EMAIL PROTECTED]
voice: (+49 2304) 467101; fax: 943357



Re: can't properly append to file from mod_perl script

2000-06-29 Thread Vivek Khera

> "RE" == Rob Egan <[EMAIL PROTECTED]> writes:

RE> CGI scripts to behave in mod_perl. All it does is capture e-mail addresses,
RE> and place them in a text file so we can gather them up later and drop them
RE> into a database. If you run the script as a regular CGI (without mod_perl
RE> enabled) it works great. But on the mod_perl enabled server, the script
RE> throws garbage into the file and overwrites previous entries if a user
RE> submits more than one e-mail address in a single session (i.e. they enter

It has nothing to do with the person quitting the browser.  It has to
do with your script using global variables.  Turn on "use strict" and
perl warnings and see what your error log says.

Then go to the mod perl guide and search for "sticky variables".

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Vivek Khera, Ph.D.Khera Communications, Inc.
Internet: [EMAIL PROTECTED]   Rockville, MD   +1-301-545-6996
GPG & MIME spoken herehttp://www.khera.org/~vivek/



RE: can't properly append to file from mod_perl script

2000-06-29 Thread Geoffrey Young

you might want to 'use strict' and see what pops up :)

additionally, you might want to read up on mod_perl_traps.pod and 
http://perl.apache.org/guide/porting.html

specifically
http://perl.apache.org/guide/porting.html#Exposing_Apache_Registry_secret


HTH

--Geoff

> -Original Message-
> From: Rob Egan [mailto:[EMAIL PROTECTED]]
> Sent: Wednesday, June 28, 2000 6:38 PM
> To: [EMAIL PROTECTED]
> Subject: can't properly append to file from mod_perl script
> 
> 
> Hi,
> 
> I am relocating content from a non-mod_perl Apache site to a new
> mod_perl/1.24 enabled Apache server and I have a problems 
> getting one of the
> CGI scripts to behave in mod_perl. All it does is capture 
> e-mail addresses,
> and place them in a text file so we can gather them up later 
> and drop them
> into a database. If you run the script as a regular CGI 
> (without mod_perl
> enabled) it works great. But on the mod_perl enabled server, 
> the script
> throws garbage into the file and overwrites previous entries if a user
> submits more than one e-mail address in a single session 
> (i.e. they enter
> one address, click "Back", then enter another address). 
> However, if the user
> submits one e-mail address, then quits their browser, 
> restarts the browser
> and enters another e-mail, it works just fine. Does anybody 
> have any idea
> why this would happen? I've included the CGI script below 
> with actual URL's
> omitted (which was written by some consultant who no longer 
> works here).
> Thanks!
> 
> -Rob
> [EMAIL PROTECTED]
> 
> -begin script text
> #!/usr/local/bin/perl
> 
> $|=1;
> 
> # Enumerate the locking options for clarity...
> $LOCK_EX = 2;
> $LOCK_UN = 8;
> $results_file = "./results.csv";
> $cl = $ENV{'CONTENT_LENGTH'};
> $rqm = $ENV{'REQUEST_METHOD'};
> 
> sub lock {
>   # print "locking";
>   flock(RESULTS, $LOCK_EX);
>   # print "seeking";
>   # seeks to the end of the file in case
>   # someone got while we were waiting for the lock
>   seek(RESULTS, 0, 2);
>   # print "locked";
> }
> 
> sub unlock {
>   # print "unlocking";
>   flock(RESULTS, $LOCK_UN);
>   # print "unlocked";
> }
> 
> sub web_die {
> print "Location:  http://";
> die("\n");
> }
> 
> sub web_die_action {
> print "Location:  http://";
> die("\n");
> }
> 
> sub return_error
> {
>   local ($status, $keyword, $message) = @_;
> 
>   print "Content-type: text/html", "\n";
>   print "Status: ", $status, " ", $keyword, "\n\n";
> 
>   print < 
> Unexpected CGI Error
> 
> $keyword
> $message
> 
> 
> End_of_Error
>   exit(1);
> }
> sub write_entry
> {
>   # Lock after you open
>   &lock();
> 
>   $count = 0;
>   foreach (keys %FORM)
>   {
>$count++;
>   }
> 
>   for ($i = 0; $i < $count; $i++)
>   {
> $index = $i + 1;
> if ($FORM{"FIELD_$index"} eq "")
>  {
>   $FORM{"FIELD_$index"} = "NO ENTRY";
>  }
> $FORM{"FIELD_$index"} =~ s/\"/\"\"/g;  # 
> ...change " to ""
> $FORM{"FIELD_$index"} =~ s/\r//g;  # 
> ...kill line feeds
> $FORM{"FIELD_$index"} =~ s/\n/ /g; # 
> ...change cr to whitespace
> $FORM{"FIELD_$index"} = "\"" . 
> $FORM{"FIELD_$index"} . "\"";
> print RESULTS $FORM{"FIELD_$index"};
> print RESULTS ","
>}
>   print RESULTS "\n";
> 
>   # Unlock before you close
>   &unlock();
> 
>   close(RESULTS);
> 
>   &location;
> }
> 
> if ($rqm eq "POST")
>  {
>   read(STDIN, $buffer, $cl);
>   @pairs = split(/&/, $buffer);
>   $q = 0;
>   foreach $pair (@pairs)
>{
> $q++;
> ($name, $value) = split(/=/, $pair);
> $FORM{"FIELD_$q"} = $value;
> $FORM{"FIELD_$q"} =~ tr/+/ /;
> $FORM{"FIELD_$q"} =~ 
> s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
> if ($FORM{"FIELD_$q"} eq "0-12")
>  {
>&location;
>exit(0);
>  }
>}
>  }
> elsif ($cl > 0)
>  {
>   &web_die_action;
> # Error: form results must be submitted with method POST
>  }
> 
> ###
> if (! (-e $results_file))
> {
>   if (open (RESULTS, ">results.csv"))
>   {
>   &write_entry;
>   }
>   else
>   {
>   &return_error (500, "Results Error", "Cannot 
> create results.csv to store
> entries.");
>   }
> }
> 
> else
> {
>   if (! ((-r $results_file) && (-w $results_file)) )
>   {
>   &return_error (500, "Results Error", "Cannot 
> read or write to
> results.csv.");
>   }
>   else
>   {
>   open(RESULTS, ">>results.csv") || &web_die;
>   &write_entry;
>   }
> }
> exit(0);
> sub location
> {
> print "Location:  http://";
> }
>