Beispiel Terminkalender programmieren

Im Folgenden programmieren wir uns einen Veranstaltungskalender für die eigene Website. Die Termine werden in einer MySQL-Datenbank abgelegt. Der Kalender soll untereinander alle Termine für den aktuellen Monat anzeigen und einen Link zu dem kommenden Monat und zum Vormonat bieten.

Eintragen, Löschen und Ändern der Termine soll möglich sein.

Vorüberlegungen zum PHP-Kalender:

Wir benötigen in der Datenbank folgende Felder:

id: eine eindeutige Nummer, um die Einträge verwalten zu können

datum: an welchem Datum ist der Termin

titel: Für die Kurzanzeige der Titel

beschreibung: großes Textfeld, das alle Informationen zum Termin enthält

Wie legen also als erstes in phpMyAdmin unsere Datenbank Terminkalender an: CREATE DATABASE `terminkalender` ;

Und dann legen wir unsere MySQL-Tabelle mit dem Namen "termine" an:

MySQL-Anweisung: erstellen Datenbank terminkalender
CREATE TABLE `termine` (
  `id` INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  `datum` DATE NOT NULL ,
  `titel` VARCHAR( 256 ) NOT NULL ,
  `beschreibung` BLOB NOT NULL
) ENGINE = MYISAM ;

Zum Testen tragen wir von Hand ein paar Termine ein. Später werden neue Termine über ein Formular eingetragen.

MySQL-Anweisung: 2 Einträge in Datenbank terminkalender
INSERT INTO `termine` (`id`,`datum`,`titel`,`beschreibung`)
VALUES (
NULL , '2012-08-10', 'PHP-Kurs.com besuchen ab 9:00', ''
), (
NULL , '2012-08-16', 'Geburtstag Elke', ''
);

Um jetzt unsere erste Anzeige zu erhalten (wenn es keine Angabe gibt, alle Termine des aktuellen Monats), müssen wir als erstes eine Verbindung zu unserer Datenbank herstellen. Diese Datei nennen wir "termin-konfiguration.php".

Es werden alle benötigten Daten hinterlegt (die MySQL-Zugangsdaten bekommen Sie normalerweise von Ihrem Provider beim Anlegen der Datenbank).

PHP-Quellcode
define ( 'MYSQL_HOST', 'localhost' );
define ( 'MYSQL_BENUTZER', 'root' );
define ( 'MYSQL_KENNWORT', '' );
define ( 'MYSQL_DATENBANK', 'terminkalender' );

Nun bauen wir die Verbindung zu Datenbank auf ? dazu wird mysql_connect die bereits definierten Konstanten übergeben.

Das @ vor mysql_connect unterbindet eventuelle Fehlermeldungen, die den Nutzer nur verunsichern ? sollte der Verbindungsaufbau nicht klappen, überprüfen wir es anhand der anschließenden if-Abfrage.

PHP-Quellcode
$db_link = @mysql_connect (MYSQL_HOST,
                           MYSQL_BENUTZER,
                           MYSQL_KENNWORT);
 
if ( ! $db_link )
{
  // hier sollte dann später dem Programmierer eine
  // E-Mail mit dem Problem zukommen gelassen werden
  // die Fehlermeldung für den Programmierer sollte
  // das Problem ausgeben mit: mysql_error()
  die('keine Verbindung zur Zeit möglich - später probieren ');
}

Beide obigen PHP-Code-Teile in der Datei "termin-konfiguration.php" abspeichern. Beide am Stück:

PHP-Quellcode: termin-konfiguration.php
<?php
define ( 'MYSQL_HOST', 'localhost' );
define ( 'MYSQL_BENUTZER', 'root' );
define ( 'MYSQL_KENNWORT', '' );
define ( 'MYSQL_DATENBANK', 'terminkalender' );
 
$db_link = @mysql_connect (MYSQL_HOST,
                           MYSQL_BENUTZER,
                           MYSQL_KENNWORT);
 
