Einsatz der Kombination von PHP/FI und mSQL

geschrieben von Uwe Debacher im September 97

Im folgenden Text soll es darum gehen, wie man mit der Programmierumgebung PHP/FI und dem Datenbanksystem mSQL Datenbankanwendungen innerhalb eines Intranetsystems erstellen kann. Es müssen folgende Bedingungen erfüllt sein:

Ein Problem besteht darin, daß hier mit drei verschiedenen Programmen gearbeitet wird, die jeweils ihre eigene Programmiersprache besitzen. Die Befehle müssen aber alle in den gleichen Programmtext eingebunden sein. Grundlage ist immer eine HTML-Seite. Es ist deshalb wichtig zu beachten, an wen sich der jeweilige Programmierbefehl jeweils richtet.

1. Formulare in HTML

Im Text will ich nicht auf die Grundlagen von HTML eingehen. Lediglich auf die Arbeit mit Formularen.
Alle Eingaben, die wir in den folgenden Abschnitten programmieren wollen erfolgen in ein HTML-Formular. Ein Formular besteht mindestens aus den folgenden Tags:
(Kursiv gesetzte Wörter sind Platzhalter für eigene Bezeichner)

<FORM ACTION="auswert.phtml" METHOD="get">
<INPUT TYPE="text" NAME="name" SIZE="Size" MAXLENGTH="Länge">
<INPUT TYPE="submit" VALUE="Absenden">
<INPUT TYPE="reset" VALUE="Verwerfen">
</FORM>

Mit dem Einleitungstag muß ein Programm angegeben werden, das die Eingabedaten auswertet, in diesem Fall ein Programm namens "auswert.phtml". Zusätzlich muß angegeben werden, wie dieses Programm die Daten erhält. Dazu gibt es die Möglichkeiten "get" und "post". Bei der Methode "get" werden die Daten einfach an die URL des Auswertprogrammes angehängt:

auswert.phtml?name=Meier&vorname=Klaus

Bei der Methode "post" sieht man diese Daten nicht, da eine Art Dialog erfolgt. Bei der Programmentwicklung ist die Methode "get" praktischer, im endgültigen Programm ist "post" vorteilhafter.

Die zweite Zeile definiert ein Eingabefeld mit dem Namen "name" und der Größe "Size". Diese Angabe betrifft nur die Darstellung auf dem Bildschirm. Die Maximalzahl der Zeichen die eingegeben werden kann wird auf Länge" festgelegt.

Normalerweise hat ein Formular natürlich mehr als ein Eingabefeld. Die einzelnen Felder werden dabei durch ihre Namen unterschieden.

Wichtig für jedes Formular ist auch ein "Knopf" zum Abschicken. Dazu dient der Typ "submit". Die Daten im Formular werden ausgelesen und an das Auswertprogramm übergeben. Üblich in Formularen ist auch ein "Resetknopf". Klickt man auf diesen Knopf, so werden alle Eingabefelder gelöscht.

1.1 Ergänzungen zu Formularen

Als "action" kann anstelle eines eigentlichen Auswertprogrammes auch eine Mail verschickt werden:
<FORM ACTION="mailto:debacher@lbs.hh.schule.de" METHOD="post">
Das Eingabefeld vom Typ text" erlaubt auch die Angabe eines Wertes, der vorab in das Feld eingetragen wird.
<INPUT TYPE="text" NAME="name" VALUE="Klausi">
Diese Möglichkeit ist besonders dann wichtig, wenn man mittels Formular vorhandene Datensätze ändern möchte.

Es stehen innerhalb eines Formulars nicht nur Eingabezeilen zu Verfügung.

1.2 Hidden

Eine Angabe der folgenden Art:
<INPUT TYPE="hidden" NAME="name" VALUE="Klausi">
bewirkt keinerlei Darstellung auf dem Bildschirm. Dieses Feld wird mit seinem Wert einfach nur an das Auswertprogramm übergeben, ohne daß der Benutzer Eingabe machen kann oder überhaupt etwas von diesem Feld bemerkt. Dieser Tag macht nur Sinn, wenn ein VALUE mit angegeben wird.

