Tutorial: Englische Online-Übungen mit PHP und MySQL c 2004 Jochen Grundmann http://www.online-platform.net Dieser Text unterliegt der GNU General Public License. Er darf als ganzes oder in Auszügen kopiert werden, vorausgesetzt, dass sich dieser Copyright Vermerk auf jeder Kopie befindet. Online-Übungen mit PHP und MySQL Seite 2 1 Online-Übungen mit PHP und MySQL Jeder, der Englisch lernt oder lehrt, weiß wie wichtig es ist, den behandelten Stoff anhand von Übungen zu wiederholen. Kann man sich als Lernender doch dazu durchringen Übungen zu machen, ist häufig niemand da, der die Übungen korrigiert, so dass man nicht weiß, ob, und wenn ja welche, Fehler gemacht wurden. Es gibt zwar unzählige CBTs mit zahlreichen Übungen, die vom Computer korrigiert werden, aber die wirklich guten haben natürlich ihren Preis. Alternativ dazu finden sich auch viele Übungen im Internet, die ebenfalls sofort korrigiert werden. Aber schließlich müssen diese online verfügbaren Übungen auch irgendwo her kommen, jemand muss sie erstellt haben. Auch dazu gibt es mittlerweile eine Reihe von kostenlosen Tools im Internet. Wer sich mit PHP und MySQL auskennt, kann sich solche Übungen aber auch leicht selbst erstellen. In diesem Tutorial möchte ich einige Möglichkeiten aufzeigen, wie man das realisieren kann. Einige Vorkenntnisse über PHP und MySQL sind dabei leider unabdingbar. 1.1 Vokabeltest Als erstes Beispiel möchte ich zeigen, wie man einen einfachen Vokabeltest programmieren kann. Dazu wird zuerst eine neue Datenbank angelegt, die den Namen online_tests bekommt. In dieser Datenbank werden auch die für die weiteren Beispiele benötigten Tabellen angelegt. mysql> create database online_tests; Anschließend wird eine Tabelle mit dem Namen vokabeln_01 in dieser Datenbank angelegt. mysql> -> -> -> -> create table vokabeln_01 ( id int not null auto_increment, englisch varchar (250), deutsch varchar (250), primary key (id)); Diese Tabelle bekommt drei Felder, das erste Feld dient dazu einen Datensatz eindeutig identifizieren zu können und wird deshalb auch als Primärschlüssel definiert, das zweite Feld nimmt die englische Vokabel auf und das dritte Feld die deutsche Übersetzung. c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 3 Anschließend werden einige Beispielvokabeln in die Tabelle eingetragen. mysql> -> -> -> insert into vokabeln_01 (englisch, deutsch) values (’to go’, ’gehen’), (’to see’, ’sehen’), (’to read’, ’lesen’), (’to hear’, ’hören’); Die Tabelle sieht dann wie folgt aus: mysql> select * from vokabeln_01; +----+----------+---------+ | id | englisch | deutsch | +----+----------+---------+ | 1 | to go | gehen | | 2 | to see | sehen | | 3 | to read | lesen | | 4 | to hear | hören | +----+----------+---------+ 4 rows in set (0.00 sec) Wer keinen root-Zugriff auf die Datenbank hat oder nicht so geübt im Umgang mit der Befehlskonsole ist, kann diese Arbeiten natürlich auch mit PHPMyAdmin oder ähnlichen Tools erledigen. Der Vokabeltest soll so funktionieren, dass der Benutzer das deutsche Wort angezeigt bekommt und dahinter in einem Texteingabefeld die englische Entsprechung eingeben muss. Dazu wird zunächst ein PHP Script benötigt, dass die entsprechen Daten aus der Datenbank einliest. Außerdem soll das Script gewährleisten, dass es keine Rolle spielt, wie viele Vokabeln in der Tabelle stehen. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php $server = "127.0.0.1"; $user = "root"; $password =""; $connection = mysql_connect($server, $user, $password); if ($connection) echo "Verbindung zum Server hergestellt<br><br>"; else { echo "Keine Verbindung hergestellt<br>"; exit(); } mysql_select_db("online_tests"); echo "<form action=’vocab.php’ method=’post’>"; $sql = "select * from vokabeln_01"; $result = mysql_query ($sql); c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Seite 4 echo "<table>"; $counter = 1; echo "<tr><td colspan = ’2’> Bitte geben Sie bei Verben das \"to\" mit ein</td></tr>"; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; echo "<tr><td>".$row->deutsch."</td>"; echo "<td><input type = ’text’ name =’$feld’" .$row->englisch."</td></tr>"; } $counter++; echo "<tr><td colspan = ’2’> <input type=’submit’ name=’check’ value=’Check’></td></tr>"; echo "</table></form>"; mysql_close(); ?> Die Zeilen 1 - 12 dienen dazu die Verbindung zum Datenbankserver aufzubauen. Diese Zeilen werden in jedem Script benötigt, in dem auf die Datenbank zugegriffen wird. Deshalb lagere ich diese Zeilen in eine externe Datei aus und binde sie immer über eine include Anweisung ein. Anschließend wird eine Abfrage gestartet, die alle Felder der Tabelle vokabeln_01 ausliest (Zeile 14). Das Ergebnis der Abfrage wird in der Variablen $result gespeichert (Zeile 15)und mit der Funktion mysql_fetch_row in der while-Schleife Zeile für Zeile abgearbeitet (Zeile 19). Der deutsche Begriff wird ausgegeben und daneben ein Texteingabefeld zur Eingabe des englischen Ausdrucks. Damit das Script unabhängig von der Anzahl der Vokabeln in der Tabelle ist, muss für jedes Eingabefeld ein anderer Name generiert werden. Dies geschieht, indem die Variable $counter bei jedem Schleifendurchlauf inkrementiert wird und an den Text "feld" gehängt wird. Das erste Texteingabefeld bekommt dann den Namen feld1, das zweite den Namen feld2 usw. Dieses Script sorgt allerdings nur für die Ein- und Ausgabe der Vokabeln. Eine Auswertung der eingegeben Vokabeln erfolgt noch nicht. Im action Attribut des form Tags wird der Name der Datei angegeben, die für die Auswertung zuständig ist. In dem folgenden Beispiel soll u. a. gezeigt werden, wie die Ausgabe und die Auswertung des Formulars in einer einzigen Datei erfolgen kann. Dazu bedarf es natürlich einiger Änderungen im Script. 1 2 3 4 5 <?php include ("db_connect.php"); if (!$_POST["check"]) { echo "<form action=’vocab.php’ method=’post’>"; c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Seite 5 $sql = "select * from vokabeln_01"; $result = mysql_query ($sql); echo "<table>"; $counter = 1; echo "<tr><td colspan = ’2’> Bitte geben Sie bei Verben das \"to\" mit ein</td></tr>"; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; echo "<tr><td>".$row->deutsch."</td>"; echo "<td><input type = ’text’ name =’$feld’" .$row->englisch."</td></tr>"; $counter++; } echo "<tr><td colspan = ’2’> <input type=’submit’ name=’check’ value=’Check’></td></tr>"; echo "</table></form>"; } else echo "Hier erfolgt die Auswertung"; mysql_close(); ?> Folgende Änderungen sind notwendig: Zunächst wird eine if -Bedingung eingefügt, in der Wert des submit-Buttons abgefragt wird. Auf diesen greift PHP, wie bei allen Formularfeldern, über das name-Attribut zu. Wenn dieser keinen Wert hat (also nicht angeklickt wurde), werden die Anweisungen unter if durchgeführt (das Formular wird angezeigt, Zeilen 4 - 21), ansonsten wird der else-Teil abgearbeitet. Werfen wir jetzt einen Blick auf die Auswertung der eingegebenen Daten in der else-Anweisung. 1 2 3 4 5 6 7 8 9 10 11 12 else { $sql = "select * from vokabeln_01"; $result = mysql_query ($sql); echo "<table>"; $counter = 1; while ($row = mysql_fetch_object ($result)) { echo "<tr><td>"; $feld = "feld".$counter; if ($_POST[$feld] == $row->englisch) echo $_POST[$feld]." ist richtig<br>"; else echo $_POST[$feld]." ist falsch<br>"; c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL 13 14 15 16 17 Seite 6 $counter++; echo "</td></tr>"; } echo "</table>"; } Zunächst werden wieder die Daten aus der Tabelle eingelesen. Da nicht bekannt ist, wie viele Formularfelder vorhanden sind, muss wieder dafür gesorgt werden, dass über eine Variable (in diesem Fall $counter ) fortlaufende Namen erzeugt werden. Dann wird über eine if Anweisung die Eingabe des Benutzers mit dem Wert in der Datenbank verglichen (Zeile 10) und anschließend eine Erfolgs- oder Misserfolgsmeldung ausgegeben. Auf diese Art und Weise lassen sich auch Übungen erstellen, mit denen man unregelmäßige Verben abfragen kann. 1.2 Unregelmäßige Verben Die Tabelle, die für die Speicherung der unregelmäßigen Verben benötigt wird, bekommt insgesamt fünf Spalten, da außer der deutschen Übersetzung die drei Formen eines Verbs erfasst werden müssen. Diese Tabelle wird wie folgt angelegt. mysql> -> -> -> -> -> -> create table irrverbs_01 ( id int not null auto_increment, deutsch varchar (100), form1 varchar (100), form2 varchar (100), form3 varchar (100), primary key (id)); Auch in diese Tabelle werden wieder ein paar Beispieldaten eingetragen. mysql> -> -> -> -> insert into irrverbs_01 (deutsch, form1, form2, form3) values (’gehen’, ’go’, ’went’, ’gone’), (’sehen’, ’see’, ’saw’, ’seen’), (’fangen’, ’catch’, ’caught’, ’caught’), (’fliegen’, ’fly’, ’flew’, ’flown’); c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 7 Die Tabelle sieht dann so aus: mysql> select * from irrverbs_01; +----+---------+-------+--------+--------+ | id | deutsch | form1 | form2 | form3 | +----+---------+-------+--------+--------+ | 1 | gehen | go | went | gone | | 2 | sehen | see | saw | seen | | 3 | fangen | catch | caught | caught | | 4 | fliegen | fly | flew | flown | +----+---------+-------+--------+--------+ 4 rows in set (0.02 sec) Die Übung lässt sich auf verschiedene Arten aufbauen. Man kann den deutschen Begriff vorgeben und alle drei Formen des Verbs abfragen, man kann aber auch mehrere Sachen vorgeben und nur eine oder zwei Formen abfragen, je nachdem, wie schwierig die Übung werden soll. Das folgende Beispielscript gibt den deutschen Begriff und die erste Form des englischen Verbs vor, die anderen beiden Formen sollen geübt werden. 1 2 3 4 5 6 7 8 include ("db_connect.php"); if (!$_POST["check"]) { echo "<form action=’irrverbs.php’ method=’post’>"; $sql = "select * from irrverbs_01"; $result = mysql_query ($sql); echo "<table>"; echo "<tr><td><b>Deutsch</b></td><td><b>Infinitiv </b> </td><td><b>Past</b></td><td><b>Past Participle</b></td></tr>"; 9 $counter = 1; 10 while ($row = mysql_fetch_object ($result)) 11 { 12 $form2 = "form1_".$counter; 13 $form3 = "form2_".$counter; 14 echo "<tr><td>".$row->deutsch."</td>"; 15 echo "<td>".$row->form1."</td>"; 16 echo "<td><input type = ’text’ name =’$form2’" .$row->englisch."</td>"; 17 echo "<td><input type = ’text’ name =’$form3’" .$row->englisch."</td></tr>"; 18 $counter++; 19 } 20 echo "<tr><td colspan = ’2’><input type=’submit’ name=’check’ value=’Check’></td></tr>"; 21 echo "</table></form>"; c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL 22 Seite 8 } Der erste Teil des Scripts unterscheidet sich nur in wenigen Punkten von dem Beispiel für Vokabeltests. Da hier mehrere Felder abgefragt werden, müssen auch mehrere TextEingabefelder eingefügt werden (Zeile 16 - 17). Für jedes einzufügende Text-Eingabefeld wird ein neuer Name generiert, die über die Variablen $form1 und $form2 inkrementiert werden. Wenn bei einer Übung alle drei Formen eines Verbs abgefragt werden sollen, würde man einfach ein drittes Text-Eingabefeld einfügen. Anschließend erfolgt die Überprüfung der Eingabe. 1 2 3 4 5 6 7 else { $sql = "select * from irrverbs_01"; $result = mysql_query ($sql); echo "<table width = ’80%’ border=’0’ align=’center’>"; $counter = 1; echo "<tr><td colspan=’3’align=’center’> <h3> Past </h3></td><td colspan=’3’ align=’center’><h3>Past Participle</h3></td></tr>"; 8 echo "<tr><td><h4>Ihre Eingabe</h4></td><td><h4>Richtige Eingabe</h4></td><td><h4>Ergebnis</h4></td><td><h4> Ihre Eingabe</h4></td><td><h4>Richtige Eingabe</h4></td><td><h4> Ergebnis</h4></td></tr>"; 9 while ($row = mysql_fetch_object ($result)) 10 { 11 $form2 = "form1_".$counter; 12 $form3 = "form2_".$counter; 13 echo "<tr><td>".$_POST[$form2]."</td><td>". $row->form2."</td>"; 14 if ($_POST[$form2] == $row->form2) echo "<td><font color=’blue’>richtig</font></td>"; 15 else echo "<td><font color=’red’>falsch</font></td>"; 16 echo "<td>".$_POST[$form3]."</td><td>".$row->form3."</td>"; 17 if ($_POST[$form3] == $row->form3) echo "<td><font color=’blue’>richtig</font></td>"; 18 else echo "<td><fontcolor=’red’>falsch</font></td></td>"; 19 $counter++; 20 echo "</tr>"; 21 } 22 echo "</table>"; 23 } 24 mysql_close(); c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 9 Bei der Auswertung wird folgendermaßen vorgegangen (die von mir verwendete ist natürlich eine von vielen Möglichkeiten): Zuerst wird die Benutzereingabe der zweiten Verbform ausgegeben, dann der entsprechende Eintrag aus der Datenbank (Zeile 15). Anschließend werden diese beiden verglichen und entweder richtig oder falsch ausgegeben (Zeile 16 - 17). Danach wird dieser Vorgang für die dritte Verbform wiederholt (Zeile 18 - 20). 1.3 Lückentexte I Aufwendiger in der Programmierung, aber dafür auch interessanter und leistungsfähiger, sind Lückentexte, bei denen ein Benutzer ganze Sätze bekommt und z. B. das Verb in der richtigen Zeit einsetzen muss. An der Stelle, wo in einem geschriebenen Text die Lücke gelassen wird, muss bei einem computerbasierten System ein Formulartextfeld eingefügt werden. Wie immer wird auch hier zunächst eine Tabelle benötigt, die die Beispielsätze aufnimmt. Diese wird wie folgt angelegt. mysql> -> -> -> -> create table gaps ( id int not null auto_increment, sentence varchar(255), solution varchar (100), primary key (id)); Die zweite Spalte nimmt den Beispielsatz auf, die dritte Spalte enthält die Lösung. Auf dem Bildschirm sieht die Ausgabe eines Beispielsatzes z. B. so aus: Yesterday I a new car (buy). Der Benutzer ist aufgefordert die korrekte Zeit des Verbs buy einzugeben. In der Tabelle liegen die Beispielsätze dann in dieser Form vor: Yesterday I :gap: a new car (buy). Immer dort, wo im Satz eine Lücke erscheinen soll wird die Zeichenfolge :gap: eingegeben. Es kann auch jede andere Zeichenfolge sein, man sollte nur darauf achten, dass diese Zeichenfolge sonst nicht vorkommt. In die Spalte solution kommt das Verb in der richtigen Zeit, also bought. Der Eintrag der Beispielsätze in die Tabelle erfolgt über die folgenden Zeilen: mysql> -> -> -> insert into gaps (sentence, solution) values (’Yesterday I :gap: a new car (buy).’, ’bought’), (’Last week I :gap: in the cinema (go)’, ’went’); c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 10 Die Tabelle sieht dann wie folgt aus: mysql> select * from gaps; +----+---------------------------------------+----------+ | id | sentence | solution | +----+---------------------------------------+----------+ | 1 | Yesterday I :gap: a new car (buy). | bought | | 2 | Last week I :gap: in the cinema (go). | went | +----+---------------------------------------+----------+ 2 rows in set (0.03 sec) Das für die Verarbeitung zuständige PHP Script unterscheidet sich nur in wenigen Punkten von dem ersten Beispiel. Zunächst wieder nur der erste Teil des Scripts. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php include ("db_connect.php"); if (!$_POST["check"]) { echo "<form action=’gaps.php’ method=’post’>"; $sql = "select * from gaps"; $result = mysql_query ($sql); echo "<table>"; $counter = 1; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; $sentence = eregi_replace (":gap:", "<input type= ’text’ name =’$feld’>", $row->sentence); echo "<tr><td>".$sentence."</td></tr>"; $counter++; } echo "<tr><td colspan = ’2’> <input type=’submit’ name=’check’ value=’Check’></td></tr>"; echo "</table></form>"; } ?> In der while-Schleife, mit der das Abfrageergebnis durchlaufen wird, wird mit der Funktion eregi_replace nach der Zeichenfolge :gap: in der Spalte sentence gesucht und durch ein Texteingabefeld ersetzt. Das Ergebnis wird dann auf dem Bildschirm ausgegeben. c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 11 Die Funktion eregi_replace benötigt drei Argumente: 1. Argument: die zu suchende Zeichenfolge 2. Argument: der Ersetzungstext 3. Argument: der String, in dem die Ersetzung vorgenommen werden soll Die Überprüfung der Benutzereingabe ist dagegen wieder annähernd identisch mit der Auswertung beim Vokabeltest. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 else { $sql = "select * from gaps"; $result = mysql_query ($sql); echo "<table>"; $counter = 1; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; if ($_POST[$feld] == $row->solution) echo "richtig<br>"; else echo "falsch<br>"; $counter++; } echo "</table>"; } Die Eingabe des Benutzers wird mit der Lösung, wie sie in der Datenbank steht, verglichen und eine entsprechende Erfolgs- oder Misserfolgsmeldung ausgegeben (Zeile 10 - 11). Damit ein Benutzer besser erkennen kann was er wo falsch gemacht hat, wird der o. a. Code für die Ausgabe folgendermaßen geändert. 1 2 3 4 5 6 7 8 9 10 11 12 13 else { $sql = "select * from gaps"; $result = mysql_query ($sql); echo "<table>"; $counter = 1; echo "<tr><td><b>Ihre Eingabe</b></td><td><b>Richtige Eingabe</b></td></tr>"; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; if ($_POST[$feld] == $row->solution) { $sentence1 = eregi_replace (":gap:", "<b>".$_POST[$feld]. c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL 14 15 16 17 18 19 20 21 22 23 24 25 26 Seite 12 "</b>",$row->sentence); $sentence2 = eregi_replace (":gap:", "<b>". $row->solution."</b>", $row->sentence); echo "<tr><td>".$sentence1."</td><td>$sentence2 </td><td><fontcolor=’blue’>Richtig</font></td></tr>"; } else { $sentence1 = eregi_replace (":gap:", "<b>".$_POST[$feld]. "</b>",$row->sentence); $sentence2 = eregi_replace(":gap:","<b>". $row->solution."</b>", $row->sentence); echo "<tr><td>".$sentence1."</td><td>$sentence2</td> <td><font color=’red’>falsch</font></td></tr>"; } $counter++; } echo "</table>"; } Jetzt wird der komplette Satz mit der Benutzereingabe und der Satz mit der richtigen Lösung ausgegeben. Dazu noch der Hinweis, ob die Eingabe richtig oder falsch war und, damit es besser zu erkennen ist, farblich hervorgehoben. Auch hier wird wieder mit der Funktion eregi_replace die Zeichenfolge :gap: durch die Benutzereingabe bzw. die richtige Lösung aus der Spalte solution ersetzt. Wenn man möchte kann man statt richtig oder falsch auch entsprechende Smilies ausgeben lassen. Damit ein Benutzer besser einschätzen kann wie gut (oder wie schlecht) er abgeschnitten hat, wird zum Schluss noch die Anzahl der richtigen und falschen Antworten ausgegeben. Dazu werden zwei weitere Variablen (eine für richtige Antworten und eine für falsche) in das Script eingefügt, die entsprechend inkrementiert werden. Der Wert dieser Variablen wird dann am Ende angezeigt. 1 2 3 4 5 6 7 8 9 10 else { $sql = "select * from gaps"; $result = mysql_query ($sql); echo "<table>"; $counter = 1; $r=0; $f=0; echo "<tr><td><b>Ihre Eingabe</b></td><td><b> Richtige Eingabe</b></td></tr>"; while ($row = mysql_fetch_object ($result)) c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL 11 12 13 14 15 16 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Seite 13 { $feld = "feld".$counter; if ($_POST[$feld] == $row->solution) { $sentence1 = eregi_replace (":gap:", "<b>".$_POST[$feld]. "</b>",$row->sentence); $sentence2 = eregi_replace (":gap:", "<b>".$row->solution. "</b>", $row->sentence);17 echo "<tr><td>".$sentence1."</td><td> $sentence2</td><td><fontcolor=’blue’>Richtig</font></td></tr>"; $r++; } else { $sentence1 = eregi_replace (":gap:", "<b>".$_POST[$feld]. "</b>",$row->sentence); $sentence2 = eregi_replace (":gap:", "<b>".$row-> solution. "</b>", $row->sentence); echo "<tr><td>".$sentence1."</td><td>$sentence2</td> td><font color=’red’>falsch</font></td></tr>"; $f++; } $counter++; } echo "<tr><td>Richtig: ".$r."</td><td>Falsch: ".$f."</td></tr>"; echo "</table>"; } Den beiden Variablen $r (für richtige Antworten) und $f (für falsche Antworten) wird ein Anfangswert von 0 zugewiesen (Zeile 7-8). Bei einer richtigen Antwort wird $r inkrementiert (Zeile 19), bei einer falschen Antwort $f (Zeile 27). Am Ende des Scripts wird dann der Wert ausgegeben (Zeile 31). Um außer der Anzahl von richtigen und falschen Antworten auch den jeweiligen prozentualen Anteil auszugeben, müssen im obigen Script nach Zeile 31 noch die folgenden Codezeilen einfügt werden. 1 2 3 4 $gesamt = $r+$f; $r_prozent = $r*100/$gesamt; $f_prozent = $f*100/$gesamt; echo "<tr><td>Richtig: ".$r_prozent."%</td><td> Falsch: ".$f_prozent."%</td></tr>"; Zunächst wird die Gesamtanzahl von Antworten an die Variable $gesamt gebunden, indem man die richtigen und falschen Antworten addiert. Anschließend wird der prozentuale Anteil c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 14 errechnet (Zeile 2-3) und ausgegeben (Zeile 4). 1.4 Lückentexte II Das obige Beispiel geht allerdings davon aus, dass jeder Satz genau ein Feld hat, dass ausgefüllt werden soll. Aber wie müssen Script und Datenbanktabelle aufgebaut werden, wenn ein Beispielsatz entweder keins oder mehrere auszufüllende Felder aufweist? Welche Zeit in einem Satz verwendet werden muss entscheidet nicht selten der Kontext, so dass Füllsatze benötigt werden, die nur der Erläuterung dienen, aber selbst keine Lücke enthalten. Bei Fragen und zusammengesetzten Zeiten (z. B. Present Perfect oder Future) werden Subjekt und Verb vertauscht und es werden plötzlich zwei Eingabefelder pro Satz benötigt. Ein solcher Satz könnte dann so aussehen: What you (do) when you grow up? Würde der Satz auf diese Art aufgebaut, wäre sofort klar, dass es sich hier um eine zusammengesetzte Zeit handelt. Eine mögliche Lösung wäre es den Satz folgendermaßen aufzubauen: What (you, do) when you grow up? Nicht nur das in der richtigen Zeit einzusetzende Verb, sondern Subjekt und Verb werden in Klammern hinter die Lücke gesetzt. Der dazugehörige Lösungseintrag würden dann lauten: are you going to do Das Subjekt wird also mit in die Lösung aufgenommen. Bei Aussagesätzen würde es folgendermaßen aussehen: (I, be) an acrobat in a circus. Auf diese Art wird für eine Eingabe auch nur ein Eingabefeld benötigt. Zusammen gehörende Sätze werden jeweils in einem eigenen Datensatz gespeichert. Damit für den Benutzer deutlich wird, welche Sätze zusammen gehören wird außer Satz und Lösung ein weiteres Feld in die Tabelle aufgenommen, dass diese Sätze durchnummeriert. mysql> -> -> -> -> -> create table gaps2 ( id int not null auto_increment, number varchar (20), sentence varchar (255), solution varchar (50), primary key (id)); c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 15 Für jeden Satz wird nur ein Eingabefeld gebraucht, bei Füllsätzen wird die Spalte solution mit einem Strich (-) ausgefüllt. Bei der Spalte number wird so verfahren, dass immer bei dem Datensatz, mit dem eine neue Reihe von Sätzen beginnt, das Feld mit einer fortlaufenden Zahl ausgefüllt wird, bei allen weiteren Sätzen die dazu gehören wird das Feld leer gelassen. Die ausgefüllte Tabelle sieht dann so aus: mysql> select * from gaps_new; +----+--------+-----------------------------------------------------+----------------------+ | id | number | sentence | solution | | 1 | 1. | What :gap: (you, do) when you grow up? | are you going to do | | 2 | NULL | :gap: (I, be) an acrobat in a circus. | I am going to be | | 3 | 2. | Why are you getting out the jack? | | | 4 | NULL | We have a puncture and :gap: (I, change) the wheel. | I am going to change | | 5 | NULL | :gap: (I, help) you. | I will help | | 6 | 3. | Do you see that car? | | | 7 | NULL | :gap: (they, raffle) it for charity. | they are going to | | | | | raffle | +----+--------+-----------------------------------------------------+----------------------+ 7 rows in set (0.00 sec) Der Eintrag NULL in der Spalte number bedeutet, dass das Feld keinen Eintrag hat, also leer ist. Der erste Teil des Scripts liest wie beim obigen Script die Datensätze ein und ersetzt die Zeichenfolge :gap: durch ein Texteingabefeld. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 include ("db_connect.php"); if (!$_POST["check"]) { echo "<form action=’gaps2.php’ method=’post’>"; $sql = "select * from gaps_new"; $result = mysql_query ($sql); echo "<table border=’0’ align=’center’>"; echo "<tr align=’center’ height =’50’ valign =’top’> <td colspan = ’2’><h3>Bitte geben Sie die richtige Zeit ein </h3></td></tr>"; $counter = 1; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; echo "<tr><td>".$row->number."</td>"; $sentence = eregi_replace (":gap:", "<input type= ’text’ name =’$feld’>", $row->sentence); echo "<td>".$sentence."</td></tr>"; $counter++; } echo "<tr align=’center’><td colspan = ’2’ valign = ’bottom’ c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 16 height=’60’> 19 <input type=’submit’ name=’check’ value=’Check’></td></tr>"; 20 echo "</table></form>"; 21 } Die Auswertung in der else-Anweisung ist wesentlich komplexer aufgebaut als in den vorangegangenen Beispielen. Schließlich muss jetzt berücksichtigt werden, dass einige Datensätze kein Eingabefeld enthalten, also auch nicht ausgewertet werden können. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 else { $sql = "select * from gaps_new"; $result = mysql_query ($sql); echo "<table align=’center’ width =’90%’ border = ’0’>"; $counter = 1; $r=0; $f=0; echo "<tr align=’center’><td>&nbsp;</td><td><b> Ihre Eingabe</b></td><td><b>Richtige Eingabe</b></td></tr>"; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; if ($row->solution =="-") { echo "<tr><td>".$row->number."</td><td>&nbsp;</td> <td>".$row->sentence."</td> <td>".$row->sentence."</td><td>-</td></tr>"; } else { if ($_POST[$feld] == $row->solution) { $sentence1 = eregi_replace (":gap:", "<b>". $_POST[$feld]."</b>",$row->sentence); $sentence2 = eregi_replace (":gap:", "<b>".$row->solution." </b>", $row->sentence); echo "<tr><td>".$row->number."</td> <td>".$sentence1." </td><td>".$sentence2."</td><td><font color=’blue’> Richtig</font></td></tr>"; $r++; } else { c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 17 30 $sentence1 = eregi_replace (":gap:", "<b>".$_POST[$feld]. "</b>",$row->sentence); 31 $sentence2 = eregi_replace (":gap:", "<b>".$row->solution. "</b>", $row->sentence); 32 echo "<tr><td>".$row-> number." </td><td>"$sentence1."</td> 33 <td>".$sentence2."</td><td><font color=’red’>Falsch</font></td></tr>"; 34 $f++; 35 } 36 } 37 $counter++; 38 } 39 echo "<tr><td colspan = 4>&nbsp;</td></td></tr>"; 40 echo "<tr><td>&nbsp;</td><td>Richtig: ".$r."</td><td> Falsch: ".$f."</td></tr>"; 41 $gesamt = $r+$f; 42 $r_prozent = $r*100/$gesamt; 43 $f_prozent = $f*100/$gesamt; 44 echo "<tr><td>&nbsp;</td><td>Richtig: ".$r_prozent."%</td><td> Falsch: ".$f_prozent."%</td></tr>"; 45 echo "</table>"; 46 } Bei der Auswertung wird zuerst überprüft, ob das Feld solution mit einem Strich (-) ausgefüllt ist (Zeile 13). Ist das der Fall, wird der Satz so wie er in der Tabelle steht ausgegeben. Wenn nicht, wird in der else-Anweisung ab Zeile 18 in einer neuen if -Anweisung (Zeile 20)überprüft, ob die Benutzereingabe mit der in der Tabelle stehenden Lösung übereinstimmt und eine entsprechende Erfolgsmeldung ausgegeben. Wenn nicht, wird in der else-Anweisung ab Zeile 27 eine entsprechende Misserfolgsmeldung ausgegeben. Außerdem werden wie im vorangegangenen Beispiel die richtigen und falschen Antworten gezählt und am Ende ebenfalls ausgegeben. 1.5 Finde das Gegenteil Im letzten Beispiel bekommt der Benutzer ein Adjektiv vorgegeben und soll aus einer Liste mit mehreren Antworten das Gegenteil heraussuchen. Die Tabelle, in der die Daten zu diese Übung gespeichert werden, wird wie folgt angelegt. mysql> -> -> -> create table adj_pairs ( id int not null auto_increment, adjective varchar (50), answer1 varchar (50), c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL -> -> -> -> Seite 18 answer2 varchar (50), answer3 varchar (50), solution varchar (50), primary key (id)); Die zweite Spalte nimmt das abzufragende Adjektiv auf, die Spalten drei bis fünf die möglichen Antworten. Damit die Aufgabe auch überprüft und ausgewertet werden kann, wird in der letzten Spalte noch einmal die Lösung gespeichert. Auch in diese Tabelle werden zwei Beispieldatensätze eingetragen. mysql> -> -> -> -> insert into adj_pairs (adjective, answer1, answer2, answer3, solution) values (’easy’, ’hard’, ’difficult’, ’heavy’, ’difficult’), (’sad’, ’happy’, ’lucky’, ’mad’, ’happy’); Die Tabelle hat dann folgenden Inhalt. mysql> select * from adj_pairs; +----+-----------+---------+-----------+---------+-----------+ | id | adjective | answer1 | answer2 | answer3 | solution | +----+-----------+---------+-----------+---------+-----------+ | 1 | easy | hard | difficult | heavy | difficult | | 2 | sad | happy | lucky | mad | happy | +----+-----------+---------+-----------+---------+-----------+ 2 rows in set (0.00 sec) Die Ausgabe soll so erfolgen, dass der Benutzer das Adjektiv, zu dem er das Gegenteil finden soll, angezeigt bekommt und dahinter drei radio-Buttons, mit den zur Auswahl stehenden Adjektiven. Auch hier ist der Code wieder nahezu identisch mit dem Code aus den vorangegangenen Beispielen. 1 2 3 4 5 6 7 include ("db_connect.php"); if (!$_POST["check"]) { echo "<form action=’adj.php’ method=’post’>"; $sql = "select * from adj_pairs"; $result = mysql_query ($sql); echo "<table>"; c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL 8 9 10 11 12 13 14 15 16 17 18 19 20 Seite 19 echo "<tr><td colspan=’4’ align=’center’ valign = ’top’ height=’60’><h3>Finden Sie das Gegenteil</h3></td></tr>"; $counter = 1; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; echo "<tr align=’left’><td>".$row->adjective."</td> <td><input type = ’radio’ name = ’$feld’ value=’$row->answer1’>".$row->answer1."</td><br>"; echo "<td><input type = ’radio’ name = ’$feld’ value = ’$row->answer2’>".$row->answer2."</td><br>"; echo "<td><input type = ’radio’ name = ’$feld’ value = ’$row->answer3’>".$row->answer3."</td></tr>"; $counter++; } echo "<tr align=’center’><td colspan = ’4’ valign = ’bottom’ height=’60’><input type=’submit’ name=’check’ value=’Check’># </td></tr>"; echo "</table></form>"; } Nach dem Aufbau der Verbindung zur Datenbank, folgt die Abarbeitung des Abfrageergebnisses in der while-Schleife (ab Zeile 10). Auch hier werden wieder unterschiedliche Namen für die radio-Buttons durch Inkrementieren der Variablen $counter erzeugt. Vor jeder möglichen Antwort wird dann ein radio-Button eingefügt (Zeile 13 - 18). Das zu einer Antwort gehörende Adjektiv wird dem value-Attribut des radio-Buttons zugeordnet). Durch Verwendung des gleichen Namens bei den radio-Buttons werden diese automatisch zu einer Gruppe zusammengefasst und es ist nur eine Antwort möglich. Die Antworten des Benutzers werden dann in der else-Anweisung ausgewertet. 1 2 3 4 5 6 7 8 9 10 11 else { $sql = "select * from adj_pairs"; result = mysql_query ($sql); echo "<table border=’1’ align=’center’ width=’50%’>"; echo "<tr><td colspan = ’2’>Ihre Auswahl</td> <td colspan = ’2’>Richtige Auswahl</td></tr>"; $counter = 1; while ($row = mysql_fetch_object ($result)) { $feld = "feld".$counter; echo "<tr><td>".$row->adjective."</td><td>".$_POST[$feld]. c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 20 "</td><td>".$row->solution."</td>"; if ($_POST[$feld]==$row->solution) 12 13 { 14 echo "<td>Richtig</td>"; 15 } 16 else echo "<td>Falsch</td>"; 17 $counter++; 18 echo "</tr>"; 19 } 20 echo "</table>"; 21} Der Wert des ausgewählten Buttons wird mit der Lösung verglichen, (Zeile 12) bei Übereinstimmung wird eine Erfolgsmeldung ausgegeben, ansonsten eine Misserfolgsmeldung. In meinen Augen etwas den Lesefluss störend ist jetzt noch die Ausgabe der geklammerten Angaben. Mit ein klein wenig Mehraufwand können bei der Auswertung der Sätze diese noch entfernt werden. Dazu wird die folgende Funktion ans Ende des Scripts eingefügt. 1 2 3 4 5 6 7 8 9 10 function remove ($brackets) { $erg1 = strpos($brackets, "("); $erg2 = strpos($brackets, ")"); $erg4 = $erg2 - $erg1 + 1; $erg3 = substr($brackets, $erg1, $erg4); $such = "\(".$erg3."\)"; $erg = eregi_replace ($such, "", $brackets); return $erg; } Zum Entfernen bietet sich die Funktion eregi_replace an, mit der Teile eines Strings ersetzt werden können. Hier kommt allerdings erschwerend hinzu, dass die zu entfernende Zeichenfolge bei jedem Satz unterschiedlich ist. Das einzige, was alle Strings gemiensam haben, sind die Klammern am Anfang und am Ende. Zunächst werden mit der Funktion strpos diese beiden Zeichen innerhalb des Satzes gesucht (Zeile 3 und 4). Diese Funktion liefert einen numerischen Wert zurück, der wiedergibt, an welcher Position sich das Zeichen befindet. Diese beiden Zahlen werden jetzt voneinander subtrahiert und wenn man dann noch 1 addiert haben wir die Länge des in Klammern stehenden Ausdrucks Zeile 5). Anschließend wird mit der Funktion substr ein Teilstring, der genau aus dem geklammerten Ausdruck besteht, erzeugt (Zeile 6) und dieser wird dann an die Funktion eregi_replace übergeben und aus dem Satz entfernt (Zeile 8). Da Ergebnis der Funktion ist der Satz ohne den in Klammern stehenden Text. Im Code muss jetzt nur noch die Funktion replace c 2004 Jochen Grundmann Online-Übungen mit PHP und MySQL Seite 21 aufgerufen werden. Um nicht noch einmal den gesamten Code anzuzeigen erfolgt hier nur der entscheidende Ausschnitt. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 if ($_POST[$feld] == $row->solution) { $sentence1 = eregi_replace (":gap:", "<b>".$_POST[$feld]."</b>" ,$row->sentence); $sentence1 = remove ($sentence1); $sentence2 = eregi_replace (":gap:", "<b>" .$row->solution."</b>", $row->sentence); $sentence2 = remove ($sentence2); echo "<tr><td>".$row->number."</td><td>".$sentence1."</td> <td>".$sentence2."</td><td><font color=’blue’> Richtig</font></td></tr>"; $r++; } else { $sentence1 = eregi_replace (":gap:", "<b>".$_POST[$feld]. "</b>",$row->sentence); $sentence1 = remove ($sentence1); $sentence2 = eregi_replace (":gap:", "<b>".$row->solution. "</b>", $row->sentence); $sentence2 = remove ($sentence2); echo "<tr><td>".$row->number."</td><td>".$sentence1."</td> <td>".$sentence2."</td><td><font color=’red’> Falsch</font></td></tr>"; $f++; } In den Zeilen 4, 6, 14 und 16 wird der aus der Datenbank ermittelte Satz an die Funktion replace übergeben und das Ergebnis wird ausgegeben. Ich hoffe, ich habe in diesem Tutorial zeigen können, dass es gar nicht so schwierig ist, solche Übungen selbst zu erstellen. Bei der Formatierung der Seiten habe ich mich bewusst auf das Notwendigste beschränkt, da die Funktionalität wichtiger ist als das Layout. Der nächste Schritt könnte jetzt sein, die Ergebnisse der Übungen zu protokollieren, damit ein Benutzer sehen kann wie oft er welche Übung gemacht hat und wie er dabei abgeschnitten hat, damit er seine Fortschritte überprüfen kann. c 2004 Jochen Grundmann