Quakenet/#php Tutorial

Hinweis: Wenn sie diese Seite von einer externen URL aufgerufen haben achten sie darauf das alle Kapitel aufeinander aufbauen. Stellen sie daher sicher dass sie alle vorherigen Kapitel gelesen haben, da sie sonst relevante Informationen übersehen.

Erweitertes Newsskript

  1. Funktionalität des neuen Newsskripts
  2. Aufbaue der MySQL-Tabellen
  3. Kategorie hinzufügen
  4. Kategorie bearbeiten
  5. Kategorie löschen
  6. News hinzufügen
  7. News bearbeiten
  8. News löschen
  9. News anzeigen
  10. SELECT-Anfragen gruppieren und Spezialfunktionen verwenden
  11. Entwickeln der SELECT-Anfrage für die News
  12. News laden und anzeigen
  13. Anzeigen und schreiben von Newskommentaren
  14. Newskommentar bearbeiten
  15. Kommentare löschen

1. Funktionalität des neuen Newsskripts

Da wir nun ein Loginsystem haben können wir ein neues Newsskript mit mehr Funktionalität schreiben. Neben der eigentlichen News wird es im Newssystem auch Links für Quellen, Kommentare für Newsbeiträge und Newskategorien geben.

2. Aufbaue der MySQL-Tabellen

Wir werden user Newssystem so schreiben das eine News zu einer Kategorie gehört. Wenn man möchte das eine News zu mehreren Kategorien gehört muss man ähnliche Tabellen wie für unser Adminbereich anlegen. In unserem Fall erstellen wir zuerst die Tabelle News_Kategorie für die Kategorien.

Dann gibt es natürlich die Tabelle News mit den Newseinträgen.

Für die Kommentare der News legen wir die Tabelle News_Kommentar an.

Falls es zu einer News Quellenangaben oder anderseitig Links gibt werden diese in der Tabelle News_Link gespeichert.

Diese Tabellen fügen wir nun mit phpMyAdmin in die Datenbank ein. Die alte News-Tabelle muss man ggf. vorher löschen.

3. Kategorie hinzufügen

Zuerst schreiben wir den Adminteil in der wir die Kategorien bearbeiten können da es ohne Kategorien auch keine News geben kann. In der Rechteliste-Tabelle fügen wir dafür das neue Recht NewsKat ein. Aufgrund des neuen Recht werden wir die Dateien admin_NewsKat_add.php, admin_NewsKat_edit.php und admin_NewsKat_del.php hinzufügen müssen. Aber zuerst der Teil zum hinzufügen neuer Kategorien.

Zuerst schreiben wir die Template-Datei admin_NewsKat_add.tpl.

<form action="index.php?section=admin&amp;cat=NewsKat&amp;action=add" method="post">
    <fieldset>
        <legend>Newskategorie hinzufügen</legend>
        <label>Name: <input type="text" name="Name" /></label>
        <input type="submit" name="formaction" value="Kategorie hinzufügen" />
    </fieldset>
</form>

Die Include-Datei admin_NewsKat_add.php sieht wie folgt aus.

<?php
$ret 
= array();
$ret['filename'] = 'admin_NewsKat_add.tpl';
$ret['data'] = array();
if (
'POST' != $_SERVER['REQUEST_METHOD']) {
    return 
$ret;
}
if (!isset(
$_POST['formaction'], $_POST['Name'])) {
    return 
INVALID_FORM;
}
if (
'' == $Name trim($_POST['Name'])) {
    return 
EMPTY_FORM;
}
$sql 'SELECT
            ID
        FROM
            News_Kategorie
        WHERE
            Name = ?'
;
if (!
$stmt $db->prepare($sql)) {
    return 
$db->error;
}
$stmt->bind_param('s'$Name);
if (!
$stmt->execute()) {
    return 
$stmt->error;
}
if (
$stmt->fetch()) {
    return 
'Es ist bereits eine Kategorie mit diesen Namen vorhanden.';
}
$stmt->close();
$sql 'INSERT INTO
            News_Kategorie(Name)
        VALUES
            (?)'