if ( ! $db_link )
{
  // hier sollte dann später dem Programmierer eine
  // E-Mail mit dem Problem zukommen gelassen werden
  // die Fehlermeldung für den Programmierer sollte
  // das Problem ausgeben mit: mysql_error()
  die('keine Verbindung zur Zeit möglich - später probieren ');
}
?>

PHP-Terminkalender Hauptprogramm – Termine anzeigen

Es werden nun alle Termine für einen Monat angezeigt. Sollte kein Monat angegeben sein, wird der aktuelle Monat verwendet. Unsere neue Datei nennen wir terminanzeige.php

PHP-Quellcode: Monat zum anzeigen festlegen
// wenn ein Monat angegeben ist, werden die Daten kontrolliert
if ( $_GET['monat'] )
  {
  if ( (INT) $_GET['monat'] > 0 AND (INT) $_GET['monat'] < 13 )
  {
    $monat = (INT) $_GET['monat'];
  }
  else
  {
    // something is wrotten - es wird aktuelle Monat verwendet
    $monat = date("n");
  }
}
else
{
  // ist kein Monat angegeben, wird der aktuelle Monat verwendet
  $monat = date("n");
}

Das Gleiche für das Jahr

PHP-Quellcode: Jahr festlegen
if ( $_GET['jahr'] )
{
  if ( (INT) $_GET['jahr'] > 0 AND (INT) $_GET['jahr'] < 3000 )
  {
    $jahr = (INT) $_GET['jahr'];
  }
  else
  {
    $jahr = date("Y");
  }
}
else
{
  $jahr = date("Y");
}

Und für den Besucher (und für den Programmierer zu Kontrolle) die Ausgabe von Monat und Jahr.

PHP-Quellcode
// Ausgabe vom Monat und dem Jahr
echo "<h1>Terminkalender $monat.$jahr</h1>";

Über die MySQL-Befehl findet die Eingrenzung der Termine auf den gewünschten Monat und das gewünschte Jahr statt.

PHP-Quellcode
$sql = "
    SELECT
      id, datum, titel, beschreibung
    FROM termine
    WHERE
      YEAR(datum) = '$jahr'
    AND
      MONTH(datum) = '$monat'
    ORDER BY datum
";

Die SQL-Anweisung wird über mysql_query ausgeführt – gefolgt von einer Sicherheitsabfrage, ob die Ausführung funktioniert hat.

PHP-Quellcode
$db_erg = mysql_query( $sql );
if ( ! $db_erg )
{
  die('Ungültige Abfrage: ' . mysql_error());
}

Es erfolgt die Ausgabe der Ausgabe der Anzahl der Termine – die Ermittlung funktioniert über mysql_num_rows, wobei bereits die mysql_query-Abfrage im Vorfeld erfolgt sein muss.

PHP-Quellcode
$anzahl_eintraege = mysql_num_rows($db_erg);
echo "<p>Anzahl der Einträge: $anzahl_eintraege</p>";

Wenn es nun mindestens einen Termin gibt, erfolgt die Ausgabe in einer Tabelle (hier kann man bestimmt sich noch am Design austoben ? hier zählt erstmal die Funktion :) )

Die von der Datenbank gelieferten Ergebnisse werden über mysql_fetch_array in einer Array übertragen und per while-Schleife solange durchlaufen, bis alle Einträge ausgegeben worden sind.

PHP-Quellcode: Ausgabe der Daten
echo '<table border="1">';
while ($zeile = mysql_fetch_array( $db_erg, MYSQL_ASSOC))
{
  echo '<tr>';
  echo '<td>'. $zeile['datum'] . '</td>';
  echo '<td>';
  echo '<b>'. $zeile['titel'] . '</b><br>';
  echo $zeile['beschreibung'];
  echo '</td>';
  echo '</tr>';
}
echo '</table>';

