#!/usr/bin/perl # # vcounter ### # use in web page # # without Server Side Includes: # # # (change the script name vcounter to vcounter.cgi as necessary.) # # options include: # page=PAGE_NAME The NAME can be any text string you like (no spaces). # If unspecified the pages path/name is taken from # the DOCUMENT_URI environment variable (SSI) # or the HTTP_REFERER variable (non-SSI). # style=STYLE_NAME The style of digits to be used in the counter. # "text" is the default. Other options are given by # the names of the subdirectories in the $digits_dir. # Currently: "led", "led_g", "led_r", "odometer", # "odometer_sm", "curly", "rosewood"... # More GIFs can be added, just create the coresponding # directory and the "size" file containing: # x (all digits within a # style must be the same size). # show=counter displays "[counter value]" (default action) # show=all displays "[counter value] hits since [date initalized]" # show=date displays just the "[date initialized]", no counter increment # show=nothing displays nothing, but does increment the counter file # digits=N pads the counter with left zeros to be at least N digits # commas=0 remove commas from text counter # trans=r,g,b rgb color to make transparent # increment=0 no counter increment (in case of multiple counters on a page) # block=N block incrementing from consecutive reloads for N seconds # # Un fichier compteur est composé des 5 champs suivants: # Valeur actuelle|Date modification|IP du client|Valeur initiale|Date de création ### use CGI qw(:cgi); use Fcntl qw(:flock); use GD; use IO::File; ############################## # Déclaration des variables. # ############################## ### site defaults: $wd = '/data/cgi-bin/counter/'; # full directory path to the root of site $digits_dir = 'digits/'; # dir of GIF digits (relative to $wd) $log_dir = 'logs/'; # dir for log files (relative to $wd) $error_log ="$wd$log_dir"."error.log"; %valid_servers = ('153.89.19.231'=> 1, # nrbstl27 # valid **remote** servers for counters (1=yes 0=no) '153.89.18.132' => 1, # nrb673 '153.89.19.83' => 1, '153.89.16.220' => 1, #matsya '153.89.19.130' => 1, '153.89.19.161' => 1, '153.89.19.4' => 1); $acces_string = 'accès depuis le'; # text displayed between counter and date for show=all $pwd = 'try_TO_find_this'; # Mot de passe nécessaire pour que le script passe en mode "admin". # User overridable defaults: $show = 'counter'; # Valeurs possibles : "counter", "date", "all", "nothing". $style = 'text'; # Valeurs possibles : soit "text", soit un style graphique. $digits = 0; # Nombre minimum de chiffres à afficher dans le compteur. $block = 0; # Block counter from incrementing from consecutive hits # by the same host within x seconds. $increment = 1; # Le compteur s'auto-incrémente. $commas = 1; # Utiliser de virgules dans l'affichage en mode text. $start = -1; # Ne pas (ré)initialiser le compteur. # Si start > -1 => (ré)initialiser le compteur à la valeur de start. $admin_mode = 'no'; # En mode admin, le script a la permission de réinitialiser le compteur. # Parse options from the query string: $page = lc(param('page')) if (length(param('page'))); $show = lc(param('show')) if (length(param('show'))); $style = lc(param('style')) if (length(param('style'))); $digits = lc(param('digits')) if (length(param('digits'))); $trans = lc(param('trans')) if (length(param('trans'))); $block = lc(param('block')) if (length(param('block'))); $commas = lc(param('commas')) if (length(param('commas'))); $start = lc(param('start')) if (length(param('start'))); $increment = 0 if (lc($show) eq 'date'); $increment = lc(param('increment')) if (length (param('increment'))); $admin_mode = 'yes' if (param('pwd') eq "$pwd"); $style = "text" if ($show ne "counter"); # Le paramètre show est prioritaire au paramètre style => forcer le style à "text" si show <> "counter". $filename = "$wd$log_dir$page".'.cnt'; #$logname = "$wd$log_dir$page".'.log'; # Variables temporelles: $time=time(); # Heure de mise à jour du compteur. ($sec,$min,$hour,$mday,$mon,$year) = (localtime(time))[0,1,2,3,4,5]; $sec = "0$sec" if($sec < 10); $min = "0$min" if($min < 10); $hour = "0$hour" if($hour < 10); $mday="0$mday" if($mday < 10); $mon = "0$mon" if($mon < 10); $year += 1900; ######################################## # Entrée dans le traitement principal. # ######################################## # Vérifier que le compteur est bien appelé à partir du site TELEDISnet. #if(!valid($ENV{'REMOTE_ADDR'})) { # write_error_log ("Appel du compteur \'$page\' par un hôte non autorisé ($ENV{'REMOTE_ADDR'})."); # write_browser ("Ce compteur ne peut être utilisé que dans un site TELEDISnet."); # exit(0); #} # Vérifier la présence du paramètre page. if(!length(param('page'))) { write_browser ("Impossible d'afficher le compteur: paramètre page manquant!"); exit(0); } # Création/Réinitialisation du compteur si start > -1. if(($start < -1) || ($start > -1 && $admin_mode eq "no")) { &print_empty; # Interdiction d'initialiser un compteur à une valeur négative. exit(0); } elsif ($start > -1 && $admin_mode eq "yes") { &new_counter; &print_empty; exit(0); } # Vérifier que le compteur appelé existe. if((!existing_file("$filename")) && ($admin_mode eq "yes")) { write_browser ("not_found"); exit(0); } elsif ((!existing_file("$filename")) && ($admin_mode eq "no")) { write_browser ("Le compteur '$page' n'a pas été créé. Veuillez vous rendre sur le site www.teledisnet.be pour initialiser votre compteur."); exit(0); } # Vérifier la présence des fichiers images du style graphique souhaité sur le serveur. if( ($style ne "text") && (!existing_file("$wd$digits_dir$style/size")) ) { &print_empty; exit(0); } # Incrémentation du compteur. if($increment == 1) { &update_counter; } # Affichage du compteur. if($style eq "text") { &print_count_text; } else { &print_count_graphic; } exit(0); ############################################################################# ## F o n c t i o n s ## ############################################################################# ############################################### # Autorisation de l'hôte à appeler le script. # ############################################### sub valid { if($valid_servers{$_[0]}) { return 1; } else { return 0; } } #################################################### # Vérifie la présence d'un fichier sur le serveur. # #################################################### sub existing_file { $file = "@_"; if((-e "$file")) { return 1; #le fichier existe } else { return 0; #le fichier n'existe pas } } ########################################## # Création/Réinitialisation du compteur. # ########################################## sub new_counter { sysopen(handle_count, $filename, O_TRUNC|O_CREAT|O_WRONLY) || write_error_log("Tentative d'ouverture du fichier '$filename': $!."); flock(handle_count, LOCK_EX) || write_error_log ("Tentative de verrouillage du fichier '$filename': $!."); print handle_count "$start\|$time\|$start\|$time\|$ENV{REMOTE_ADDR}\n"; close(handle_count) || write_error_log ("Tentative de fermeture du fichier '$filename': $!."); } ############################ # Mise à jour du compteur. # ############################ sub update_counter { open(handle_count,"+< $filename") || write_error_log("Tentative d'ouverture du fichier '$filename': $!."); flock(handle_count, LOCK_EX) || write_error_log ("Tentative de verrouillage du fichier '$filename': $!."); chomp($line = ); ($line_count_current,$line_date_modif,$line_count_init,$line_date_init,$line_previous_host) = split(/\|/,$line); # Ne pas incrémenter le compteur si la période entre deux appels du compteur par une même IP est plus petite que le block_time. if( ($line_previous_host ne $ENV{REMOTE_ADDR}) || ($time-$line_date_modif > $block) ) { $line_count_current++; seek(handle_count, 0, 0) || write_error_log("Impossible de se positionner au début du fichier '$filename': $!."); print handle_count "$line_count_current\|$time\|$line_count_init\|$line_date_init\|$ENV{REMOTE_ADDR}\n"; truncate(handle_count, tell(handle_count)) || write_error_log("Impossible de tronquer le fichier '$filename': $!."); } close(handle_count) || write_error_log("Impossible de fermer le fichier '$filename': $!."); } ############################################## # Affichage de qqch censé être rien du tout. # ############################################## sub print_empty { if($style eq "text") { write_browser (" "); } else { $| = 1; binmode STDOUT; print "Content-type: image/gif\n"; print "Pragma: no-cache\n"; print "Expires: now\n\n"; $blank = new GD::Image(1,1); $backgrnd = $blank->colorAllocate(0,0,0); $blank->transparent($backgrnd); print $blank->gif; } } ######################################## # Affichage du compteur en mode texte. # ######################################## sub print_count_text { open(handle_count,"< $filename") || write_error_log("Tentative d'ouverture du fichier '$filename': $!."); chomp($line = ); close(handle_count) || write_error_log("Impossible de fermer le fichier '$filename': $!."); ($line_count_current,$line_date_modif,$line_count_init,$line_date_init,$line_previous_host) = split(/\|/,$line); # Récupération de la date d'initialisation. @months = ("janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"); ($mday,$mon,$year) = (localtime($line_date_init))[3,4,5]; $year += 1900; # Ajout des virgules dans le nombre si nécessaire. if($commas) { $count_string = ""; $count_length = length($line_count_current); for($i = 0; $i < $count_length; $i++) { $count_string = substr($line_count_current,$count_length-$i-1,1)."$count_string"; $count_string = ",$count_string" if ( (($i+1)%3 == 0) && ($i<$count_length-1) ); } } else { $count_string = $line_count_current; } # Affichage du compteur. if($show eq "all") { write_browser("$count_string $acces_string $mday $months[$mon] $year"); } elsif ($show eq "date") { write_browser("$mday $months[$mon] $year"); } elsif ($show eq "counter") { write_browser("$count_string"); } else { &print_empty; } } #################################### # Affichage du compteur graphique. # #################################### sub print_count_graphic { open(handle_count,"< $filename") || write_error_log("Tentative d'ouverture du fichier '$filename': $!."); chomp($line = ); close(handle_count) || write_error_log("Impossible de fermer le fichier '$filename': $!."); ($count,$line_date_modif,$line_count_init,$line_date_init,$line_previous_host) = split(/\|/,$line); # Ajout de "0" devant la valeur du compteur si nécessaire. for ($i = length($count); $i < $digits; $i++){ $count = "0$count"; } $count_length = length($count); open(handle_size, "$wd$digits_dir$style/size") || write_error_log("Style graphique '$style' introuvable: $!") ; ($digit_width, $digit_height) = split (/x/,); close(handle_size) || write_error_log("Impossible de fermer le fichier '$filename': $!."); $image_width = $digit_width * $count_length; $image = new GD::Image($image_width,$digit_height); for($i=0; $i<$count_length; $i++) { $number = substr($count,$i,1); open (handle_digit, "$wd$digits_dir$style/$number".'.gif') || write_error_log("Impossible de trouver le fichier '$wd$digits_dir$style/$number.gif': $!"); $digit = newFromGif GD::Image(handle_digit); $image->copy($digit, $i*$digit_width, 0, 0, 0, $digit_width, $digit_height); close(handle_digit) || write_error_log("Impossible de fermer le fichier '$wd$digits_dir$style/$number.gif': $!."); } if($trans) { ($r,$g,$b) = split(/\,/, $trans); $trn_color = $image->colorClosest($r,$g,$b); $image->transparent($trn_color); } $count_image = $image->gif; $| = 1; binmode STDOUT; print "Content-type: image/gif\n"; print "Pragma: no-cache\n"; print "Expires: now\n\n"; print "$count_image"; } ########################################## # Ecriture dans un fichier log d'erreur. # ########################################## sub write_error_log { my $error = "@_"; open (handle_error, ">> $error_log"); flock(handle_error, LOCK_EX); print handle_error "$mday\/$mon\/$year $hour:$min:$sec : $error\n"; close(handle_error); } ############################################ # Affichage d'un texte dans le navigateur. # ############################################ sub write_browser { my $txt = "@_"; if(($style eq "text") && ($admin_mode eq "yes")) { print "Content-type: text/html\n\n"; print "$txt"; } elsif(($style eq "text") && ($admin_mode eq "no")) { print "Content-Type: application/x-javascript\n\n"; print "\n"; } else { &print_empty; } }