;
if (!
$stmt $db->prepare($sql)) {
    return 
$db->error;
}
$stmt->bind_param('s'$Name);
if (!
$stmt->execute()) {
    return 
$stmt->error;
}
$stmt->close();
return 
showInfo('Die Kategorie wurde hinzugefügt.');
?>

4. Kategorie bearbeiten

Wir beginnen wieder zuerst mit den Template-Dateien. Zuerst schreiben wir die Datei admin_NewsKat_edit_select.tpl um eine Kategorie auszuwählen.

<?php
/* Daten:
 *   Kategorien - Ein Array mit allen bereits vorhandenen Kategorien. Bei einem Arrayelement
 *                ist der Schlüssel die ID und der Wert der Name der Kategorie.
 */
?><form action="index.php?section=admin&amp;cat=NewsKat&amp;action=edit" method="post">
    <fieldset>
        <legend>Kategorie wählen</legend>
        <label>Kategorie <select name="KatID">
            <option value="0">Bitte wählen</option>
            <?php foreach ($data['Kategorien'] as $key => $value) { ?>
            <option value="<?php echo $key; ?>"><?php echo htmlspecialchars($value); ?></option>
            <?php } ?>
            </select></label>
        <input type="submit" name="formaction" value="Kategorie wählen">
    </fieldset>
</form>

In der Include-Datei zeigen wir dieses Template an wenn die Datei nicht mit der POST-Methode aufgerufen wurde.

<?php
$ret 
= array();
$ret['filename'] = 'admin_NewsKat_edit_select.tpl';
$ret['data'] = array();
if (
'POST' != $_SERVER['REQUEST_METHOD']) {
    
$sql 'SELECT
                ID,
                Name
            FROM
                News_Kategorie
            ORDER BY
                Name ASC'
;
    if (!
$result $db->query($sql)) {
        return 
$db->error;
    }
    
$Kategorien = array();
    while (
$row $result->fetch_assoc()) {
        
$Kategorien[$row['ID']] = $row['Name'];
    }
    
$ret['data']['Kategorien'] = $Kategorien;
    return 
$ret;
}
?>

Wenn wir nun eine Kategorie auswählen zeigen wir die Daten in einem weiteren Template admin_NewsKat_edit_show.tpl an.

<?php
/* Daten:
 *    KatID - Die ID von der Kategorie
 *    Name - Der Name der Kategorie
 */
?><form action="index.php?section=admin&amp;cat=NewsKat&amp;action=edit" method="post">
    <fieldset>
        <legend>Kategorie bearbeiten</legend>
        <label>Name: <input type="text" name="Name" value="<?php echo htmlspecialchars($data['Name']); ?>" /></label>
        <input type="submit" name="formaction" value="Kategorie speichern" />
        <input type="hidden" name="KatID" value="<?php echo $data['KatID']; ?>" />
    </fieldset>
</form>

Anhand der benötigten Variablen wissen wir wie unserer Include-Datei aussehen muss.

<?php
    
// [...]
    
$ret['data']['Kategorien'] = $Kategorien;
    return 
$ret;
}
if (!isset(
$_POST['formaction'], $_POST['KatID'])) {
    return 
INVALID_FORM;
}
if (
'' == $KatID trim($_POST['KatID'])) {
    return 
EMPTY_FORM;
}
$sql 'SELECT
            ID,
            Name
        FROM
            News_Kategorie
        WHERE
            ID = ?'
;
if (!
$stmt $db->prepare($sql)) {
    return 
$db->error;
}
$stmt->bind_param('i'$KatID);
if (!
$stmt->execute()) {
    return 
$stmt->error;
}
$stmt->bind_result($KatID$Name);
if (!
$stmt->fetch()) {
    return 
'Es wurde keine News mit der angegebenen ID gefunden.';
}
$stmt->close();
if (
$_POST['formaction'] == 'Kategorie speichern') {
    
// todo
} else {
    
$ret['data']['KatID'] = $KatID;
    
$ret['data']['Name'] = $Name;
    
$ret['filename'] = 'admin_NewsKat_edit_show.tpl';
    return 
$ret;
}
?>

Wenn der Admin auf Kategorie speichern klickt speichern wie den neuen Namen ab, solange er nicht doppel oder leer ist.