Jetzt wird der Speicher geleert und die Verbindung zum MySQL beendet mit:

PHP-Quellcode
mysql_free_result( $db_erg );

Im letzten Schritt möchten wir noch 3 Links haben - einen zum Anzeigen des Folgemonats, einen zum Sprung zum aktuellen Monat, einen Link zum vergangenen Monat. Interessant wird es bei den Jahresübergängen.

PHP-Quellcode: Links erzeugen zum blättern
// Vormonat Kontrolle, ob bereits Januar
if ( $monat == 1 )
{
  $vmonat = 12;
  $vjahr = bcsub ( $jahr, 1 );
}
else
{
  $vmonat = bcsub ( $monat, 1 );
  $vjahr = $jahr;
}
 
echo '<a href="terminanzeige.php';
echo '?monat='. $vmonat;
echo '&jahr='. $vjahr;
echo '">Vormonat</a>';
echo ' | ';
echo '<a href="terminanzeige.php';
echo '?monat='. date("n");
echo '&jahr='. date("Y");
echo '">akt. Monat</a>';
 
echo ' | ';
 
// nächster Monat - Kontrolle, ob bereits Dezember
if ( $monat == 12 )
{
  $nmonat = 1;
  $njahr = bcadd ( $jahr, 1 );
}
else
{
  $nmonat = bcadd ( $monat, 1 );
  $njahr = $jahr;
}
echo '<a href="terminanzeige.php';
echo '?monat='. $nmonat;
echo '&jahr='. $njahr;
echo '">nächster Monat</a>';

Im nächsten Schritt sollen Termine erfasst werden. Dazu benötigen wir ein Formular mit den entsprechenden Feldern ? hierbei wird nun nicht auf Sicherheit geachtet, da die Annahme zugrunde liegt, dass nur berechtigte Personen Termine erfassen, ändern und löschen dürfen. Soll dies auch für unbekannte Benutzer möglich sein (Websitebenutzer), muss unbedingt auf Sicherheit geachtet werden!

Wir geben unser Formular unter der Auflistung aus. Es werden 3 Felder benötigt ? das Datumsfeld, ein Feld für die Terminbeschreibung und ein Textbereich für die ausführliche Fassung.

Dabei sollte bei der Übertragungsmethode method="POST" unbedingt POST gewählt werden, da sonst die Datenmenge (Textbereich für Beschreibung) für GET zu viel werden könnte.

PHP-Quellcode
// Anzeige Formular
echo '<hr />';
echo '<form name="" action="" method="POST">';
 
echo '<p>Datum in der Form JJJJ-MM-TT<br>';
echo '<input type="text" name="termin[datum]" size="10">';
echo '</p>';
 
echo '<p>Kurzbeschreibung<br>';
echo '<input type="text" name="termin[kurzbeschreibung]">';
echo '</p>';
 
echo '<p>ausführliche Beschreibung<br>';
echo '<textarea name="termin[beschreibung]" rows="9" cols="80">';
echo '</textarea></p>';
echo '<input type="hidden" name="vorgang" value="neu">';
echo '<input type="Submit" name="" value="speichern">';
 
echo '</form>';

Im Formular gibt es ein verstecktes Feld mit dem Name "vorgang" - über dieses kann nach Absenden des Formulars angefragt werden, was mit den Daten geschehen soll.

Nun folgt vor der Ausgabe der Tabelle eine Abfrage, ob neue Daten vorhanden sind, und wenn ja, werden diese gespeichert.

PHP-Quellcode: speichern neuer Daten
// Speichern neuer Daten
if ( $_POST['vorgang'] == 'neu' )
{
  speichere_daten ( $_POST['termin'] );
}

Das Speichern erfolgt über den Funktionsaufruf speichere_daten ( $_POST['termin'] ); - durch die Übergabe der Arrays $_POST kann in der Funktion direkt auf die Daten zugegriffen werden. Die praktische Übergabe durch $_POST['termin'] ist auch der Grund für die Schreibweise vorher im Formular mit <input type="text" name="termin[datum]" value="" size="10" maxlength="10">.

