CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
Paging records

 



darian
Deleted

Mar 7, 2000, 12:23 AM

Post #1 of 7 (1003 views)
Paging records Can't Post

Ok using the script below I am trying to page through some records at 10 a time. For some reason all I seem to get is an error reported by Carp as this:

Software error:
Execution of members.pl aborted due to compilation errors.
Please send mail to this site's webmaster for help.

Not sure where the error lies at though. I really hate when programs give you a general error like this.

#!/usr/local/bin/perl -w
use vars qw(%config $in);
use CGI qw(:cgi);
use CGI::Carp qw(fatalsToBrowser);
$in = new CGI;
%config = (
lock => 1,
member_text => "/data1/hypermart.net/tplg/members/mem.txt"
);

$action = $in->param('action'); #Get the action input from the url.
$start = $in->param('start');

print $in->header('text/html'); #print the header info and tells the browser that
#we are about to print text.

open(FILE, "$config{'member_text'}") or &die("$!"); #now we open the member text if we can't open it die and
#print out an error using CGI.pm

if(%config{'lock'} == 1) { flock FILE,2; } #use file lock if user activates it in the config section
#the 2 uses the file exclusively.
@lines=<FILE>; #store the file in an array @lines.
close(FILE); #close the file.
$count=0;
foreach $line (@lines) {
$count++;
($name, $email) = split(/\|/,$line);
}
$i=1;
$x=1;
while (($x<11) and ($i<=$count))
print "$i - Name: $name[$i]<br>\n";
print " Email: $email[$i]\n<P>\n";
$i++;
$x++;
}



Cretep
User

Mar 7, 2000, 2:16 AM

Post #2 of 7 (1003 views)
Re: Paging records [In reply to] Can't Post

Try running the program at the command line using the -wc switch. Heres an example:
scorpius:/ > cd some/place
scorpius:/some/place >scriptname.pl -wc

This will pin point the problem.

Regards

Peter Crouch


darian
Deleted

Mar 7, 2000, 2:37 AM

Post #3 of 7 (1003 views)
Re: Paging records [In reply to] Can't Post

Unfortunatley I can't do that as I am using hypermart as a host and don't have a machine with Perl installed on it to test this. Frown


japhy
Enthusiast

Mar 7, 2000, 3:53 AM

Post #4 of 7 (1003 views)
Re: Paging records [In reply to] Can't Post

I found a couple points in your code that could be causing the errors, so I'll reproduce your code and pinpoint the trouble-spots. It IS very good that you use -w and the CGI module. You don't need to "use vars", though, if you're not doing "use strict" (which you might not be ready for).

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


#!/usr/local/bin/perl -w
use vars qw(%config $in);
use CGI qw(:cgi);
use CGI::Carp qw(fatalsToBrowser);
$in = new CGI;
%config = (
lock => 1,
member_text => "/data1/hypermart.net/tplg/members/mem.txt",
);

$action = $in->param('action');
$start = $in->param('start');

print $in->header('text/html');

open(FILE, "$config{'member_text'}") or &die("$!"); </pre><HR></BLOCKQUOTE>

Here's the first iffyness. As of Perl 5, you no longer need to put an ampersand (&) in front of calls to non-builtin subroutines, and here, you're using it in front of a built-in, which makes it try to call a user-defined function. Remove the &, and one problem will be fixed.

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


if(%config{'lock'} == 1) { flock FILE,2; }
</pre><HR></BLOCKQUOTE>

To get at hash elements, either use $hash{KEY} or @hash{KEY1,KEY2,KEY3,...}. Doing %hash{KEY} in the way you do there would elicit the following error from Perl:

Can't use subscript on hash deref at -e line 1, near "{KEY}"
(Did you mean $ or @ instead of %?)


Which is Perl's way of saying "hashes aren't used like that." You'd want to say:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


if ($config{lock}) { flock FILE, 2 }
</pre><HR></BLOCKQUOTE>

You don't need quotes around a "simple" hash key (one that's just a string of letters, underscores, and numbers), and you don't need to test for equivelency to 1, you just need to see if the value is true.

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


@lines=<FILE>;
close(FILE);
$count=0;
foreach $line (@lines) {
$count++;
($name, $email) = split(/\|/,$line);
}
</pre><HR></BLOCKQUOTE>

It appears you've forgotten to actually put these in the @name and @email arrays. Smile And before you think of using $name[$count] and $email[$count], please remember that arrays in Perl start at 0, and the preferred method of placing an element at the end of an array is via the push() function. And it's nicer (and smarter) to not slurp an entire file into an array, if you can avoid it:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


while (<FILE> ) { # line is in $_
chomp; # remove the ending newline
($name,$email) = split /\|/; # split() defaults to splitting on $_
push @name, $name;
push @email, $email;
}
close FILE;
</pre><HR></BLOCKQUOTE>

And in your final section of the code:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


$i=1;
$x=1;
while (($x<11) and ($i<=$count))
print "$i - Name: $name[$i]<br>\n";
print " Email: $email[$i]\n<P>\n";
$i++;
$x++;
}
</pre><HR></BLOCKQUOTE>