<?php
// [...]
if ($_POST['formaction'] == 'Kategorie speichern') {
    if (!isset(
$_POST['Name'])) {
        return 
INVALID_FORM;
    }
    if (
'' == $Name trim($_POST['Name'])) {
        return 
EMPTY_FORM;
    }
    
$sql 'SELECT
                ID
            FROM
                News_Kategorie
            WHERE
                Name = ? AND
                ID != ?'
;
    if (!
$stmt $db->prepare($sql)) {
        return 
$db->error;
    }
    
$stmt->bind_param('si'$Name$KatID);
    if (!
$stmt->execute()) {
        return 
$stmt->error;
    }
    if (
$stmt->fetch()) {
        return 
'Es ist bereits eine Kategorie mit den Namen vorhanden.';
    }
    
$stmt->close();
    
$sql 'UPDATE
                News_Kategorie
            SET
                Name = ?
            WHERE
                ID = ?'
;
    if (!
$stmt $db->prepare($sql)) {
        return 
$db->error;
    }
    
$stmt->bind_param('si'$Name$KatID);
    if (!
$stmt->execute()) {
        return 
$stmt->error;
    }
    return 
showInfo('Die Kategorie wurde bearbeitet.');
} else {
// [...]
?>

5. Kategorie löschen

Wie beim Bearbeiten schreiben wir ein Template welches eine Auswahlliste aller Kategorien bereitstellt. Das Template ist fast identisch wie beim Bearbeiten.

<?php
/* Daten:
 *   Kategorien - Ein Array mit allen bereits vorhandenen Kategorien. Bei einem Arrayelement
 *                ist der Schlüssel die ID und der Wert der Name der Kategorie.
 */
?><form action="index.php?section=admin&amp;cat=NewsKat&amp;action=del" method="post">
    <fieldset>
        <legend>Kategorie wählen</legend>
        <label>Kategorie <select name="KatID">
            <option value="0">Bitte wählen</option>
            <?php foreach ($data['Kategorien'] as $key => $value) { ?>
            <option value="<?php echo $key; ?>"><?php echo htmlspecialchars($value); ?></option>
            <?php } ?>
            </select></label>
        <input type="submit" name="formaction" value="Kategorie löschen">
    </fieldset>
</form>

In der Include-Datei laden wir erstmal alle Kategorien in ein Array und zeigen das Template an.

<?php
$ret 
= array();
$ret['filename'] = 'admin_NewsKat_del.tpl';
$ret['data'] = array();
$sql 'SELECT
            ID,
            Name
        FROM
            News_Kategorie
        ORDER BY
            Name ASC'
;
if (!
$result $db->query($sql)) {
    return 
$db->error;
}
$Kategorien = array();
while (
$row $result->fetch_assoc()) {
    
$Kategorien[$row['ID']] = $row['Name'];
}
$ret['data']['Kategorien'] = $Kategorien;
if (
'POST' != $_SERVER['REQUEST_METHOD']) {
    return 
$ret;
}
?>

Beim Löschen müssen wir aufpassen das wir keine Kategorie löschen zu denen noch Newsbeiträge gehören. Daher schreiben wir einige Abfragen ob wir die News auch wirklich löschen können.

<?php
// [...]
if ('POST' != $_SERVER['REQUEST_METHOD']) {
    return 
$ret;
}
if (!isset(
$_POST['formaction'], $_POST['KatID'])) {
    return 
INVALID_FORM;
}
if (
'' == $KatID trim($_POST['KatID'])) {
    return 
EMPTY_FORM;
}
$sql 'SELECT
            ID
        FROM
            News_Kategorie
        WHERE
            ID = ?'
;
if (!
$stmt $db->prepare($sql)) {
    return 
$db->error;
}
$stmt->bind_param('i'$KatID);
if (!
$stmt->execute()) {
    return 
$stmt->error;
}
$stmt->bind_result($KatID);
if (!
$stmt->fetch()) {
    return 
'Es wurde keine Kategorie mit der angegebenen ID gefunden.';
}
$stmt->close();

$sql 'SELECT
            ID
        FROM
            News
        WHERE
            KatID = ?'
;
if (!
$stmt $db->prepare($sql)) {
    return 
$db->error;
}
$stmt->bind_param('i'$KatID);
if (!
$stmt->execute()) {
    return 
$stmt->error;
}
if (
$stmt->fetch()) {
    return 
'Es gibt noch Newsbeiträge die diese Kategorie verwenden.';
}
$stmt->close();

$sql 'DELETE FROM
            News_Kategorie
        WHERE
            ID = ?'
;
if (!
$stmt $db->prepare($sql)) {
    return 
$db->error;
}
$stmt->bind_param('i'$KatID);
if (!
$stmt->execute()) {
    return 
$stmt->error;
}
$stmt->close();
return 
showInfo('Die Kategorie wurde gelöscht.');
?>

6. News hinzufügen

Beim hinzufügen (und bearbeiten) einer News müssen wir uns überlegen wie wir die Formulare aufbauen. Neben der eigentlichen News müssen z.B. auch die Newslinks angegeben werden. Es gibt verschiedene Möglichkeiten wie man das machen kann.

So hoffnungslos es auch scheinen mag, es gibt ne Lösung genannt Session. Wir bereiten die Newserstellung vor indem wir erst alle Daten in einer Session speichern und dann erst in die Datenbank einfügen wenn wir fertig sind. So wird die Datenbank nicht vorher mit ungenutzten Müll gefüttert sondern alle Daten liegen erstmal in der Session. Wenn der Vorgang abgebrochen wird verfällt die Session eh nach einiger Zeit.

Zur Vorbereitung der Session setzen wir die session.use_only_cookies-Einstellung auf 1, damit die Session-ID nur per Cookie übermittelt wird. Dies machen wir in der index.php-Datei nach dem einstellen des Error-Reportings.

<?php
error_reporting
(E_ALL);
ini_set('display_errors'1);
ini_set('session.use_only_cookies'1);

// [...]
?>

Die Template-Datei sieht nun sehr überladen aus.

<?php
/* Daten:
 *    Titel - Der Titel der News
 *    Inhalt - Der Text der News
 *    KatID - Die ID der aktuell gewählten Kategorie
 *    Kategorien - Ein Array mit allen Kategorien. Bei einem Arrayelement ist der Schlüssel
 *                 die ID und der Wert der Name der Kategorie.
 *    Links - Ein Array mit den Links die zu der News gehört. Bei einem Arrayelement ist der
 *            Schlüssel eine fortlaufende Nummer, der Wert entspricht einem assoziativen
 *            Array mit den Schlüssel 'URL' und 'Beschreibung' mit den entsprechenden Werten.
 */
?><form action="index.php?section=admin&amp;cat=News&amp;action=add" method="post">
    <fieldset>
        <legend>News hinzufügen</legend>
        <label>Titel <input type="text" name="Titel" value="<?php echo htmlspecialchars($data['Titel']); ?>" /></label>
        <label>Inhalt <textarea name="Inhalt" cols="40" rows="10"><?php echo htmlspecialchars($data['Inhalt']); ?></textarea></label>
        <label>Kategorie <select name="KatID">
            <option value="0">Bitte wählen</option>
            <?php foreach ($data['Kategorien'] as $key => $value) {
                      if ($data['KatID'] == $key) { ?>
            <option value="<?php echo $key; ?>" selected="selected"><?php echo htmlspecialchars($value); ?></option>
            <?php     } else { ?>
            <option value="<?php echo $key; ?>"><?php echo htmlspecialchars($value); ?></option>
            <?php     }
                  } ?>
                </select>
            </label>
        <fieldset>
            <legend>Newslinks</legend>
            <?php if (count($data['Links'])) { ?>
            <ul>
                <?php foreach ($data['Links'] as $key => $value) { ?>
                <li><label>
                    <input type="checkbox" name="LinkID[]" value="<?php echo $key; ?>"/>
                        <?php echo htmlspecialchars($value['Beschreibung']); ?></label> - 
                        <a href="<?php echo htmlspecialchars($value['URL']); ?>"><?php echo htmlspecialchars($value['URL']); ?></a>
                </li>
                <?php } ?>
            </ul>
            <input type="submit" name="formaction" value="Markierte Links löschen" />
            <?php } else { ?>
            <p class="info">
                Es sind momentan keine Links hinzugefügt.
            </p>
            <?php } ?>
            <fieldset>
                <legend>Neuen Link hinzufügen</legend>
                <label>URL: <input type="text" name="URL" /></label>
                <label>Beschreibung: <input type="text" name="Beschreibung" /></label>
                <input type="submit" name="formaction" value="Link hinzufügen" />
            </fieldset>
        </fieldset>
        <input type="submit" name="formaction" value="News hinzufügen" />
    </fieldset>
</form>

Wie man sieht wird das Template mit diversen Werten gefüllt und das Template selbst enthält mehrere Submit-Buttons mit unterschiedlichen Beschriftungen für entsprechend unterschiedliche Aktionen. All diese Aktionen müssen wir in unserem PHP-Skript abfragen. Außerdem müssen wir eine Session starten und alle Felder vorinitialisieren.

<?php
$ret 
= array();
$ret['filename'] = 'admin_News_add.tpl';
$ret['data'] = array();

$sql 'SELECT
            ID,
            Name
        FROM
            News_Kategorie
        ORDER BY
            Name ASC'
;
if (!
$result $db->query($sql)) {
    return 
$db->error;
}
$Kategorien = array();
while (
$row $result->fetch_assoc()) {
    
$Kategorien[$row['ID']] = $row['Name'];
}
$ret['data']['Kategorien'] = $Kategorien;

session_start();
if (!isset(
$_SESSION['News']) OR 'POST' != $_SERVER['REQUEST_METHOD']) {
    
$_SESSION['News'] = array();
    
$_SESSION['News']['Titel'] = '';
    
$_SESSION['News']['Inhalt'] = '';
    
$_SESSION['News']['KatID'] = 0;
    
$_SESSION['News']['Links'] = array();
} else {
    
// [...]
}
$ret['data']['Titel'] = $_SESSION['News']['Titel'];
$ret['data']['Inhalt'] = $_SESSION['News']['Inhalt'];
$ret['data']['KatID'] = $_SESSION['News']['KatID'];
$ret['data']['Links'] = $_SESSION['News']['Links'];
return 
$ret;
?>

Falls ein Formularknopf verwendet wird prüfen wir zuerst ob alle Formularfelder vorhanden ist, egal ob wir sie in diesem Aufruf verwenden oder nicht. Danach speichern wir stehts die Felder Titel, Inhalt und KatID in der Session.

<?php
// [...]
} else {
    
// Aufruf der POST und Session vorinitialisiert
    
if (!isset($_POST['formaction'], $_POST['Titel'], $_POST['Inhalt'],
            
$_POST['KatID'], $_POST['URL'], $_POST['Beschreibung'])) {
        return 
INVALID_FORM;
    }

    
// speichern der allgemeinen newsdaten
    
$_SESSION['News']['Titel'] = $_POST['Titel'];
    
$_SESSION['News']['Inhalt'] = $_POST['Inhalt'];
    
$_SESSION['News']['KatID'] = $_POST['KatID'];
}
// [...]
?>

