Forum Moderators: coopster & phranque

Message Too Old, No Replies

Top 5 List

Nearly there, just got one more step

         

TheLynxEffect

6:34 am on Oct 8, 2001 (gmt 0)



Hi guys and gals,

(It's stickytape, just under a different name - lost my password for stickytape and I haven't got that e-mail account any more! DOH)

Anyway....

I don't know if any of you lot remember but some time ago I wanted to write a script which allows people to rate certain items. Well, I've managed to write it....almost.

What I've got at the moment is a script which takes a rating (out of 10) from a form then creates a filename.dat file (if one doesn't exist already), then writes to that file, writing the number of hits that page has received, the number of votes that have been cast, the average vote so far and the IP of the person casting the vote.

It all works just like I want it to so far. However, the final stage of what I want is to create a dynamic top 5(or 10) list of the top voted pages. i.e. somehow take the average from all the filename.dat files and then work out which 5 (or 10) are the highest values, then print these in a table.

So how do I go about this bit then? I'm quite proud of my little self for getting this far, but I'm a bit stumped. I'm guessing I'm going to need sessions (which I'm not particularly hot on!) but any method which works is fine by me!

All help appreciated!

Rich

sugarkane

4:00 pm on Oct 8, 2001 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member




Hi sticky, erm, lynxeffect ;)

Generally, if you already have the averages calculated, you'd read the average from each file and put it in an array / hash (depending on which language you're using), then sort the array and print out just the top 5 or 10 entries.

You were doing this in PHP, weren't you?

TheLynxEffect

2:21 pm on Oct 10, 2001 (gmt 0)



Yes, I was doing it in PHP (sorry I should have said that).

How do I go about reading the files? All the files are in different directories i.e:

folderA/filename.dat
folderB/filename.dat
folderC/filename.dat

etc

and like I said, each file contains other information too (such as the IP address) - that info is ¦ separated.

Once again, any help is ALWAYS appreciated!

Rich

sugarkane

7:47 pm on Oct 10, 2001 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



The simplest way to read a file is using the file() function which reads each line of the file into an array - eg:

$array=file('filename.dat');

If the file is a single line, that line will be in $array[0]

As to reading all the files in turn, prolly the best way (if you know the filenames beforehand) is to put the filenames into an array and use a for{} loop to read them in turn - eg

$dirs=("dir1/filename.dat", "dir2/filename.dat");
for ($i=0; $i < count($dirs); $i++) {
$foo=file("$i");
# do stuff with $foo[0] here
}

To deal with the ¦ delimiting, use the split() function - eg

$array=split("¦", $foo[0]);

TheLynxEffect

4:32 pm on Oct 11, 2001 (gmt 0)



OK then,
I'm getting the general idea of what you're doing here....I think.
What I guess I really want to do is read all the files, in particular, read all the AVERAGE vote parts in each file.

Currently, all the filename.dat files contain (in this order) the following information:

# of hits ¦ # of votes ¦ Average Vote ¦ IP of last visitor ¦ IP of last voter

So from this info, I want to read the 3rd bit of data in that. How do I do this? Is it using the

$array=split("¦", $foo[2]);

thingy? Am I right in putting [2] in there? - because it's the 3rd part of data, or is the [0] for something else?

What does the above give me? i.e. what is the split function doing? Does it read ALL the info in the file, then put it into an array, then extract the bit you tell it to?

So, once I have done this, I will have a list of all the averages right? How do I then read this file and extract, say the top 5?

If I haven't got the first bit right - i.e. about reading all the averages, then don't worry about explaining the getting the top 5 bit - I want to actually understand what's going on here, because I will prolly be using this sort of stuff in the future! (Of course, if you're feeling in a particularly helpful mood today then you could go on to explain about the Top 5 bit :) )

As always, ANY help is seriously appreciated. Thanks for the info and help so far sugarkane,

Rich

TheLynxEffect

9:08 am on Oct 12, 2001 (gmt 0)



OK, I'm getting really REALLY frustrated now. It just wont work. I think I might have got the wrong end of the(prolly the wrong)stick.

Any chance you can explain it Sugar? Or anyone else for that matter. I also don't seem to be able to find a reference for it anywhere.

I've also tried looking for scripts which do this kind of thing at every script resource I know: hotscripts, WMB, cgi-resources, scriptworld, freescripts, the lot but none.

Anyone??

sugarkane

9:14 am on Oct 12, 2001 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Okay, once you've read the file using $foo=file('yadda.txt'), the first line will be in $foo[0]

You then want to pass the line through split:

