3. Workshop: Notizbuch in PHP mit mySQL (von Michael Christoph)
Hat jetzt bloß keiner meinen Workshop zu PHP in der letzten AMIGA aktuell
gelesen oder hat sich jeder darauf verlassen, dass schon irgendjemand auf
den Aufruf antwortet? Fakt ist, dass keine einzige Reaktion erfolgte! Somit
ist es natürlich für mich, wie auch die anderen Artikelschreiber, schwierig
zu erfahren, worüber man schreiben soll, damit es euch interessiert.
* ALSO WEITER MIT mySQL
Da jedoch mySQL recht populär ist und auch als Portierung für den Amiga
vorliegt, wird es wohl den einen oder anderen doch interessieren.
mySQL-Logo:
Also gibt es diesmal als Fortsetzung zum Kalender eine Notizfunktion.
Die komplette Datenverwaltung überlassen wir dabei der mySQL-Datenbank.
* DIE UMGEBUNG KOMMT ZUERST
Diesmal vorweg ein paar einführende Worte über den Aufbau und die
Funktionsweise. Als "notizbuch.html" ist eine Einstiegsseite definiert, die
Frames benutzt. Dadurch muss nicht immer die komplette Seite neu aufgebaut
werden, sondern es kann ein Teil ausgetauscht werden (bei uns die Notizen
rechts). Der linke Frame enthält ein leicht erweitertes PHP-Skript des
Kalenders, genannt "notizkalender.php". Jede einzelne Monatszahl ist jetzt
ein Link in der Form:
<a href="notizeintrag.php?tag=$tag&monat=$monat&jahr=$jahr" target=''> [hier steht die Monatszahl] </A>
Beim Anklicken der Zahl wird also der Link geladen beziehungsweise unser
neues Skript "notizeintrag.php" aufgerufen. Übergeben werden in URL-
Notation die einzelnen Parameter: Tag, Monat und Jahr. Mittels ‚target‘
wird der Frame definiert, in dem das Ergebnis angezeigt werden soll (also
die rechte Fensterhälfte).
Zusätzlich wurde der Kalender noch so abgeändert, dass der Vorgängermonat
über dem Kalender und der Nachfolgemonat unter dem Kalender platziert wird,
und nicht mehr links/rechts davon. Eine Erweiterungsmöglichkeit wäre zum
Beispiel, mehrere Monate im Voraus auszugeben (einfach mittels for-
Schleife).
* DAS IST NEU
Wenden wir uns jetzt der neuen Datei "notizeintrag.php" zu. Es handelt sich
wieder um PHP-Code, wie die Endung bereits verrät. Neu ist vor allem die
Benutzung der mySQL-Funktionen.
* MEHR ZU mySQL GIBT'S DORT
Auch hierfür möchte ich Interessierte wieder auf das Amiga Magazin 08/2001
beziehungsweise online http://www.meicky-soft.de/amiga-magazin/mysql.html
verweisen. Dort habe ich ausführlich die Installation von mySQL am Amiga
beschrieben. Auch Datenbankdesign und SQL sind dort Themen des zweiten
Kursteiles.
* EINE DATENBANK MUSS HER
Bevor die Notizdatenbank benutzt werden kann, muss sie erst einmal
definiert werden. Da in der Amiga-Portierung das "CREATE DATABASE" Kommando
nicht korrekt funktioniert, ist mittels "makedir <datenbankname>" ein
Verzeichnis für die neue Datenbank anzulegen. Standardmäßig hat dies im
Verzeichnis "mysql:data/" zu erfolgen (wenn nicht anders in my.cnf
definiert).
Als nächstes muss noch die eigentliche Tabelle (die umgangssprachlich auch
gern als Datenbank bezeichnet wird) angelegt werden. Zum Beispiel
CREATE TABLE notizbuch (id INT NOT NULL AUTO_INCREMENT,
datum DATE,
uhrzeit TIME,
text CHAR(100),
PRIMARY KEY(id)
);
Mögliche Datentypen sind (unter anderem) INT für Zahlen, REAL für
Fließkommazahlen, DATE für Datumswerte, TIME für Zeitwerte, CHAR für eine
definierte Anzahl an Zeichen. VARCHAR kann dynamisch bis zu 4096 Zeichen
aufnehmen.
Jeder Satz erhält bei uns eine eindeutige Nummer (id). Damit wird er für
Änderungen oder zum Löschen gefunden. Die Nummer wird automatisch von mySQL
vergeben (der letzte Tabelleneintrag wird um eins erhöht). Für schnelleren
Zugriff erklären wir dieses Feld auch als Indexfeld. PRIMARY legt außerdem
fest, dass jede 'id' nur einmal benutzt werden kann, also nicht zwei Sätze
mit identischer 'id' vorhanden sein können.
* EINE VERBINDUNG ZUR DATENBANK MUSS HERGESTELLT WERDEN
Mittels mysql_connect() wird eine Verbindung zum Datenbankserver
hergestellt. Alternativ gibt es das mysql_pconnect()-Kommando, das eine
persistente Verbindung herstellt. Das heißt, wenn mehrmals auf die
Datenbank zugegriffen werden soll, bleibt die Verbindung bestehen und wird
nicht immer neu aufgebaut.
Beide Funktionen erwarten den Namen des Hosts, einen Benutzernamen und
dessen Passwort. Da alle diese Werte im Klartext übergeben werden müssen,
sollten sie nicht direkt im PHP-Skript abgelegt werden, sondern per
include-Anweiung eingebunden werden. Die separate Datei mit diesen Werten
muss außerdem außerhalb des normalen Webspaces liegen (in der Regel htdocs-
Verzeichnis). Nur so ist sichergestellt, dass niemand von außen per HTTP
oder FTP auf die Datei zugreifen und deren Inhalt lesen kann.
Wenn die Verbindung hergestellt werden konnte, liefert die Funktion einen
positiven Wert. Dann muss nur noch die Datenbank ausgewählt werden, mit der
gearbeitet werden soll. Im Fehlerfall wird lediglich ein entsprechender
Hinweis ausgegeben und das PHP-Skript abgebrochen.
$connID = @mysql_pconnect($mysqlhost, $mysqluser, $mysqlpasswd);
if($connID)
{
mysql_select_db($mysqldatabase); /* Datenbank connectieren */
return( $connID );
}
else
{
echo "<BR><font color='red'>Keine Verbindung zur Datenbank möglich !</font><BR>\n";
echo "Fehlerursache: " . mysql_error() . "<BR>\n";
exit(); /* Skript abbrechen */
}
* UND SCHON KANN DER TABELLENINHALT ANGEZEIGT WERDEN
Mittels SELECT wird in mySQL nach Datensätzen gesucht. Dabei können auch
sehr komplexe Suchbedingungen und Gruppierungsanweisungen verwendet werden.
Zusätzlich können auch noch Verknüpfungen mit anderen Tabellen ins Spiel
kommen (JOIN). Wir beschränken uns jedoch auf eine ganz einfache Syntax:
Alle Einträge zu einem Datum sollen angezeigt werden. Die zugehörigen Daten
liefert der Aufruf von
SELECT * FROM notizbuch WHERE datum = '$suchdatum' ORDER BY uhrzeit;
wobei die gefundenen Treffer nach der Uhrzeit sortiert ausgegeben werden
sollen. Im PHP-Code muss das ganze noch in eine mysql_query() gepackt
werden.
Weitere benötigte Funktionen sind
- mysql_num_rows : liefert die Anzahl an Treffern (Zeilen)
- mysql_fetch_object : liefert einen kompletten Datensatz
Jetzt muss nur noch eine Tabelle im HTML-Code ausgespuckt werden, damit
eine saubere Formatierung im Browser möglich ist. Dabei werden die
gefundenen Daten als Formular aufbereitet, so dass jederzeit einfach
Änderungen an den Einträgen möglich sind.
Zuerst kommt jetzt der PHP-Code für die ganze Datenbankabfrage:
/* ab hier Anzeige des Tabelleninhalts (der Notizen) */
if(isset($jahr))
{
$suchdatum = date("Y-m-d",mktime(0,0,0,$monat,$tag,$jahr));
/* formatieren als jahr-monat-tag */
echo "Eintragungen für\n<H1>$tag. $monatstr[$monat] $jahr</H1><BR><BR>\n";
echo "<table border=0>\n";
echo " <tr><th>Uhrzeit</th><th>Eintragung</th><th>Aktionen</th></tr>\n";
/* Datenbankabfrage starten */
$result = mysql_query("SELECT * FROM notizbuch WHERE datum = '$suchdatum' ORDER BY uhrzeit");
if($result)
{
/* Anzahl Zeilen ermitteln */
$rows = mysql_num_rows($result);
if($rows > 0)
{
/* Tabellen-Inhalt ausgeben */
while($dbentry = mysql_fetch_object($result))
{
eintrag_zeigen($dbentry->id,
$dbentry->datum,
substr($dbentry->uhrzeit,0,5), /* Sekunden weg */
$dbentry->text);
}
}
else
{
echo "<tr><td colspan=3><i>keine Eintragungen vorhanden</i></td></tr>\n"; }
}
//else: Datenbank existiert nicht oder SQL-Fehler
/* entfernt die Ergebnisdaten aus dem Speicher */
mysql_free_result($result);
Fehlt uns noch die Funktion eintrag_zeigen(), die einen einzelnen
gefundenen Datensatz als Formular aufbereitet erzeugt:
function eintrag_zeigen($dbid,$dbdatum,$dbuhrzeit,$dbtext)
{
echo "<tr>\n";
echo "<form name='notizbuch_$dbid' action='notizeintrag.php' method='post'>\n";
echo " <td><input type=text name='uhrzeit' value='$dbuhrzeit' maxlength=5></td>\n";
echo " <td><input type=text name='text' value='$dbtext' maxlength=100></td>\n";
echo " <td><input type=hidden name='datum' value='$dbdatum'>\n";
echo " <input type=hidden name='id' value='$dbid'>\n";
echo " <input type=submit name='form_loeschen' value='löschen'>\n";
echo " <input type=submit name='form_aendern' value='ändern'>\n";
echo " </td>\n";
echo "</form>\n";
echo "</tr>\n";
}
Die beiden 'hidden'-Felder werden nicht im Browser angezeigt, sondern
dienen uns lediglich als Merkfeld. Zum einen für die Datensatznummer und
zum anderen für das Tagesdatum. Ein Eintrag kann also nur innerhalb des
aktuellen Tages durch Änderung der Uhrzeit verschoben werden, nicht aber
auf einen anderen Tag. Die beiden 'submit'-Einträge erzeugen einen Button
im Browser, mit dem die Änderungen in die Tabelle zurückgeschrieben werden
können oder ganz aus der Tabelle gelöscht werden.
Fehlt uns also nur noch die Möglichkeit, auch Daten in die Tabelle hinein
zu bekommen. Dazu wird ganz einfach am Ende ein leeres Formular erzeugt und
mit einem passenden Button versehen:
echo "<tr>\n";
echo "<form name='notizbuch_0' action='notizeintrag.php' method='post'>\n";
echo " <td><input type=text name='uhrzeit' value='' maxlength=5></td>\n";
echo " <td><input type=text name='text' value='' maxlength=100></td>\n";
echo " <td><input type=hidden name='datum' value='$suchdatum'>\n";
echo " <input type=hidden name='id' value='0'>\n";
echo " <input type=submit name='form_neu' value='neu erfassen'>\n";
echo " </td>\n";
echo "</form>\n";
echo "</tr>\n";
* DIE BUTTONS BRAUCHEN EINEN VERTEILER
Wenn einer der Buttons angeklickt wird, wird das Formular an uns selbst
geschickt (bewirkt der Teil action='notizeintrag.php'). Man könnte hier
zwar auch eine andere Datei verwenden, da aber auch bei
Änderungen/Löschungen die Notizeinträge wieder am Bildschirm angezeigt
werden sollen, bietet es sich geradezu an, alles in einer Datei
zusammenzufassen.
Allerdings wird ein Unterscheidungsmerkmal benötigt, mit dem wir
feststellen können, ob wir durch Anklicken eines Datums oder Buttons
aufgerufen wurden. Eine ganz einfache Möglichkeit stellt hierbei das 'id'-
Feld dar. Bei den Aktionen Neu, Bearbeiten und Löschen ist dieses immer
vorhanden, während es bei der Auswahl des Tagesdatums nicht da ist.
In einer zweiten Abfrage kann dann unterschieden werden, welche Aktion
genau zu erfolgen hat.
/* wurde ein Formular übergeben? */
if(isset($id))
{
if(isset($form_neu)) eintrag_neu($datum,$uhrzeit,$text);
if(isset($form_aendern)) eintrag_aendern($id,$datum,$uhrzeit,$text);
if(isset($form_loeschen)) eintrag_loeschen($id);
/* zur anzeige unten wird das Datum wieder zerlegt erwartet */
/* mit substr() wird der String zerlegt und */
/* mit sprintf() evtl. führende Nullen entfernt */
$jahr = sprintf("%d",substr($datum,0,4));
$monat = sprintf("%d",substr($datum,5,2));
$tag = sprintf("%d",substr($datum,8,2));
}
Nach jeder dieser Aktionen soll auch wieder der aktuelle Tabelleninhalt
angezeigt werden. Problematisch dabei ist jedoch, dass die Felder tag,
monat und jahr nicht mehr existieren - sie werden nur vom Kalender
mitgeliefert.
Eine Möglichkeit wäre nun, diese drei Felder in weiteren hidden-Einträgen
der Formulare unterzubringen. Da wir aber sowieso das aktuelle Datum haben,
können wir auch einfach dieses zerlegen. Zu beachten ist lediglich, dass es
in amerikanischer Notation vorliegt. Also zuerst das Jahr, dann Monat und
ganz rechts der Tag. Da das Datum mit führenden Nullen erzeugt wird, müssen
wir noch zu einem Trick greifen, um diese wieder zu entfernen. Denn
ansonsten, wird ein "09" als Oktalzahl 9 = nicht möglich/ungültig
betrachtet.
Also wird der Teilstring mittels sprintf() in eine Zahl umgewandelt
(%d = Dezimal). Dabei verschwinden dann die Nullen. Alternativ könnte auch
abgefragt werden, ob das erste Zeichen eine Null ist und dann der String
direkt manipuliert werden.
Nach diesem Ausflug fehlen uns nur noch die oben aufgeführten drei
Funktionen, um neue Einträge in die Tabelle zu schreiben, vorhandene
Tabelleneinträge zu verändern oder Tabelleneinträge zu löschen.
* EINEN NEUEN EINTRAG ERZEUGEN
Um einen neuen Tabelleneintrag zu erzeugen, werden das Datum, die Uhrzeit
und der Text erwartet. Die 'id' wird von mySQL selbständig hochgezählt. Es
hat keine Bedeutung, was als erstes Value übergeben wird. Optional könnte
auch jedes einzelne Feld mittels 'SET <feldname> = <wert>' belegt werden.
Dabei spielt die Reihenfolge keine Rolle, und es müssen auch nicht alle
Felder angegeben werden.
function eintrag_neu($dbdatum,$dbuhrzeit,$dbtext)
{
$result = mysql_query("INSERT INTO notizbuch VALUES(0,'$dbdatum','$dbuhrzeit','$dbtext');");
if($result)
{
/* liefert die Satz-Id, interessiert uns aber nicht weiter */
$newid = mysql_insert_id($result);
}
else
{
echo "<BR><font color='red'>EINFÜGEN WAR NICHT MÖGLICH!</font><BR>\n";
echo "Fehlerursache: " . mysql_error() . "<BR>\n";
}
}
* EINTRAG BEARBEITEN
Wenn ein Eintrag bereits in der Liste war, muss dieser mit REPLACE oder
UPDATE bearbeitet werden. Anhand der 'id' erkennt mySQL automatisch den
Satz, der geändert werden muss. Übergeben werden in diesem Fall alle
Inhalte, wobei sich aber das Datum niemals ändern kann, da der Benutzer nur
die Uhrzeit und den Text im Browser bearbeiten kann.
function eintrag_aendern($dbid,$dbdatum,$dbuhrzeit,$dbtext)
{
$result = mysql_query("REPLACE INTO notizbuch VALUES($dbid,'$dbdatum','$dbuhrzeit','$dbtext');");
if($result)
{
}
else
{
echo "<BR><font color='red'>ÄNDERN WAR NICHT MÖGLICH!</font><BR>\n";
echo "Fehlerursache: " . mysql_error() . "<BR>\n";
}
}
* EINTRAG LÖSCHEN
Das Löschen eines Satzes gestaltet sich recht einfach. Es wird nur ein
eindeutiger Schlüssel benötigt. In unserem Fall ist dies wieder die 'id'.
function eintrag_loeschen($dbid)
{
$result = mysql_query("DELETE FROM notizbuch WHERE id = $dbid;");
if($result)
{
}
else
{
echo "<BR><font color='red'>LÖSCHEN WAR NICHT MÖGLICH!</font><BR>\n";
echo "Fehlerursache: " . mysql_error() . "<BR>\n";
}
}
In allen drei Funktionen wird im Fehlerfall ein kurzer Hinweis im Browser
ausgegeben und die Fehlerursache mittels mysql_error() von mySQL abgefragt.
Damit wäre die komplette Funktionalität beschrieben.
Diese Datei ist im Browser anzugeben
Hiermit wird der linke Kalender erzeugt
Hiermit werden die rechten Eintragungen verarbeitet
Die ausgelagerte Connect-Funktion
* NOCH EIN PAAR GRAFIKEN
Abschließend noch Grafiken der drei verschiedenen Amiga-Browser (Voyager
3.3 konnte ich nicht zum Offline-Betrieb überreden).
AWebII 3.3:
IBrowse-Demo 1.12:
Voyager-Demo 2.95:
Beim Testen ist noch zu beachten, dass der Browser nicht auf seinen Cache
zurückgreift, sondern die Dateien immer frisch vom Server anfordert. Bei
AWeb ist unter Einstellungen/Netzwerkeinstellungen auf der Seite "Puffer"
der Eintrag "überprüfe Pufferkopie" auf "immer" zu setzen. Zwar ist in
jedem Header <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> gesetzt, doch
beachtet kein einziger Amiga-Browser diesen Meta-Tag.
* UND WAS KOMMT DANN?
Das hängt auch von euch, den Lesern ab. Über Zuschriften aller Art freue
ich mich genauso wie Carsten.
Michael Christoph <michael@meicky-soft.de>
|