Wenn wir einen Link hinzufügen wollen prüfen wir die beiden Felder URL und Beschreibung und erweitern das Array.

<?php
    
// [...]
    // speichern der allgemeinen newsdaten
    
$_SESSION['News']['Titel'] = $_POST['Titel'];
    
$_SESSION['News']['Inhalt'] = $_POST['Inhalt'];
    
$_SESSION['News']['KatID'] = $_POST['KatID'];

    if (
'Link hinzufügen' == $_POST['formaction']) {
        if (
'' == $URL trim($_POST['URL']) OR
                
'' == $Beschreibung trim($_POST['Beschreibung'])) {
            return 
EMPTY_FORM;
        }
        
$_SESSION['News']['Links'][] = array('URL' => $URL'Beschreibung' => $Beschreibung);
    }
}
// [...]
?>

Wenn wir Links löschen wollen durchlaufen wir das Array und löschen die entsprechenden Arrayelemente aus der Liste.

<?php
        
// [...]
        
$_SESSION['News']['Links'][] = array('URL' => $URL'Beschreibung' => $Beschreibung);
    }
    if (
'Markierte Links löschen' == $_POST['formaction']) {
        if (!isset(
$_POST['LinkID'])) {
            return 
EMPTY_FORM;
        }
        if (!
is_array($_POST['LinkID'])) {
            return 
INVALID_FORM;
        }
        foreach (
$_POST['LinkID'] as $IDs) {
            unset(
$_SESSION['News']['Links'][$IDs]);
        }
    }
}
// [...]
?>