1.3 Password

Auch dies ist nur eine Variation des Types Text.
<INPUT TYPE="password" NAME="name">
Hierbei wird der Eingabetext nicht auf dem Bildschirm dargestellt.

1.4 Textarea

Mit diesem Tag wird ein Eingabefeld definiert, dessen Höhe und Breite festgelegt werden müssen
<TEXTAREA NAME="name" ROWS=Höhe COLS=Breite>
</TEXTAREA>
Dem Eingabefeld kann man leider keine Maximalzahl von Zeichen übergeben. Höhe und Breite beziehen sich auf die Bildschirmdarstellung. Innerhalb des Bereiches kann gescrollt werden.

Vorgaben werden hier nicht mit dem value Tag eingetragen, sondern zwischen Anfangs- und Endtag gesetzt.

1.5 Auswahlfelder

Will man keine freie Eingabe zulassen, sondern dem Benutzer nur die Auswahl zwischen vorgegebenen Werten ermöglichen, dann bietet sich die folgende Kombination an:
<SELECT NAME="name" SIZE=Zeilen>
<OPTION VALUE="wert">Beschreibungstext
<OPTION SELECTED VALUE="wert">Beschreibungstext
...
</SELECT>

Hiermit stelle ich dem Benutzer ein Feld zur Verfügung, das mit einem Mausklick geöffnet wird und die angegebenen Einträge zur Auswahl stellt. Nachdem ein Eintrag angeklickt wurde schließt sich das Auswahlfenster wieder.

Ein Wert darf durch Zusatz von SELECTED als voreingestellt gekennzeichnet werden. Dieser Wert erscheint dann auch im geschlossenen Eingabefeld.

1.6 Checkboxen

Die Verwendung von Auswahlfeldern ist sehr platzsparend. Manchmal möchte man aber alle Optionen immer auf dem Bildschirm sehen, dann arbeitet man besser mit Checkboxen
<INPUT TYPE="checkbox" NAME="name1" VALUE="wert1">Text1<br>
<INPUT TYPE="checkbox" NAME="name2" VALUE="wert2">Text2<br>
Für jeden der Einträge taucht auf dem Bildschirm ein ankreuzbares Kästchen auf. Diese Kästchen sind voneinander unabhängig. Es können also z.B. alle Kästchen oder kein Kästchen angekreuzt sein. Läßt man den VALUE-Eintrag weg, so wert im Zweifelsfall der Wert "on" genommen.

1.7 Radiobuttons

Will man erreichen, daß immer nur eine Möglichkeit aus einer Auswahl markiert werden kann, dann arbeitet man besser mit Radiobuttons:
<INPUT TYPE="radio" NAME="name" VALUE="eintrag1">Text1<br>
<INPUT TYPE="radio" NAME="name" VALUE="eintrag2">Text2<br>

Hier haben alle Felder den gleichen Namen aber unterschiedliche Werte.

1.8 Ein kleines Beispiel

Im folgenden Seitenquelltext sind fast alle Möglichkeiten berücksichtig:

<!-- Bespielformular von Uwe Debacher,
erstellt am 18.09.97
letzte Aenderung am 18.09.97 -->
<HTML><HEAD><TITLE>Beispielformular</TITLE></HEAD><BODY>
<CENTER><H1>Beispielformular</H1></CENTER>
<FORM ACTION="auswert.phtml" METHOD="get">

<!-- Ein normales Eingabefeld -->
Wie hei&szlig;t du?<br>
<INPUT TYPE="text" NAME="name" SIZE=20 MAXLENGTH=50>

<!-- Ein Textfeld -->
<p>Sage mir deine Meinung:<br>
<TEXTAREA NAME="meinung" ROWS=3 COLS=60>Ich habe keine eigene Meinung</TEXTAREA>

