Redaktionssystem mit PHP5 & MySQL
Mini-CMS

DeveloperIT-ProjekteSoftware

PHP und MySQL sind auch in den neuesten Versionen ein Erfolg versprechendes Gespann. Der Workshop zeigt, wie Sie die neue MySQLi-Erweiterung von PHP 5 für ein Mini-CMS nutzen.

MySQL improved

Redaktionssystem mit PHP5 & MySQL

Am 14. Juli erschien PHP 5 endlich als Final. Die Erwartungen der Entwicklergemeinde an das neue Release waren hoch. In Sachen Datenbank konzentrierten sich die Publikationen in den vergangenen Wochen und Monaten auf das dateibasierte SQLite. Doch hinter den Kulissen wurde auch fleißig an der MySQL-Erweiterung gearbeitet. Heraus kam MySQLi. Das Ziel ist, eine neue Erweiterung für PHP 5 und alle MySQL-Versionen ab 4.1 zu bieten.

Die MySQLi-Erweiterung wird zu Recht als verbessert bezeichnet ? das i steht
für improved. Sie unterstützt die neuen Funktionen von MySQL 4.1 (aktuell Beta) und MySQL 5 (aktuell Alpha). Dazu zählen unter anderem Transaktionen und Subselects beziehungsweise mehrfache Abfragen. Dazu gibt es eine komplett objektorientierte Schnittstelle. Sie können MySQLi allerdings auch wie gewohnt per Funktionen bedienen. Da jedoch objektorientierte APIs im Zuge der verbesserten Objektorientierung in PHP 5 immer wichtiger werden, setzt dieser Workshop auf MySQLi in Verbindung mit Objekten.


Die Idee

Redaktionssystem mit PHP5 & MySQL

Ziel dieses Workshops ist, ein kleines Redaktionssystem zu entwickeln. Notwendige Funktionen sind das Lesen und Schreiben in eine MySQL-Datenbank. Dabei kommen vier Module zum Einsatz:

– Das Anzeige-Modul stellt die Artikel des Redaktionssystems dar.
– Das Datenbank-Modul erledigt die Verbindung zur Datenbank.
– Das Login- und Admin-Modul stellt den Administrator-Bereich zur Verfügung, in dem Artikel eingepflegt werden können.
– Das Bearbeiten-Modul erlaubt per Online-HTML-Editor, die Artikel zu verändern und neue in der Datenbank zu speichern.

Jedes Modul besteht aus einer Include-Datei, die eine Klasse enthält. Die Site
an sich hat drei Seiten: eine Hauptseite (index.php), die Seite für Administratoren (admin.php) und schließlich noch eine Seite zum Erstellen und Bearbeiten von Artikeln (bearbeiten.php).


Installation

Redaktionssystem mit PHP5 & MySQL

Als Datenbank benötigen Sie MySQL ab Version 4.1. Aktuell ist gerade 4.1.3. Version 5 gibt es als Alpha.

In PHP 5 ist keine MySQL-Unterstützung mitinstalliert. Hintergrund sind Lizenzstreitereien: MySQL steht unter der GPL, die wesentlich freizügiger ist als die PHP-Lizenz. Sonderlizenzen für einige Projekte sollen hier Abhilfe schaffen.

Zur eigentlichen Installation: Unter Linux verweisen Sie auf das Programm mysql_config, das bei MySQL ab Version 4.1 mitgeliefert wird:

-with-mysql=/pfad/mysql_config

Pfad ist Ihr Installationspfad. Die normale MySQL-Erweiterung müssen Sie unter Umständen ausschalten:

-without-mysql

Unter Windows ist die MySQLi-Erweiterung als DLL im Erweiterungsverzeichnis (php/ext/) zu finden (php_mysqli.dll). Sie benötigt die Bibliothek libmysqli.dll aus dem Programmverzeichnis von PHP. Wenn Sie PHP als Apache- oder ISAPI-Modul installiert haben, müssen Sie diese Datei in C:\Windows\System32 kopieren, damit PHP sie findet. Testen Sie zum Schluss mit phpinfo(), ob die Installation geklappt hat.


Datenbank anlegen

Redaktionssystem mit PHP5 & MySQL

Bei MySQL wird zwar der MySqlManager mitgeliefert, sehr komfortabel ist das aber nicht. Sie können alternativ auch ein Tool wie PhpMyAdmin verwenden, das in Version 2.6.0 auch für MySQLi ausgerüstet ist. Allerdings ist es aktuell noch im Beta-Stadium. Damit PhpMyAdmin mit MySQLi läuft, müssen Sie jedoch noch eine kleine Änderung in der Konfigurationsdatei config.inc.php vornehmen. Suchen Sie nach:

$cfg['Servers'][$i]['extension']

und tragen Sie dort statt mysql einfach mysqli als Wert ein. Legen Sie nun eine neue Datenbank an. Sie erhält den Namen minired. Die Tabelle artikel enthält alle Texte für das Redaktionssystem, die Tabelle nutzer die Nutzernamen und Passwörter für die Zugriffsberechtigten.

Der Primärschlüssel der Tabelle artikel ist das Feld id, das per auto-increment selbstständig durchgezählt wird. Zusätzlich gibt es die Felder titel (Typ: varchar, Zeichen: 50), inhalt (Typ: varchar, Zeichen: 255) und Datum (Typ: date im Format JJJJ-MM-TT).

Die Tabelle nutzer hat den Primärschlüssel nutzer_id ? ebenfalls ein auto-increment. Der Nutzername wird in name (Typ: varchar, Zeichen: 20) gespeichert, das Passwort in passwort (Typ: varchar, Zeichen: 20). Die beiden Tabellen benötigen keine Beziehung zueinander.

Sie sollten nun noch ein paar Dummy-Daten eintragen, um gleich testen zu können. Das passende SQL-Skript finden Sie auf der Heft-CD, wenn Sie es lieber direkt verwenden, statt mit einer Administrationsoberfläche zu arbeiten.


Zentrales CSS

Redaktionssystem mit PHP5 & MySQL

Noch ein paar Worte zur Gestaltung: Ein Redaktionssystem sollte auf allen Seiten in einheitlichem Gewand auftreten. Um das zu realisieren, kommt ein zentrales Stylesheet zum Einsatz.

Das Stylesheet positioniert div-Bereiche und färbt sie. Hier beispielsweise der Seiten-Header:

.header {
background: #00014C;
width: 100%;
height: 100px;
padding: 20px;
padding-left: 50px;
margin: 0px;
}

In diesen Bereichen kommen Blockelemente zum Einsatz, die vor allem Schriftformatierung enthalten. Hier beispielhaft das Format für eine Überschrift:

h1 {
font-family: Verdana, sans-serif;
font-size: 22pt;
color: #DCDCDC;
margin-top: 10px;
margin-bottom: 5px;
}

Sie finden das CSS unter dem Namen style.css auf der Heft-CD.


Datenbank-Modul

Redaktionssystem mit PHP5 & MySQL

Das Datenbank-Modul soll allen anderen drei Modulen zur Verfügung stehen und als solches unabhängig sein. Um dies zu erreichen, realisieren Sie es am besten als Include-Datei und verlinken es:

include_once("datenbank.inc.php");

Das Datenbankmodul besteht aus einer Klasse. In dieser Klasse sind die wichtigsten Einstellungen private Eigenschaften. Nur die Verbindung an sich ist public, also auch außerhalb der Klasse verfügbar, da dieses Objekt später noch gebraucht wird:

class abfrage {
private $server;
private $user;
private $pswd;
private $db;
public $connect;

Die Datenbankverbindung wird im Konstruktor hergestellt, also wenn die Klasse erstellt wird. In PHP 5 müssen Sie dafür nicht mehr eine Methode verwenden, die genauso heißt wie die Klasse. Stattdessen steht die Methode __construct() zur Verfügung. Übrigens erkennen Sie an den aufeinander folgenden Unterstrichen spezielle Methoden für objektorientierte Sonderaufgaben.

Die Parameter, die Sie beim Instanziieren eines Objekts angeben, landen beim Konstruktor. Das folgende Skript speichert die Daten in Eigenschaften und stellt dann die Datenbankverbindung her:

function __construct($server, $user,
$pswd, $db) {
$this->server = $server;
$this->user = $user;
$this->pswd = $pswd;
$this->db = $db;
$this->connect = new mysqli
($this->server, $this->user,
$this->pswd, $this->db);

Die Verbindung zur Datenbank realisiert das mysqli-Objekt. Würden Sie mit den Funktionen der MySQLi-Erweiterung arbeiten, müssten Sie stattdessen die mysqli_connect()-Funktion verwenden. Aber dieser Artikel verfolgt den objektorientierten Weg.


Fehler abfangen

Redaktionssystem mit PHP5 & MySQL

Nun fangen Sie noch eventuelle Fehler ab. Dies geht einfach per Funktion:

if (mysqli_connect_errno()) {
printf("Verbindung gescheitert: %s\", mysqli_connect_error());
exit();
}
}

Die Datenbankverbindung wird hier ? streng objektorientiert ? geschlossen, wenn das Objekt gelöscht wird. Dazu dient der Destruktor:

function __destruct() {
$this->connect->close();
}

Als Letztes benötigt das Datenbank-Modul noch eine Methode, um Abfragen zu realisieren. Hier sehen Sie die Flexibilität des objektorientierten Ansatzes: Eine Methode erledigt alle Abfragen, ganz gleich ob lesend oder schreibend. Sie erhält den SQL-String mit der Abfrage einfach als Parameter:

function abfragen($query) {
if($ergebnisse = $this->connect->query($query)) {
return $ergebnisse;
} else {
return "";
}
}


Anzeige-Modul

Redaktionssystem mit PHP5 & MySQL

Das Datenbank-Modul erlaubt nur den Zugriff auf die Datenbank, stellt aber nichts dar. Dafür ist das Anzeige-Modul zuständig. Es steckt ebenfalls in einer eigenen Include-Datei: anzeigen.inc.php.

Um die Klasse in einer Seite einzusetzen, binden Sie zuerst die Include-Datei ein wie oben gesehen. Die Verbindung zum Datenbank-Modul erfolgt gleich im Konstruktor, das Ende der Verbindung im Destruktor. Die Verbindung wird in einer privaten Eigenschaft gespeichert:

function __construct() {
$this->aufruf = new abfrage("Host", "Nutzername", "Passwort", "minired");
}
function __destruct() {
unset($this->aufruf);
}

Tragen Sie für die Datenbankverbindung noch den Host, Nutzernamen und das Passwort Ihrer MySQL-Installation ein. Nun können Sie beliebige Methoden programmieren, um die Daten aus der Datenbank auszulesen. Das Grundprinzip ist immer gleich. Mit der Methode abfragen() des Datenbank-Moduls führen Sie eine Abfrage aus.

$abfrage = $this->aufruf->abfragen
("SELECT * FROM artikel");

Das Ergebnis speichern Sie dann in beliebiger Form. Die MySQLi-Erweiterung bietet hier eine Vielzahl an Methoden. fetch_assoc() liefert beispielsweise ein assoziatives Array von jeder Reihe. Das Redaktionssystem enthält zwei Methoden zum Auslesen. Bereitstellen() liefert nur Nachrichten, die nicht älter sind als 120 Tage. Hierzu wird einfach das Feld datum aus der Datenbank ausgelesen und von der aktuellen Zeit, jeweils umgewandelt in einen Zeitstempel, abgezogen:

while ($ergebnis = $abfrage->fetch_assoc()) {
$datum = strtotime ($ergebnis["datum"]);
$differenz = mktime() ? $datum;
if($differenz < (120 * 24 * 60 * 60)) {
$ergebnisse[$i] = $ergebnis;
$i++;
}
}

Die zweite Funktion bereitstellen_alle() liefert alle Daten. Sie kommt im Admin-Modul zum Einsatz, um auch ältere Nachrichten noch anzuzeigen.


Formatieren

Redaktionssystem mit PHP5 & MySQL

Das Anzeige-Modul enthält aber noch eine weitere wichtige Methode: formatieren() dient dazu, die Rohdaten, die bereitstellen() und bereitstellen_alle() liefern, in ein Ausgabeformat zu übersetzen. Über einen Parameter hat der Programmierer die Möglichkeit, zwischen Tabellen-Darstellung und CSS-Darstellung zu wechseln. Standardwert ist die CSS-Darstellung. Die eigentliche Ausgabe erfolgt in der Datei index.php. Zuerst wird ein Objekt der Klasse anzeigen instanziiert, dann werden die beschriebenen Methoden eingesetzt, um die Daten in formatierter Form zu erhalten:

$anzeigen = new anzeigen();
$news_roh = $anzeigen->bereitstellen();
$news = $anzeigen->formatieren($news_roh);

Die Nachrichten stecken nun als String in der Variablen $news. Im Körper der HTML-Seite landen die Daten dann auf klassischem Weg durch Ausgabe der Variablen:


Administration

Redaktionssystem mit PHP5 & MySQL

Für den Login in den Administrationsbereich enthält die Datei index.php ein kleines Formular:




UID


PSWD



Dieses Formular wird an die zweite Seite admin.php verschickt. Die Login-Prüfung und das Session-Management stecken in einem weiteren Modul login.inc.php. Vier Methoden sind relevant:

- Der Konstruktor prüft, ob die Session existiert, und startet sie, falls nicht.
- session_pruefen() testet mit einer Session-Variablen, ob der Nutzer gerade eingeloggt ist. Wenn nicht, wird er auf index.php weitergeleitet. Dies verhindert unberechtigten Direktzugriff auf den Administrationsbereich.
- einloggen() prüft die Nutzerauthentifizierung gegen die Datenbank und ändert den Status der Session-Variable auf true. Sie kommt in admin.php zum Einsatz.
- ausloggen() kommt auf index.php zum Einsatz und setzt die Session-Variable beim Ausloggen auf false zurück.

Besonders interessant aus Sicht der MySQLi-Erweiterungen ist die Möglichkeit, Strings mit Escape-Zeichen zu versehen. Wenn Sie Nutzereingaben nicht absichern, öffnen Sie Ihre Website für SQL-Injections. In der alten MySQL-Erweiterung gab es dafür die Funktion mysql_escape_string(). Das Pendant in MySQLi heißt mysqli_escape_string() beziehungsweise in der Langfassung und eigentlichen Hauptform mysqli_real_ escape_string(). Die MySQLi-Variante verlangt allerdings nicht nur einen String als Parameter, sondern auch das mysqli-Objekt. Der Hintergrund: MySQL unterstützt in den neueren Versionen beispielsweise auch Unicode-Zeichensätze. mysqli_escape_string() ändert sein Escape-Verhalten je nach dem verwendeten Zeichensatz:

$login_abfrage = new abfrage
("localhost", "root", "", ""minired");
$sql = "SELECT nutzer_id FROM nutzer
WHERE name='" . mysqli_escape_string
($login_abfrage->connect, $_POST["user"]);
$sql .= "' AND passwort='" .
mysqli_escape_string($login_abfrage
->connect, $_POST["pass"]) . "'";

Zurück zum Admin-Bereich: Die Darstellung wird hier mit einer anderen Methode des Anzeige-Moduls realisiert, mit formatieren_bearbeiten(). Diese Methode versieht den Titel von jeder News mit einem Link. Er erhält die ID aus der Datenbank als Anhängsel, das dann über den URL übermittelt wird:

$news .= "";
$news .= $titel . "

";


Bearbeiten-Modul

Redaktionssystem mit PHP5 & MySQL

Die Seite zum Bearbeiten ist bearbeiten.php. Sie dient dazu, neue Datenbankeinträge anzulegen und bestehende zu bearbeiten. Nun sind für beides aber unterschiedliche SQL-Befehle notwendig, INSERT und UPDATE. Die Lösung ist einfach: Das Redaktionssystem verwendet die Einfügen-Variante, wenn keine ID an den URL angehängt ist. Wenn doch, wird die Datei bearbeitet.

Das Bearbeiten-Modul steckt in der Datei bearbeiten.inc.php. Konstruktor und Destruktor sind für die Datenbank-Verbindung mittels Datenbank-Modul zuständig. Die Methode daten_abfragen() liefert die Daten, wenn eine bestehende Nachricht bearbeitet werden soll. Daten_speichern() legt die Daten in die Datenbank, wenn das Formular mit der Submit-Schaltfläche verschickt wird.

Und so geht es: Beim Aufruf der Methode in der Datei bearbeiten.php prüft das Skript, ob eine GET-Variable vorhanden ist. Je nachdem werden dann die Methoden mit oder ohne ID aufgerufen:

$bearbeiten = new bearbeiten();
if (isset($_GET["datei"])) {
$bearbeiten->daten_speichern ($_GET["datei"]);
$daten = $bearbeiten ->daten_abfragen($_GET["datei"]);
} else {
$bearbeiten->daten_speichern();
$daten = $bearbeiten ->daten_abfragen();
}

Die Methoden selbst besitzen einen Standardwert 0 für die ID. Nun hilft eine einfache Fallunterscheidung weiter. Im Fall der Auslese-Funktion wird entweder ein Array mit dem jeweiligen Artikel aus der Datenbank ausgelesen oder ein leeres Array zurückgeliefert:

function daten_abfragen($id = 0) {
if($id != 0) {
$abfrage = $this->aufruf
->abfragen(?SELECT * FROM artikel WHERE id='" .
mysqli_escape_string($this ->aufruf->connect, $id) . "'");
return $abfrage->fetch_assoc();
} else {
return array("titel"=>"", "inhalt"=>"", "datum"=>"");
}
}

Die Methode daten_speichern() funktioniert analog, nur dass hier entweder UPDATE oder INSERT zum Einsatz kommt.


Online-Editor

Redaktionssystem mit PHP5 & MySQL

PHP-seitig sind Sie damit am Ende angekommen. Als zusätzliche Funktionalität finden Sie im Redaktionssystem noch einen Online-Editor für HTML namens HTMLArea (www.interactivetools.com/products/htmlarea). Er basiert auf HTML, CSS und Javascript und funktioniert im IE ab Version 5.5 und Mozilla 1.3. Um ihn zu verwenden, laden Sie die Daten von Version 3 (im Beta-Stadium) herunter und entpacken Sie sie in ein Verzeichnis. Das Redaktionssystem verwendet das Unterverzeichnis htmlarea.

Aus den mitgelieferten Beispielen können Sie sich nun den Einbau-Code kopieren. Vorsicht: Die Angaben auf der Website betreffen die alte Version. Wenn Sie keine Zusatzfunktionalität wie Rechtschreibprüfung benötigen, verwenden Sie zum Kopieren die Datei core.html. In der Datei bearbeiten.php finden Sie eine vereinfachte Einbau-Variante mit bereits leicht angepassten Tool-Leisten. Hier der wichtigste Ausschnitt:


Dazu kommt im body-Tag der Aufruf der Start-Funktion:


Fazit

Redaktionssystem mit PHP5 & MySQL

Trotz SQLite und anderer konkurrierender Datenbanksysteme muss sich das Duo PHP und MySQL auch in Zukunft nicht verstecken. Die MySQLi-Erweiterung macht vor allem beim objektorientierten Ansatz eine gute Figur.