Der spaßige Teil ist die Aktion News hinzufügen. Zuerst prüfen wir ob alle Texte eingegeben sind, dann ob die gewählte Kategorie auch existiert und fügen dann die News und die Links in die Datenbank ein.

<?php
        
// [...]
        
foreach ($_POST['LinkID'] as $IDs) {
            unset(
$_SESSION['News']['Links'][$IDs]);
        }
    }
    if (
'News hinzufügen' == $_POST['formaction']) {
        if (
'' == $Titel trim($_SESSION['News']['Titel']) OR
                
'' == $Inhalt trim($_SESSION['News']['Inhalt']) OR
                
'' == $KatID trim($_SESSION['News']['KatID'])) {
            return 
EMPTY_FORM;
        }
        
$Links $_SESSION['News']['Links'];

        
// gucken ob es die Kategorie gibt
        
$sql 'SELECT
                    ID
                FROM
                    News_Kategorie
                WHERE
                    ID = ?'
;
        if (!
$stmt $db->prepare($sql)) {
            return 
$db->error;
        }
        
$stmt->bind_param('i'$KatID);
        if (!
$stmt->execute()) {
            return 
$stmt->error;
        }
        
$stmt->bind_result($KatID);
        if (!
$stmt->fetch()) {
            return 
'Es wurde keine Kategorie mit der angegebenen ID gefunden.';
        }
        
$stmt->close();

        
$sql 'INSERT INTO
                    News(Titel, Inhalt, Datum, KatID, AutorID)
                VALUES
                    (?, ?, NOW(), ?, ?)'
;
        if (!
$stmt $db->prepare($sql)) {
            return 
$db->error;
        }
        
$stmt->bind_param('ssii'$Titel$Inhalt$KatID$UserID);
        if (!
$stmt->execute()) {
            return 
$stmt->error;
        }
        
$NewsID $stmt->insert_id;
        
$stmt->close();

        
$sql 'INSERT INTO
                    News_Link(NewsID, URL, Beschreibung)
                VALUES
                    (?,?,?)'
;
        if (!
$stmt $db->prepare($sql)) {
            return 
$db->error;
        }  
        foreach (
$Links as $Link) {
            
$stmt->bind_param('iss'$NewsID$Link['URL'], $Link['Beschreibung']);
            if (!
$stmt->execute()) {
                return 
$stmt->error;
            }
        }
        
$stmt->close();
        unset(
$_SESSION['News']); // Sessiondaten löschen, brauchen wir nicht mehr.
        
return showInfo('Die News wurde hinzugefügt.');
    }
}
// [...]
?>

