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.

Ein kleines CMS mit XML-Dateien StartseiteTutorials ↪ Ein kleines CMS mit XML-Dateien