Sichten teilen

Dynamische Websites sind meist von Datenbanken abhängig. Deren Bestände lassen sich ‘on the fly’ vom Server zu Surfer übertragen. PHP ist eine Skriptsprache, die die Integration von DBMS-Daten in HTML-Dateien erleichtert.

In Pocket speichern vorlesen Druckansicht 19 Kommentare lesen
Lesezeit: 9 Min.
Von
  • Henning Behme
Inhaltsverzeichnis

Was Skriptsprachen im Web angeht, ist Perl nicht alles. Neben dieser Allzwecksprache hat sich PHP auf vielen Sites durchgesetzt, schließlich stecken hinter dem Begriff LAMP nicht zufällig Linux, Apache, MySQL und PHP. Hinter dem rekursiven Akronym steckt ‘PHP: Hypertext Preprocessor’ - und genau das leistet die Sprache, denn anders als Perl verarbeitet PHP Code, der in ‘normales’ HTML eingebettet wird. Das folgende Schnipsel aus einer HTML-Datei gibt das aktuelle Datum aus:

<p>Letzte Veränderung am 
<?php
$today = date("d. m. Y");
echo "$today";
?>
</p>

Dabei sorgen d und m für die Ausgabe der Tage/Monate mit führender Null (andere Optionen sind in der Datei function.date.html im doc-Verzeichnis der PHP-Distribution zu finden). Statt des einleitenden <?php kann es auch <?PHP oder einfach <? heißen. Und neuerdings ist auch die Syntax von Microsofts Active Server Pages (ASP) möglich: <% ... %>. In diesem Artikel benutze ich die erste Variante, vor allem deshalb, weil sie eine XML-konforme Processing Instruction darstellt.

Bei PHP handelt es sich um eine serverseitig arbeitende Skriptsprache, die wie Perl entweder von einem für sich stehenden Interpreter oder von einem Apache-Modul umgesetzt wird (siehe den Artikel auf Seite 48 in iX 6/2000). Interpreter oder Modul erhalten die HTML-Datei mit PHP-Code als Eingabe und liefern reines HTML an den Browser. PHP erkennt ‘seinen’ Code an den oben erwähnten Steuerzeichen (<?php ... ?>).

PHP kann mit einer Reihe von Datenbanksystemen umgehen; hier soll MySQL im Vordergrund stehen. Um auf eine vorhandene MySQL-Datenbank zuzugreifen, ist es wie in Perl notwendig, eine Verbindung aufzubauen, ein Select-Statement an ein Ergebnis zu binden und dies in HTML auszugeben. Das folgende Beispiel geht davon aus, dass eine einzige PHP-Datei das Eingangsformular als HTML darstellt und abhängig von den Benutzereingaben weiter vorgeht.

Mehr Infos

Listing 1: HTML-Formular

<html>
<head>
<title>Suche in iX-Buchbesprechungen</title>
<link title="php" type="text/css" rel="stylesheet"
href="php.css">
</head>

<body>
<h2>Suche in iX-Buchbesprechungen</h2>
<?php

if ($whatsit == "") {
?>
<form method="get"
action="<?php echo $PHP_SELF;?>"
enctype="application/x-www-form-urlencoded"
name="Suchen">
<table>
<tr><td>Schlagwort&nbsp;</td>
<td><input type="text" name="s_schlag"
size="20" maxlength="50"></td>
</tr>
<tr><td>Autor&nbsp;</td>
<td><input type="text" name="s_autor"
size="20" maxlength="50"></td>
</tr>
<tr><td>Verlag&nbsp;</td>
<td><input type="text" name="s_verlag"
size="20" maxlength="50"></td>
</tr>
</table>
<input type="submit" name="whatsit" value="Suchen">
</form>

<?php
} elseif ( $whatsit == "Suchen") {
// Bearbeitung der Eingabe (Listing 2)
}
?>
// HTML-Fuss
</body>
</html>