7. News bearbeiten

Wenn wir eine News bearbeiten benutzen wir den selben Formularaufbau wie beim Hinzufügen. Wir müssen nur die Session anders vorinitialisieren. Statt leere Strings und Arrays füllen wir die Session mit einem Datensatz aus der News-Tabelle.

Zuerst schreiben wir den einfachen Fall wo wir eine News über eine Dropdown-Liste auswählen. Die admin_News_edit_select.tpl-Datei sieht wie folgt aus.

<?php
/*
 * Daten:
 *    News - Ein Array mit allen Newsbeiträgen. Bei einem Arrayelement ist der Schlüssel
 *           Die ID der News und der Wert ist ein assoziatives Array mit den folgenden
 *           Werten:
 *               Datum - Das Datum wann die News geschrieben wurde
 *               Titel - Der Titel der News, ungekürzt.
 */
?><form action="index.php?section=admin&amp;cat=News&amp;action=edit" method="post">
    <fieldset>
        <legend>News wählen</legend>
        <label>News: <select name="NewsID">
            <option value="0">Bitte wählen</option>
            <?php foreach ($data['News'] as $key => $value) { ?>
            <option value="<?php echo $key; ?>">(<?php echo htmlspecialchars($value['Datum']); ?>)
                <?php echo htmlspecialchars($value['Titel']); ?></option>
            <?php } ?>
            </select></label>
        <input type="submit" name="formaction" value="News wählen" />
    </fieldset>
