# Die Programmierung

Bei seiner Geburt ist ein Mensch so unfertig, wie ein an einem schönen blauen Montag in Taiwan hergestellter Computer vor der Programmierung.
Wolfgang Körner

Nachdem die gesamte Vorarbeit geleistet worden ist, folgt nun die Programmierung der eigentlichen Seite.

# Die Konfigurationsdateien

Die Webseite soll auch in Anbetracht äußerer Einflüsse möglichst flexibel bleiben. Aus diesem Grund sollten Konfigurationsdateien verwendet werden, die verschiedene, immer wieder benötigte Variablen enthalten.

# base.inc.php

In der Datei base.inc.php wird die Konfiguration der Webseite vorgenommen. Dort wird ein Array definiert, das den Titel, den Namen des zu verwendenden Templates oder auch Start- und Endezeichenfolgen für die Platzhalter enthält. Da gewisse Dinge der Webseite sich nicht regelmäßig ändern, wie z. B. die Navigationsleiste, kann auch diese dort definiert werden. Außerdem können in dieser zentralen Konfigurationsdatei Funktionen definiert werden, die bei jedem Aufbau der Webseite benötigt werden.

# database.inc.php

In dieser Konfigurationsdatei wird ein Array definiert, das alle wichtigen Daten für den Zugriff auf die Datenbank enthält, wie z. B. den Servernamen, den Benutzernamen und das Passwort. Aber auch der Name der zu verwendenden Datenbank wird hier festgelegt.

# Sicherheit

Aus Sicherheitsgründen sollten die Konfigurationsdateien als PHP-Scripts definiert werden. Sollte doch jemand einmal Zugriff auf das inc-Verzeichnis erhalten, werden die Dateien vor der Ausgabe im Browser geparst, und der Browser gibt lediglich ein leeres Dokument aus.

Denken Sie unbedingt daran, das Verzeichnis durch .htaccess zusätzlich zu schützen. Selbst wenn die Dateien zuvor geparst werden – es ist einfach wesentlich sicherer.

# functions.inc.php

Diese Datei ist das Kernstück des gesamten Projekts. Sie enthält alle Funktionen, die den auszugebenden Inhalt erzeugen. Hauptsächlich sind dies also Funktionen, die eine Verbindung zur Datenbank aufbauen und dann den Inhalt erzeugen.

# Die index.php

Das Hauptscript und das einzige Script, das überhaupt ausgeführt wird, ist die Datei index.php. Diese Datei kümmert sich um das Laden des Templates, den Aufruf der Funktionen, mit denen der Inhalt erzeugt wird, und ersetzt dann die einzelnen Platzhalter.

Doch woher soll das Script nun wissen, welche Funktionen aufzurufen sind? Dies ist eigentlich ganz einfach. Beim ersten Aufruf des Scripts wird die Einstiegsseite der Webseite ausgegeben. Dies kann eine beliebige Willkommensnachricht oder auch etwas anderes sein. Auf jeden Fall gibt es nun die Navigationsleiste aus, mit der der Benutzer durch die Webseite navigieren kann. Als Verweisziel der einzelnen Links wird dabei immer wieder das eigene Script angegeben. Sobald nun ein Link ausgewählt wird, übergibt sich das Script selbst ein Kommando, indem es das Kommando über die URI übergibt. Das Kommando wird interpretiert, und dann wird der entsprechende Inhalt erzeugt.

Das auszuführende Kommando wird mit einer switch-Anweisung überprüft. Je nachdem, welches Kommando übergeben worden ist, tritt nun ein anderer Fall ein. Dementsprechend wird eine der Funktionen aus der functions.inc.php aufgerufen und der erzeugte Inhalt in einer Variablen zwischengespeichert. Zum Schluss wird der entsprechende Platzhalter durch den Wert der Variablen ersetzt.

