#!/usr/bin/perl
# AdServer (c) RZ-Online GmbH by jo 1999-2009
# Version 1.0 erste eingesetzte Version 7/1999
# Version 1.1 mit dynamischer Verteilung über die Laufzeit bei def. MaxViews
# Version 1.2 mit 'strftime'-Option in Link und Bild-Source
# Version 1.3 serverunabhängig (.basic.conf-File eingeführt) 9/2000
# Version 1.4 multiprozessfähig, mit Logbuch 10/2000
# Version 1.5 mit Cookie-Sperrliste für PopUps etc. 11/2002
# Version 1.5.1 *alle* Pfade per Konfigurationsdatei einstellbar 2/2003
# Version 1.6 in den Feldern "Name" "Link" und "Bild" kann jetzt die
# Zeichenfolge #a-b stehen. Sie wird durch Zufallszahlen von
# a bis b ersetzt.
# Version 1.7 mit Templates für teilweise (Flash) oder komplette Anzeigendefinition
# Version 1.8 Templates auch per SSI-Kommando-Parameter nutzbar
# Version 1.9 AdServer kann per shared memory (IPC::Cache) nachfolgenden Aufrufen eine Botschaft
# hinterlassen, um z.B. zum Banner passende Skyscraper ("Wallpaper") zu platzieren (uid)
# Dazu muss der Sperrvermerk (LOCKT) bei beiden Anzeigen ein Sternchen sein "*".
# Cookie-Sperrliste suspendiert, weil Cookies nur mit IFrames genutzt werden können.
# Fallback von Superbannern auf 468/234er Paare eingebaut:
# (a) Auto Fallback mangels 728er Banner (b) Forced Fallback via Dummy-Anzeige _falback\d*_
# Version 1.9.1 Fallbacks mangels Bedarf auskommenmtiert. (12/08)
# Version 1.9.2 adKeyRules zum Umschreiben abgelaufener adKeys eingebaut (1/09)
use lib '/usr/online/lib';
use Time::Local;
use Time::HiRes qw(gettimeofday);
use POSIX qw(strftime);
use Logbook;
use Jo qw(ReadBasicConfig LockFileT UnlockFile TimeStr GetPID UnEscape);
use CGI::Fast;
use IPC::Cache;
use strict;
# Diese globalen Variablen können in 'adserver.basic.conf' im Programmpfad überladen werden
my $counterDir; # Verzeichnis der Zähl-Dateien für Views und Clicks.
my $configFile; # Konfigurationsdatei
my $configTempFile; # nobody's Tabelle ;-)
my $baseURL; # URL des WebServers
my $cgiURL; # Script-URI dieses Scripts
my $adServerLog; # Logbuch-Datei
my $transGIF; # transparentes GIF für Dummies
# Ende der überladbaren Variablen
my $defBlock="ANZEIGEN"; # dieser Block ist obligatorisch.
my $userBlock="LASTUSER"; # dieser Block ist obligatorisch.
my $adKeys='ADKEYS'; # dieser Block ist obligatorisch.
my $makroBlock="RESSORTMAKROS"; # dieser Block ist optional.
my $httpHTMLHeader="content-type: text/html \n\n";
my (@anzeigen,%blocks,%makros,%tab,%axel,$now,$nextUpdate,$updatePending);
my ($lastUser,$fallbackAdKey)=('??','nationalnews');
my ($log,$cache,%idList,%adKeyRules);
# %blocks sind die Blöcke in der Definitionsdatei.
# @anzeigen ist die Liste der Anzeigen, also ein Abbild der Zeilen im Block [ANZEIGEN].
# %tab ist ein Hash von Arrays: der Ressort-Streulisten. Diese sind Arrays mit Anzeigen-Indizes (Anzahl=Gewichtung).
# %axel ist eine Hilfstabelle mit Anzeigennamen und zugehörigen Indizes zum schnelleren Zugriff auf die Anzeigen via Namen.
# $now ist die aktuelle Uhrzeit, die bei jedem FCGI-Schleifendurchlauf ermittelt wird.
# $nextUpdate ist die Zeit des nächsten Tabellen- (%tab) Updates. Die Tabelle wird ca. alle 2 Minuten neu aufgebaut.
# $lastUser ist der letzte User, der schrieb. Wird wg. unterschiedlichen Domains vom JS übergeben.
# [trenner][Anzahl] wird vor Anzeigen[gruppe] gesetzt
my @prolog = ( ["",""], ["","
"] );
my @epilog = ( ["",""], ["","
"] ); # dahinter "
my @einleitung = ( ["","",""], ["",""," | "]); # [trenner][Anzahl] wird vor jeder einzelnen Anzeige gesetzt
my @ausleitung = ( [" ","
","
"], [""," | ",""] ); # dahinter
my @dummyGrafik= ("
","
");
my $prg=$0; $prg=~ s/.+?\/([\w-]+\.(:?pl|fcg))$/$1/;
my $updateTime=120;
my $debug= ($0=~ /\.pl$/) || 0;
$SIG{USR1} = sub { $updatePending++ };
sub JavaScript {
print "\n";
}
sub Log {
if (open DAT,">>$counterDir/update.log") {
if (LockFileT(\*DAT,0.67)) {
print DAT TimeStr()," ",sprintf("%8.8s ",$$),join("\n",@_),"\n";
UnlockFile(\*DAT);
}
close DAT
}
}
sub EraseNumFromArray {
my ($a,$item)=@_;
my $i=0; my $j=-1;
while ($i<=$#{$a}+1) { # läuft eins über die Arraygrenze hinaus!
if ($j>=0) {
if (@{$a}[$i] != $item) {
splice(@{$a},$j,$i-$j);
$i=$j; $j=-1;
}
}
elsif (@{$a}[$i] == $item) {
$j=$i
}
$i++;
}
}
sub Escape2 {
my $s=$_[0];
$s=~s/(\;|\,)/sprintf("\$%2.2lx",ord($1))/ge;
return $s;
}
sub UnEscape2 {
my $s=$_[0];
$s=~s/\$([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
return $s;
}
sub Signed {
return 1 if $_[0] eq "R4Ts95tsa";
print $httpHTMLHeader;
JavaScript('alert("Ungültiger Funktionsaufruf des AdServers!");');
return 0;
}
sub ValidAnz { # testet auf Gültigkeit einer Anzeige
my ($index,$anzeige)=@_;
my $a=$anzeigen[$index];
my ($startT,$endT);
return 0 unless (($a->{NAME} =~ /^_fallback[\w\-]*_$/) or
(
($a->{WERT}>0) and ($a->{PATH}) and
((!$a->{MAXVIEWS}) or ($a->{VIEWS}+$a->{_VIEWS} < $a->{MAXVIEWS})) and
(($a->{LINK}) or ($a->{NAME}=~/#\d+-\d+/) or (exists $blocks{$a->{NAME}})) and
(($a->{BILD}) or ($a->{NAME}=~/#\d+-\d+/) or (exists $blocks{$a->{NAME}}))
)
); # skip, weil kein Wert, kein Ressort,
# Maxviews überschritten,
# weder Link noch Block, weder Bild noch Block.
# Achtung: hier keine Prüfung bei Random-Block-Anzeigen!
if ($a->{STARTT}) {
my ($mday,$mon,$year)=split /\./,$a->{STARTT},3;
$year-=1900 if $year>1900;
$startT=timelocal(0,0,0,$mday,--$mon,$year);
return 0 if $now < $startT;
} # skip, weil Starttermin noch nicht erreicht
if ($a->{ENDT}) {
my ($mday,$mon,$year)=split /\./,$a->{ENDT};
$year-=1900 if $year>1900;
$endT=timelocal(59,59,23,$mday,--$mon,$year);
return 0 if $now > $endT;
} # skip, weil Endetermin überschritten
if (($startT) and ($endT) and ($a->{MAXVIEWS})) {
my $T=$endT-$startT; # gesamte Anzeigen-Laufzeit in Sek.
my $t=$now-$startT; # verstrichene "
my $e=$a->{MAXVIEWS} * $t / $T; # rechnerische Views bisher
return ($a->{VIEWS}+$a->{_VIEWS} > $e) ? -1 : 1;
}
return 1
}
sub ReadCounter {
my $name=$_[0];
my ($views,$clicks);
if (open(DAT,"<$counterDir/$name.counter")) {
($views,$clicks)=;
close DAT;
}
return (int $views,int $clicks);
}
sub WriteAllCounters {
my $res=1;
for (@anzeigen) {
if ((($_->{_VIEWS}) or ($_->{_CLICKS})) and
((open(DAT,"+<$counterDir/".$_->{NAME}.".counter")) or
(open(DAT,"+>$counterDir/".$_->{NAME}.".counter")))) {
if (LockFileT(\*DAT,0.67)) {
($_->{VIEWS},$_->{CLICKS})=;
$_->{VIEWS}+=$_->{_VIEWS};
$_->{CLICKS}+=$_->{_CLICKS};
$_->{_VIEWS}=0;
$_->{_CLICKS}=0;
seek DAT,0,0;
print DAT $_->{VIEWS}."\n".$_->{CLICKS}."\n";
UnlockFile(\*DAT);
}
else {
$res=0;
}
close DAT;
}
}
return $res;
}
sub Update {
my $verbose=$_[0];
$updatePending=0;
my $res=ReadConfig() || "o.k.";
$log->Write("Update($verbose) with RES=$res (PIDs=".join(',',GetPID()).")");
print $httpHTMLHeader;
if ($res ne "o.k.") {
JavaScript('alert("FEHLER - AdServer NICHT neu initialisiert:\n'.$res.'");','parent.location.reload(true);') if $verbose;
return $res
}
MakeTable();
JavaScript('alert("AdServer neu initialisiert.");','parent.location.reload(true);') if $verbose;
return "";
}
sub MakeTable {
my ($a,$i,$v,$k,@r);
my $index=-1;
undef %tab;
foreach $a(@anzeigen) {
$index++;
next if ValidAnz($index)<=0;
foreach $v(split /\s*,\s*/,$a->{PATH}) {
if ((exists $makros{$v}) and (defined $makros{$v}{RUBRIKEN})) { # Ressort-Makros auflösen
for (split /\s*,\s*/,$makros{$v}{RUBRIKEN}) { push @r,$_ }
} else {
push @r,$v
}
}
for (@r) {
push @{$tab{$_}},$index
# aktuellen Anzeigenindex einmal merken # Streutabelle jetzt in "putAd" jo 22.11.02
}
undef @r;
}
}
sub ReadConfig {
return "Zaehlerdatei(en) nicht geschrieben!" if (@anzeigen) and (!WriteAllCounters());
undef %blocks; undef %makros; undef @anzeigen; undef %axel;
my $anzLabel;
open DAT,"<$configFile" or return "Konfiguration \"$configFile\" nicht gefunden!";
while () {
if (s/^\s*\[(\w+)\]/$1/) { # *
$anzLabel=$1
} elsif (($anzLabel) and (/\S+/) and not (/^\#/)) {
s/[\s\n]*$//;
push @{$blocks{$anzLabel}},$_
}
}
close DAT;
return "Konfiguration unvollständig: '$defBlock' Marke fehlt!" unless exists $blocks{$defBlock};
while (my $s=shift @{$blocks{$defBlock}}) {
my ($label,$wert,$ressorts,$link,$bild,$startT,$endT,$lockT,$maxViews)=split /\s*;\s*/,$s;
$wert=99 if $wert>99; # Maximalgewichtung 99
my ($v,$k)=ReadCounter($label);
$link="$baseURL$link" if ($link) and ($link!~ /^https?:\/\//) and ($link!~ /^TEMPLATE\s*=/);
$bild="$baseURL$bild" if ($bild) and ($bild!~ /^https?:\/\//) and ($bild!~ /^ADKEY\s*=/);
push @anzeigen,{
NAME=>$label,
WERT=>$wert,
PATH=>$ressorts,
LINK=>UnEscape2($link),
BILD=>UnEscape2($bild),
STARTT=>$startT,
ENDT=>$endT,
LOCKT=>$lockT,
MAXVIEWS=>$maxViews,
VIEWS=>$v,
CLICKS=>$k,
_VIEWS=>0,
_CLICKS=>0
};
if ($label=~ s/#(\d+)-(\d+)$//) { # Random-Anweisung für die Hilfstabelle entfernen
my ($start,$end)=($1,$2);
for (my $i=$start; $i<=$end; $i++) {
$axel{$label.$i}=$#anzeigen; # Hilfstabelle (Accelerator) aufbauen
}
} else {
$axel{$label}=$#anzeigen; # Hilfstabelle (Accelerator) aufbauen
}
}
undef $blocks{$defBlock};
my $i=0;
while (my $s=shift @{$blocks{$makroBlock}}) {
my ($k,$v)=split /\s*=\s*/,$s;
$makros{$k}{RUBRIKEN}=$v;
$makros{$k}{NUM}=$i++;
}
undef $blocks{$makroBlock};
$lastUser=shift @{$blocks{$userBlock}};
undef $blocks{$userBlock};
$fallbackAdKey=shift @{$blocks{$adKeys}};
my $adKeyList=shift @{$blocks{$adKeys}};
my @a=split /\s*,\s*/,$adKeyList;
while (@a) { my ($k,$v)=(shift @a,shift @a); $adKeyRules{$k} = $v || '' };
undef $blocks{$adKeys};
return "";
}
sub WriteConfig { # schreibt temporäre Version auf /var/www/inter
my (@zeilen,$s,$skip); # Wrapper kopiert diese
open DAT,"<$configFile" or return "Konfiguration $configFile nicht gefunden!";
@zeilen=;
close DAT;
open DAT,">$configTempFile" or return "Konfiguration $configTempFile nicht zum Schreiben geöffnet!";
for (@zeilen) {
next if ($skip) and not (/^\s*\[(\w+)\]/); # weiter bis neue Gruppe beginnt
$skip=0;
print DAT $_;
if (/^\s*\[$userBlock\]/) {
print DAT "$lastUser\n\n";
$skip++;
}
elsif (/^\s*\[$defBlock\]/) {
foreach $s(@anzeigen) {
print DAT join(";",$s->{NAME},$s->{WERT},$s->{PATH},Escape2($s->{LINK}),Escape2($s->{BILD}),$s->{STARTT},$s->{ENDT},$s->{LOCKT},$s->{MAXVIEWS}),"\n";
}
print DAT "\n";
$skip++;
}
}
close DAT;
return "";
}
#sub EraseNumFromTabs { # alternativ könnte MakeTable() benutzt werden ;-)
# my $num=$_[0];
# for (values %tab) { EraseNumFromArray($_,$num) }
# for (keys %axel) { undef $axel{$_} if $axel{$_}==$num } z.Zt. nicht erwünscht
#}
sub BuildTab {
my ($adTab,$cookie)=@_; # adTab ist eine Liste mit Anzeigenindizes
my (@tmp,$i,$j); # tmp wird die gefilterte und gewichtete Streutabelle
AD: foreach $i (@{$adTab}) {
# Cookie basierte Sperre suspendiert, weil der AdServer ohne iframes keine Cookies setzen kann, jo 22.11.05
# if ($anzeigen[$i]->{LOCKT}) {
# my $ad=$anzeigen[$i]->{NAME};
# for (split /\s*;\s*/,$cookie) { next AD if /^$ad=/ }
# }
if (($anzeigen[$i]->{NAME} !~ /skyscraper$/) or ($anzeigen[$i]->{LOCKT} ne '*')) {
for ($j=0; $j<$anzeigen[$i]->{WERT}; $j++) { push @tmp,$i }
}
}
@{$adTab}=@tmp;
return $#tmp+1;
}
sub HashValue {
my $s=shift;
my $y=0;
for (my $i=0; $i[0];
} else {
push @buffer,$prolog[$trenner][$anzahl>1]
}
my $nowgenau=scalar gettimeofday(); $nowgenau=~ s/\.//; $nowgenau=substr($nowgenau,0,12);
my $hashUID=HashValue($uniqueID);
if (($uniqueID) and (not $anzeige) and ($path =~ /skyscraper$/i) and ($anzeige=$cache->get($uniqueID))) {
$cache->set($uniqueID,undef);
$log->Write("Wallpaper-Match (Sky): Name=$anzeige UID=$uniqueID",3)
}
for ($i=0; $i<$anzahl; $i++) {
if ($anzeige) { # Anzeigenname bekannt (Festplatzierung)
$n=$axel{$anzeige};
unless ((defined $n) and (ValidAnz($n,$anzeige))) { # Anzeige nicht vorhanden / noch (nicht gültig)
$log->Write("Keine festplatzierte Anzeige '$anzeige' verfügbar (Dokument=$filename, \$n=$n)");
next
}
} elsif (($path) and (exists($tab{$path}))) {
@tmp=@{$tab{$path}}; # temporäres Array zuweisen
BuildTab(\@tmp,$cookie); # Anzeigen nach Cookie-Sperrliste ausblenden, Rest nach Gewicht expandieren
} else {
# if ($path =~ /^(\w+)728$/) {
# $log->Write('Superbanner gegen 468er+234er austauschen (keine Superbanner definiert)',3);
# PutAd($1.'468',$src,2,'',$trenner,$filename,$cookie,$adKey,$addTemplate,$uniqueID);
# return
# } else {
$log->Write("Keine Anzeige für Pfad '$path' verfügbar (Dokument=$filename [$ENV{HTTP_REFERER}])",3);
# }
next # Tabelle ist leer, keine Anzeige vorgesehen
}
unless ($anzeige) {
$n=$#tmp;
if ($n<0) {
# if ($path =~ /^(\w+)728$/) {
# PutAd($1.'468',$src,2,'',$trenner,$filename,$cookie,$adKey,$addTemplate,$uniqueID);
# $log->Write("Superbanner gegen 468+234-Banner ausgetauscht (keine Anzeige für '$path')",3);
# return
# } else {
$log->Write("Keine passende Anzeige verfügbar (Dokument=$filename)",2);
# }
next # keine Anzeige (mehr) verfügbar
}
$n=$tmp[int(rand 1+$n)];
# if (($anzeigen[$n]->{NAME} =~ /^_fallback[\w\-]*_$/) and ($path =~ /^(\w+)728$/)) {
# PutAd($1.'468',$src,2,'',$trenner,$filename,$cookie,$adKey,$addTemplate,$uniqueID);
# $log->Write("Superbanner gegen 468+234-Banner ausgetauscht (fallback erzwungen)",3);
# return
# }
}
if (($uniqueID) and ($anzeigen[$n]->{LOCKT} eq '*') and ($anzeigen[$n]->{NAME} =~ /^(.+?)(?:banner|\d+)$/i)) {
$cache->set($uniqueID,$1.'skyscraper');
$log->Write("PUT Wallpaper-Banner: $anzeigen[$n]->{NAME} UID=$uniqueID",3)
}
my $l=($anzahl<2) ? 0 : ($i) ? 2 : 1;
push @buffer,$einleitung[$trenner][$l];
my $link=$anzeigen[$n]->{LINK};
my $randNum;
if ($link) {
if ($link !~ s/^TEMPLATE\s*=//) { # Normalfall: verlinktes Banner
my ($src,$masse1,$masse2,$alt)=split(/ +/,$anzeigen[$n]->{BILD},4);
$masse1=~ s/^(width|height)=(\d+)/$1=\"$2\"/; $masse2=~ s/^(width|height)=(\d+)/$1=\"$2\"/;
$alt="alt=\"Klick!\"" unless $alt=~ /alt\s*=/i;
$link=~ s/#(\d+)-(\d+)/$randNum || ($randNum=($1+int(rand $2+1-$1)))/e;
$src=~ s/#(\d+)-(\d+)/$randNum || ($randNum=($1+int(rand $2+1-$1)))/e;
$link=strftime $link,localtime;
$src=strftime $src,localtime;
$link=~ s/([\?\&])/'%'.sprintf("%2.2lx",ord $1)/eg; # codieren, falls Parameter in der URL vorhanden sind [7.12.99 jo]
push @buffer,"
";
} else { # Bild in universalem TEMPLATE-Block (aus adserver.conf-Datei) einbauen
my @a=@{$blocks{$link}};
my $subst=$anzeigen[$n]->{BILD};
if ((!$subst) or ($subst =~ /^ADKEY(?:\s*=\s*(.+))?$/i)) {
if ($adKey) {
$subst=$adKey # AdKey aus Anzeigenaufruf (Parameterübergabe [1])
} else {
$subst=($1) ? $1 : $fallbackAdKey; # Defaults aus Anzeigendefinition [2] oder Fallback [3] aus DEFAULTADKEY der .config
}
}
$adKey=$adKeyRules{$adKey} if %adKeyRules and (defined $adKeyRules{$adKey}); # neu eingefügt, um abgelaufene AdKeys überschreiben zu können JO 8.1.09
map { # Platzhalter im Block durch Code (aus Feld 'BILD' oder Aufruf-Parameter 'adKey') ersetzen
s/%%SRC/$subst/g;
s/%%NAME/$anzeigen[$n]->{NAME}/g;
s/%%TIMESTAMP/$nowgenau/g;
s/%%DOC/$baseURL$filename/g;
s/%%ENV\{(\w+)\}/$ENV{$1}/g;
s/%%UID/$uniqueID/g;
s/%%HASHUID/$hashUID/g;
} @a;
push @buffer,join("\n",@a);
}
} else {
my $name=$anzeigen[$n]->{NAME};
$name=~ s/#(\d+)-(\d+)/$randNum || ($randNum=($1+int(rand $2+1-$1)))/e;
# $log->Write("Block '$name' ausgelost",3);
my @a=@{$blocks{$name}};
map {
s/%%SRC/$src/g;
s/%%TIMESTAMP/$nowgenau/g;
s/%%DOC/$baseURL$filename/g;
s/%%ENV\{(\w+)\}/$ENV{$1}/g;
s/%%UID/$uniqueID/g;
s/%%HASHUID/$hashUID/g;
} @a; # Platzhalter im Block durch Code ersetzen
push @buffer,join("\n",@a);
# push @buffer,$dummyGrafik[$path=~ /468$/ || 0] if $anzeigen[$n]->{LOCKT}; zur Zeit suspendiert, jo 22.11.05
}
push @buffer,$ausleitung[$trenner][$l];
$anzeigen[$n]->{_VIEWS}++;
EraseNumFromArray(\@tmp,$n) if @tmp;
if (($trenner) and ($anzahl>1)) {
if ($path=~ /468$/) { $path=~ s/468$/234/ } else { $path=~ s/234$/468/ }
}
}
if ($addTemplate) {
push @buffer,$blocks{$addTemplate}->[1];
} else {
push @buffer,$epilog[$trenner][$anzahl>1]
}
# print "Set-Cookie: ",$anzeigen[$n]->{NAME},"=set;EXPIRES=",scalar gmtime(time()+$anzeigen[$n]->{LOCKT}*60.),";PATH=/;\n" if $anzeigen[$n]->{LOCKT}; suspendiert, jo 22.11.05
print $httpHTMLHeader,join("\n",@buffer)
}
sub Click {
my ($link,$filename,$doc)=@_;
my $n=0;
$n=$axel{$filename};
if (defined $n) {
if ($link) {
$link=~ s/%([\da-f]{2})/chr(hex($1))/eg; # decodieren 7.12.99 jo
} else {
$link=$anzeigen[$n]->{LINK} # hinterlegten Link nutzen, falls kein anderer mitgeteilt (DEFAULT) 28.11.06 jo
}
$anzeigen[$n]->{_CLICKS}++;
$log->Write("Klick auf Anzeige \"$filename\" LINK=$link DOC=$doc",2);
if ($link) {
print "Location: $link\n\n\n"
} else {
print "$httpHTMLHeader\n"
}
}
else # nur bei Ablauf/Streichung einer Anzeige denkbar, seltener Fall
{ print $httpHTMLHeader,"[Anzeige '$filename' nicht gefunden]\n" }
}
sub PutData {
my $reload=$_[0];
my ($k,$v,@zeilen,@a);
my $i=0;
for (@anzeigen) {
$v=ValidAnz($i++);
if ($v>0) {
$k="!"
}
elsif ($v<0) {
$k="*"
}
else {
$k=" "
}
push @zeilen,join ";",$_->{NAME},$_->{WERT},$_->{PATH},Escape2($_->{LINK}),Escape2($_->{BILD}),$_->{STARTT},$_->{ENDT},$_->{LOCKT},$_->{MAXVIEWS},$_->{VIEWS}+$_->{_VIEWS},$_->{CLICKS}+$_->{_CLICKS},$k;
}
push @a,"var a=new Array();";
$i=0;
for (sort @zeilen) {
push @a,"a[",$i++,"]=\"$_\";"
}
push @a,"var r=new Array();";
$i=0;
my @tmp=sort { $makros{$a}{NUM} <=> $makros{$b}{NUM} } keys %makros;
foreach $k(@tmp) {
push @a,"r[",$i++,"]=\"$k\";";
for (split /\s*,\s*/,$makros{$k}{RUBRIKEN}) {
push @a,"r[",$i++,"]=\"$_\";";
}
}
if ($reload) {
push @a,"parent.ads_main.Reloaded();"
}
else {
push @a,"parent.ads_main.Init();"
}
print $httpHTMLHeader;
JavaScript(@a);
}
sub GetData {
my $s=$_[0];
my (@a,%t,$label,$wert,$ressorts,$link,$bild,$startT,$endT,$lockT,$maxViews,$v,$k);
for (@anzeigen) { # Views und Klicks in %t zwischenspeichern
$t{$_->{NAME}} = {
VIEWS=>$_->{VIEWS},
CLICKS=>$_->{CLICKS},
_VIEWS=>$_->{_VIEWS},
_CLICKS=>$_->{_CLICKS}
}
}
undef @anzeigen; undef %axel; # Array und Zugriffstabelle wird komplett neu aufgebaut
@a=split(/\|/,$$s);
for (@a) {
($label,$wert,$ressorts,$link,$bild,$startT,$endT,$lockT,$maxViews)=split /;/;
next if $label eq "(neu)";
push @anzeigen,{
NAME=>$label,
WERT=>$wert,
PATH=>$ressorts,
LINK=>UnEscape2($link),
BILD=>UnEscape2($bild),
STARTT=>$startT,
ENDT=>$endT,
LOCKT=>$lockT,
MAXVIEWS=>$maxViews,
VIEWS=>(exists $t{$label}) ? $t{$label}->{VIEWS} : 0,
CLICKS=>(exists $t{$label}) ? $t{$label}->{CLICKS} : 0,
_VIEWS=>(exists $t{$label}) ? $t{$label}->{_VIEWS} : 0,
_CLICKS=>(exists $t{$label}) ? $t{$label}->{_CLICKS} : 0
};
$axel{$label}=$#anzeigen;
}
undef @a;
MakeTable();
$s=WriteConfig();
if ($s) {
print $httpHTMLHeader;
JavaScript('alert("ACHTUNG!\n'.$s.'");')
}
else {
PutData(1)
}
}
sub GetLastMod {
my ($s,$m,$h,$d,$mon,$y)=localtime((stat $configFile)[9]);
$mon++; $y+=1900;
$s=~s/(^\d$)/0$1/; $m=~s/(^\d$)/0$1/;
return "$d.$mon.$y $h:$m:$s von $lastUser";
}
sub LastMod {
my ($s,$m,$h,$d,$mon,$y)=localtime((stat $configFile)[9]);
$mon++; $y+=1900;
$s=~s/(^\d$)/0$1/; $m=~s/(^\d$)/0$1/;
print $httpHTMLHeader;
JavaScript("parent.ads_main.lastMod=\"".GetLastMod()."\";","parent.ads_main.CheckLastMod();");
}
sub PrintError {
my $error=shift;
print $httpHTMLHeader;
print "FEHLER - $error\n";
$log->Write($error);
}
MAIN: {
umask 002;
ReadBasicConfig(sub{eval $_[0]}); # Optionale Datei zum Ändern der Standard-Konfiguration
my $error=ReadConfig();
$cache = new IPC::Cache({ namespace => 'RZOAdServer', expires_in => 15 });
$log=Logbook->new($adServerLog,1,1,2+$debug,10000);
srand(time+$$);
$log->Write("*** $0 launched (debug=$debug, cache=".($cache!=0).") ***",2);
while (my $q=new CGI::Fast) {
$now=time();
$error=Update(0) if $updatePending;
my $cmd=$q->param('cmd');
if ($now>=$nextUpdate) { # ca. alle zwei Minuten:
$nextUpdate=(WriteAllCounters()) ? $now+$updateTime+int(rand 30) : $now+1+int(rand 30) ; # Zaehler wegschreiben
MakeTable(); # Tabelle neu aufbauen
$log->Write('Mem info before Purge:'.IPC::Cache::SIZE(),2) if $debug;
IPC::Cache::PURGE(); # shared Memory aufräumen
$log->Write('Mem info after Purge:'.IPC::Cache::SIZE(),2) if $debug;
}
if (!$cmd) {
if ($error) {
PrintError($error)
} else {
if ($q->param('oldMode')) {
print $q->header # wird nicht mehr unterstützt
} else {
PutAd($q->param('path') || '',$q->param('src') || '',
$q->param('anzahl') || 1,$q->param('anzeige') || '',
$q->param('blank') || 0,$q->param('doc') || $ENV{'DOCUMENT_URI'} || '',
$q->param('cookie') || $ENV{'HTTP_COOKIE'},
$q->param('adKey') || '',$q->param('template') || '',$q->param('uid') || '')
}
}
} elsif ($cmd eq 'CLICK') {
if ($error) {
PrintError($error);
}
else {
Click($q->param('url') || "",$q->param('anzeige'),$q->param('doc') || $ENV{'DOCUMENT_URI'})
}
} elsif (($cmd eq 'GETDATA') && (Signed($q->param('sgn')))) {
PutData();
} elsif (($cmd eq 'PUTDATA') && (Signed($q->param('sgn')))) {
$lastUser=$q->param('user');
GetData(\$q->param('data'));
$log->Write("Got new data (master)");
sleep 1;
local $SIG{USR1} = 'IGNORE';
kill 'USR1',GetPID();
} elsif ($cmd eq 'LASTMOD') {
LastMod()
} elsif (($cmd eq 'UPDATE') && (Signed($q->param('sgn')))) {
$error=Update(1);
local $SIG{USR1} = 'IGNORE';
kill 'USR1', GetPID();
}
}
$log->Write("DOWN");
}