</form>

Der erste Teil des PHP-Skripts sieht wie folgt aus.

<?php
$ret 
= array();
$ret['filename'] = 'admin_News_edit_select.tpl';
$ret['data'] = array();
if (
'POST' != $_SERVER['REQUEST_METHOD']) {
    
$sql 'SELECT
                ID,
                Titel,
                Datum
            FROM
                News
            ORDER BY
                Datum DESC'
;
    if (!
$result $db->query($sql)) {
        return 
$db->error;
    }
    
$News = array();
    while (
$row $result->fetch_assoc()) {
        
$News[$row['ID']] = array('Datum' => $row['Datum'], 'Titel' => $row['Titel']);
    }
    
$ret['data']['News'] = $News;
} else {
    
// [...]
}
return 
$ret;
?>

Da wir fast die gleiche Formular fürs Bearbeiten benutzen wie fürs Hinzufügen einer News können wir die bereits vorhandene Template-Datei kopieren und in admin_News_edit_details.tpl speichern.

<?php
/* Daten:
 *    Titel - Der Titel der News
 *    Inhalt - Der Text der News
 *    KatID - Die ID der aktuell gewählten Kategorie
 *    Kategorien - Ein Array mit allen Kategorien. Bei einem Arrayelement ist der Schlüssel
 *                 die ID und der Wert der Name der Kategorie.
 *    Links - Ein Array mit den Links die zu der News gehört. Bei einem Arrayelement ist der
 *            Schlüssel eine fortlaufende Nummer, der Wert entspricht einem assoziativen
 *            Array mit den Schlüssel 'URL' und 'Beschreibung' mit den entsprechenden Werten.
 */
?><form action="index.php?section=admin&amp;cat=News&amp;action=edit" method="post">
    <fieldset>
        <legend>News bearbeiten</legend>
        <label>Titel <input type="text" name="Titel" value="<?php echo htmlspecialchars($data['Titel']); ?>" /></label>
        <label>Inhalt <textarea name="Inhalt" cols="40" rows="10"><?php echo htmlspecialchars($data['Inhalt']); ?></textarea></label>
        <label>Kategorie <select name="KatID">
            <option value="0">Bitte wählen</option>
            <?php foreach ($data['Kategorien'] as $key => $value) {
                      if ($data['KatID'] == $key) { ?>
            <option value="<?php echo $key; ?>" selected="selected"><?php echo htmlspecialchars($value); ?></option>
            <?php     } else { ?>
            <option value="<?php echo $key; ?>"><?php echo htmlspecialchars($value); ?></option>
            <?php     }
                  } ?>
                </select>
            </label>
        <fieldset>
            <legend>Newslinks</legend>
            <?php if (count($data['Links'])) { ?>
            <ul>
                <?php foreach ($data['Links'] as $key => $value) { ?>
                <li><label>
                    <input type="checkbox" name="LinkID[]" value="<?php echo $key; ?>"/>
                        <?php echo htmlspecialchars($value['Beschreibung']); ?></label> - 
                        <a href="<?php echo htmlspecialchars($value['URL']); ?>"><?php echo htmlspecialchars($value['URL']); ?></a>
                </li>
                <?php } ?>
            </ul>
            <input type="submit" name="formaction" value="Markierte Links löschen" />
            <?php } else { ?>
            <p class="info">
                Es sind momentan keine Links hinzugefügt.
            </p>
            <?php } ?>
            <fieldset>
                <legend>Neuen Link hinzufügen</legend>
                <label>URL: <input type="text" name="URL" /></label>
                <label>Beschreibung: <input type="text" name="Beschreibung" /></label>
                <input type="submit" name="formaction" value="Link hinzufügen" />
            </fieldset>
        </fieldset>
        <input type="submit" name="formaction" value="News bearbeiten" />
    </fieldset>
</form>

In der Include-Datei müssen wir nun entsprechend auf die Submit-Buttons reagieren. Zuerst müssen wir jedoch die Session füllen.

<?php
    