Nur zur Ausgabe des Formulars in Abbildung 1 kommt es, wenn die Variable $whatsit keinen Wert besitzt; dafür dient die Abfrage am Anfang von Listing 1. Der Wert (Suchen) wird erst in dem Moment gesetzt, in dem ein Benutzer auf den Submit-Knopf klickt, der am Schluss von Listing 1 auf diesen Namen gesetzt ist:

<input type="submit" 
name="whatsit"
value="Suchen">

weist $whatsit den Wert ‘Suchen’ zu, was bewirkt, dass dasselbe Skript durch eine PHP-Variable <?php echo $PHP_SELF;?> erneut aufgerufen wird - diesmal ist $whatsit gesetzt und Bestandteil der Information, die per get (als Methode) übertragen wird. Formularwerte sind über ihren Namen innerhalb von PHP wie andere Variable ansprechbar. Ihnen ist jeweils nur ein Dollarzeichen voranzustellen. Im vorliegenden Fall existieren bis zu vier Variablen: das erwähnte $whatsit sowie die ebenfalls über das Formular erzeugten $s_autor, $s_schlag und $s_verlag.

Die Bearbeitung der Eingabe fehlt in Listing 1; der entsprechende Code enthält die Anfrage an die Datenbank sowie die Ausgabe in HTML - in Listing 2 zu sehen. Für die Verbindung zu MySQL ist Ähnliches erforderlich wie in Perl:

  • Ein Aufruf der Funktion mysql_connect() mit den Parametern für Host, Benutzer und Passwort: mysql_connect($host,$user,$password);. Die sind hier als vorher gesetzt angenommen.
  • Öffnen der gewünschten Datenbank durch mysql_select_db("biblio");.
  • Formulieren der Anfrage durch $my_query = "select [datenfelder] from [tabellen] where [bedingungen]";.
  • Speichern des Ergebnisses in einer Variablen: $my_res = mysql_query($my_query);.
  • Ausgabe der Daten in einer Schleife: while ($this_row = mysql_fetch_row($my_res)) { ... }.
Mehr Infos

Listing 2: MySQL-Anfrage in PHP

  $host="localhost";
$user="admin";
$password="my_db_passwd";

$my_query = "select a.vorname, a.nachname, v.name, v.ort";
$my_query .= ", b.titel, b.untertitel, b.jahr, b.waehrung";
$my_query .= ", b.preis, b.bild, b.seiten, b.id, b.isbn";
$my_query .= ", rez.vorname, rez.nachname";
$my_query .= ", b.rez_monat, b.rez_jahr";
$my_query .= " from autoren a, buecher b, verlage v, rez_aut r,";
$my_query .= " rezensenten rez where ";

if ($s_autor) {
$my_query .= " a.nachname like ";
$my_query .= "'%";
$my_query .= $s_autor;
$my_query .= "%'";
}

if ($s_autor && ($s_schlag || $s_verlag)) {
$my_query .= " and ";
}

if ($s_schlag) {
$my_query .= " b.titel like ";
$my_query .= "'%";
$my_query .= $s_schlag;
$my_query .= "%'";
}

if ($s_schlag && $s_verlag) {
$my_query .= " and ";
}

if ($s_verlag) {
$my_query .= " v.name like ";
$my_query .= "'%";
$my_query .= $s_verlag;
$my_query .= "%'";
}

$my_query .= " and";
$my_query .= " r.buch_id = b.id";
$my_query .= " and";
$my_query .= " a.id = r.autor_id";
$my_query .= " and";
$my_query .= " v.id = b.verlag_id";
$my_query .= " and";
$my_query .= " b.rez_id = rez.id";

$my_query .= " order by a.nachname ";

mysql_connect($host,$user,$password);
mysql_select_db("biblio");

$my_res = mysql_query($my_query);

echo "<table border='2' align='center' cellspacing='0' cellpadding='2'>";
echo "<caption><h1>Suchergebnis für &quot; $s_autor &quot;</h1></caption>\n\n";