<!-- Ein Auswahlfeld -->
<p>Welches Verkehrsmittel benutzt du zur Schule?
<SELECT NAME="verkehrsm" SIZE=1>
<OPTION VALUE="b">BUS
<OPTION VALUE="a">Auto
<OPTION SELECTED VALUE="f">Fahrrad
</SELECT>

<!-- Checkboxen -->
<p>Besuchst du einen oder mehrere der folgenden Leistungskurse?:<br>
<INPUT TYPE="checkbox" NAME="mathe">Mathematik
<INPUT TYPE="checkbox" CHECKED NAME="info">Informatik

<!-- Radiobuttons -->
<p>Wie gef&auml;llt dir diese Schule?:<br>
<INPUT TYPE="radio" NAME="urteil" VALUE="s">Sehr gut
<INPUT TYPE="radio" NAME="urteil" CHECKED VALUE="g">Gut
<INPUT TYPE="radio" NAME="urteil" VALUE="m">Mittel
<P><CENTER>
<INPUT TYPE="submit" VALUE="Absenden">
<INPUT TYPE="reset" VALUE="Verwerfen">
</CENTER>
</FORM>
</BODY></HTML>

Netscape macht daraus die folgende Darstellung:

 
Klickt man einfach nur auf Absenden" ohne weitere Eingaben zu machen, so erscheint folgende URL in der Eingabezeile:
http://server/lk/auswert.phtml?name=&meinung=Ich+habe+keine+eigene+Meinung&verkehrsm=f&info=on&urteil=g

Damit sieht man genau welche Daten an das Auswertprogramm übergeben werden.

2. PHP/FI Grundlagen

Bei PHP handelt es sich im Prinzip um eine Erweiterung von HTML. Alle PHTML-Dokumete werden vom Apache-Webserver nach speziellen Programmier-Befehlen durchsucht. Gefundene Befehle werden ausgeführt. Der Benutzer bekommt immer eine normale HTML-Seite geliefert, da alle Befehle schon vom Webserver ausgeführt wurden.

Es ist also wichtig, daß jedes PHTML-Programm immer eine korrekte HTML-Seite zurückliefert.

Eine PHTML-Seite erkennt der Apache an der speziellen Endung .phtml, man kann ihn aber auch so konfigurieren, daß er jede .htm Seite nach entsprechenden Befehlen durchsucht.

PHTML-Befehle werden durch ein einleitendes Fragezeichen kenntlich gemacht:

<? $a=5>

Innerhalb der spitzen Klammern können mehrere (beliebig viele) Befehle stehen, die dann aber immer mit einem Semikolon beendet sein müssen:

<? $a="Hallo Welt";
echo $a>

Der Echo-Befehl bewirkt eine Ausgabe an den Browser.

Dieses kurze Beispiel würde den Text Hallo Welt" auf dem Bildschirm ausgeben. Dabei wird vorausgesetzt, daß um die beiden Zeilen herum der normale HTML-Rahmen vorhanden ist.

Die komplette Seite hat also folgenden Inhalt:

<HTML><HEAD><TITLE>Testprogramm</TITLE></HEAD><BODY>
<CENTER><H1>Testprogramm</H1></CENTER>
<? $a="Hallo Welt";
echo $a>
</BODY></HTML>

2.1 Variablen in PHP

Variablen werden durch ein vorangestelltes $ Zeichen gekennzeichnet. Es gibt drei Variablentypen:

Die Typzuordnung erfolgt automatisch. Die Typzuordnung spielt aber keine sehr große Rolle.

Es gibt aber eine ganze Menge Besonderheiten im Zusammenhang mit Variablen.

$a="Hallo";
$$a="Welt";

Das doppelte $ hat die Bedeutung, daß der Wert von $a als Variablenbezeichner benutzt wird. Die zweite Zeile hat also den gleichen Effekt wie:

$Hallo="Welt";

