Was soll das Script eigentlich tun? Nun, es gibt häufiger den Spruch des Tages oder ähnliches. So etwas mit PHP zu realisieren wird schwierig. Wenn man einen Spruch des Tages realisieren will, hat man zwei Teilprobleme: Erstens muß man für diesen Tag einen Spruch auswählen und diesen zweitens anzeigen. Ersteres könnte man theoretisch dadurch lösen, daß man um Mitternacht ein Script aufruft, das den gewählten Spruch irgendwo speichert, von wo er dann den ganzen Tag lang ausgegeben werden kann.
PHP bietet allerdings von sich aus keine Möglichkeit, zu gewissen Zeiten irgendetwas automatisch zu machen. Die einzige Möglichkeit ist, mit einem Hilfsprogramm, wie z.B. CRON unter Unix, zum gewünschten Zeitpunkt das Ganze anzustoßen. Es gibt auch noch die Bastellösung, bei der bei der Ausgabe immer abgeprüft wird, ob es der erste Aufruf an diesem Tag ist und wenn ja, wird ein neuer Spruch ausgewählt.
Um das Ganze etwas einfacher zu halten, wird bei jedem Aufruf ein Spruch ausgewählt, der dann ausgegeben wird.
Kommen wir nun aber zum Programmieren. Als erstes stellt sich, wie immer, die Frage nach
der Tabelle. Dies sollte hier kein großes Problem sein.
CREATE TABLE spruch ( SID int not null primary key auto_increment, Spruch text, anzeigen bool ) TYPE=MYISAM; CREATE unique INDEX spruch_idx_Spruch ON spruch (Spruch(200));
Neben dem eigentlichen Text und einem eindeutigen Schlüssel habe ich noch eine kleine Spalte ,anzeigen` eingeführt, über die man später verhindern kann, daß ein Spruch angezeigt wird.
Viel interessanter ist die zweite Anweisung. Im Endeffekt will ich nur erreichen, daß ein Spruch nicht zweimal eingetragen werden kann. Im Prinzip kein Problem, ein UNIQUE im CREATE TABLE auf ,,Spruch`` sorgt schon dafür, sollte man meinen. Dem ist aber leider nicht so, da ,,Spruch`` vom Typ TEXT ist und dieser in Sachen Index etwas anders funktioniert als z.B. VARCHAR (d.h. er erlaubt keinen). Ab MySQL Version 3.23 ist es aber möglich, über diese zweite Anweisung einen Index auf eine TEXT-Spalte zu legen, wobei dann nur die ersten n Buchstaben genutzt werden (hier sind es 200).
Nachdem nun die Tabellenerstellung geklärt ist, kommen wir zu den eigentlichen PHP-Scripten. Hier stellt sich wieder die Frage, nämlich, in welcher Reihenfolge sie programmiert werden sollten. Ich habe mich für die folgende entschieden:
Kurze Begründung:
Das Einfügen in die Datenbank kann über ein einfaches SELECT von Hand überprüft
werden. Der zufällige Spruch ist ja das eigentliche Ziel des Ganzen; hier könnte man
jetzt auch schon fast aufhören; zumindest kann man jetzt das Ganze in Betrieb nehmen. Um
einen Spruch zu löschen, muß man ihn irgendwie auswählen; deshalb die Gesamtausgabe vor
dem Löschen. Über Löschen und anschließendes Einfügen kann man im Prinzip auch ändern; um das
aber etwas komfortabler zu machen, gibt es als Letztes auch noch ein Ändern.
Es erfolgt keinerlei Authentifizierung, d.h. jeder kann beliebige Daten in die Datenbank einfügen. Wie man eine entsprechende Paßwortüberprüfung einbauen könnte, steht im Kapitel 11.1.3.
In der Variable $anzeigen bzw. im Checkbox-Inputfeld wird nicht der Wert übergeben, der nachher in der Datenbank stehen soll (0 oder 1), sondern ,,checked`` oder ,,``. Dadurch wird zwar die Wiederanzeige des Formulars einfacher, aber das Einfügen in die Datenbank etwas schwieriger. Es ist also eigentlich egal, wie man es realisiert.
<?php // Verbindungsdaten MySQL DB $DB_HOST = "localhost"; $DB_USER = "cr"; $DB_PASS = "123"; $DB_NAME = "cr"; $DatenOK = true; $Fehler = ""; if (isset($_GET["submit"])){ // Formular wurde abgeschickt -> Daten pruefen if ($_GET["Spruch"] == ""){ $DatenOK = false; $Fehler .= "Bitte noch einen Text eingeben!<br>\n"; $daten["Spruch"] = ""; } else { // Daten OK $daten["Spruch"] = $_GET["Spruch"]; } // anzeigen kann nur true oder false sein // bei true ist es gesetzt if (isset($_GET["anzeigen"])){ $daten["anzeigen"] = 1; } else { $daten["anzeigen"] = 0; } if ($DatenOK){ // Daten in DB eintragen mysql_connect($DB_HOST, $DB_USER, $DB_PASS) OR die("Konnte DB nicht erreichen!"); mysql_select_db($DB_NAME) OR die("Konnte DB nicht erreichen"); mysql_query(sprintf('INSERT INTO spruch (Spruch, anzeigen) VALUES ("%s" , %d)', addslashes($daten["Spruch"]), $daten["anzeigen"])); switch (mysql_errno()){ case 0: // Alles OK header('Location: http://'.$_SERVER["HTTP_HOST"]. substr($_SERVER["PHP_SELF"],0, strrpos($_SERVER["PHP_SELF"],'/')) .'/show_all.php4'); exit; continue; case 1062: // Spruch doppelt eingetragen $DatenOK = false; $Fehler .= "Den Spruch gibt es schon<br>\n"; continue; default: // Sonstiger Fehler // -> Fehlermeldung ausgeben $DatenOK = false; $Fehler .= "MySQL: ".mysql_errno().": ". mysql_error()."<br>\n"; } } } else { // Werte vorbelegen $daten["Spruch"] = ""; $daten["anzeigen"] = 1; } ?> <html> <head> <title>SDA eintragen</title> </head> <body> <?php if (!$DatenOK){ echo "<h1>$Fehler</h1>"; } ?> <form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="GET"> <div align="center"> <p> <textarea name="Spruch" rows="5" cols="80"><?php echo htmlentities($daten["Spruch"]); ?></textarea> </p> Spruch anzeigen <input type="checkbox" name="anzeigen" value="checked" <?php echo ($daten["anzeigen"] ? "checked" : ""); ?>><p> <input type="submit" name="submit" value=" Alles OK "> </div> </form> </body>
Ansonsten sollte das Script eigentlich selbsterklärend sein. In der ersten Datei, die ich sda.php4 genannt habe, wird eine Funktion get_spruch() realisiert. Diese kann dann später aus beliebigen anderen Dateien per include() eingefügt werden.
Es gibt auch noch eine zweite Funktion get_sprueche, die ein Array mit mehreren Sprüchen zurück gibt. Diese Funktion ist praktisch, wenn du verhindern willst, das deine Besucher den Server mit ständigem Neuladen der Webseite überlasten, um an alle Sprüche zu kommen. ;-)
<?php /** * Holt einen zufaelligen Spruch aus der Datenbank * und gibt ihn als String zurueck */ function get_spruch(){ // Verbindungsdaten MySQL DB $DB_HOST = "localhost"; $DB_USER = "cr"; $DB_PASS = "123"; $DB_NAME = "cr"; mysql_connect($DB_HOST, $DB_USER, $DB_PASS) OR die("Konnte DB nicht erreichen!"); mysql_select_db($DB_NAME) OR die("Konnte DB nicht erreichen"); $res = mysql_query('SELECT Spruch, SID*0+rand() AS sort FROM spruch WHERE anzeigen = 1 ORDER BY sort LIMIT 1'); if (!$row = mysql_fetch_array($res)){ echo "Fehler im Script!"; } return $row["Spruch"]; } /** * Holt die gewuenschte Zahl an Spruechen aus der * Datenbank und gibt diese als Array zurueck. * Wird nichts angegeben, werden 3 Sprueche aus der * Datenbank geholt. */ function get_sprueche($anzahl=3){ // Verbindungsdaten MySQL DB $DB_HOST = "localhost"; $DB_USER = "cr"; $DB_PASS = "123"; $DB_NAME = "cr"; mysql_connect($DB_HOST, $DB_USER, $DB_PASS) OR die("Konnte DB nicht erreichen!"); mysql_select_db($DB_NAME) OR die("Konnte DB nicht erreichen"); $res = mysql_query(sprintf('SELECT Spruch, SID*0+rand() AS sort FROM spruch WHERE anzeigen = 1 ORDER BY sort LIMIT %d', $anzahl)); while($row = mysql_fetch_array($res)){ $sprueche[] = $row["Spruch"]; } return $sprueche; } ?>
Und um zu sehen, daß die Funktion tatsächlich funktioniert, hier noch ein sehr
kompliziertes Script.
<?php // Wir wollen sauber programmieren error_reporting(E_ALL); include('./sda.php4'); ?> <html> <head> </head> <body> <pre> <?php echo get_spruch(); ?> </pre> </body>
Und hier das zweite Script, für mehrere Sprüche. Es liest aus einen
GET-Parameter die gewünschte Anzahl der Sprüche.
<?php // Wir wollen sauber programmieren error_reporting(E_ALL); include('./sda.php4'); if (isset($_GET["anzahl"]) && is_numeric($_GET["anzahl"]) && $_GET["anzahl"] > 0) { $anzahl = $_GET["anzahl"]; } else { $anzahl = 3; } ?> <html> <head> </head> <body> <?php $sprueche = get_sprueche($anzahl); foreach ($sprueche AS $spruch){ printf("<pre>\n%s\n</pre>\n", $spruch); } ?> </body>
Auch hier erfolgt keinerlei Paßwortabfrage oder ähnliches, das heißt jeder kann sich alle Sprüche ansehen.
Das Script ist nicht sehr elegant programmiert, aber es funktioniert.
<?php // Verbindungsdaten MySQL DB $DB_HOST = "localhost"; $DB_USER = "cr"; $DB_PASS = "123"; $DB_NAME = "cr"; mysql_connect($DB_HOST, $DB_USER, $DB_PASS) OR die("Konnte DB nicht erreichen!"); mysql_select_db($DB_NAME) OR die("Konnte DB nicht erreichen"); ?> <html> <head> <title>SDA ansehen</title> </head> <body> <center> <a href="insertchange.php4">Neu einfügen</a> </center> <ul> <?php $res = mysql_query('SELECT SID, Spruch FROM spruch ORDER BY SID'); while ($row = mysql_fetch_array($res)){ printf('<li><pre>%s</pre> <a href="insertchange.php4?SID=%d">Ändern</a> <a href="delete.php4?SID=%d">Löschen</a>'."\n", $row["Spruch"], $row["SID"], $row["SID"]); } ?> </ul> </body>
Nach dem Löschen kann man entweder eine Erfolgsmeldung ausgeben, oder einfach wieder auf z.B. die Übersichtsseite weiterleiten, was hier gemacht wird.
<?php if (!isset($_GET["SID"]) || !is_numeric($_GET["SID"])){ die("Fehler"); } // Verbindungsdaten MySQL DB $DB_HOST = "localhost"; $DB_USER = "cr"; $DB_PASS = "123"; $DB_NAME = "cr"; mysql_connect($DB_HOST, $DB_USER, $DB_PASS) OR die("Konnte DB nicht erreichen!"); mysql_select_db($DB_NAME) OR die("Konnte DB nicht erreichen"); mysql_query(sprintf('DELETE FROM spruch WHERE SID=%d', $_GET["SID"])); header('Location: http://'.$_SERVER["HTTP_HOST"]. substr($_SERVER["PHP_SELF"],0, strrpos($_SERVER["PHP_SELF"],'/')) .'/show_all.php4'); ?>
Die Änderungen sind eigentlich relativ einfach. Als erstes wird die Datenbankverbindung immer aufgebaut, da sie an mehreren Stellen benötigt wird (hätte man auch durch eine Funktion eleganter lösen können). Als nächstes muß bei der Datenprüfung nun auch die Spruch-ID geprüft werden. Hier beschränke ich mich auf die Prüfung, ob es eine Zahl ist. Die eigentliche SQL-Anweisung muß natürlich auch erweitert werden, die Fehlerabfrage kann dann jedoch wieder dieselbe sein. Schließlich müssen auch irgendwo die alten Werte geholt werden und als letztes wird das HTML-Formular so erweitert, daß es bei Bedarf auch noch die Spruch-ID wieder übergibt. Das waren dann auch schon alle Änderungen und wir haben unser Änderungsscript fertig.
<?php // Verbindungsdaten MySQL DB $DB_HOST = "localhost"; $DB_USER = "cr"; $DB_PASS = "123"; $DB_NAME = "cr"; // erstmal ist alles OK $DatenOK = true; $Fehler = ""; mysql_connect($DB_HOST, $DB_USER, $DB_PASS) OR die("Konnte DB nicht erreichen!"); mysql_select_db($DB_NAME) OR die("Konnte DB nicht erreichen"); if (isset($_GET["submit"])){ // Formular wurde abgeschickt -> Daten pruefen if ($_GET["Spruch"] == ""){ $DatenOK = false; $Fehler .= "Bitte noch einen Text eingeben!<br>\n"; $daten["Spruch"] = ""; } else { // Daten OK $daten["Spruch"] = $_GET["Spruch"]; } // anzeigen kann nur true oder false sein // bei true ist es gesetzt if (isset($_GET["anzeigen"])){ $daten["anzeigen"] = 1; } else { $daten["anzeigen"] = 0; } if (isset($_GET["SID"])){ // Eine Spruch-ID wurde übergeben // -> sie muß geprüft werden // // Überprüfung, ob sie tatsächlich existiert, // könnte auch noch erfolgen if (!is_numeric($_GET["SID"])){ $DatenOK = 0; $Fehler .= "Ungültige Spruch-ID übergeben!<br>\n"; } else { // Daten OK $daten["SID"] = $_GET["SID"]; } } if ($DatenOK){ // Daten in DB eintragen if (isset($daten["SID"])){ // Spruch-ID wurde übergeben // -> Spruch wird geändert mysql_query(sprintf('UPDATE spruch SET Spruch="%s", anzeigen=%d WHERE SID=%d', addslashes($daten["Spruch"]), $daten["anzeigen"], $daten["SID"])); } else { // neuer Spruch -> einfügen mysql_query(sprintf('INSERT INTO spruch (Spruch, anzeigen) VALUES ("%s" , %d)', addslashes($daten["Spruch"]), $daten["anzeigen"])); } // MySQL-Rückgabewert auswerten // Wenn OK -> Weiterleiten // sonst -> Fehlermeldung switch (mysql_errno()){ case 0: // Alles OK header('Location: http://'.$_SERVER["HTTP_HOST"]. substr($_SERVER["PHP_SELF"],0, strrpos($_SERVER["PHP_SELF"],'/')) .'/show_all.php4'); exit; continue; case 1062: // Spruch doppelt eingetragen $DatenOK = false; $Fehler .= "Den Spruch gibt es schon<br>\n"; continue; default: // Sonstiger Fehler // -> Fehlermeldung ausgeben $DatenOK = false; $Fehler .= "MySQL: ".mysql_errno().": ". mysql_error()."<br>\n"; } } } elseif (isset($_GET["SID"])){ // es soll der Spruch SID geändert werden // -> bisherige Werte laden // // SID muss an der Stelle nicht auf numerisch // getestet werden, da es nur mit %d im sprintf() // genutzt wird $res= mysql_query(sprintf('SELECT SID, Spruch, anzeigen FROM spruch WHERE SID=%d', $_GET["SID"])); if (!$row = mysql_fetch_array($res)){ $DatenOK = false; $Fehler .= "Konnte Spruch nicht laden"; } $daten["SID"] = $row["SID"]; $daten["Spruch"] = $row["Spruch"]; $daten["anzeigen"] = $row["anzeigen"]; } else { // Werte vorbelegen $daten["Spruch"] = ""; $daten["anzeigen"] = 1; } ?> <html> <head> <title>SDA eintragen</title> </head> <body> <?php if (!$DatenOK){ echo "<h1>$Fehler</h1>"; } ?> <form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="GET"> <div align="center"> <p> <textarea name="Spruch" rows="5" cols="80"><?php echo htmlentities($daten["Spruch"]); ?></textarea> </p> Spruch anzeigen <input type="checkbox" name="anzeigen" value="checked" <?php echo ($daten["anzeigen"] ? "checked" : ""); ?>><p> <?php if (isset($daten["SID"])){ // zum Ändern auch die SID übergeben printf('<input type="hidden" name="SID" value="%d">', $daten["SID"]); } ?> <input type="submit" name="submit" value=" Alles OK "> </div> </form> </body>
Ähnliches gilt für das HTML-Layout der Adminseiten. Hier steht es fest in jeder Datei; flexibler wären dann z.B. HTML-Header und HTML-Footer Dateien, die jeweils per include() eingebunden würden.
Ein Programmieren mit Copy and Paste geht zwar am Anfang schneller, aber sobald man etwas ändern muß, wird es aufwendig, weil jede Stelle geändert werden muß. Beim Ändern hätte man auch das Einfügescript kopieren und dann anpassen können, dann hätte man sich die Abfragen gespart. Allerdings wäre der Aufwand beim Einfügen eines weiteren Feldes größer gewesen. Bei dieser Lösung muß an 4 Stellen erweitert werden: bei der Datenprüfung, den beiden SQL-Anweisungen und dem HTML-Formular. Bei der Kopierlösung müßte man zwei mal 3 Stellen ändern.