while ($this_row = mysql_fetch_row($my_res)) {
printf("<tr><td><img src='get_image.php3?ID=");
echo $this_row[11];
printf("'></td>");
printf("<td>%s %s<br>\n", $this_row[0], $this_row[1]);
printf("<strong>%s</strong><br>\n", $this_row[4]);
printf("%s<br>\n", $this_row[5]);
printf("%s (%s) %s<br>\n", $this_row[3], $this_row[2], $this_row[6]);
printf("%s Seiten<br>", $this_row[10]);
printf("ISBN %s<br>", $this_row[12]);
printf("%s %s<br>\n", $this_row[7], $this_row[8]);
printf("<strong>Rezension:</strong> %s %s \n", $this_row[13], $this_row[14]);
printf("in Heft %s/%s</td></tr>\n", $this_row[15], $this_row[16]);
}
echo "</table>";
mysql_close();

HTML-Ausgabe der MySQL-Anfrage (Abbildung 2)

Listing 2 zeigt ein ausführliches Select-Statement, das unter anderem eine Anfrage enthält, die das Skript in kleinen Schritten zusammensetzt. Im Grunde handelt es sich um eine übliche SQL-Anfrage, die hier lediglich durch die Stückelung auffällt. Nur in der ersten Zeile ist eine Zuweisung durch das Gleichheitszeichen angebracht. Im Übrigen sorgt der Punkt in $my_query .= ...; dafür, dass das dem Gleichheitszeichen Folgende dem Inhalt der Variablen angehängt wird. Einige Formulierungen sehen recht umständlich aus, etwa die Frage nach einem Autorennamen, der von Jokern (%) umgeben ist:

$my_query .= "’%";
$my_query .= $s_autor;
$my_query .= "%’";

Grund für das Zerlegen der Joker- und Anführungszeichen ist, dass PHP bei einem sinnvollerweise kürzeren Ausdruck wie $my_query .= "’%$s_autor%’"; mit den einfachen Anführungszeichen nicht zurecht kommt und einen Fehler liefert.

Insgesamt gliedert sich die Anfrage in zwei Teile: die Auswahl der Felder und die Bedingungen, die erfüllt sein sollen. Da es drei Eingabemöglichkeiten gibt, enthält das Skript in mehreren if-Konstrukten mögliche zusätzliche Bedingungen. Voraussetzung in diesem Skript ist ein Autorenname als Bestandteil der Eingabe. Deswegen sind diese Teile des where nicht von einem if umschlossen wie die beiden anderen Variablen. Für $s_schlag und $s_verlag bekommt die Query nur dann eine Erweiterung des where, wenn die Variable tatsächlich einen Wert besitzt.

Abgesehen von den Variablen enthält die where-Klausel eine Reihe von Bedingungen, für die die Lektüre des Kastens ‘Das Projekt’ auf Seite 53 in iX 6/2000 sicherlich sinnvoll ist. Denn erst, wenn man weiß, welche Relationen warum welche Felder enthalten und wozu die Kreuztabelle ‘rez_aut’ da ist, erschließt sich der Sinn:

where a.nachname like ’%$s_autor%’  
and r.buch_id = b.id
and a.id = r.autor_id
and v.id = b.verlag_id
and b.rez_id = rez.id

Um die richtige Auswahl zu generieren, muss die Buch-ID mit dem Wert von buch_id in der genannten Kreuztabelle übereinstimmen; Auch der Verlagsname soll nur in den Fällen ausgegeben werden, wenn er als ID auch unter verlag_id in der Buchtabelle erscheint. Fehlen solche Bedingungen, landen beispielsweise alle Verlage im HTML-Dokument.

In der while-Schleife, die die Ausgabe besorgt, steckt ein weiterer PHP-Aufruf. Denn das Umschlagbild des jeweiligen Buches ist in MySQL als Blob (binary large object) gespeichert. Um die Abbildung in die Ausgabetabelle zu integrieren, ruft die erste Schleifenzeile die Datei get_image.php3 mit der ID des Buches auf. Die Verzweigung in eine andere PHP-Datei erklärt sich vielleicht bei einem Blick in Listing 3, das vor der Ausgabe der Grafik einen ‘neuen’ Inhaltstyp (Content-Type) deklariert und erst danach die Daten an den Webserver schickt. Dieser Trick - eine zweiten Datei zu benutzen - ist erforderlich, weil eine Datei nur einen Content-Type erzeugen und nicht mitten in der Ausgabe zu einem anderen umsteigen dar.

