PHP/Tutorials/Automatische Erzeugung einer Sitemap
Eine Sitemap bietet dem Nutzer eine übersichtliche Darstellung aller Seiten einer Website. Diese kann von Hand gepflegt werden, was aber bei Änderungen und größeren Webauftritten aufwendig werden kann. Mithilfe eines PHP-Skriptes lassen sich die sowieso schon in der Ordner-Struktur vorhandenen Informationen auslesen.
Inhaltsverzeichnis
Das Szenario
Um das Grundprinzip einfach zu halten, sei hier eine einfache Website vorausgesetzt, die aus mehreren .html-Dateien in Ordnern besteht. Die Kategorisierung erfolgt darüber, in welchem Ordner die betreffende HTML-Datei zu finden ist, dabei können auch mehrere Unterordner in einem Verzeichnis enthalten sein. Außerdem setzen wir voraus, dass jedes HTML-Dokument eine Überschrift der Ebene 1 besitzt. Der Aufbau sei wie folgt:
Sitemap ├── Fotografie │ ├── index.html │ ├── lieblingsbilder.html │ └── Makrofotografie │ └── index.html ├── index.html ├── sitemap.php ├── Urlaubsberichte │ └── mond.html └── Webentwicklung └── marquee.html
Die Vorgehensweise
Das Skript muss den Ordner einlesen und fängt dabei auf der obersten Ebene an. Trifft es dabei auf eine HTML-Datei, so muss es den Inhalt des h1-Elementes auslesen und ausgeben und auf diese Datei verlinken. Trifft es hingegen auf einen Ordner, so muss das Vorgehen von neuem beginnen und nach vollständiger Abarbeitung dieses Zweigs wieder mit dem Inhalt des Ordners fortfahren, bei dem unterbrochen wurde. Dieses Vorgehen nennt man Rekursion.
Konkret realisiert wird dieses durch eine Funktion, die sich im Falle eines Ordners selbst erneut aufruft und im Falle einer HTML-Datei lediglich eine Ausgabe erzeugt. Da Ordner nicht unendlich tief verschachtelt sein kann – Tricks mit Symbolischen Links in einem untergeordneten Ordner auf einen übergeordneten Ordner mal außen vor – bricht die Rekursion irgendwann ab und wird nicht zur Endlosrekursion.
Das Skript
<?php
function recurse ($dir) {
$files = array_diff (scandir ($dir), ['.', '..']);
foreach ($files as $file) {
if (is_dir ($dir.'/'.$file)) {
echo '<li><a href="'.htmlspecialchars($dir.'/'.$file).'"><b>'.htmlspecialchars($file).'</b></a><ul>'.PHP_EOL;
recurse ($dir.'/'.$file);
echo '</ul></li>'.PHP_EOL;
} elseif (pathinfo($dir.'/'.$file, PATHINFO_EXTENSION) == 'html') {
preg_match("'<h1>(.*?)</h1>'si", file_get_contents($dir.'/'.$file), $heading);
echo '<li><a href="'.htmlspecialchars($dir.'/'.$file).'">'.strip_tags($heading[1]).'</a></li>'.PHP_EOL;
}
}
}
?>
<!-- html --->
<ul>
<?php
// Aufrufen mit dem aktuellen Verzeichnis ('.'),
// ggf. anpassen, wenn sitemap.php nicht im Root-Verzeichnis der Website liegt
recurse('.');
?>
</ul>
Der Code erzeugt eine Struktur wie die folgende (Verlinkung der Einfachheit halber weggelassen):
- Fotografie
- Makrofotografie
- Die kleinen Dinge ganz groß herausbringen
- Übersicht über Fotografie
- Bilder-Best-of von 2020
- Makrofotografie
- Urlaubsberichte
- Warum man Sauerstoff mit zum Mond nehmen sollte...
- Webentwicklung
- Das marquee-Element ist noch nicht tot!
- Startseite
Denkbare Erweiterungen
Natürlich ist dieses Sitemap-Skript unvollkommen und nur auf den konkreten Fall dieser simplen Beispiel-Website angepasst, wie sie in der Praxis vermutlich kaum bzw. nicht vorkommt. Dadurch ist es leicht verständlich und gut für eigene Zwecke anpassbar. Ideen hierfür:
- Unterordner von der Sitemap ausschließen – möglicher Ansatz: globales Array mit auszuschließenden Pfaden
- Kategorie-Bezeichnung nicht aus dem Ordner-Namen ableiten, sondern aus der h1-Überschrift eines beinhaltenden index.html-Dokuments – möglicher Ansatz: in Rückgabewert von
recurse()
auswerten, innerhalb der Funktion wird dies als String zurückgegeben - anderen Namen als die h1-Überschrift in der Sitemap – möglicher Ansatz: in den Dateien einen HTML-Kommentar oder eine Meta-Angabe notieren, die vom Skript ausgelesen und – falls vorhanden – den Wert der h1-Überschrift in der Sitemap überschreibt
- Eventuell möchte man die Sitemap bei Webauftritten mit vielen Seiten und Besuchern nicht bei jedem Aufruf der Sitemap neu generieren, sondern sie cachen. Dazu könnte man die generierte Seite in einer Datei zwischenspeichern und sofern diese Datei noch zu alt ist, den Inhalt der Datei ausgeben und nur dann neu generieren, falls die Datei vor einer längeren Zeit zuletzt neu generiert wurde.