$split_array=split("¦", $foo[0]);

$split_array will now contain the various sections of data, one per array element - if you want the 3rd part, it'll be in $split_array[2]

Does that make sense?

TheLynxEffect

1:30 pm on Oct 12, 2001 (gmt 0)



errm, I think so, but I don't have time to check it out now. I'm going home for the weekend, so I'll check it on Sunday evening, Monday morning. Thanks for the help so far sugarkane! Always appreciated!

If anyone finds any pre-made script for this sort of thing, let me know, I've looked EVERYWHERE....if no one can find one, when I get this done, I'll give everyone credit for it and publish it, cos I reckon it could be quite useful!

Rich

netcommr

2:13 pm on Oct 12, 2001 (gmt 0)

10+ Year Member



#!/usr/bin/perl

use strict;

#change 'pathtofolders' to directory holding folderA
my $mainfolder = "/pathtofolders";

my ($avevote,$temp,$top1,$top2,$top3,$top4,$top5);
opendir(LIST,"$mainfolder");
foreach (readdir(LIST)) {
if ($_ eq "." ¦¦ $_ eq "..") { next }
opendir(LIST2,"$mainfolder/$_");
foreach (readdir(LIST2)) {
if ($_ eq "." ¦¦ $_ eq "..") { next }
open(FILE,"$_");
while(<FILE>) {
($avevote,$avevote,$avevote) = split("¦",$_);
if ($avevote > $top1) { $temp = $top1; $top1 = $avevote; $avevote = $temp; };
if ($avevote > $top2) { $temp = $top2; $top2 = $avevote; $avevote = $temp; };
if ($avevote > $top3) { $temp = $top3; $top3 = $avevote; $avevote = $temp; };
if ($avevote > $top4) { $temp = $top4; $top4 = $avevote; $avevote = $temp; };
if ($avevote > $top5) { $top5 = $avevote };
}
close(FILE);
}
closedir(LIST2);
}
closedir(LIST);
print "Content-type: text/html\n\n";
print "<html><body><h2>Top Rated Sites by Voter Averages</h2>";
print "Top Site 1: $top1<br>";
print "Top Site 2: $top2<br>";
print "Top Site 3: $top3<br>";
print "Top Site 4: $top4<br>";
print "Top Site 5: $top5<br>";
print "</body></html>";
exit;

----------------------------------------

may have errors, let me know if it crashes. didn't test it and just out of memory so might be something wrong.

opps, had to disable smileys

(edited by: netcommr at 2:24 pm (gmt) on Oct. 12, 2001

netcommr

2:19 pm on Oct 12, 2001 (gmt 0)

10+ Year Member




yes there is a bug after looking at it.

if you only have 1 entry in the db, it will show as top for all 5 spots, or if you have 3 entries in db, then smallest will show for 3,4,5

see if you can stop that from happening... ;) let me know if it stumps ya

TheLynxEffect

5:13 pm on Oct 14, 2001 (gmt 0)



Thats errm, good....errm...apparently. I don't know perl at all, and even though I can run it on my server, I'd rather know what my scripts were doing and know how to adapt them. However, if I can't do it by the end of the month, I'll implement your script. so thanks!

Sugarkane, I've just read your explanation and it seems very straight forward. I will give that a go tonight and report back with how I'm doing and any problems ( :) ) I'm having

Cheers again both of you

Rich

netcommr

1:43 am on Oct 15, 2001 (gmt 0)

10+ Year Member



I'll run it down line by line so you can see what it's doing, may be of help to ya.

#change 'pathtofolders' to directory holding folderA
my $mainfolder = "/pathtofolders";

# just declaring variables you will be using
my ($avevote,$temp,$top1,$top2,$top3,$top4,$top5);

# this line just opens the directory (for reading)
# you have entered into the variable $mainfolder
opendir(LIST,"$mainfolder");