Noch ungewöhnlicher ist der Umgang mit Arrays. Diese werden dynamisch und sehr flexibel angelegt.

$a[0]="Hallo";
$a[1]="Welt";

legt ein zweidimensionales Feld an, das aber jederzeit erweitert werden kann. Die Definition hätte man auch abkürzen können mittels:

$a[]="Hallo";
$a[]="Welt";

Den Rest denkt sich das System hinzu, wobei der Index jeweils hochgezählt wird.

Natürlich dürfen auch Strings als Index auftauchen:

$a["Hallo"]="Welt;

Zur Arbeit mit Arrays kennt php die Funktionen: Next(), Prev(), Reset(), End() und Key().

2.2 Bedingte Anweisungen

Für bedingte Anweisungen besitzt das System folgendes Konstrukt:

IF (Bedingung);
  Befehle;
ENDIF;

Folgende Variation hat den gleichen Effekt, ist aber weniger lesbar

IF (Bedingung) {;
  Befehle;
};

Auch eine zweiseitige Auswahl ist möglich:

IF (Bedingung);
  Befehle;
ELSE;
 Befehle
ENDIF;

Will man noch mehr Fälle unterscheiden, so ist auch folgende Erweiterung vorhanden:

ELSEIF (Bedingung);
Befehle;

Wichtig ist, daß die Bedingung immer in Klammern gesetzt werden muß. In der Bedingung können folgende Vergleichsoperatoren auftauche:

Innerhalb der Bedingung können mehrere Teilbedingungen verknüpft werden. Dafür gibt es die folgenden Operatoren:

Ein kleines Beispiel:

$a=5;
$b=-3;
IF ($a>0 && $b>0);
 echo "Beide Zahlen sind positiv";
ELSEIF ($a<0 && $b<0);
 echo "Beide Zahlen sind negativ";
ELSE
 echo "Ein dritter Fall";
ENDIF;

2.3 Switch

Für Mehrseitige Auswahlen gibt es in Pascal das CASE. In PHP erreicht man den gleichen Effekt mit SWITCH.

SWITCH(Ausdruck);
CASE wert1;
 Befehle1;
 BREAK;
CASE wert2;
 Befehle2;
 BREAK;
DEFAULT;
 Befehle3;
 BREAK;
ENDSWITCH;

Ein Beispiel findet sich unter 2.5.

2.4 Wiederholungen

Schleifen werden mittels:

WHILE (Bedingung);
 Befehle;
ENDWHILE;

Für jede Wiederholstruktur ist es wichtig, daß die ausgeführten Befehle die Bedingung verändert, sonst läuft die Schleife endlos.

Ein einfaches Beispiel:

$i=0;
WHILE ($i<10);
 echo "$i<p>";
 $i++;
ENDWHILE;

Hiermit werden die Ziffern von 0 bis 9 ausgegeben.

2.5 Ein Programm zur Formularauswertung

Nach diesen Einführungen nun das Programm zur Auswertung unseres Formulars. Das Programm wertet die Daten aus und gibt eine Rückmeldung an den Benutzer:

<!-- Auswertungsprogramm fuer das Bespielformular von Uwe Debacher,
erstellt am 18.09.97
letzte Aenderung am 18.09.97 -->
<HTML><HEAD><TITLE>Auswertung</TITLE></HEAD><BODY>
<CENTER><H1>Auswertung</H1></CENTER>
Hallo <b>
<? IF (!$name);
 $name="Namenlos";
ENDIF;
echo $name>
</b><p>
<? SWITCH($verkehrsm);
 CASE "b";
 echo "Hoffentlich bekommst du im Bus immer einen Sitzplatz";
 BREAK;
CASE "a";
 echo "Wo bleibt das Umweltbewu&szlig;tsein? Fahr doch mit dem Bus";
 BREAK;
DEFAULT;
 echo "Das Fahrrad ist doch ein umweltfreundliches Verkehrsmittel";
 BREAK;
