Okay...here is the next step...which is going to be a bit complicated...I would not attempt it if it is late at night or early in the morning.
BTW: The earlier steps in this Mod is to collect the ID ratings, and also to reduce abusive ratings of your records. These earlier steps DO NOT ADD THE VALUE into the "rating" field in your database file.
Get it?
Please attempt the next steps with care....make complete backups of all your files, ESPECIALLY your database file...
To test this phase of the Mod, copy your default.db file.
This will also entail some testing and experimenting on your part, okay?
Are you ready....we here go....
1) Add the following variable definition in your
default.cfg file:
Change
20 to the field number for your
rating field.
2) Create a blank file and name it
default.db.bak. Change the permission of this file to 666 (rw-rw-rw-). Put it in the same directory as your default.db file.
Now you will have to make a decision...do you want the Ratings to show up dynamically (which will slow down traffic) or do you want to add the Ratings via another script that will build ratings in your fields (not dynamic, but will not affect traffic, yet is more intensive on CPU and memory usage, since you will have to use Cron to make it pseudo-dynamic.)
Dynamic Ratings 1) Add the following sub-routine in your
rate.cgi file:
Code:
sub build_update_ratings {
# --------------------------------------------------------
# Updates the ratings of each link.
#
# Let's collect the ratings.
my ($id, %rating, %votes, @values, $input);
opendir (HITS, $db_rates_path) or &cgierr ("unable to open ratings directory: $db_rates_path. Reason: $!");
while (defined ($id = readdir HITS)) {
next unless ($id =~ /^\d+$/);
open (HIT, "$db_rates_path/$id") or &cgierr ("unable to open rating counter: $db_rates_path/$id. Reason: $!");
my $input = <HIT>;
chomp $input;
($votes{$id}, $rating{$id}) = split /\s/, $input;
close HIT;
}
closedir HITS;
# Update the links database.
open (DB, "$db_file_name") or &cgierr ("unable to open links database: $db_links_name. Reason: $!");
open (DBTMP, ">$db_file_name.bak") or &cgierr ("unable to open temp links database: $db_links_name.bak. Reason: $!");
LINE: while (<DB> ) {
/^#/ and print OUT and next LINE; # Skip comment Lines.
/^\s*$/ and next LINE; # Skip blank lines.
chomp; # Remove trailing new line.
@values = split /\Q$db_delim\E/;
$id = $values[0];
if (exists $votes{$id}) {
$values[$db_rating] = (($values[$db_rating] * $values[$db_votes]) + $rating{$id}) /
($values[$db_votes] + $votes{$id});
$values[$db_rating] = sprintf ("%.2f", $values[$db_rating]);
}
print DBTMP &join_encode(&array_to_hash(0, @values));
}
close DB;
close DBTMP;
if (-s "$db_file_name.bak" > 0) {
if (! rename ("$db_file_name.bak", $db_links_name)) {
print "\tCouldn't rename! Had to copy. Strange: $!\n";
open (DBTMP, ">$db_file_name") or
&cgierr ("unable to open links database: $db_file_name. Reason: $!");
open (DB, "$db_file_name.bak") or
&cgierr ("unable to open temp links database: $db_file_name.bak. Reason: $!");
while ( ) { print DBTMP; }
close DB;
close DBTMP;
}
else { chmod 0666, $db_links_name; }
}
else {
&cgierr ("Error building! Links database is 0 bytes!");
}
# Delete the ratings.
foreach (keys %votes) {
unlink ("$db_rates_path/$_") or &cgierr ("unable to remove rating: $db_rates_path/$_. Reason: $!");
}
}
2) To call this sub-routine, in your
rate.cgi file, add the following codes:
Code:
&build_update_ratings
BEFORE the following codes:
(or &site_html_rate_success; depending on what you called the success routine.)
Non-Dynamic via db.cgi script - Manual 1) Add the same sub-routine to your
db.cgi file:
Code:
sub build_update_ratings {
# --------------------------------------------------------
# Updates the ratings of each link.
#
# Let's collect the ratings.
my ($id, %rating, %votes, @values, $input);
opendir (HITS, $db_rates_path) or &cgierr ("unable to open ratings directory: $db_rates_path. Reason: $!");
while (defined ($id = readdir HITS)) {
next unless ($id =~ /^\d+$/);
open (HIT, "$db_rates_path/$id") or &cgierr ("unable to open rating counter: $db_rates_path/$id. Reason: $!");
my $input = <HIT>;
chomp $input;
($votes{$id}, $rating{$id}) = split /\s/, $input;
close HIT;
}
closedir HITS;
# Update the links database.
open (DB, "$db_file_name") or &cgierr ("unable to open links database: $db_links_name. Reason: $!");
open (DBTMP, ">$db_file_name.bak") or &cgierr ("unable to open temp links database: $db_links_name.bak. Reason: $!");
LINE: while (<DB> ) {
/^#/ and print OUT and next LINE; # Skip comment Lines.
/^\s*$/ and next LINE; # Skip blank lines.
chomp; # Remove trailing new line.
@values = split /\Q$db_delim\E/;
$id = $values[0];
if (exists $votes{$id}) {
$values[$db_rating] = (($values[$db_rating] * $values[$db_votes]) + $rating{$id}) /
($values[$db_votes] + $votes{$id});
$values[$db_rating] = sprintf ("%.2f", $values[$db_rating]);
print "Content-type: text/html\n\n";
print "Database Ratings Updated."
}
print DBTMP &join_encode(&array_to_hash(0, @values));
}
close DB;
close DBTMP;
if (-s "$db_file_name.bak" > 0) {
if (! rename ("$db_file_name.bak", $db_links_name)) {
print "\tCouldn't rename! Had to copy. Strange: $!\n";
open (DBTMP, ">$db_file_name") or
&cgierr ("unable to open links database: $db_file_name. Reason: $!");
open (DB, "$db_file_name.bak") or
&cgierr ("unable to open temp links database: $db_file_name.bak. Reason: $!");
while ( ) { print DBTMP; }
close DB;
close DBTMP;
}
else { chmod 0666, $db_links_name; }
}
else {
&cgierr ("Error building! Links database is 0 bytes!");
}
# Delete the ratings.
foreach (keys %votes) {
unlink ("$db_rates_path/$_") or &cgierr ("unable to remove rating: $db_rates_path/$_. Reason: $!");
}
}
2) Then add the following in the
elsif section in the
sub main routine in the
db.cgi file:
Code:
elsif ($in{'build_ratings'}) { if ($per_admin) { &build_update_ratings; } else { &html_unauth; } }
3) Then add a link in the
sub html_admin_display to this routine with the following codes:
Code:
<a href="$db_script_link_url&build_ratings=1">
4) Then to build new ratings you will have to access the Admin Console via the db.cgi and click on that link.
Non-Dynamic via db.cgi script - Automatic via Cron 1) Create a new script called
buildrates.cgi. It should look like the following:
Code:
#!/usr/local/bin/perl
# This script builds ratings for DBMAN
# database.
# Required Librariers
# --------------------------------------------------------
eval {
($0 =~ m,(.*)/[^/]+,) && unshift (@INC, "$1"); # Get the script location: UNIX /
($0 =~ m,(.*)\\[^\\]+,) && unshift (@INC, "$1"); # Get the script location: Windows \
require "./default.cfg"; # Change this to full path to links.cfg if you have problems.
require "./html.pl";
};
if ($@) {
print "HTTP/1.0 200 OK\n";
print "Content-type: text/plain\n\n";
print "Error including libraries: $@\n";
print "Make sure they exist, permissions are set properly, and paths are set correctly.";
exit;
}
# ========================================================
eval { &main; }; # Trap any fatal errors so the program hopefully
if ($@) { &cgierr("fatal error: $@"); } # never produces that nasty 500 server error page.
exit; # There are only two exit calls in the script, here and in in &cgierr.
=============================================
# Additional Configurations
$db_script_path = "./";
sub main {
#-------------------------------------------
# Builds Ratings
# Let's collect the ratings.
my ($id, %rating, %votes, @values, $input);
opendir (HITS, $db_rates_path) or &cgierr ("unable to open ratings directory: $db_rates_path. Reason: $!");
while (defined ($id = readdir HITS)) {
next unless ($id =~ /^\d+$/);
open (HIT, "$db_rates_path/$id") or &cgierr ("unable to open rating counter: $db_rates_path/$id. Reason: $!");
my $input = <HIT>;
chomp $input;
($votes{$id}, $rating{$id}) = split /\s/, $input;
close HIT;
}
closedir HITS;
# Update the links database.
open (DB, "$db_file_name") or &cgierr ("unable to open links database: $db_links_name. Reason: $!");
open (DBTMP, ">$db_file_name.bak") or &cgierr ("unable to open temp links database: $db_links_name.bak. Reason: $!");
LINE: while (<DB> ) {
/^#/ and print OUT and next LINE; # Skip comment Lines.
/^\s*$/ and next LINE; # Skip blank lines.
chomp; # Remove trailing new line.
@values = split /\Q$db_delim\E/;
$id = $values[0];
if (exists $votes{$id}) {
$values[$db_rating] = (($values[$db_rating] * $values[$db_votes]) + $rating{$id}) /
($values[$db_votes] + $votes{$id});
$values[$db_rating] = sprintf ("%.2f", $values[$db_rating]);
}
print DBTMP &join_encode(&array_to_hash(0, @values));
}
close DB;
close DBTMP;
if (-s "$db_file_name.bak" > 0) {
if (! rename ("$db_file_name.bak", $db_links_name)) {
print "\tCouldn't rename! Had to copy. Strange: $!\n";
open (DBTMP, ">$db_file_name") or
&cgierr ("unable to open links database: $db_file_name. Reason: $!");
open (DB, "$db_file_name.bak") or
&cgierr ("unable to open temp links database: $db_file_name.bak. Reason: $!");
while ( ) { print DBTMP; }
close DB;
close DBTMP;
}
else { chmod 0666, $db_links_name; }
}
else {
&cgierr ("Error building! Links database is 0 bytes!");
}
# Delete the ratings.
foreach (keys %votes) {
unlink ("$db_rates_path/$_") or &cgierr ("unable to remove rating: $db_rates_path/$_. Reason: $!");
}
}
sub array_to_hash {
# --------------------------------------------------------
# Converts an array to a hash using db_cols as the field names.
#
my ($hit, @array) = @_;
my ($i);
return map { $db_cols[$i] => $array[$hit * ($#db_cols+1) + $i++] } @_;
}
sub join_encode {
# --------------------------------------------------------
# Takes a hash (ususally from the form input) and builds one
# line to output into the database. It changes all occurrences
# of the database delimeter to '~~' and all newline chars to '``'.
my %hash = @_;
my ($tmp, $col, $output);
foreach $col (@db_cols) {
$tmp = $hash{$col};
$tmp =~ s/^\s+//g; # Trim leading blanks...
$tmp =~ s/\s+$//g; # Trim trailing blanks...
$tmp =~ s/\Q$db_delim\E/~~/og; # Change delimeter to ~~ symbol.
$tmp =~ s/\n/``/g; # Change newline to `` symbol.
$tmp =~ s/\r//g; # Remove Windows linefeed character.
$output .= $tmp . $db_delim; # Build Output.
}
chop $output; # remove extra delimeter.
$output .= "\n"; # add linefeed char.
return $output;
}
2) Then set-up a shell file and also edit your crontab, if you access to your shell account via telnet...Refer to the FAQ in the LINKS 2.0 section in the Resource Center for information on setting up Crontab. Use this stand alone script to automatically update ratings via Cron.
REALLY hope this helps.
------------------
Eliot Lee * Be sure to visit the
Resource Center for
FAQ's,
Modifications and
Extra Goodies!!
* Search Forums!
* Say NO to Duplicate Threads.
----------------------
[This message has been edited by Eliot (edited February 16, 2000).]