# scans through each of the contents of the directory
foreach (readdir(LIST)) {

# gets the next entry in the directory if it is
# looking at the parent directory link(..) or
# current directory link(.)
if ($_ eq "." ¦¦ $_ eq "..") { next }

# new line I added here which skips the entry
# if it is not a directory
next unless -d "$_";

# if the current selection passes the above 2 tests
# then it opens the directory, scans over each
# entry and performs the first test
opendir(LIST2,"$mainfolder/$_");
foreach (readdir(LIST2)) {
if ($_ eq "." ¦¦ $_ eq "..") { next }

# if you will have any files or folders in these
# subdirectories holding your data files that you
# don't want to read or open, test for them here
# --I added to skip other directories
next if -d "$_";

# open the current file for reading
open(FILE,"$_");

# scan the file one line at a time
while(<FILE>) {

# split line of data on the '¦' and put contents
# of the third column in the $avevote variable
# --a non-standard trick to do it with 1 variable
($avevote,$avevote,$avevote) = split("¦",$_);

# next 5 lines test to see if the data in $avevote
# is greater then the current values in the $top variables
# if not, then skips to next line
# if true, then takes the value of the $top and
# stores it in a $temp variable just to hold it
# while the $avevote is copied to the $top variable
# then the old value of the $top is copied to $avevote
# --this just swaps the value basically to put
# the highest values at the top and lowest fall
# off the bottom
if ($avevote > $top1) { $temp = $top1; $top1 = $avevote; $avevote = $temp; };
if ($avevote > $top2) { $temp = $top2; $top2 = $avevote; $avevote = $temp; };
if ($avevote > $top3) { $temp = $top3; $top3 = $avevote; $avevote = $temp; };
if ($avevote > $top4) { $temp = $top4; $top4 = $avevote; $avevote = $temp; };
if ($avevote > $top5) { $top5 = $avevote };
}

# this closes the current open file
close(FILE);

# this point the script loops to get the next file
}

# when all the files have been read, the
# subdirectory is closed
closedir(LIST2);

# loops to get the next subdirectory (IE folderB)
}

# all subdirectories have been scanned and no
# more data to read, close $mainfolder
closedir(LIST);

# this is a required header so the browser can
# read your output, without it your script crashes
print "Content-type: text/html\n\n";

# this line just print a header, add what
# ever you need to print here
print "<html><body><h2>Top Rated Sites by Voter Averages</h2>";

# these lines print your top listings,
# variable $top1 is 1st, $top5 is 5th
print "Top Site 1: $top1<br>";
print "Top Site 2: $top2<br>";
print "Top Site 3: $top3<br>";
print "Top Site 4: $top4<br>";
print "Top Site 5: $top5<br>";

# this is just for continuity of the above header
print "</body></html>";

# this just tell the server, "I'm Done"
exit;

---------------------

basically, all it does is open ALL of the folders, (folderA,B,C,etc), which are in the $mainfolder. Then it opens all the files in each folder and reads each line of the file. By the end it will have the highest value found for average votes stored in the $top1 variable, next highest in $top2, etc.

If you want to display more than the top 5, say top 10, then add $top6 - $top10 in 3 places. The first place is in the variable declaration line. Second is in the jumble of lines which do the swapping of values, just make sure the last line (currently $top5) is formatted like it is and all above it are in the same format as they are now. You can't just add more lines without changing line 5. Then, last of all, you need to print the values.

Just remember it will open ALL folders in $mainfolder and scan ALL files contained in them. That means any folders, or files in those folders, you don't want opened, you need to put in tests to skip them.

#TIP - the 'use strict;' line is for developement stage only, remove from script once you are finished with it, it will run faster. The "strict" is use to help you manage all your variables so you don't make mistakes, such as typos. This will force the script to crash if you have an undefined variable name, such as you try to use '$avvote' by mistake. It has more meaning than this, but for short scripts like this, thats the best benefit. Also, it is a good idea to use the -w flag after the #!/usr/bin/perl line during testing, this is for warnings output.
such as #!/usr/bin/perl -w

A great tool for testing scripts is testmy.cgi available here [perlarchive.com], this link is posted because the Craig Richards [craigrichards.com] site is down. If his site does not come back up and you can't find it, I will make it available.

TheLynxEffect

10:11 am on Oct 15, 2001 (gmt 0)



netcommr, thanks a lot for putting a lot of time and effort into this, I really appreciate it.

This will probably really annoy you, but I think I'm starting to make progress with the PHP script now, so it looks like I am going to be able to use that. However, I will keep a copy of that script (which I now (almost) fully understand thanks to your descriptions) in my spare scripts folder, just in case.

This is why I love WebmasterWorld so much, 'cos there's always someone available to help, and usually it's someone with years of experience that can explain something better than most of my University lecturers could!

If you 2 guys (and anyone else) could keep your eyes peeled on this thread for the next couple of days I would really appreciate it, cos I've nearly finished the PHP version of this. I will probably need some last minute help etc!

Thanks again both of you,

Rich

