The first thing i do is determine or find a purpose, i can't stand doing work for no purpose what so ever
so...purpose: to modify counter.pl so that it has an adjustable "backbuffer" of a certain number of ip-numbers that will be ignored (and the now requesting ip number will be added to them), this backbuffer should be rotating, for instance a 10 number backbuffer will protect against 10 "force refreshes". it is put there to stop multiple fast "refresh page" requests from pumping up the counter too much
method: use a data file, read from this data file, compare to the ip numbers, add in the new number, remove the oldest one and overwrite the file
the data file (tenlines.dat) will simply have the format:
xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx xxx.xxx.xxx.xxxthat is to say,
#!/path/to/perl -w
$datafile='tenlines.dat';
$repeats=0; #part of 1st and 2nd try..not needed for 3rd
open (READIT,"$datafile")||die "Can't open $datafile: $!\n\n";
while(<READIT>)
{
chomp($_); #this was here for all tries
$ARRAY[$repeats]=$_;
$repeats++;
}
close (READIT) || die "Can't close $datafile: $!\n\n";
sub arraydump1 #first try..just dump the array to the screen
{
$runs=0;
until ($runs eq $repeats)
{
print ("$ARRAY[$runs]\n");
$runs++;
}
}
arraydump1();
ok output there, it just lists the file, it doesn't even change itall it does is open the file, read the file(dumping newlines) into $ARRAY
but it does so in a clumsy ugly messy not "stylish" way(using 2 variables for process control among other things)
thus came 2nd try (same file, comment out some lines, add some new ones):
#!/path/to/perl -w
$datafile='tenlines.dat';
$repeats=0; #part of 1st and 2nd try..not needed for 3rd
open (READIT,"$datafile")||die "Can't open $datafile: $!\n\n";
while(<READIT>)
{
chomp($_);#this was here for all tries
$ARRAY[$repeats++]=$_;
}
close (READIT) || die "Can't close $datafile: $!\n\n";
this one still used the arraydump1()but it's still clumsy using variables for process control
thus 3rd try (same file, comment out some lines, add some new ones:
#!/path/to/perl -w
$datafile='tenlines.dat';
open (READIT,"$datafile")||die "Can't open $datafile: $!\n\n";
while(<READIT>)
{
chomp($_);#this was here for all tries
push @ARRAY,$_; #third try
}
close (READIT) || die "Can't close $datafile: $!\n\n";
sub arraydump2 #second try, just dump the array to the screen
{
foreach $wild (@ARRAY)
{
print ("$wild\n");
}
}
#arraydump2();
ok now it looks prettier, and reads it, now to add a value to it (i will only put up the "sub arraydump")
sub arraydump3 #try 3, also dumps the first value and adds one value to the end
{
shift @ARRAY;
push @ARRAY,"111.111.new.111"; #this will contain "$ENV{REMOTE_ADDR}"
foreach $out (@ARRAY)
{
print("$out\n");
}
}
arraydump3();
this one changes one value but still just dumps it to the screenit does work for all except the file handling
sub arraydump4 #4th try to clean up n pretty it up (also adds output to file)
{
open (WRITEIT,">$datafile") || die "Can't open $datafile for W: $!\n\n";
shift @ARRAY;
push @ARRAY,$ENV{SHELL}; #will be $ENV{REMOTE_ADDR}
foreach $out (@ARRAY)
{
print (WRITEIT "$out\n");
}
close (WRITEIT)||die "Can't close $datafile from W: $!\n\n";
}
arraydump4();
and here everything works, all it needs is the conditional "if matching a value in @ARRAY, then don't add to hits in the counter, otherwise, do" integration into the counter.pl script (and i'll leave that for later)
some nitpickers might notice that:
#!/path/to/perl -w $datafile='tenlines.dat'; $repeats=0; #part of 1st and 2nd try..not needed for 3rd open (READIT,"$datafile")||die "Can't open $datafile: $!\n\n"; while(of course that would get cleaned up before i use it in a "production" script) { chomp($_);#this was here for all tries #1st try #$ARRAY[$repeats]=$_; #$repeats++; # #2nd try $ARRAY[$repeats++]=$_; push @ARRAY,$_; #third try } close (READIT) || die "Can't close $datafile: $!\n\n"; sub arraydump1 #first try..just dump the array to the screen { $runs=0; until ($runs eq $repeats) { print ("$ARRAY[$runs]\n"); $runs++; } } #arraydump1(); sub arraydump2 #second try, just dump the array to the screen { foreach $wild (@ARRAY) { print ("$wild\n"); } } #arraydump2(); sub arraydump3 #try 3, also dumps the first value and adds one value to the end { shift @ARRAY; push @ARRAY,"111.111.new.111"; #this will contain "$ENV{REMOTE_ADDR}" foreach $out (@ARRAY) { print("$out\n"); } } #arraydump3(); sub arraydump4 #4th try to clean up n pretty it up (also adds output to file) { open (WRITEIT,">$datafile") || die "Can't open $datafile for W: $!\n\n"; shift @ARRAY; push @ARRAY,$ENV{SHELL}; #will be $ENV{REMOTE_ADDR} foreach $out (@ARRAY) { print (WRITEIT "$out\n"); } close (WRITEIT)||die "Can't close $datafile from W: $!\n\n"; } arraydump4();
----end first session----
----2002-10-22:early am, quick thought----
i may have pissed in my own pool, as it stands now i can't figure out a "pretty" way of checking all the elements in the @ARRAY and add a 1 to a counter only if _none_ of them match a value taken from the user
of course i COULD go
if (){
}elsif(){
}elsif(){
}
a very long unless && unless could also do it, but equally uglybut both would negate the point of using it the way i do, all of a sudden the user would have to go into the perl script and add lines, cluuumsy, not acceptable...blabla
will keep at it
----end quick thought----
----from last till----2002-10-25:early am----
problem solved after much experimenting, and learning and reading, even though it may not be the prettiest way, for now it's fully acceptable, it fulfills the criteria i started out with, i may clean up the code later, but at the moment i just don't know enough about return values and how perl handles them, to make it really really pretty
i'll post the experiment example codes later on
too mushy brained at the moment
#!/path/to/perl -w
#$debug=1;
$value='10.0.0.1';
$hits='100';
@ARRAY = qw(10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5 10.0.0.6);
if ($debug)
{
foreach $out (@ARRAY)
{
print ("$out\n");
}
}
$hittmp=$hits;
$end=@ARRAY;
foreach $check (@ARRAY)
{
if ($check ne $value)
{
$hittmp++;
}
}
$hittmp=++$hittmp-$end;
print ("$value\n$end\n$hits\n$hittmp\n"); #test output
my $ARRAYREFERANCE = \@ARRAY;# print "@{$ARRAYREFERANCE}\n";
unless ($ARRAYREFERANCE =~ /10.0.0.1/)
{
$hits++;
}
print ("$hits\n\n");
neither of these worked but they taught me about array referances and a lot about how arrays handle, fair dealthis next one is an exerpt where i used the standard write and read routines but tried to add checking(actually i don't know what i was thinking at this point, i was just messing about and not thinking much)
#test variables
$value='/bin/bash';
$hits='100';
sub checker #man this is so clumsy
{
$values=@ARRAY;
$values--;
foreach $check (@ARRAY)
{
if ($check ne $value)
{
$hits++;
}
}
$hits=$hits-$values;
print ("$hits,$values\n\n");
}
#checker();
sub checker2
{
my $ARRAYREFERANCE = \@ARRAY;# print "@{$ARRAYREFERANCE}\n";
unless (@{$ARRAYREFERANCE} eq $value)
{
$hits++;
}
print ("$hits\n\n");
}
#checker2();
as most can see it's the one used in subroutines above this one, heh no i had to give up that approach largely
-------
anyway after some sleep after a lotta bad dreams and low sleep for a while, i finally started thinking a little again
how DOES perl read a variable in a "while loop"?
well normally, perl reads into a variable, separating the "while" iterations with "separator" (normally eol (end of line, newline), and ending the "while" with eof (end of file)
but...BUT this is settable
part of my problem was that i wanted the ip numbers in an array so i could simply just dump the first one , push the new one onto the end and "foreach" print it to the file (rotate out one old ip, rotate in one new) fifo style
but, that array was also where i had problems, cause an array is multiple elements, thus needed testing as such, meaning the math got all messed up for me
but...just imagine, if i read that ipblock file into one scalar, in one piece(usually not a good idea since it consumes a lot of memory, but for an ipblock file we are talking what?...20 lines max of xxx.xxx.xxx.xxx, that's 20x15 characters+newlines still not much to bitch about) if i read it into one long scalar and then pattern match it, with a match being "don't do it" hmmmmmmm, and then AFTER that convert it to an array, dump the first element and add a new one at the end...that could work couldn't it?
first i had to look up how to change the "separator for standard variable"
then i had to look up a lotta other stuff too, but in the end after much experimenting, reading and cursing and more experimenting and learning i ended up with 2 subroutines (i wrote them as subs), when i "integrated" them, i had to dump that due to a lack of patience at the moment, i wanted this working, and i've not learned how perl passes variables in and out of subroutines to the level where i'm "comfortable" with it yet
sub ipread
{
my($iplist);
local($/)= undef;
open (READIT, "$datafile")||die "Can't open $datafile for R: $!\n\n";
$iplist=<READIT>;
close (READIT)||die "Can't close $datafile for R: $!\n\n";
unless ($iplist =~ /10.0.0.1/)
{
$hits++;
}
print ("$iplist, $hits\n\n");
return($iplist);
}
$transfer = ipread();
sub ipwrite
{
my($transfer) = shift;
open (WRITEIT,">$datafile")||die "Can't open $datafile for W: $!\n\n";
@ARRAY = split (/\n/, $transfer);
#foreach $out (@ARRAY){chomp($out);}
shift @ARRAY;
push @ARRAY,$ENV{SHELL}; #will be $ENV{REMOTE_ADDR}
foreach $out (@ARRAY)
{
chomp($out);
print (WRITEIT "$out\n");
}
#print (WRITEIT "$ENV{SHELL}\n");
close (WRITEIT)||die "Can't close $datafile from W: $!\n\n";
}
ipwrite($transfer);
these are in fact very close to what i used in the end, i did try to use subroutines, and in my test script the subroutines worked, it was in the intergration i messed up on subroutinesthe end result is downloadable in the devel area as a zip file counterip.zip
so since i'm a learner, this may not be the best way (probably isn't) or the neatest way, but dammit i'm proud i did it at all. ssi using perl counters are a dime a dozen and many of those don't have "flood protect", this one doesn't use ssi, AND has flood protect and i'm just a learner, yeah me proud! better believe it!
#!/path/to/perl
# -w
# for more debugging
# copyright wlofie@yahoo.com 2002-10-25
# no warranties given, no responsibility taken
# All these are local paths
# the data file for the counter, it contains a number and a newline
$datafile='/cgi-bin/counter_ip.dat';
# the html page where the counter is placed
$htmlfile='/webpages/htmlsida1.html';
# the picture that is placed in the html page
# and is called from there with <img src="/path/to/this/script.pl">
#don't forget to place <!---Cstart--->b<!---Cend---> on a line of it's own
# and don't put anything inside it
$picturefile='/webpages/images/linux.gif';
$ipdatafile='/cgi-bin/counterip.dat';
sub updatehits
{
#read datafile and add 1 to it, then over write it
open (R_DATA,"$datafile")|| die "Can't open $datafile: $!\n\n";
$hits=<R_DATA>;
chomp($hits);
my($iplist);
local($/)= undef;
open (READIT, "$ipdatafile")||die "Can't open $ipdatafile for R: $!\n\n";
$iplist=<READIT>;
close (READIT)||die "Can't close $ipdatafile for R: $!\n\n";
unless ($iplist =~ /$ENV{REMOTE_ADDR}/)
{
++$hits;
}
close (R_DATA)|| die "Can't close $datafile: $!\n\n";
#update the data file
open (RW_DATA,">$datafile")|| die "Can't Open $datafile for RW: $!\n\n";
print(RW_DATA "$hits\n");
close (RW_DATA) || die "Can't Close $datafile from RW: $!\n\n";
#--- now we convert it and write it
open (WRITEIT,">$ipdatafile")||die "Can't open $ipdatafile for W: $!\n\n";
@ARRAY = split (/\n/, $iplist);
shift @ARRAY;
push @ARRAY,$ENV{REMOTE_ADDR}; #will be $ENV{REMOTE_ADDR}
foreach $out (@ARRAY)
{
chomp($out);
print (WRITEIT "$out\n");
}
close (WRITEIT)||die "Can't close $ipdatafile from W: $!\n\n";
}
sub passthedata
{
#this sub passes (writes the data to the html file)
open(R_PAGE,"$htmlfile")||die "Can't open $htmlfile for R: $!\n\n";
open(RW_PAGE,">$htmlfile.tmp")||die "Can't open $htmlfile.tmp for W: $!\n\n";
while(<R_PAGE>)
{
if (/<!---Cstart--->.*<!---Cend--->/)
{
print (RW_PAGE "<!---Cstart--->$hits<!---Cend--->\n");
}
else
{
print (RW_PAGE);
}
}
close (R_PAGE)||die "Can't close $htmlfile from R: $!\n\n";
close (RW_PAGE)|| die "Can't close $htmlfile.tmp from RW: $!\n\n";
rename ("$htmlfile.tmp",$htmlfile)||die "can't rename $htmlfile.tmp to $htmlfile: $!\n\n";
}
sub sendthepic
{
#this sub sends the pic to the page
open (R_PIC,"$picturefile")||die "Can't open $picturefile for R: $!\n\n";
while (<R_PIC>)
{
print(STDOUT $_);
}
close (R_PIC) || die "Can't close $picturefile from R: $!\n\n";
}
updatehits();
sendthepic();
passthedata();
----end n:th session----