Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:
I'm trying to match a word in the database and record it's occurence, I'm just using a form to post to the script.
My form:
<FORM ACTION="cgi-bin/basic2.pl" METHOD="POST">
<SELECT NAME="browser">
<OPTION VALUE="microsoft">microsoft</OPTION>
<OPTION VALUE="netscape">netscape</OPTION>
<OPTION VALUE="aol">aol</OPTION>
<OPTION VALUE="mozilla">mozilla</OPTION>
<OPTION VALUE="opera">opera</OPTION>
</SELECT>
<INPUT TYPE="SUBMIT" VALUE="Submit">
</FORM>
My code:
#!/perl/bin/perl
print "Content-type: text/html\n\n";
$logpath = "data/browser.dat";
&parse;
sub parse{
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
@pairs = split(/&/, $ENV{'QUERY_STRING'});
}
elsif ($ENV{'REQUEST_METHOD'} eq 'POST') {
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
@pairs = split(/&/, $buffer);
}
else {exit;}
foreach $pair (@pairs) {
($name, $value) = split(/=/, $pair);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s/<!--(.|\n)*-->//g;
$form{$name} = $value;
}
}
$browser = $form{'browser'};
open (LOG, "$logpath");
@data = <LOG>;
close(LOG);
$not_found = 1;
open (LOG, ">$logpath");
foreach $line(@data) {
chomp($line);
($fcount,$fbrowser)= split(/\|/,$line);
if ($fbrowser eq $browser) {
$not_found = 0;
$fcount = $fcount+1;
print LOG "$fcount|$fbrowser\n";
}
else {
print "$line";
}
}
close(LOG);
if($not_found) {
open (LOG,">>$logpath");
print "1|$browser";
close(LOG);
}
# just prints out log to browser
open (LOG, "$logpath");
@data = <LOG>;
close(LOG);
foreach $line(@data) {
chomp($line);
print "$line<br>";
}
close(LOG);
print "<p>$not_found";
It's is always not_found
Janitored by Arunbear - added readmore tags, as per Monastery guidelines
Re: Need help with searching flatfile and updating it.
by Fletch (Bishop) on Apr 25, 2005 at 01:57 UTC
|
- use CGI, don't reinvent the wheel.
- ALWAYS CHECK THE RETURN ON SYSTEM CALLS SUCH AS open()
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Need help with searching flatfile and updating it.
by chas (Priest) on Apr 25, 2005 at 02:14 UTC
|
It isn't at all clear to me that your splitting on '&' of $buffer or $ENV{'QUERY_STRING'} (and your further decoding) is going to get you the exact data you need. It may...I'm not claiming it definitely won't, but life would be much easier if you use CGI.pm and the "param" method to get the data you need. You won't have to worry about GET or POST methods and the decoding of the encoded data will be done automatically for you. If you are going to use Perl, make use of one of the most useful modules available; you'll be glad you did!
chas | [reply] [Watch: Dir/Any] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Need help with searching flatfile and updating it.
by jasonk (Parson) on Apr 25, 2005 at 03:50 UTC
|
The bigger problems you have with re-inventing wheels that should not be reinvented notwithstanding, your main problem is the fundamentally broken loop that is looking at the data that came from the file. Without resorting to rewriting code for you, in english your program does this:
- Open $logpath and read in the contents
- Iterate through the lines found there, and
- If the browser in this line is the one from the form, increment it's counter and print it to the log
- If the browser in this line is not the one from the form, print it to STDOUT
In a nutshell, this means that the browser that matches the form entry gets printed to the log, while the others get printed to the browser. I bet if you looked at the logfile, you would find it always contains at most 1 line.
There are however, several other problems with this code:
- Always, Always, Always use '-w' and 'use strict'.
- Doing your own parameter parsing instead of using CGI is just asking for trouble.
- Not checking the return code from your open calls means you may be truncating your logfile to rewrite it, even though the script didn't read any data from it in the first place.
- Not handling locking means that if two people submit the form at the same time, your logfile could very likely be nuked by the second one.
We're not surrounded, we're in a target-rich environment! |
---|
| [reply] [Watch: Dir/Any] |
|
"In a nutshell, this means that the browser that matches the form entry gets printed to the log, while the others get printed to the browser."
I forgot to remark on that in my reply, but I didn't undertand the point of that print either. In fact, it isn't even being printed to the browser I think, because the print "Content-type: text/html\n\n"; doesn't occur till later.
chas
| [reply] [Watch: Dir/Any] [d/l] |
Thanks for everybody's help!
by Anonymous Monk on Apr 25, 2005 at 05:23 UTC
|
| [reply] [Watch: Dir/Any] |
Re: Need help with searching flatfile and updating it.
by pearlie (Sexton) on Apr 25, 2005 at 04:46 UTC
|
Hello,
You can use Tie::file module to read and update the file. | [reply] [Watch: Dir/Any] |
I have it working, but sorting is very greedy.
by Anonymous Monk on Apr 25, 2005 at 05:11 UTC
|
#!/perl/bin/perl -w
use CGI;
$q = new CGI;
for $key ( $q->param() ) { $form{$key} = $q->param($key); }
$logpath = "data/browser.dat";
$temppath = "C:/Documents and Settings/Owner/My Documents/My Website/c
+gi-bin/data/temp.dat";
$browser = $form{'browser'};
open (LOG, "$logpath");
@data = <LOG>;
close(LOG);
$not_found = 1;
if($browser) {
open (LOG, ">$logpath");
foreach $line(@data) {
chomp($line);
($fcount,$fbrowser)= split(/\|/,$line);
if ($fbrowser eq $browser) {
$not_found = 0;
$fcount = $fcount+1;
print LOG "$fcount|$fbrowser\n";
}
else {
print LOG "$line\n";
}
}
close(LOG);
if($not_found) {
open (LOG,">>$logpath");
print LOG "1|$browser";
close(LOG);
}
}
# prints out log and form to browser
print "Content-type: text/html\n\n";
open (LOG, "$logpath");
@data = <LOG>;
close(LOG);
foreach $line(@data) {
chomp($line);
print "$line<br>";
}
close(LOG);
print <<EOT;
<FORM ACTION="basic.pl" METHOD="POST">
<SELECT NAME="browser">
<OPTION VALUE="microsoft">microsoft</OPTION>
<OPTION VALUE="netscape">netscape</OPTION>
<OPTION VALUE="aol">aol</OPTION>
<OPTION VALUE="mozilla">mozilla</OPTION>
<OPTION VALUE="opera">opera</OPTION>
</SELECT>
<INPUT TYPE="SUBMIT" VALUE="Submit">
</FORM>
EOT
# If you would like to suggest a better way to sort here is the rest o
+f the code.
sub getBrowsers {
%browse=();
open(INF,"$logpath") || print "Cannot open logs.dat file\n";
@hits= <INF>;
close(INF);
open(TEMP,">>$temppath") || print "Cannot open temp.dat file\n";
foreach $i (@hits) {
chomp($i);
($hits,$browser)= split(/\|/,$i);
for ($t=1;$t<$hits;$t++) {
print TEMP "$browser\n";
}
}
close(TEMP);
open(TEMP,"$temppath") || print "Cannot open temp.dat file\n";
@temp= <TEMP>;
close(TEMP);
foreach $i (@temp) {
$browse{$i}++;
}
print <<EOT;
<TABLE width="99%" cellpadding="3" cellspacing="1" border="0" bgCo
+lor="#0080ff">
<TR><TD bgColor="#ccccff" height="25" colspan="2"><SPAN class="tit
+le">Top Browsers</SPAN></TD></TR>
EOT
$max = 1;
foreach $key (sort BrowserSort (keys(%browse))) {
($max > $browse{$key}) || ($max = $browse{$key});
($max >= 401) && ($divisor = $max/401);
($max < 401) && ($multiplier = 401/$max);
($divisor) && ($width = sprintf("%0d",$browse{$key}/$divisor));
($multiplier) && ($width = sprintf("%0d",$browse{$key} * $multipli
+er));
print "<tr><td bgColor=\#FFFFFF align=left><a href=$key>$key</a><b
+r><img src=../images/pix.gif width=1 height=2><br>
<img src=../images/blue.gif width=$width height=10></td><td bg
+Color=\#FFFFFF align=right valign=bottom>$browse{$key}</td></tr>\n";
}
print "</table><p>\n";
}
sub BrowserSort {
$browse{$b} <=> $browse{$a};
}
&getBrowsers;
unlink($temppath);
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
#!/perl/bin/perl -w
use CGI;
$q = new CGI;
for $key ( $q->param() ) { $form{$key} = $q->param($key); }
$logpath = "data/browser.dat";
$browser = $form{'browser'};
open (LOG, "$logpath");
@data = <LOG>;
close(LOG);
$not_found = 1;
if($browser) {
open (LOG, ">$logpath");
foreach $line(@data) {
chomp($line);
($fcount,$fbrowser)= split(/\|/,$line);
if ($fbrowser eq $browser) {
$not_found = 0;
$fcount = $fcount+1;
print LOG "$fcount|$fbrowser\n";
}
else {
print LOG "$line\n";
}
}
close(LOG);
if($not_found) {
open (LOG,">>$logpath");
print LOG "1|$browser";
close(LOG);
}
}
# prints out log and form to browser
print "Content-type: text/html\n\n";
open (LOG, "$logpath");
@data = <LOG>;
close(LOG);
foreach $line(@data) {
chomp($line);
print "$line<br>";
}
close(LOG);
print <<EOT;
<FORM ACTION="basic.pl" METHOD="POST">
<SELECT NAME="browser">
<OPTION VALUE="microsoft">microsoft</OPTION>
<OPTION VALUE="netscape">netscape</OPTION>
<OPTION VALUE="aol">aol</OPTION>
<OPTION VALUE="mozilla">mozilla</OPTION>
<OPTION VALUE="opera">opera</OPTION>
</SELECT>
<INPUT TYPE="SUBMIT" VALUE="Submit">
</FORM>
EOT
| [reply] [Watch: Dir/Any] [d/l] |
|
|
|