Mehr Infos

Listing 3: Blob darstellen

<?php
if ($ID != 0) {
$img_query = "select bild from buecher where $ID = id";
$host="localhost";
$user="admin";
$password="my_db_passwd";

mysql_connect($host,$user,$password);
mysql_select_db("biblio");

$my_res = mysql_query($img_query);

if (mysql_affected_rows() > 0) {
header("Content-type: image/jpeg");
print(mysql_result($my_res, 0, "bild"));
}
}
?>

get_image.php3 prüft, ob eine ID vorhanden ist, schickt eine vorgegebene Anfrage an die Tabelle buecher und kontrolliert sicherheitshalber noch, ob die Anzahl der betroffenen Reihen größer als Null ist. In

mysql_result($my_res, 0, "bild")
Mehr Infos

steht der zweite Parameter für das erste Arrayelement von $my_res und der dritte bezeichnet den Namen des Tabellenfeldes, das die Daten enthält. Leider ist der PHP-Dokumentation und -Literatur ein solches Detail nicht zu entnehmen; dort steht lediglich, wie man ‘on-the-fly’ GIF-Bilder generiert. Hilfe brachte die PHP Knowledge Base (siehe den Kasten ‘Web-Ressourcen’), die genau diese Frage klärt.

Was die restlichen Ausgaben angeht, ist ein bisschen Zählen angesagt, denn das Select-Statement gibt die Reihenfolge vor, in der die Werte im Array $this_row stehen. Deshalb enthalten die printf()-Aufrufe jeweils Verweise auf das ‘zuständige’ Element.

Die hier vorgestellte DBMS-Anfrage gibt nur den gesuchten Autorennamen aus. Sollen all seine Autoren Bestandteil der Ausgabe sein, ist eine zusätzliche Query nötig. Dies noch längere Listing ist hier gesondert enthalten.

Mehr Infos

Listing: Vollständige MySQL-Anfrage

<html>
<head>
<title>Suche in iX-Buchbesprechungen</title>
<link title="php" type="text/css" rel="stylesheet"
href="php.css">
</head>

<body>

<h2>Suche in iX-Buchbesprechungen</h2>

<?php

