Ein kleines CMS mit XML-Dateien
Für fmbjoern.de kommen XML-Dateien zum Einsatz - eine mySQL-Datenbank ist nicht nötig - und trotzdem kann das Ganze komfortabel über einen Adminbereich konfiguriert werden. Wie das prinzipiell funktioniert zeige ich mithilfe unseres Loginscripts vom letzen Tutorial: wir erstellen ein kleines 1-Seiten CMS, beispielsweise für eine Newsseite.
Neben dem Loginscript brauchen wir auch eine kleine XML-Datei, die den Inhalt unserer Newsseite enthält. Bevor wir bequem neue Beiträge über ein Admininterface hinzufügen können, programmieren wir die Ausgabe auf der Homepage, deswegen erstellen wir folgende inhalte.xml:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item id="2">
<heading>Meine zweite Überschrift</heading>
<content><![CDATA[
<p>Inhalt der <strong>zweiten</strong> Meldung!</p>
]]></content>
</item>
<item id="1">
<heading>Meine erste Überschrift</heading>
<content><![CDATA[
<p>Inhalt der <strong>ersten</strong> Meldung!</p>
]]></content>
</item>
</items>
Unser Grundgerüst beinhaltet jetzt zwei kurze Meldungen, die wir nun auf einer Website mit PHP ausgeben wollen. Dazu versorgt uns PHP mit den SimpleXML-Funktionen: wir erstellen unsere news.php und erstellen ein neues SimpleXML-Objekt aus der XML-Datei.
<?php
$news = simplexml_load_file('inhalte.xml');
?>
Mit einer einfachen foreach-Schleife können wir nun die Meldungen formatiert ausgeben:
<?php
$news = simplexml_load_file('inhalte.xml');
foreach ($news as $newsitem) {
echo '<h2>'.(string)$newsitem->heading.'</h2>';
echo (string)$newsitem->content;
echo '<hr />';
}
?>
Diese Schleife und unsere XML-Datei lässt sich natürlich noch beliebig erweitern, Beispiele dazu findet man auf PHP.net. Jetzt widmen wir uns aber dem zweiten Teil der Aufgabenstellung: wir wollen die XML-Datei über einen Adminbereich in PHP verwalten und neue Inhalte erstellen beziehungsweise alte Inhalte bearbeiten. Dazu bauen wir zunächst unser Loginscript in die news.php ein:
<?php
session_start();
function member() {
if (isset($_REQUEST['logout'])) {
unset($_SESSION['user']);
} elseif (isset($_SESSION['user'])) {
return true;
} elseif (isset($_REQUEST['username']) && isset($_REQUEST['password'])) {
if ($_REQUEST['username'] == 'admin' && $_REQUEST['password'] == 'demo') {
$_SESSION['user'] = true;
return true;
}
}
return false;
}
$news = simplexml_load_file('inhalte.xml');
if (member()) {
echo 'Willkommen, Admin! <a href="?logout=1">ausloggen</a>';
} else {
foreach ($news as $newsitem) {
echo '<h2>'.(string)$newsitem->heading.'</h2>';
echo (string)$newsitem->content;
echo '<hr />';
}
echo 'Admin bitte einloggen!';
echo '<form name="login" action="" method="post">';
echo 'Name: <input type="text" name="username" /><br />';
echo 'Passwort: <input type="password" name="password" /><br />';
echo '<input type="submit" name="login" value="Einloggen" />';
echo '</form>';
}
?>
Jetzt fehlt nur noch der Adminbereich und ein paar Funktionen, die für uns Inhalte in der XML-Datei ändern. Zunächst kümmern wir uns um neue Inhalte - wir ermitteln die höchste verwendete ID in unserer inhalte.xml:
<?php
// ...
if (member()) {
$maxid = 0;
foreach ($news as $newsitem) {
if ($newsitem['id'] > $maxid) $maxid = $newsitem['id']; // höchste ID
}
}
// ...
?>
Als nächstes schreiben wir die Fuktion addNews(), die eine neue Meldung mit der nächthöheren ID erstellt. Ein einfaches Formular übergibt die neue Meldung an diese Funktion:
<?php
function addNews($id,$heading,$content) {
global $news;
$news->addChild('item');
$news->item[count($news)-1]->addAttribute('id',$id);
$news->item[count($news)-1]->addChild('heading',utf8_encode(htmlspecialchars($heading)));
$news->item[count($news)-1]->addChild('content',utf8_encode(htmlspecialchars($content)));
$news->asXML('inhalte.xml');
}
?>
Der Adminbereich mit der Funktion ein neues Newsitem zu erstellen, sieht jetzt so aus:
<?php
// ...
if (member()) {
function addNews($id,$heading,$content) {
global $news;
$news->addChild('item');
$news->item[count($news)-1]->addAttribute('id',$id);
$news->item[count($news)-1]->addChild('heading',utf8_encode(htmlspecialchars($heading)));
$news->item[count($news)-1]->addChild('content',utf8_encode(htmlspecialchars($content)));
$news->asXML('inhalte.xml');
}
if (isset($_POST['newitem'])) addNews($_POST['id'],$_POST['heading'],$_POST['content']);
echo 'Willkommen, Admin! <a href="?logout=1">ausloggen</a>';
$maxid = 0;
foreach ($news as $newsitem) {
if ($newsitem['id'] > $maxid) $maxid = $newsitem['id']; // höchste ID
}
echo '<form name="newitemform" action="" method="post">';
echo '<input type="hidden" name="id" value="'.($maxid+1).'" />';
echo 'Titel: <input type="text" name="heading" value="Titel" /><br />';
echo 'Text: <textarea name="content">Inhalt...</textarea><br />';
echo '<input type="submit" name="newitem" value="Neuen Eintrag erstellen" />';
echo '</form>';
}
// ...
?>
Bestehende Inhalte sollen natürlich auch möglichst einfach bearbeitet werden können, dazu stellen wir im Adminbereich alle Inhalte als Formularfelder dar - Änderungen können einfach eingegeben werden und nach einem Klick auf speichern wird die bearbeitete Meldung in der XML-Datei gespeichert.
<?php
// ...
if (member()) {
// ... addNews()
echo 'Willkommen, Admin! <a href="?logout=1">ausloggen</a>';
$maxid = 0;
foreach ($news as $newsitem) {
if ($newsitem['id'] > $maxid) $maxid = $newsitem['id']; // höchste ID
echo '<form name="itemeditform'.(string)$newsitem['id'].'" action="" method="post">';
echo '<input type="hidden" name="id" value="'.(string)$newsitem['id'].'" />';
echo 'Titel: <input type="text" name="heading" value="'.(string)$newsitem->heading.'" /><br />';
echo 'Text: <textarea name="content">'.(string)$newsitem->content.'</textarea><br />';
echo '<input type="submit" name="edititem" value="Änderungen speichern" />';
echo '</form>';
}
// ... addNews-Formular
}
// ...
?>
Damit das funktioniert, benötigen wir für unser XML-CMS noch eine Funktion editNews(), die die Änderungen auch tatsächlich in die Datei schreibt.
<?php
function editNews($id,$heading,$content) {
global $news;
$hlp = $news->xpath('//item[@id="'.$id.'"]');
$hlp[0]->content = htmlspecialchars($content);
$hlp[0]->heading = htmlspecialchars($heading);
$news->asXML('inhalte.xml');
}
?>
Jetzt können News erstellt und bearbeitet werden. Doch was ist mit löschen? Nun, wir erstellen unsere Funktion deleteNews() und fügen dem Formular jedes Eintrages noch einen "Löschen"-Button hinzu.
<?php
function deleteNews($id) {
global $news;
$i=0;
foreach ($news as $item) {
if ($item['id'] == $id) $del=$i;
$i++;
}
unset($news->item[$del]);
$news->asXML('inhalte.xml');
}
?>
Und so sieht das Ergebnis - ein fertiges, sehr einfaches Newsscript - dann aus:
<?php
session_start();
function member() {
if (isset($_REQUEST['logout']) && !isset($_REQUEST['username'])) {
unset($_SESSION['user']);
} elseif (isset($_SESSION['user'])) {
return true;
} elseif (isset($_REQUEST['username']) && isset($_REQUEST['password'])) {
if ($_REQUEST['username'] == 'admin' && $_REQUEST['password'] == 'demo') {
$_SESSION['user'] = true;
return true;
}
}
return false;
}
$news = simplexml_load_file('inhalte.xml');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>News</title>
</head>
<body>
<?php
if (member()) {
function addNews($id,$heading,$content) {
global $news;
$news->addChild('item');
$news->item[count($news)-1]->addAttribute('id',$id);
$news->item[count($news)-1]->addChild('heading',utf8_encode(htmlspecialchars($heading)));
$news->item[count($news)-1]->addChild('content',utf8_encode(htmlspecialchars($content)));
$news->asXML('inhalte.xml');
}
if (isset($_POST['newitem'])) addNews($_POST['id'],$_POST['heading'],$_POST['content']);
function editNews($id,$heading,$content) {
global $news;
$hlp = $news->xpath('//item[@id="'.$id.'"]');
$hlp[0]->content = htmlspecialchars($content);
$hlp[0]->heading = htmlspecialchars($heading);
$news->asXML('inhalte.xml');
}
if (isset($_POST['edititem'])) editNews($_POST['id'],$_POST['heading'],$_POST['content']);
function deleteNews($id) {
global $news;
$i=0;
foreach ($news as $item) {
if ($item['id'] == $id) $del=$i;
$i++;
}
unset($news->item[$del]);
$news->asXML('inhalte.xml');
}
if (isset($_POST['deleteitem'])) deleteNews($_POST['id']);
echo 'Willkommen, Admin! <form name="logout" action="" method="post"><input type="submit" name="logout" value="ausloggen" /></form>';
$maxid = 0;
foreach ($news as $newsitem) {
if ($newsitem['id'] > $maxid) $maxid = $newsitem['id']; // höchste ID
echo '<form name="itemeditform'.(string)$newsitem['id'].'" action="" method="post">';
echo '<input type="hidden" name="id" value="'.(string)$newsitem['id'].'" />';
echo 'Titel: <input type="text" name="heading" value="'.(string)$newsitem->heading.'" /><br />';
echo 'Text: <textarea rows="10" cols="30" name="content">'.(string)$newsitem->content.'</textarea><br />';
echo '<input type="submit" name="edititem" value="Änderungen speichern" /> <input type="submit" name="deleteitem" value="Löschen" />';
echo '</form>';
}
echo '<form name="newitemform" action="" method="post">';
echo '<input type="hidden" name="id" value="'.($maxid+1).'" />';
echo 'Titel: <input type="text" name="heading" value="Titel" /><br />';
echo 'Text: <textarea name="content">Inhalt...</textarea><br />';
echo '<input type="submit" name="newitem" value="Neuen Eintrag erstellen" />';
echo '</form>';
} else {
foreach ($news as $newsitem) {
echo '<h2>'.(string)$newsitem->heading.'</h2>';
echo (string)$newsitem->content;
echo '<hr />';
}
echo 'Admin bitte einloggen!';
echo '<form name="login" action="" method="post">';
echo 'Name: <input type="text" name="username" /><br />';
echo 'Passwort: <input type="password" name="password" /><br />';
echo '<input type="submit" name="login" value="Einloggen" />';
echo '</form>';
}
?>
</body>
</html>
Damit die Datei vernünftig in UTF-8 kodiert wird, habe ich das HTML-Grundgerüst noch hinzugefügt.