First (and syntax-wise), you're missing the opening { on your while statement. But from a getting-things-done point of view, you should probably change this code a bit. You only want to print (at most) the first 10 sets of information, right? Then you could have done a few things differently: save only the first ten sets of information, and then stop processing the file; or you could get rid of that $x variable by testing $i twice (make sure it's less than 10 AND less than the number of elements in the arrays):

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


for ($i = 0; $i < 10 and $i < @name; $i++) {
print "$i - Name: $name[$i]<br>\n";
print "Email: $email[$email]<br><br>\n";
}
</pre><HR></BLOCKQUOTE>

By testing "$i < @name", we are using @name in scalar context to get the NUMBER of elements in it.

If you want to use the first method I discussed (saving only the first 10 records), then you can change the program (from the while-loop until the end) to:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


while (<FILE> ) {
chomp;
($name,$email) = split /\|/;
push @name, $name;
push @email, $email;
# leave the loop if there are 10
# elements in the @name array
last if @name == 10;
}

for $i (0 .. 10) {
print "$i - Name: $name[$i]<br>\n";
print "Email: $email[$email]<br><br>\n";
}
</pre><HR></BLOCKQUOTE>

And finally, depending on whether or not you'll end up really needing those arrays, you can just print the name/email stuff IN the while loop AS you get the stuff:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


$i = 0;
while (<FILE> ) {
chomp;
($name,$email) = split /\|/;
print "$i - Name: $name<br>\n";
print "Email: $email<br><br>\n";
$i++;
last if $i == 10; # leave if we've seen 10 records
}
</pre><HR></BLOCKQUOTE>

If anything I've suggested seems over your head, don't rush to using it, and instead, stick with things you're more familiar with. We can discuss this on the forum so that other people that might not totally get this can better understand it.


japhy
Enthusiast

Mar 8, 2000, 4:32 AM

Post #5 of 7 (1003 views)
Re: Paging records [In reply to] Can't Post

It looks good, darian. I'm a little puzzled about the

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


if ($end) { $start = $end }
else { $start = 0 }
</pre><HR></BLOCKQUOTE>

I'm not sure where $end is originating. I would probably end up writing this as:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


$start = param('start') &#0124; &#0124; 0;
</pre><HR></BLOCKQUOTE>

This means "$start is either the value of the 'start' parameter in the CGI query, or the number 0". The reason we need to manually supply the "or 0" option is because if there wasn't a 'start' parameter in the CGI query, the value is not 0, but undef, and when you use an undef value, Perl will usually let you know you probably shouldn't be doing that -- it won't kill your program, but it'll write a warning.

In fact, $start can be the variable you use in your loop (and here's where $end comes in). Oh, don't let the first statement in the for-loop condition fool you; it's merely setting two variables, $start and $end.

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


for (
$start = param('start') &#0124; &#0124; 0, $end = $start + 10;
$start < $end and $start < @name;
$start++
) {
print "$start - $name[$start] - $email[$start]<br>\n"; # whatever
}

if ($num = (@name - $start)) {
$num = 10 if $num > 10;
print << "HTML STUFF";
<form method="post" action="foo.cgi">
<input type="hidden" name="start" value=$start>
<input type="submit" value=" View Next $num ">
</form>
HTML STUFF
}
</pre><HR></BLOCKQUOTE>

If I've done my job right, then the only part of my code that might be confusing you a bit is that last if-block. You'll notice the condition of the if-block is

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


if ($num = (@name - $start)) { ... }
</pre><HR></BLOCKQUOTE>

I DO mean to use = and NOT ==. Basically, I'm saying:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


$num = (@name - $start);
if ($num) { ... }
</pre><HR></BLOCKQUOTE>

But, being me, I plonk that into one line. If $num is NOT 0, then there are still more records to be displayed, so we're going to display the "view next X" button. However, maybe there AREN'T 10 more records, but 5 or 2. So I get $num to be the difference between how many there are, and where we're currently at, and then I say:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>


$num = 10 if $num > 10;
</pre><HR></BLOCKQUOTE>

If $num is already bigger than 10, make it 10, because that's the greatest number of records to show at one time.

I hope this helps you.


jumaru
Deleted

Mar 8, 2000, 10:27 AM

Post #6 of 7 (1003 views)
Re: Paging records [In reply to] Can't Post

Hi everybody
How Can I show the next 10 records if I want 10 records per page
Thanks


darian
Deleted

Mar 8, 2000, 10:42 AM

Post #7 of 7 (1003 views)
Re: Paging records [In reply to] Can't Post

Ok now lets see if I can get the next 10 to display. How about this:

<BLOCKQUOTE><font size="1" face="Arial,Helvetica,sans serif">code:</font><HR>

if($end) {$start eq $end;}
else {$start == 0;}
for ($i = $start; $i < $start + 10 and $i < @name; $i++) {
print "$i - Name: $name[$i]<br>\n";
print "Email: $email[$email]<br><br>\n";
}
<form action="myscript.pl" mehtod="post">
<input type="hidden" name="start" value=$i>
<input type="submit" value="Next 10">
</form></pre><HR></BLOCKQUOTE>

How close am I on this one?

BTW Great tutorial above japhy. Thanks.



[This message has been edited by darian (edited 03-08-2000).]

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives