Unterabschnitte


Kleines Bannerscript

In diesem Kapitel zeige ich, wie ein Script zum Bannereinblenden und -zählen aussehen kann. Es erhebt keinen Anspruch darauf, perfekt zu sein oder alles zu können. Es soll nur ein paar Möglichkeiten von PHP demonstrieren.

Was soll das Script können?

Das Ganze habe ich in zwei Teile geteilt; das Script aus dem ersten Teil erfüllt die Anforderungen der ersten beiden Punkte, das zweite kann alles geforderte. Zu Demonstrationszwecken wurde das erste Script sowohl ohne als auch mit Datenbank realisiert, das zweite hingegen der Einfachheit halber nur mit Datenbank.


Erste Realisierung

Als erstes stellt sich die Frage, welche Daten gespeichert werden müssen. Im Moment sind das noch nicht viele:

Den ersten Punkt können wir dadurch abhaken, daß wir mit Hilfe der ,directory functions` auslesen lassen, welche Dateien in einem Verzeichnis existieren. Für die Lösung ohne Datenbank habe ich dies auch gemacht, bei der zweiten Variante dagegen alle Dateinamen in eine Tabelle geschrieben und dann aus dieser einen zufälligen Eintrag auswählen lassen. Man könnte dies natürlich kombinieren, indem man ein Script schreibt, was alle möglichen Dateinamen aus dem Verzeichnis ausliest und dann in die Tabelle schreibt, um dann nachher nur mit der Tabelle zu arbeiten.

Die ganze Administrationsoberfläche habe ich bei diesem Beispiel ganz dezent ignoriert; d.h. die Dateinamen müssen von Hand in die SQL-Tabelle eingetragen werden, und wie häufig welches Banner angezeigt wurde, muß ebenfalls von Hand aus den Dateien ausgelesen bzw. aus der Tabelle abgefragt werden.

Bei dem folgenden Script erledigen die beiden Funktionen genau dasselbe - mit dem Unterschied, daß die erste Funktion ohne Datenbank arbeitet.

Noch ein kurzes Wort zu Installation: Beide Funktionen gehen davon aus, daß die Banner im Unterverzeichnis ,banner` liegen. Die Dateisystemvariante benötigt zusätzlich noch ein Verzeichnis, in dem die Dateien zum Zählen liegen, das wird hier ,rw` genannt.

Für die Datenbankversion wird auch eine entsprechende Tabelle benötigt, für die hier die entsprechende create table-Anweisung steht.


CREATE TABLE banner(
  BID     int not null primary key auto_increment,
  Name    varchar(50) not null,
  shown   int,
  unique(Name)
);

Das Script sollte durch die Kommentare eigentlich soweit selbsterklärend sein.


<?php

function file_get_name(){

  function get_file_array(){
    // gibt ein Array mit allen Dateinamen zurück
    $handle=opendir('banner'); 
    while ($file = readdir($handle)){
      if ($file != "." && $file != ".."){
        $ret[]=$file;
      }
    }
    return $ret;
  }

  // alle Dateinamen in Array schreiben  
  $files = get_file_array();

  // Zufall initialisieren
  srand((double)microtime()*1000000);
  $nr = rand(0,count($files)-1);
 
  // zufällige Datei auswählen
  $banner = $files[$nr];
  
  //Zähler für Datei erhöhen

  // Dateiname für Zähler in $filename schreiben
  $filename = "rw/".$banner;
  if (file_exists($filename)){
    $fp = fopen($filename,"r+");
    flock($fp,2);
    $count = fgets($fp,1024);
    if (empty($count)){
      $count = 0;
    }
    $count++;
    fseek($fp,0);
  } 
  else {
    $fp = fopen($filename,"w");
    $count = 1;
  }
  fwrite($fp,$count);
  fclose($fp);
  return $banner;
}


function db_get_name(){
  $DB_HOST   = "localhost";
  $DB_USER   = "cr";
  $DB_PASSWD = "123";
  $DB_NAME   = "cr";

  mysql_connect($DB_HOST, $DB_USER, $DB_PASSWD);
  mysql_select_db($DB_NAME);

  $res = mysql_query('select BID, Name, BID*0+rand() AS sort 
                      from banner
                      order by sort
                      LIMIT 1;');

  if (!$res){
    // Fehler
    echo "Fehler in der Datenbank";
    return false;
  }

  // Ergebnis holen
  $row = mysql_fetch_array($res);

  // shown-Zähler um eins erhöhen
  mysql_query(sprintf('update banner 
                       set shown = shown+1
                       where BID=%d',
		      $row["BID"]));

  // Bildname zurück geben
  return $row["Name"];
}

?>

<html>
<head>
<title>Banner</title>
</head>
<body>
<img src="banner/<?php echo file_get_name(); ?>">
<img src="banner/<?php echo db_get_name(); ?>">
</body>
</html>


Zweite Realisierung

Nachdem wir nun die Grundfunktionalität haben, heißt es, das Ganze noch etwas zu erweitern. Es fehlen nämlich noch zwei Anforderungspunkte: Ersteres sollte kein Problem sein. An Stelle von ,<img src=...>` geben wir einfach ein ,<a href=...><img src=...></a>` aus. Dann haben wir allerdings ein Problem; wir können nicht zählen, wie häufig auf ein Banner geklickt wurde. Das Klicken findet auf Clientseite statt und dort haben wir mit PHP keine Möglichkeit, irgendetwas zu machen[*]. Also müssen wir uns etwas anderes überlegen.

Die Lösung ist relativ einfach. Wir geben nicht die eigentliche URL an, sondern ein Script auf unserem Server, was in Ruhe zählen kann und dann auf die richtige URL weiterleitet. Ich habe das hier in einem Script erledigt.

Aber erstmal zu unserer Tabelle in der Datenbank. Diese muß jetzt natürlich auch nochmal geringfügig erweitert werden. Es fehlen nämlich die Felder für die Klicks und für die URL. Im Endeffekt ergibt sich daraus folgendes create table:

CREATE TABLE banner(
  BID     int not null primary key auto_increment,
  Name    varchar(50) not null,
  URL     varchar(100) not null,
  shown   int,
  clicked int,
  unique(Name)
);

Nun aber zum Script. Der erste Teil (die Funktion ,show_banner`) ist fast identisch mit der Funktion aus der ersten Realisierung. Sie gibt nun allerdings nicht mehr den Bildnamen, sondern das Ganze als Link zurück.