Neben dem Kommando muss gelegentlich jedoch noch ein weiterer Wert übergeben werden, und zwar die ID bzw. der Primärschlüssel eines beliebigen Datensatzes einer beliebigen Tabelle der Datenbank. Diese ID wird dann der aufzurufenden Funktion übergeben. Die Funktion gibt dann immer den gewünschten Datensatz zurück. Auf diese Weise kann so z. B. eine Übersicht der Artikel erzeugt werden, und durch einen Klick auf einen der Artikel wird dieser dann ausgegeben.

Die Datei index.php sieht folgendermaßen aus:

<?php

  /* �bergebene Variablen auslesen */
  $cmd = $_GET['cmd'];
  $id = $_GET['id'];
  
  /* Konfigurationsdateien laden */
  include('inc/base.inc.php');
  include('inc/functions.inc.php');

  /* Template einlesen  */
  $template = get_file_as_string($base['template']);
  
  /* Inhalt laden */
  switch(strtolower($cmd))
  {
    default:
    case 'news':
      $base['content'] = '<h4>'.$base['actual'].'<i>News</i></h4>';
      $base['content'] .= load_content_news();
      break;
    case 'newsdet':
      $base['content'] = '<h4>'.$base['actual'].'<i>News / Detailansicht</i></h4>';
      $base['content'] .= load_content_newsdetailed($id);
      break;
    case 'downloads':
      $base['content'] = '<h4>'.$base['actual'].'<i>Downloads</i></h4>';
      $base['content'] .= load_content_downloads();
      break;
    case 'downloadsdet':
      $base['content'] = '<h4>'.$base['actual'].'<i>Downloads / Detailansicht</i></h4>';
      $base['content'] .= load_content_downloadsdetailed($id);
      break;
    case 'articles':
      $base['content'] = '<h4>'.$base['actual'].'<i>Artikel</i></h4>';
      $base['content'] .= load_content_articles();
      break;
    case 'articlesdet':
      $base['content'] = '<h4>'.$base['actual'].'<i>Artikel / Detailansicht</i></h4>';
      $base['content'] .= load_content_articlesdetailed($id);
      break;
    case 'links':
      $base['content'] = '<h4>'.$base['actual'].'<i>Links</i></h4>';
      $base['content'] .= load_content_links();
      break;
    case 'admin':
      header('Location: admin/index.php');
      break;
  }
  
  /* Platzhalter ersetzen */
  $template = str_replace($base['tag_start'].'title'.$base['tag_end'],$base['title'],$template);
  $template = str_replace($base['tag_start'].'shortnav'.$base['tag_end'],$base['shortnav'],$template);
  $template = str_replace($base['tag_start'].'navigation'.$base['tag_end'],$base['navigation'],$template);
  $template = str_replace($base['tag_start'].'content'.$base['tag_end'],$base['content'],$template);
  $template = str_replace('$PHP_SELF',$PHP_SELF,$template);
  
  /* Template ausgeben */
  echo stripslashes($template);

?>

Listing 4.1: Die Datei index.php

Sobald das Script aufgerufen wurde, wird versucht, den beiden Variablen $cmd und $id die über die URI möglicherweise übergebenen Parameter zuzuweisen. Wurde kein Parameter übergeben, erhalten die Variablen einen leeren Wert.

Im nächsten Schritt werden dann die Konfigurationsdateien geladen. Dies ist zum einen die base.inc.php und zum anderen die functions.inc.php. Die base.inc.php wird benötigt, da in dieser Datei eine Funktion definiert wurde, die eine Datei als einen einzigen String einliest. Da die functions.inc.php die Funktionen enthält, um den Inhalt zu erzeugen, wurde auch die Datei bereits an dieser Stelle eingebunden. In der index.php erfolgt kein Datenbankzugriff, deshalb muss auch die Datei database.inc.php nicht eingebunden werden.

# Template einlesen

Nun wird das Template eingelesen. Hierfür wird die Funktion get_file_as_string verwendet. Diese liest die als Parameter übergebene Datei ein und gibt sie als String zurück. Die Funktion sieht folgendermaßen aus:

function get_file_as_string($filename)  
{  
  $tmprslt = file($filename);  
  $tmprslt = implode('',$tmprslt);  
  return $tmprslt;  
}