(P.S. - what's with the smiley in the last script, is it meant to be a smiley or is it meant to be ;) and you forgot to turn smileys off? hehe lol)

Just noticed something quite neat. When you shorten WebmasterWorld with the letters "W M W" but without the spaces, it automatically replaces it. Nice little function!

TheLynxEffect

1:41 am on Oct 18, 2001 (gmt 0)



Nope, it's just not having any of it! someone please explain what I'm doing wrong, this has to be the most frustrating thing EVER!!

Currently, I have a file called index2.dat which is as follows:

[center]4¦3¦7.6666666666667¦127.0.0.1¦127.0.0.1[/center]

Then, I'm trying to do this simplest part and split this file into it's constituents using the split function as you suggested. The php script looks as follows:

<?PHP

$myfile=file("index2.dat");
print ($myfile[0]);

$split_myfile=split("¦",$myfile);
print ($split_myfile[2]);

?>

I've put that first print function in there to test that the file is actually opening correctly, which it is, because when I run the script, I get a printout like I should.

However, when it comes to the 2nd print function, the one after the file has been split, NOTHING is printed. Nothing what-so-ever.

I think that once I have this problem solved, I'll be able to do the rest (touch wood). I'll probably be using the sort() function, but I may write my own, depends.

Can someone, ANYONE, please, PLEASE help me solve this, it's 02:36 and I need to go to bed. It's been frustrating me for the best part of 4 hours, and I have NO idea where I'm going wrong.....anyone?

TheLynxEffect

2:18 am on Oct 18, 2001 (gmt 0)



YEAH!!!!!!

I've fixed it. I don't know why it requires this, maybe someone could tell me. Frankly, I couldn't care, because it's 03:11 now and I am very tired and I have lectures tomorrow. Bummer! Anyway, here's the fix:

I had to implode the index2.dat file first like so:

[center]$implode_myfile = implode($myfile, "¦");[/center]

Then I had to resplit it, like so:

[center]$split_implode_myfile = split("¦",$implode_myfile);[/center]

Then I could print it like so:

[center]print ($split_implode_myfile[2]);[/center]

I don't know why I had to employ this method, like I said, if someone know's why, I wouldn't mind them telling me..... I'll read up on it tomorrow! :)

Anyway, Just two stages left now for this script I feel:

1) Work out how to grab ALL the filename.dat files into 1 array (i.e. just the average vote from each)
2) Sort the Top 5 out and print

Anyone got any helpful hinters along these lines?

Rich

TheLynxEffect

4:37 pm on Oct 18, 2001 (gmt 0)



Bugger. Maybe working at that time in the morning is a bad idea.

It's chosen NOT to work now. I don't understand why.

At the moment my script separates the data by using ¦ and not ¦ - when I try and use split to separate them by using split

("¦",$myfile); 

where

$myfile
is a variable which has the file in it.

When I do that and run the script is gives an error:

Unexpected Regex Error (14)

Any ideas anyone? This is really bugging me now.

I've tried swapping the ¦ for ¦ with ereg_replace, but it comes up with a blank - i.e. it's saying there aren't any ¦ in the file. I'm really confused about this too??

Ideas....anyone?

Hmm, just noticed something.... in the text above I'm trying to have a solid vertical bar (i.e. like an "l") and a split vertical bar ("¦") It appears that they come out the same charcter

sugarkane

11:21 am on Oct 19, 2001 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



> Unexpected Regex Error (14)

D'oh!

Looking back at this I gave you some bad advice - the syntax should be:

split("\¦", $myfile);

( ¦ == solid bar)

TheLynxEffect

2:21 pm on Oct 19, 2001 (gmt 0)



It only goes and works! I think I should have spotted that too Sugar. Actually, looking in my book it says that it should have worked! Hmmm, maybe I'll inform Mr. Leon Atkinson. (Author)

Anyway, right, now that know how to extract 1 average from 1 file.....I now need to extract several averages from several files.... lets see if Richard can do that this afternoon.

Cheers again,

Rich

TheLynxEffect

3:49 pm on Oct 20, 2001 (gmt 0)



Okey, so Rich has managed to extract the averages from more than one file, but manually. I need to write a for() loop for it.

When I try and do this, is seems to get the filename's incorrect. What I mean is, if I put 2 filenames into the array, it tries to locate a file which has both of the filenames together....i.e.

If I have filenameA.txt and filenameB.txt in the array, it tries to find "filenameAfilenameB.txt"

Me is confused....

sugarkane

5:28 pm on Oct 20, 2001 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



How are you setting up the array? That could be where the problem is...

ADDED:
...or, how are you getting the filenames from the array? I you're using file($array) that would probably produce the problem you describe - you'd need to use file($array[0]), file($array[1]) etc