Die größte Änderung befindet sich im Hauptprogramm. Hier wird nun nicht mehr nur die Funktion aufgerufen, sondern es gibt eine Fallunterscheidung. Wird das Ganze ohne ,bid` aufgerufen, so wird das Banner zurückgegeben, ansonsten wird der Klick gezählt und zur URL weitergeleitet.

Die Kombination in einem Script mag für diesen Fall einfacher sein, weil man alles zusammen hat; häufig ist es aber wahrscheinlich besser, diese beiden Funktionen in zwei verschiedene Scripte zu packen.


<?php

$DB_HOST   = "localhost";
$DB_USER   = "cr";
$DB_PASSWD = "123";
$DB_NAME   = "cr";

mysql_connect($DB_HOST, $DB_USER, $DB_PASSWD);
mysql_select_db($DB_NAME);

function show_banner(){
  // zufälliges Banner aus DB holen
  $res = mysql_query('select BID, Name, BID*0+rand() AS sort 
                      from banner
                      order by sort
                      LIMIT 1;');

  if (!$res){
    // Fehler
    echo "Fehler in der Datenbank";
    return false;
  }

  // Ergebnis holen
  $row = mysql_fetch_array($res);

  // shown-Zähler um eins erhöhen
  mysql_query(sprintf('update banner 
                       set shown = shown+1
                       where BID=%d',
		      $row["BID"]));

  // Banner mit Link ausgeben
  printf('<a href="%s?bid=%d">'.
	 '<img src="banner/%s" border="0"></a>', 
	 $_SERVER["PHP_SELF"],
	 $row["BID"],
	 $row["Name"]);
}


/************* Hauptprogramm *************/

if (isset($_GET["bid"])){
  // bid gesetzt -> es wurde auf eine Banner geklick
  // -> User weiterleiten

  if (!is_numeric($_GET["bid"])){
    // bid muß immer numerisch sein
    die('Keine gültige ID übergeben');
  }

  // URL aus DB holen
  $res = mysql_query(sprintf('select URL 
                              from banner
                              where bid=%d',
			     $_GET["bid"]));

  if (!$row = mysql_fetch_array($res)){
    // Fehler
    die("Fehler in der Datenbank");
  }

  // click-Zaehler um eins erhöhen
  mysql_query(sprintf('update banner 
                       set clicked = clicked+1
                       where BID=%d',
		      $_GET["bid"]));

  // User auf die richtige Seite weiterleiten
  header('Location: '.$row["URL"]);
  exit;
}
else {
  // Banner anzeigen
?>
<html>
<head>
<title>Banner</title>
</head>
<body>
<?php show_banner(); ?>
</body>
</html>
<?php
}
?>

Christoph Reeg