ENDSWITCH>
<p>die Meinung:<br><i>
<?echo $meinung>
</i><br>zeigt deutlich, da&szlig; es dir auf dieser Schule <b>
<? IF ($urteil=="s");
echo "sehr gut";
ELSEIF ($urteil=="g");
echo "gut";
ELSE;
echo "nicht so gut";
ENDIF;>
</b>gef&auml;llt.<p>Als Leistungskurse hast du angegeben:<br>
<? IF ($mathe);
 echo "Mathematik<br>";
ENDIF;
IF ($info);
 echo "Informatik<br>";
ENDIF;>
</BODY></HTML>

Es ergibt sich die folgende Ausgabe:


 
 
 
 
 
 
 
 
 

In dem zugehörigen Listing sind normale HTML-Befehle und PHTML-Befehle sauber getrennt. Man darf sogar innerhalb von Strukturen die PHTML-Sequenz beenden um normale HTML-Befehle einzubinden. Das spart jeweils den Echo-Befehl. Die Trennung hat noch einen weiteren Vorteil. Da im Echo-Befehl Textkonstanten in Anführungsstriche gesetzt werden müssen, machen viele HTML-Tags Probleme, da dort ebenfalls Anführungsstriche auftauchen. Diese inneren" Anführungsstriche müssen dann als \" dargestellt werden, was die Übersichtlichkeit verringert.

Aus:

<A HREF="test.htm">Nur ein Test</A>

würde dann

echo "<A HREF=\"test.htm\">Nur ein Test</A>";

3. mSQL

SQL steht für Structured Query Language, was soviel wie strukturierte Abfragesprache bedeutet. Diese Sprache ist recht weit verbreitet und wird z.B. auch von Ms-Access unterstützt. Das m" steht für Mini, was andeuten soll, daß nicht alle Befehle unterstützt werden.

Bevor wir uns mit der Einbindung von mSQL in das PHP-System kümmern erst einmal eine Zusammenstellung der möglichen mSQL Befehle oder wie es in der Dokumentation heißt Clauses".

Alle Befehle lassen sich auch direkt an mSQL absenden. Dazu muß man in einer Telnet-Sitzung folgendes Programm aufrufen

/usr/local/Hughes/bin/msql datenbankname

In unserem Fall heißt die Datenbank lk. Datenbanken dürfen nur von einem Systemadministrator eingerichtet werden.

3.1 Create

Hiermit wird eine neue Datentabelle in einer vorhandenen Datenbank eingerichtet. Der Name der Datenbank wurde schon vorher festgelegt.

CREATE TABLE tabellen_name (
  feld_name feld_typ [not null]
  [,feld_name feld_typ [not null]]
  [,feld_name feld_typ [not null]]
)

Wird die optionale Angabe not null" gemacht, so darf dieses Feld nicht leer bleiben.

Als Feld Typen stehen u.a. zur Verfügung:

Die Tabelle darf auch über mehrere Indexfelder verfügen, die folgendermaßen definiert werden:

CREATE [UNIQUE] INDEX index_name ON tabellen_name (
 feld_name
 [,feld_name]
)

Die optionale Angabe "unique" bewirkt, daß das entsprechende Feld nicht doppelt vorkommen darf.

Beispiel:

CREATE TABLE telfonliste (
name CHAR(20)
,vorname CHAR(20)
,telefon CHAR(15)
)

3.2 Drop

Drop löscht Informationen. Eine Tabelle wird einfach gelöscht mit:

DROP TABLE tabellen_name

Ein Index wird entsprechend gelöscht mittels:

DROP INDEX index_name FROM tabellen_name

3.3 Insert

Insert dient zum Einfügen von Datensätzen in die Datenbank:

INSERT INTO tabellen_name
 [(feld_name, feld_name, ..)]
VALUES (wert1, wert2,..)

Werden die optionalen Spaltennamen weggelassen, so müssen alle Werte in der richtigen Reihenfolge angegeben werden. Will man nur einige Werte eingeben, so müssen die zugehörigen Spaltennamen angegeben sein.