Neu wird für Sie die Anweisung file sein. Dies ist eine PHP-Funktion, die eine Datei vollständig einliest und als Array zurückgibt.

array file(string filename)

Im nächsten Schritt wird das Array mit der implode-Funktion zu einer einzigen Zeichenkette zusammengesetzt und mit return zurückgegeben.

# Inhalt laden

In der index.php folgt nun die Interpretation des Kommandos mit Hilfe eines switch-Konstrukts. Dabei wird $cmd als zu überprüfende Variable verwendet und mit strtolower in Kleinbuchstaben umgewandelt. Für jedes erlaubte Kommando wurde ein Fall definiert. Je nach Fall wird dann eine entsprechende Funktion aufgerufen. An das Element mit dem Schlüssel content des Arrays $base wird daraufhin eine kurze Zeichenkette angehängt, die dem Benutzer zeigt, wo er sich gerade befindet, und außerdem der erzeugte Inhalt der aufgerufenen Funktion. Sollte keiner der Fälle eintreffen, wurde mit der default-Anweisung festgelegt, dass dann die Startseite angezeigt wird.

# Platzhalter ersetzen

Im nächsten Schritt werden die Platzhalter durch die entsprechenden Zeichenketten ersetzt. Zwar ließe sich dieser Teil des Scripts um einiges übersichtlicher gestalten, auf diese Art lässt sich aber besser nachvollziehen, was genau geschieht. Und zwar werden mit der Funktion str_replace einfach die Platzhalter ersetzt.

# Template ausgeben

Ganz zum Schluss wird dann die Seite mit einer echo-Anweisung ausgegeben. Neu ist auch die PHP-Funktion stripslashes. Sie entfernt vor Sonderzeichen einen möglichen Backslash, der das Sonderzeichen entwerten könnte.

string stripslashes(string str)

# Die Datei functions.inc.php

Alle Funktionen, die in der Datei functions.inc.php definiert wurden, besitzen den gleichen Aufbau. Zunächst wird die database.inc.php eingebunden, da die Konfigurationsdaten für den Zugriff auf die Datenbank benötigt werden. Dann wird versucht, eine Verbindung zur Datenbank aufzubauen. Wenn dies erfolgreich war, wird die korrekte Datenbank ausgewählt und eine SQL-Anweisung ausgeführt, die die benötigten Datensätze ausliest. Anschließend werden die Datensätze für die Ausgabe formatiert und mit einer return-Anweisung zurückgegeben.

Da die functions.inc.php hier vollständig abgedruckt mehrere Seiten einnehmen würde, werde ich Ihnen lediglich eine der Beispielfunktionen erläutern.

/* Gesamtübersicht der Artikel laden */  
function load_content_articles()
{
  include('inc/database.inc.php');
  $tmprslt = '';
  $connection = mysql_connect($db['host'],$db['uid'],$db['pwd']);
  if($connection)
  {
    mysql_select_db($db['db']);
    $sql = 'SELECT id, title, UNIX_TIMESTAMP(datetime) AS datetime FROM articles WHERE visible > -1 ORDER BY datetime ASC';
    $result = mysql_query($sql);
    if($result)
    {
      while($articles = mysql_fetch_object($result))
      {
        $tmprslt .= StrFTime('%d.%m.%Y %H:%M:%S ',$articles->datetime);
        $tmprslt .= "<a href=\"$PHP_SELF?cmd=articlesdet&id=$articles->id\">$articles->title</a><br>\n";
      }
    }
    mysql_close();
  }
  return $tmprslt;
}

Die Funktion load_content_articles lädt eine Übersicht aller verfügbaren Artikel. Zuerst wird die database.inc.php geladen und dem String $tmprslt eine leere Zeichenkette zugewiesen. Dieser String wird benötigt, um den Rückgabewert zwischenzuspeichern, damit die Ausgabe erst am Ende erfolgt.

Im nächsten Schritt wird mit mysql_connect versucht, eine Verbindung zur Datenbank aufzubauen. Wenn dies erfolgreich war, wird die korrekte Datenbank mit mysql_select_db ausgewählt und anschließend eine SELECT-Anweisung mit mysql_query ausgeführt.