Die Funktion nimmt die Daten und speichert diese über die SQL-Anweisung "INSERT ...". Sie sollten noch ein wenig Zeit in die Validierung der Daten stecken - hier zum Lernen soll es ohne Validierung ausreichen.

PHP-Quellcode: Funktion zu Daten speichern
// Daten speichern
function speichere_daten ( $termin )
{
  // hier sollte noch eine Validierung des Datums stattfinden
  $sql = "INSERT INTO termine
  (
    `id`, `datum` , `titel` , `beschreibung`
  )
  VALUES
  (
    NULL ,
    '". $termin['datum'] ."',
    '". $termin['kurzbeschreibung'] ."',
    '". $termin['beschreibung'] ."'
  )
  ";
 
  $db_erg = mysql_query( $sql );
  if ( ! $db_erg )
  {
    die("Ungültige Abfrage: $sql <hr>" . mysql_error());
  }
  else
  {
    echo "<h2>Termin gespeichert</h2>";
  }
}

Im nächsten Schritt wollen wir auch das Löschen von Daten ermöglich. Dazu ergänzen wir die Tabelle noch um eine weitere Spalte, die mit Links versehen wird. In den Links wird über die ID ein eindeutiger Zugriff möglich. Auch hier findet über die Variable "vorgang" eine Steuerung statt.

PHP-Quellcode
echo '<td>';
echo '<a href="terminanzeige.php?vorgang=loeschen&id=';
echo $zeile['id'];
echo '">löschen</a> ';
echo '</td>';

Am Anfang vom Programm erfolgt wieder eine Abfrage, ob die Variable "vorgang" den Inhalt "loeschen" hat. Wenn ja, erfolgt der Aufruf des Löschvorgangs über eine Funktion, der die ID übergeben wird. Da der Aufruf über einen Link stattfindet, muss die Variablenabfrage mit $_GET stattfinden!

PHP-Quellcode:
// Löschen von Einträgen
if ( $_GET['vorgang'] == 'loeschen' )
{
  loeschen_daten ( $_GET['id'] );
}

Die entsprechende Funktion beinhaltet die SQL-Anweisung "DELETE FROM ... WHERE ... LIMIT 1"

Der Zusatz "LIMIT 1" begrenzt den Schaden :) ? es wird maximal ein Datensatz gelöscht.

PHP-Quellcode: Funktion für das Löschen von DS
function loeschen_daten ( $id ) {
  // SQL-Anweisung zusammenbauen
  $sql = "DELETE FROM termine
          WHERE id='$id'
          LIMIT 1
         ";
 
  $db_erg = mysql_query( $sql );
  if ( ! $db_erg )
  {
    die("Ungültige Abfrage: $sql <hr>" . mysql_error());
  }
  else
  {
    echo "<h2>Termin gelöscht</h2>";
  }
}

Hier können Sie den Vorgang erweitern, dass vor dem Löschen erst eine Sicherheitsabfrage stattfindet!

Daten aktualisieren

Um nun Daten ändern zu können, fügen wir in der Tabelle einen weiteren Link hinzu.

PHP-Quellcode
echo '<td>';
echo '<a href="terminanzeige.php?vorgang=aendern&id=';
echo $zeile['id'];
echo '">ändern</a> ';

Am Anfang der Datei erfolgt wieder eine Abfrage und der Funktionsaufruf

PHP-Quellcode
// Daten zum Ändern anzeigen
if ( $_GET['vorgang'] == 'aendern' )
{
  anzeige_daten_zum_bearbeiten ( $_GET['id'] );
}

In der Funktion wird für diesen einen Datensatz über die entsprechende SQL-Anweisung der Inhalt geholt und in einem Formular zum Ändern angezeigt