// Formularausgabe, wenn $whatsit ("Suchen") nicht gesetzt
if ($whatsit == "") {

?>
<form method="get"
action="<?php echo $PHP_SELF;?>"
enctype="application/x-www-form-urlencoded"
name="Suchen">

<table>
<tr><td>Schlagwort </td>
<td><input type="text" name="s_schlag"
size="20" maxlength="50"></td>
</tr>
<tr><td>Autor </td>
<td><input type="text" name="s_autor"
size="20" maxlength="50"></td>
</tr>
<tr><td>Verlag </td>
<td><input type="text" name="s_verlag"
size="20" maxlength="50"></td>
</tr>
</table>

<input type="submit" name="whatsit"
value="Suchen">
</form>

<?php
} elseif ( $whatsit == "Suchen") {

// hier beginnt der Suchvorgang: DB-Verbindung aufbauen...
$host="localhost";
$user="my_db_admin";
$password="my_db_passwd";

mysql_connect($host,$user,$password);
mysql_select_db("biblio");

$my_query = "select distinct v.name, v.ort";
$my_query .= ", b.titel, b.untertitel, b.jahr, b.waehrung";
$my_query .= ", b.preis, b.bild, b.seiten, b.id, b.isbn";
$my_query .= ", rez.vorname, rez.nachname";
$my_query .= ", b.rez_monat, b.rez_jahr";
$my_query .= " from autoren a, buecher b, verlage v, rez_aut r,";
$my_query .= " rezensenten rez where ";
$my_query .= " r.buch_id = b.id";
$my_query .= " and a.id = r.autor_id";
$my_query .= " and v.id = b.verlag_id";
$my_query .= " and b.rez_id = rez.id";


// Die drei folgenden if-Konstrukte lauten, wie im Heft,
// etwas umstaendlicher:
// $my_query .= " and upper(a.nachname) like '%";
// $my_query .= strtoupper($s_autor);
// $my_query .= "%'";
// wobei hier a.nachname fuert alle drei Moeglichkeiten
// steht.

if ($s_autor) {
$my_query .= " and upper(a.nachname) like '%" . strtoupper($s_autor) . "%'";
}
if ($s_schlag) {
$my_query .= " and upper(b.titel) like '%" . strtoupper($s_schlag) . "%'";
}
if ($s_verlag) {
$my_query .= " and upper(v.name) like '%" . strtoupper($s_verlag) . "%'";
}

$my_res = mysql_query($my_query);
$my_auth_num = mysql_affected_rows();

// wenn es kein Ergebnis gibt:
if ($my_auth_num < 1) {
echo "<html><head>";
echo "<title>Nichts gefunden...</title>";
echo "</head>";
echo "<h3 align='center'><a href='";
echo $PHP_SELF . "'>Zurück zur Suche";
echo "</a></h3>";
}

// wonach gesucht worden ist:
$s_what = "";
if ($s_autor) { $s_what .= " " . $s_autor; }
if ($s_schlag) { $s_what .= " " . $s_schlag; }
if ($s_verlag) { $s_what .= " " . $s_verlag; }

// Tabelle ausgeben
echo "<table border='2' align='center' cellspacing='0' cellpadding='2'>";
echo "<caption><h1>Suchergebnis für " $s_what "</h1></caption>\n\n";

// Ergebnis auslesen
while ($this_row = mysql_fetch_row($my_res)) {
printf("<tr><td><img src='get_image.php3?ID=");
echo $this_row[9];
printf("'></td><td>");

// wenn nach Autor/inn/en gesucht:
if ($s_autor) {
$my_querya_pre = "select id from autoren where ";
$my_querya_pre .= "upper(nachname) like '%" . strtoupper($s_autor) . "%'";
$my_auth_id_res = mysql_query($my_querya_pre);

while ($auth_row = mysql_fetch_row($my_auth_id_res)) {
printf("%s %s ", $auth_row[1], $auth_row[2]);
}
}

// Query nach den Autoren eines Buches,
// wenn nicht nach Autor/inn/en gesucht:
$my_querya = "select a.id, a.vorname, a.nachname from autoren a, rez_aut r ";
$my_querya .= "where r.buch_id = " . $this_row[9];
$my_querya .= " and a.id = r.autor_id order by a.nachname";

$my_authres = mysql_query($my_querya);

// Ausgabe der Autor/inn/en
while ($auth_row = mysql_fetch_row($my_authres)) {
printf("%s %s ", $auth_row[1], $auth_row[2]);
}

printf("<br><strong>%s</strong><br>\n", $this_row[2]);
printf("%s<br>\n", $this_row[3]);
printf("%s (%s) %s<br>\n", $this_row[1], $this_row[0], $this_row[4]);
printf("%s Seiten<br>", $this_row[8]);
printf("ISBN %s<br>", $this_row[10]);
printf("%s %s<br><br>\n", $this_row[5], $this_row[6]);
printf("<strong>Rezension:</strong> %s %s \n", $this_row[11], $this_row[12]);
printf("in Heft %s/%s</td></tr>\n", $this_row[13], $this_row[14]);
}
echo "</table>";
mysql_close();
}
?>

<!-- Fusszeile -->
<p>Letzte Veränderung am
<?php
$today = date("d. m. Y");
echo "$today";
?>
von <a href="mailto:hb@ix.heise.de">hb</a></p>

</body>
</html>

Der Tipp zur PHP Knowledge Base stammt von Niels Pollem.