3.4 Select

Dies ist sicherlich die meistbenutzte clause. Hiermit wird eine vorhandene Datenbank abgefragt. Die (vereinfachte) Syntax lautet:

SELECT feld_name [,feld_name] FROM tabellen_name
[WHERE feld_name vergleichs_operator wert]
[ORDER BY feld_name [DESC]]

Als feld_name nach SELECT ist auch * als Jokerzeichen für alle Felder zulässig. Vergleichsoperatoren können sein:

Beispiele:

SELECT * FROM telefonliste

liefert als Ergebnis die vollständige Tabelle

SELECT * FROM telefonliste ORDER BY telefon

liefert die vollständige Telefonliste sortiert nach Telefonnummern

SELECT name FROM telefonliste

liefert alle Namen aus der Tabelle

SELECT name FROM telefonliste WHERE name SLIKE 'Meier'

liefert die Namen alle Einträge, die wir Meier klingen.

3.5 Delete

Hiermit werden Datensätze einer Tabelle gelöscht:

DELETE FROM tabellen_name
WHERE spalten_name vergleichs_operator wert

Beispiel:

DELETE FROM telefonliste WHERE telefon=4711
 
 

3.6 Update

Aktualisiert einen vorhandenen Datensatz:

UPDATE tabellen_name SET spalten_name=wert
WHERE spalten_name vergleichs_operator wert

Beispiel

UPDATE telefonliste SET telefon='4711' WHERE telefon='0815'
 

4. Einbindung von mSQL in PHP

Will man eine Datenbank ansprechen, so muß zuerst eine Verbindung zum mSQL-Server aufgebaut werden. Dazu dient der Befehl:

msql_connect(hostname)

Solange die Datenbank auf dem gleichen Rechner liegt wie der Webserver kann man hier einfach localhost" angeben. Also

msql_connect("localhost");

Nach Abschluß der Datenbankbenutzung sollte das Programm die Verbindung auch wieder korrekt beenden.

msql_close(hostname)

Gibt man hier keinen Hostnamen an, so werden alle Verbindungen beendet:

msql_close()

4.1 Datenbankbefehle mittels PHP

PHP stellt eine Funktion zur Verfügung, mit deren Hilfe clauses direkt an mSQL weitergegeben werden können.

Dazu dient:

ergebnisvariable=msql(Datenbankname, Abfrage)

konkret könnte das folgendermaßen aussehen:

$result=msql("lk","SELECT * FROM telefonliste");

Die Ergebnisvariable hat den Wert -1 wenn ein Fehler auftrat. Der Fehler kann dann mittels $phperrormsg abgefragt werden.

Falls die Datenbankabfrage erfolgreich war und Ergebnisse zurückliefert, ist die Ergenisvariable ein wichtiger Schlüssel zu Abfrage der Ergebnisse.

Die Zahl der gefundenen Datensätze kann mit

zahl=msql_NumRows(ergebnisvariable)

Beispiel:

$anzahl=msql_NumRows($result)

Nun kann man die Datenfelder einzeln abfragen:

daten=msql_Result(ergebnisvariable, datensatznummer, feld_name)

Beispiel:

$wert=msql_result($result, 0, "telefon");

Hiermit wird die Telefonnummer des ersten Datensatzes zurückgeliefert.

4.2 Weitere Datenbankbefehle

Informationen über die Spalten einer vorhandenen Tabelle kann man folgendermaßen abfragen:

ergebnisvariable=msql_Listfields(datenbankname, tabellenname)

Danach kann man dann die einzelnen Informationen über die Ergebnisvariable erhalten:

msql_NumFields(ergebnisvariable)

msql_FieldLen(ergebnisvariable, feld_nummer)

msql_FieldName(ergebnisvariable, feld_nummer)

msql_FieldType(ergebnisvariable, feld_nummer)