PHP-Quellcode
function anzeige_daten_zum_bearbeiten ($id)
{
  $sql = " SELECT *
           FROM termine
           WHERE id = '$id'
         ";
 
  $db_erg = mysql_query( $sql );
  if ( ! $db_erg )
  {
    die('Ungültige Abfrage: ' . mysql_error());
  }
 
  $zeile = mysql_fetch_array( $db_erg, MYSQL_ASSOC);
 
  echo '<form action="" method="POST">';
 
  echo '<p>Datum in der Form JJJJ-MM-TT<br>';
  echo '<input type="text" name="termin[datum]" value="';
  echo $zeile['datum'];
  echo '" size="10" maxlength="10">';
  echo '</p>';
 
  echo '<p>Kurzbeschreibung<br>';
  echo '<input type="text" name="termin[kurzbeschreibung]" ';
  echo 'value="';
  echo $zeile['titel'];
  echo '" size="50" maxlength="255">';
  echo '</p>';
 
  echo '<p>ausführliche Beschreibung<br>';
  echo '<textarea name="termin[beschreibung]" rows="9" ';
  echo ' cols="80">';
  echo $zeile['beschreibung'];
  echo '</textarea></p>';
 
  echo '<input type="hidden" name="termin[id]" value="';
  echo $zeile['id'];
  echo '">';
  echo '<input type="hidden" name="vorgang" value="update">';
 
  echo '<input type="Submit" value="Änderung speichern">';
  echo '</form>';
  echo '<hr>';
}

Die Steuerung erfolgt über die beiden versteckten Formularfelder "vorgang" und "id", die am Beginn unseres Scripts abgefragt werden.

PHP-Quellcode
if ( $_POST['vorgang'] == 'update' )
{
  update_daten ( $_POST['termin'] );
}

Und die Funktion zum Speichern der aktualisierten Daten:

PHP-Quellcode
// Daten updaten
function update_daten ( $termin )
{
  // hier sollte noch eine Validierung des Datums 
  // stattfinden
  $sql = "UPDATE termine SET
    `datum` = '". $termin['datum'] ."',
    `titel` = '". $termin['kurzbeschreibung'] ."',
    `beschreibung` = '". $termin['beschreibung'] ."'
  WHERE
    id = '". $termin['id'] ."'
  ";
 
  $db_erg = mysql_query( $sql );
  if ( ! $db_erg )
  {
    die("Ungültige Abfrage: $sql <hr>" . mysql_error());
  }
  else
  {
    echo "<h2>Termin geupdatet</h2>";
  }
}

Damit nach dem Speichern nicht nochmals das Formular angezeigt wird, muss die if-Anweisung für den Vorgang "aendern" ergänzt werden mit:

PHP-Quellcode
// Daten zum Ändern anzeigen
if ( $_GET['vorgang'] == 'aendern' 
     AND 
     $_POST['vorgang'] <> 'update' 
   )
{
  anzeige_daten_zum_bearbeiten ( $_GET['id'] );
}

„Ente“ gut, alles gut und satt

Dies als „kleines“ Tutorial, wie man mit Datenbanken umgehen kann. Das Beispiel in fast 300 Code-Zeilen zeigt eine prinzipielle Vorgehensweise – es fehlen noch Validierungen (damit keine falsche Daten eingegeben werden können), und die Eintrag-, Lösch- und Änderungsfunktionen sollten auf keinen Fall für fremde Websitebesucher zugänglich gemacht werden. Die Anzeige der Termine kann sehr wohl genutzt werden, da dort nur 2 Daten verwendet werden (Monat und Jahr), die validiert werden.

Hier bekommen Sie das Terminkalender-Script an einem Stück, damit die obigen Sprünge nachvollzogen werden können.

Zur Verdeutlichung ein Ablaufdiagramm:

Ablaufdiagramm Terminkalender-Anwendung