// [...]
} else {
    if (!isset(
$_POST['formaction'])) {
        return 
INVALID_FORM;
    }
    
$ret['filename'] = 'admin_News_edit_details.tpl';
    
session_start();
    if (!isset(
$_SESSION['News']) OR 'News wählen' == $_POST['formaction']) {
        if (!isset(
$_POST['formaction'], $_POST['NewsID'])) {
            return 
INVALID_FORM;
        }
        if (
'' == $NewsID trim($_POST['NewsID'])) {
            return 
EMPTY_FORM;
        }
        
$sql 'SELECT
                    ID,
                    Titel,
                    Inhalt,
                    KatID
                FROM
                    News
                WHERE
                    ID = ?'
;
        if (!
$stmt $db->prepare($sql)) {
            return 
$db->error;
        }
        
$stmt->bind_param('i'$NewsID);
        if (!
$stmt->execute()) {
            return 
$stmt->error;
        }
        
$stmt->bind_result($NewsID$Titel$Inhalt$KatID);
        if (!
$stmt->fetch()) {
            return 
'Es wurde keine News mit dieser ID gefunden.';
        }
        
$stmt->close();
        
$_SESSION['News'] = array();
        
$_SESSION['News']['ID'] = $NewsID;
        
$_SESSION['News']['Titel'] = $Titel;
        
$_SESSION['News']['Inhalt'] = $Inhalt;
        
$_SESSION['News']['KatID'] = $KatID;

        
$sql 'SELECT
                    URL,
                    Beschreibung
                FROM
                    News_Link
                WHERE
                    NewsID = ?'
;
        if (!
$stmt $db->prepare($sql)) {
            return 
$stmt->error;
        }
        
$stmt->bind_param('i'$NewsID);
        if (!
$stmt->execute()) {
            return 
$stmt->error;
        }
        
$Links = array();
        
$stmt->bind_result($URL$Beschreibung);
        while (
$stmt->fetch()) {
            
$Links[] = array('URL' => $URL'Beschreibung' => $Beschreibung);
        }
        
$stmt->close();
        
$_SESSION['News']['Links'] = $Links;
    }

    
$sql 'SELECT
                ID,
                Name
            FROM
                News_Kategorie
            ORDER BY
                Name ASC'
;
    if (!
$result $db->query($sql)) {
        return 
$db->error;
    }
    
$Kategorien = array();
    while (
$row $result->fetch_assoc()) {
        
$Kategorien[$row['ID']] = $row['Name'];
    }
    
$ret['data']['Kategorien'] = $Kategorien;
    
$ret['data']['Titel'] = $_SESSION['News']['Titel'];
    
$ret['data']['Inhalt'] = $_SESSION['News']['Inhalt'];
    
$ret['data']['KatID'] = $_SESSION['News']['KatID'];
    
$ret['data']['Links'] = $_SESSION['News']['Links'];
}
return 
$ret;
?>

Dann kommt der gleiche Programmcode zum Speichern der aktuellen Inhalte und zum Verwalten der Links.

<?php
        
// [...]
        
$stmt->close();
        
$_SESSION['News']['Links'] = $Links;
    }
    if (isset(
$_POST['Titel'], $_POST['Inhalt'], $_POST['KatID'])) {
        
// speichern der allgemeinen newsdaten
        
$_SESSION['News']['Titel'] = $_POST['Titel'];
        
$_SESSION['News']['Inhalt'] = $_POST['Inhalt'];
        
$_SESSION['News']['KatID'] = $_POST['KatID'];
    }
    
    if (
'Markierte Links löschen' == $_POST['formaction']) {
        if (!isset(
$_POST['LinkID'])) {
            return 
EMPTY_FORM;
        }
        if (!
is_array($_POST['LinkID'])) {
            return 
INVALID_FORM;
        }
        foreach (
$_POST['LinkID'] as $IDs) {
            unset(
$_SESSION['News']['Links'][$IDs]);
        }
    }

    if (
'Link hinzufügen' == $_POST['formaction']) {
        if (
'' == $URL trim($_POST['URL']) OR
                
'' == $Beschreibung trim($_POST['Beschreibung'])) {
            return 
EMPTY_FORM;
        }
        
$_SESSION['News'][