Wenn die SQL-Anweisung eine Ergebnismenge liefert, werden die Datensätze nacheinander abgearbeitet und als Objekt $articles zur Verfügung gestellt. Innerhalb des Anweisungsblocks der Schleife wird dann die Ausgabe erzeugt und an $tmprslt angehängt. Damit ein Artikel auch ausgewählt werden kann, wird der Titel des Artikels als Link ausgegeben. Dieser Link ruft dann wieder das eigene Dokument auf, übergibt das Kommando articlesdet (für die Detailansicht eines Artikels) und die ID des anzuzeigenden Artikels.

Schlussendlich wird dann die Datenbankverbindung wieder geschlossen und $tmprslt mit einer return-Anweisung zurückgegeben.

Alle anderen Funktionen sind ebenfalls so aufgebaut, nur dass einige von ihnen (diejenigen, die auf detailed enden) zusätzlich die ID des auszugebenden Datensatzes übergeben bekommen.

# Die Datei base.inc.php

Der Vollständigkeit halber wird hier der Inhalt der Datei base.inc.php gezeigt:

<?php

  /* Konfigurationsvariablen */
  $base['title'] = 'MiniCMS';
  $base['shortnav'] = '<a href="$PHP_SELF">Startseite</a> &middot; <a href="$PHP_SELF?cmd=news">News</a> &middot; <a href="$PHP_SELF?cmd=downloads">Downloads</a>';
  $base['navigation'] = '<a href="$PHP_SELF">Startseite</a><br><a href="$PHP_SELF?cmd=news">News</a><br><a href="$PHP_SELF?cmd=downloads">Downloads</a><br><a href="$PHP_SELF?cmd=links">Links</a><br><a href="$PHP_SELF?cmd=articles">Artikel</a>';
  $base['content'] = '';
  $base['actual'] = 'Sie sind hier: ';
  $base['template'] = 'templates/main.htm';

  $base['adm_title'] = 'MiniCMS - Admin';
  $base['adm_shortnav'] = '<a href="$PHP_SELF?cmd=news">News</a> &middot; <a href="$PHP_SELF?cmd=downloads">Downloads</a> &middot; <a href="logout.php">Logout</a>';
  $base['adm_navigation'] = '<a href="$PHP_SELF?cmd=news">News</a><br><a href="$PHP_SELF?cmd=downloads">Downloads</a><br><a href="$PHP_SELF?cmd=links">Links</a><br><a href="$PHP_SELF?cmd=articles">Artikel</a><br><br><a href="logout.php" class="red">Logout</a>';
  $base['adm_content'] = '';
  $base['adm_actual'] = 'Sie sind hier: ';
  $base['adm_template'] = '../templates/admmain.htm';

  $base['tag_start'] = '<@';
  $base['tag_end'] = '@>';

  /* Hilfsfunktionen */

  /* Datei als String einlesen */
  function get_file_as_string($filename)
  {
    $tmprslt = file($filename);
    $tmprslt = implode('',$tmprslt);
    return $tmprslt;
  }

?>

Listing 4.2: Die Datei base.inc.php

# Die Datei database.inc.php

Zum Abschluss wird hier der Inhalt der Datei database.inc.php ausgegeben.

<?php

  $db['host'] = 'localhost';
  $db['uid'] = '';
  $db['pwd'] = '';
  $db['db'] = 'project';

?>

Listing 4.3: Die Datei database.inc.php

# Das Projekt im Einsatz

Sobald der Benutzer nun die Webseite aufruft, wird die Startseite geladen, da keinerlei Parameter übergeben wurden. Momentan werden auf der Startseite lediglich die News angezeigt. Dann kann der Benutzer entweder über die Navigationsleiste oder über die Kurznavigation eine Rubrik auswählen und sich den Inhalt ansehen. Für den Benutzer könnte das im Browser dann folgendermaßen aussehen:

Die Ausgabe des CMS im Browser
Abbildung 4.1: Die Ausgabe des CMS im Browser