Benutzer-Werkzeuge

Webseiten-Werkzeuge


projekt-offen:software:dokuwiki
♏️ Sternzeichen des Tages: Skorpion 13.11.2026 ▼ (hier Klicken zum Öffnen) ▼
Wir wünschen allen „Skorpion“-Geborenen viel Glück und Erfolg! 🍀
📜 Der Skorpion stammt aus der Sage um Orion: Die Erdgöttin Gaia schickte ihn, um den übermütigen Jäger zu stoppen. Beide wurden schließlich an den Sternenhimmel versetzt – als Mahnung, dass auch große Stärke ihre Grenzen kennt.
Skorpion
(24. Oktober – 22. November)
📖 Weitere Infos ▼ (hier Klicken zum Öffnen) ▼
Element: 💧 Wasser  |  🪐 Herrscherplanet: Pluto
🏛️ Schutzgottheit: Pluton (Gott der Unterwelt)
📝 Charakteristik: Der Skorpion ist leidenschaftlich, intensiv und durchschauend. Er verfügt über eine magnetische Ausstrahlung und tiefe psychologische Einsicht. Ein mystischer und unergründlicher Charakter.
💞 Liebe & Kompatibilität: ✅ Passt gut mit: Krebs, Fische, Steinbock | ⚠️ Schwierig mit: Löwe, Stier
🍀 Glückszahl: 8  |  🎨 Glücksfarbe: Dunkelrot  |  📆 Glückstag: Dienstag
💎 Glücksstein: Topas  |  🦴 Körperteil: Becken
🌟 Bekannte Persönlichkeiten: Marie Curie, Pablo Picasso, Martin Luther
💡 10 Tipps für Skorpion-Geborene:
  1. Vertrauen üben – nicht jedem Misstrauen entgegenbringen
  2. Loslassen können – alte Kränkungen ruhen lassen
  3. Offenheit zeigen – nicht alles geheim halten
  4. Kompromisse eingehen – nicht nur Alles-oder-Nichts denken
  5. Gelassenheit üben – nicht jede Kleinigkeit zur Machtfrage machen
  6. Verzeihen können – auch sich selbst
  7. Leichtigkeit zulassen – nicht alles tiefgründig nehmen
  8. Kontrolle abgeben – nicht alles selbst steuern wollen
  9. Verletzlichkeit zeigen – Nähe braucht Offenheit
  10. Ruhe bewahren – nicht impulsiv reagieren
💡 Weisheit des Tages … vom: 13.11.2026 ▼ (hier Klicken zum Öffnen) ▼
Heute von: Mark Aurel (121–180), römischer Kaiser und Philosoph
Blicke in dich. In deinem Inneren ist eine Quelle, die nie versiegt, wenn du nur zu graben verstehst.
Dieser Spruch wurde bereits 1549-mal eingeblendet.
Marcus Aurelius
📜 Kurzbiografie ▼ (hier Klicken zum Öffnen) ▼
Mark Aurel (* 26. April 121 in Rom als Marcus Annius Catilius Severus; † 17. März 180 in Vindobona oder Sirmium), auch Marc Aurel oder Marcus Aurelius, war von 161 bis 180 römischer Kaiser und als Philosoph der letzte bedeutende Vertreter der jüngeren Stoa. Als Princeps und Nachfolger seines Adoptivvaters Antoninus Pius nannte er sich selbst Marcus Aurelius Antoninus Augustus. Mit seiner Regierungszeit endete in mancherlei Hinsicht eine Phase innerer und äußerer Stabilität und Prosperität für das Römische Reich, die Ära der sogenannten Adoptivkaiser. Mark Aurel war der letzte von ihnen, denn in seinem Sohn Commodus stand ein leiblicher Erbe für die Herrscherfunktion bereit. Innenpolitische Akzente setzte Mark Aurel in Gesetzgebung und Rechtsprechung, etwa bei der Erleichterung des Loses von Benachteiligten der damaligen römischen Gesellschaft wie Sklaven und Frauen. Außergewöhnlichen Herausforderungen hatte er sich hinsichtlich einer katastrophalen Tiberüberschwemmung zu stellen sowie in der Konfrontation mit der Antoninischen Pest und angesichts spontaner Christenverfolgungen innerhalb des Römischen Reiches. An den Reichsgrenzen musste er nach einer längeren Friedenszeit wieder an mehreren Fronten gegen eindringende Feinde vorgehen. Insbesondere waren der Osten des Reiches durch die Parther, über die Mark Aurels Mitkaiser Lucius Verus triumphierte, und der Donauraum durch diverse Germanen-Stämme bedroht. Sein letztes Lebensjahrzehnt verbrachte Mark Aurel daher vorwiegend im Feldlager. Hier verfasste er die Selbstbetrachtungen, die ihn der Nachwelt als Philosophenkaiser präsentieren und die mitunter zur Weltliteratur gezählt werden.

Dies ist eine alte Version des Dokuments!


Projekt: DokuWiki


Unternehmens-Wiki: Was man bei der Einführung eines Firmenwikis beachten muss…




===== Einführung und Realisierung eines Unternehmens-Wiki =====


Hier noch zwei YouTube-Videos zur Handhabung...


Webserver/htaccess/Passwortschutz

Webserver/htaccess

DokuWiki

DokuWiki ist eine einfach zu bedienende und äußerst vielseitige Open-Source-Wiki-Software, die keine Datenbank benötigt.

Es wird von den Nutzern wegen seiner sauberen und lesbaren Syntax geliebt. Die einfache Wartung, Sicherung und Integration machen es zu einem Favoriten für Administratoren. Eingebaute Zugriffskontrollen und Authentifizierungs-Connectoren machen DokuWiki besonders nützlich im Unternehmenskontext, und die große Anzahl von Plugins der lebendigen Community ermöglicht eine breite Palette von Anwendungsfällen jenseits eines traditionellen Wikis.

— Roland Otto 21.04.2026 17:42



DokuWiki (Erklärung)

.: Was ist DokuWiki – und warum gerade DokuWiki? :.

Worum geht es? Dieses ganze Wiki läuft mit DokuWiki. Der Beitrag erklärt in einfachen Worten, was ein Wiki ist, was DokuWiki besonders macht und warum es sich für Schule, Kurs, Verein und Firma gleichermaßen eignet. Zum Nachschlagen und als Einstieg für alle, die selbst ein Wiki aufsetzen wollen.

📌 Auf einen Blick

Was Wie
Art freie Wiki-Software (Open Source), seit 2004
Erfinder Andreas Gohr und die DokuWiki-Gemeinschaft
Programmiersprache PHP – läuft auf fast jedem Webspace und auch auf einem Raspberry Pi
Daten keine Datenbank – jede Seite ist eine einfache Textdatei
Rechte eingebaute Zugriffskontrolle (ACL) für Benutzer und Gruppen
Erweiterbar über tausend Plugins und viele Designs (Templates)
Lizenz GNU GPL Version 2 – kostenlos, auch für Firmen

📖 1. Was ist überhaupt ein Wiki?

Ein Wiki ist eine Webseite, die man direkt im Browser bearbeiten kann – ohne Programmierkenntnisse. Das bekannteste Beispiel ist Wikipedia. „Wiki“ kommt aus dem Hawaiischen und heißt „schnell“.

Merkmal Was bedeutet das im Alltag?
Jeder (Berechtigte) kann schreiben Wissen steckt nicht mehr nur in einem Kopf oder einem Ordner
Versionsgeschichte Jede Änderung wird gespeichert. Ein Fehler? → „Ältere Versionen“ → alte Fassung wiederherstellen
Verlinkung Seiten verweisen aufeinander – es entsteht ein Netz statt eines Stapels
Suche Volltextsuche über alle Seiten
Gleichzeitiges Arbeiten Wer eine Seite bearbeitet, sperrt sie kurz – so überschreibt niemand die Arbeit eines anderen

Merksatz: Ein Wiki ist ein gemeinsames Notizbuch mit eingebautem Gedächtnis – nichts geht verloren, alles lässt sich zurückdrehen.


📂 2. Die Besonderheit: Textdateien statt Datenbank

Die meisten Wiki- und Webseiten-Programme (z. B. MediaWiki oder WordPress) brauchen eine Datenbank. DokuWiki nicht: Jede Seite liegt als ganz normale Textdatei auf dem Server. Der Seitenname verrät sogar, wo:

Schaubild: Seitenname und Datei auf dem Server

Aus projekt-offen:software:dokuwiki wird die Datei data/pages/projekt-offen/software/dokuwiki.txt – jeder Doppelpunkt ist ein Ordner.

Was folgt daraus?

Vorteil Warum?
💾 Sicherung ist einfach Ordner data/ und conf/ kopieren – fertig. Kein Datenbank-Export
🔧 Wenig Technik Ein Webserver mit PHP genügt. Läuft auf billigem Webspace und auf dem Raspberry Pi im Homelab
👀 Lesbar ohne Wiki Die Textdateien kann man mit jedem Editor öffnen – auch in 20 Jahren noch
🚚 Umzug in Minuten Ordner auf den neuen Server kopieren, fertig
Nachteil Wann spielt das eine Rolle?
Sehr große Wikis Bei vielen zehntausend Seiten und sehr vielen gleichzeitigen Schreibern sind Datenbank-Wikis im Vorteil
Auswertungen Abfragen wie „alle Seiten mit Feld X“ gehen nur über Plugins

Für Schule, Kurs, Verein, Projekt oder Abteilung ist das so gut wie nie ein Problem.


✍️ 3. Schreiben im Wiki – die Syntax

DokuWiki-Seiten werden mit einer einfachen Auszeichnungssprache geschrieben. Man schreibt Text und markiert mit wenigen Zeichen, was fett, eine Überschrift oder ein Link sein soll. (Wer das nicht mag: In diesem Wiki gibt es zusätzlich einen Editor mit Knöpfen wie in Word.)

Man tippt Ergebnis
**fett** fett
//kursiv// kursiv
__unterstrichen__ unterstrichen
''Code'' Code
[[projekt-offen:software:dokuwiki|Link auf eine Seite]] Link auf eine Seite
* Punkt (zwei Leerzeichen davor) eine Aufzählung
====== Überschrift ====== eine große Überschrift
^ Kopf ^ Kopf ^ und | Zelle | Zelle | eine Tabelle wie diese hier

Die vollständige Übersicht gibt es auf der Seite Formatierungshilfe in diesem Wiki und bei dokuwiki.org.

Tipp zum Lernen: Bei jeder Seite auf „Quelltext anzeigen“ bzw. „Seite bearbeiten“ klicken und schauen, wie etwas gemacht ist. So lernt man die Syntax am schnellsten – auch an dieser Seite.


🏢 4. Wofür man DokuWiki einsetzen kann

Einsatz Beispiel
🏫 Schule und Kurs Unterrichtsmaterial, Anleitungen, Linksammlungen für die Klasse
🏢 Firma Wissensdatenbank, Einarbeitung neuer Kollegen, Checklisten, Handbücher
🛠️ Projekt Protokolle, Aufgaben, Entscheidungen – nachvollziehbar mit Versionsgeschichte
🏠 Homelab und privat eigenes Notizbuch: welcher Dienst läuft wo, wie wurde er eingerichtet?
🌐 Kleine Webseite DokuWiki als einfaches CMS – wie dieses Wiki

⚖️ 5. Warum hier DokuWiki – und nicht etwas anderes?

DokuWiki MediaWiki (Wikipedia) WordPress
Gedacht für Wissen gemeinsam pflegen sehr große, offene Wikis Blogs und Webseiten
Datenbank nötig ❌ nein ✅ ja ✅ ja
Rechte je Bereich ✅ eingebaut nur eingeschränkt über Plugins
Versionsgeschichte ✅ jede Seite ✅ jede Seite eingeschränkt
Aufwand für Betrieb gering mittel bis hoch mittel

Merksatz: DokuWiki ist das „kleine, robuste Werkzeug“: wenig Technik, einfache Sicherung, feine Rechte – genau richtig, wenn ein paar bis ein paar hundert Leute gemeinsam Wissen pflegen.

.: DokuWiki betreiben und anpassen – so ist dieses Wiki aufgebaut :.

Worum geht es? Hier steht, wie das EURoBa-Wiki eingerichtet ist: wie Rechte vergeben werden, wie man DokuWiki anpasst und erweitert und worauf man beim Betrieb achten muss. Zum Nachschlagen für mich – und als Vorlage für eigene Wikis.

📌 Auf einen Blick

Was Wie hier gelöst
Sprache Deutsch, Anrede mit „du“
Aussehen Standard-Template „dokuwiki“, ohne Änderungen am Template selbst
Bereiche Namensräume mit der Endung -offen (für alle) und -geschlossen (nur für Gruppen)
Erweiterungen fertige Plugins aus der Gemeinschaft + eigene EURoBa-Plugins
Sicherung vor jeder Änderung: Seiten, Daten, Plugins und Konfiguration kopieren

🔐 1. Wer darf was? – Zugriffsrechte (ACL)

ACL heißt Access Control List, auf Deutsch Zugriffsliste. Darin steht für jeden Bereich (Namensraum) und jede Gruppe, was erlaubt ist. Die Stufen bauen aufeinander auf:

Schaubild: Rechtestufen und Namensräume

Wer „Anlegen“ darf, darf auch bearbeiten und lesen. Die Tabelle zeigt ein vereinfachtes Beispiel mit erfundenen Gruppen.

So funktioniert das in der Praxis:

  • Namensräume sind Ordner. Rechte gelten für einen Namensraum samt allem, was darin liegt (projekt-offen:*).
  • Die genaueste Regel gewinnt. Gibt es eine Regel für projekt-offen:* und eine für projekt-offen:software:*, zählt für Seiten unter software die zweite.
  • Gruppen statt Einzelpersonen. Ein neuer Kursteilnehmer kommt in die Gruppe seines Kurses – und hat sofort die richtigen Rechte.
  • Der Name verrät den Schutz. Endet ein Namensraum auf -offen, ist er öffentlich, bei -geschlossen nicht. Man sieht schon am Link, ob ein Inhalt nach außen gehört.

Sicherheitsregel: So wenig Rechte wie möglich. Besucher bekommen nur „Lesen“, und nur dort, wo es gewollt ist. Schreiben dürfen nur angemeldete Benutzer in ihren Bereichen. Der Admin-Bereich bleibt für alle anderen gesperrt.


🎨 2. DokuWiki anpassen – vier Ebenen

Man kann DokuWiki auf vier Ebenen verändern, von „ein Häkchen setzen“ bis „selbst programmieren“:

Ebene Was man tut Beispiel in diesem Wiki Wissen nötig
1. Konfiguration Einstellungen im Admin-Bereich Sprache „du“, Titel, Rechte einschalten keins
2. Plugins fertige Erweiterungen installieren Akkordeons, farbige Kästen (WRAP), Schlagwörter (Tags), Kommentare, Editor mit Knöpfen wenig
3. Templates das Aussehen wählen und mit eigenem CSS anpassen Standard-Template, kleine Anpassungen im Plugin-CSS etwas CSS
4. Eigene Plugins selbst in PHP programmieren Weisheit des Tages, Sternzeichen des Tages, automatische Jahre PHP

Merksatz: So weit oben wie möglich bleiben. Was mit einer Einstellung geht, braucht kein Plugin – und was ein fertiges Plugin kann, muss man nicht selbst programmieren. Eigene Plugins lohnen sich erst, wenn es nichts Passendes gibt.

Wie eigene Plugins aufgebaut sind, zeigen die Beiträge unter Spezial-Programmierungen weiter unten auf dieser Seite. Weitere Anregungen gibt es bei den Tipps und Tricks auf dokuwiki.org.


🛡️ 3. Sicher betreiben – die Checkliste

Aufgabe Warum? Wie oft?
💾 Sicherung von data/ und conf/ Ohne Sicherung kein Zurück – bei Fehlern, Angriffen oder defektem Server vor jeder Änderung, sonst regelmäßig
⬆️ DokuWiki aktualisieren Updates schließen Sicherheitslücken. DokuWiki meldet neue Versionen im Admin-Bereich sobald ein Update erscheint
🧩 Plugins prüfen Alte, nicht mehr gepflegte Plugins sind ein Risiko bei jedem Update
🔒 HTTPS Passwörter dürfen nie unverschlüsselt übertragen werden immer
👥 Benutzer aufräumen Wer nicht mehr dabei ist, braucht keinen Zugang z. B. am Kursende
🚫 Nichts Geheimes auf -offen-Seiten Öffentliche Seiten werden auch von Suchmaschinen gelesen bei jeder neuen Seite

Gut zu wissen: Weil DokuWiki nur aus Dateien besteht, ist eine Sicherung ein einfacher Kopiervorgang – per FTP vom Webspace oder per Skript vom Raspberry Pi. Zurückspielen heißt: die Dateien wieder an ihren Platz kopieren.


🎓 4. Ideen für den Unterricht

  • Klassen-Wiki: Jede Gruppe pflegt eine Seite zu einem Thema. Über „Ältere Versionen“ sieht man, wer was beigetragen hat.
  • Syntax-Rallye: Eine Seite mit Überschrift, Tabelle, Liste, Bild und Link nachbauen – nur mit der Formatierungshilfe.
  • Rechte-Planspiel: Für eine erfundene Firma Namensräume und Gruppen planen: Wer darf was lesen und schreiben?
  • Homelab-Projekt: DokuWiki auf einem Raspberry Pi installieren, Sicherung einrichten und das Zurückspielen üben.
  • Plugin-Detektive: Herausfinden, mit welchen Plugins diese Seite gebaut ist (Tipp: Quelltext anzeigen).
.: Lizenz, Urheberrecht und Mitmachen :.

⚖️ Lizenz

DokuWiki © 2004–2026 Andreas Gohr und die DokuWiki-Gemeinschaft.

DokuWiki ist unter der GNU General Public License Version 2 veröffentlicht. Das heißt in einfachen Worten:

Man darf Bedingung
DokuWiki kostenlos nutzen – privat, in der Schule und in der Firma keine
den Programmcode lesen und verändern keine
DokuWiki (auch verändert) weitergeben auch dann wieder unter der GPL und mit Quellcode

Wer sich unsicher ist, findet Antworten in den Fragen zur Lizenz. Wer DokuWiki beruflich nutzt, kann das Projekt mit einer Spende unterstützen.

Achtung, zwei verschiedene Dinge: Die GPL gilt für die Software DokuWiki. Für die Inhalte dieses Wikis (Texte, Bilder) gilt das Urheberrecht der jeweiligen Autoren.


🤝 Mitmachen

Open Source lebt davon, dass Nutzer etwas zurückgeben. Dafür muss man nicht programmieren können:

  • Fehler und Wünsche melden oder Fragen im DokuWiki-Forum beantworten
  • bei der Übersetzung der Oberfläche helfen
  • Anleitungen und Plugin-Beschreibungen auf dokuwiki.org verbessern
  • eigene Erfahrungen teilen – so wie diese Seite

— Roland Otto 11.11.2026





Spezial-Programmierungen

.: automatische Jahre… :.

==== Überblick: Was war das Ziel? ====

Du wolltest in deiner DokuWiki‑Seite einen Satz wie

„Erfahrung von über 15 Jahren Unterricht bei der VHS.“

nicht jedes Jahr manuell anpassen, sondern automatisch berechnen lassen, ausgehend von einem festen Startdatum (z. B. 01.09.2010).

Konkret sollte also DokuWiki selbst ausrechnen:

  • wie viele volle Jahre seit einem Startdatum vergangen sind
  • und diese Zahl im Text anzeigen

Beispiel:

''Erfahrung: 15 Jahre Unterricht bei der VHS.''

statt:

''Erfahrung: {{vhsexperience>2010-09-01}}''

===== 1. Erste Idee: Fertige Plugins wie „date“ oder „year“ =====

==== 1.1 Das „date“-Plugin ====

Die ursprüngliche Idee war, ein vorhandenes Plugin zu nutzen, z. B. das Date‑Plugin.
Dieses Plugin bietet u. a. eine Syntax, um Datumsdifferenzen zu berechnen, z. B.:

''{{date>diff:2010-09-01:now:years}}''

Die Idee dahinter:

  • 2010-09-01 = Startdatum
  • now = aktuelles Datum
  • years = Ausgabe in Jahren

Erwartetes Ergebnis wäre z. B.:

''15''

oder eingebettet:

''Erfahrung: {{date>diff:2010-09-01:now:years}} Jahre Unterricht bei der VHS.''

==== 1.2 Warum das bei dir nicht funktioniert hat ====

In deinem Wiki wurde der Ausdruck aber nicht berechnet, sondern quasi „auseinandergerissen“ angezeigt, etwa so:

''Erfahrung: diff:2010-09-01:now:years Jahre Unterricht bei der VHS.''

Das ist ein typisches Zeichen dafür, dass:

  • die äußere Plugin‑Syntax ... nicht erkannt wurde
  • das Plugin nicht installiert oder nicht geladen ist
  • DokuWiki den Inhalt daher einfach als normalen Text behandelt

Zusätzlich ist das Date‑Plugin relativ alt und kann mit neueren DokuWiki‑Versionen Probleme haben (Inkompatibilität, nicht mehr gepflegt, etc.).


===== 2. Alternative: Year‑Plugin (Jahresdifferenz über das Jahr) =====

Eine einfachere Alternative ist das Year‑Plugin, das nur mit Jahreszahlen arbeitet.

Beispiel:

''{{year>2010}}''

Das berechnet:

  • aktuelles Jahr – 2010

Also z. B. im Jahr 2026:

''{{year>2010}}  →  16''

Eingebettet:

''Erfahrung: {{year>2010}} Jahre Unterricht bei der VHS.''

Vorteil:

  • sehr simpel
  • oft kompatibler als komplexere Plugins

Nachteil:

  • rechnet nur mit Jahren, nicht mit exakten Daten
  • berücksichtigt nicht, ob der Jahrestag im aktuellen Jahr schon erreicht ist

===== 3. Endgültige Lösung: Eigenes Plugin „EURoBa-VHS-Experience“ =====

Stand 11.11.2026: Das Plugin hieß zuerst vhsexperience. Seit dem 10.11.2026 heißt es eurobavhsexperience (angezeigter Name: EURoBa-VHS-Experience), denn alle selbstgeschriebenen Plugins dieses Wikis beginnen mit „EURoBa“. Dabei wurde auch ein Rechenfehler behoben (siehe 6.4). Die Schreibweise im Wiki ist unverändert – alle Seiten funktionieren weiter.

Da die fertigen Plugins nicht zuverlässig liefen bzw. nicht installiert waren, fiel die Entscheidung für eine eigene, maßgeschneiderte Lösung: ein kleines, eigenes Plugin.

Ziel:

  • Syntax im Wiki: {{vhsexperience>2010-09-01}}
  • Ausgabe im HTML: 15 Jahre

===== 4. Wie DokuWiki-Plugins grundsätzlich aufgebaut sind =====

==== 4.1 Plugin-Ordner ====

Plugins liegen in:

lib/plugins/<pluginname>/

Wichtig:

  • <pluginname> darf nur Kleinbuchstaben a–z und Ziffern 0–9 enthalten
  • keine Unterstriche, keine Bindestriche, keine Großbuchstaben
  • gültig: eurobavhsexperience – ungültig: vhs_experience, EURoBa-VHS
  • Der angezeigte Name (in plugin.info.txt) darf dagegen frei gewählt werden, z. B. „EURoBa-VHS-Experience“.

==== 4.2 plugin.info.txt ====

In jedem Plugin-Ordner liegt eine Datei plugin.info.txt. Sie sagt DokuWiki, wie das Plugin heißt, wer es geschrieben hat und wofür es gedacht ist:

base   eurobavhsexperience
author Roland Otto
email  Roland@EURoBa.de
date   2026-11-10
name   EURoBa-VHS-Experience
desc   Berechnet automatisch die vollen Jahre seit einem Startdatum. Syntax: {{vhsexperience>JJJJ-MM-TT}}
url    https://euroba.de

Wichtig: base muss exakt dem Ordnernamen entsprechen.

==== 4.3 syntax.php ====

Für eine eigene Syntax (also neue {{…}}-Konstrukte) braucht man eine syntax.php. Darin steckt eine PHP-Klasse, die von SyntaxPlugin erbt (früher hieß die Elternklasse DokuWiki_Syntax_Plugin – das funktioniert noch, ist aber veraltet).


===== 5. Das konkrete Plugin =====

==== 5.1 Ordnerstruktur ====

lib/
  plugins/
    eurobavhsexperience/
      plugin.info.txt
      syntax.php

==== 5.2 Der ursprüngliche Fehler: Ungültiger Pluginname ====

Der Ordner hieß zuerst lib/plugins/vhs_experience/. DokuWiki meldete:

Plugin name 'vhs_experience' is not a valid plugin name, only the characters a-z and 0-9 are allowed.

Der Unterstrich ist nicht erlaubt. Lösung: Ordner umbenennen, base in plugin.info.txt anpassen, Klassenname in syntax.php anpassen. Genau so lief später auch die Umbenennung in eurobavhsexperience.


===== 6. Funktionsweise des Plugins im Detail =====

==== 6.1 Grundgerüst der Klasse ====

use dokuwiki\Extension\SyntaxPlugin;
 
if (!defined('DOKU_INC')) die();   // Schutz: Datei nur über DokuWiki aufrufbar
 
class syntax_plugin_eurobavhsexperience extends SyntaxPlugin
{
    // ...
}
  • syntax_plugin_ + Ordnername → so findet DokuWiki die Klasse
  • Die Zeile mit DOKU_INC verhindert, dass jemand die Datei direkt im Browser aufruft

==== 6.2 Typ und Verhalten ====

public function getType()  { return 'substition'; }  // ersetzt Wiki-Text durch eigene Ausgabe
public function getPType() { return 'normal'; }      // steht im Fließtext, kein eigener Absatz
public function getSort()  { return 155; }           // Reihenfolge gegenüber anderen Syntax-Regeln

(Ja, substition ist bei DokuWiki tatsächlich so geschrieben – ohne zweites „tu“.)

==== 6.3 Erkennen der eigenen Syntax ====

public function connectTo($mode)
{
    $this->Lexer->addSpecialPattern('\{\{vhsexperience>.*?\}\}', $mode, 'plugin_eurobavhsexperience');
}
  • Damit sagt das Plugin zu DokuWiki: „Findest du im Text etwas wie {{vhsexperience>…}}, bin ich zuständig.“
  • Der reguläre Ausdruck: \{\{vhsexperience> am Anfang, .*? = beliebiger Inhalt (so wenig wie möglich), \}\} am Ende
  • Die Schreibweise vhsexperience im Wiki ist bewusst gleich geblieben – nur der dritte Wert (der interne Name) heißt jetzt plugin_eurobavhsexperience.

==== 6.4 Zerlegen der Syntax: handle() – und ein lehrreicher Fehler ====

public function handle($match, $state, $pos, Doku_Handler $handler)
{
    // "{{vhsexperience>" abschneiden (vorne) und "}}" (hinten)
    return ['startdate' => trim(substr($match, strlen('{{vhsexperience>'), -2))];
}

$match enthält z. B. {{vhsexperience>2010-09-01}} – übrig bleibt 2010-09-01.

Der Fehler in der ersten Fassung: Dort stand substr($match, 17, -2). {{vhsexperience> hat aber nur 16 Zeichen! Dadurch wurde die erste Ziffer der Jahreszahl mit abgeschnitten: aus 2010-09-01 wurde 010-09-01. Dass trotzdem meist die richtige Zahl herauskam, war reiner Zufall (PHP deutet „010“ großzügig).

Lehre: Keine Zahlen von Hand abzählen – strlen('{{vhsexperience>') rechnet die Länge selbst aus und stimmt immer.

==== 6.5 Ausgabe erzeugen: render() ====

public function render($mode, Doku_Renderer $renderer, $data)
{
    if ($mode !== 'xhtml') return false;      // nur für HTML-Seiten
 
    // Die Zahl ändert sich mit der Zeit → Seite NICHT fertig zwischenspeichern
    $renderer->info['cache'] = false;
 
    $start = strtotime($data['startdate']);   // "2010-09-01" → Zeitstempel
    if (!$start) {
        $renderer->doc .= '<span class="error">Ungültiges Datum</span>';
        return true;
    }
 
    $jetzt = time();
    // Differenz der Jahreszahlen …
    $jahre = (int)date('Y', $jetzt) - (int)date('Y', $start);
    // … minus 1, falls der Jahrestag in diesem Jahr noch nicht erreicht ist
    $jahrestag = strtotime(date('Y', $jetzt) . '-' . date('m-d', $start));
    if ($jetzt < $jahrestag) $jahre--;
 
    $renderer->doc .= $jahre . ' Jahre';
    return true;
}

Schritt für Schritt:

  1. Modus prüfen: Nur im HTML-Modus wird etwas ausgegeben (nicht z. B. im RSS-Feed).
  2. Zwischenspeicher abschalten: DokuWiki speichert fertige Seiten normalerweise zwischen. Ohne $renderer→info['cache'] = false stünde nach dem Jahrestag weiter die alte Zahl da – bis jemand die Seite bearbeitet. (Auch das fehlte in der ersten Fassung.)
  3. Startdatum einlesen: strtotime() wandelt den Text in einen Zeitstempel um; klappt das nicht → „Ungültiges Datum“.
  4. Jahresdifferenz: z. B. 2026 − 2010 = 16
  5. Jahrestag prüfen: Jahrestag 2026 = 2026-09-01. Liegt heute davor, wird ein Jahr abgezogen → 15.
  6. Ausgabe: 15 Jahre

===== 7. Verwendung im Wiki =====

Erfahrung: {{vhsexperience>2010-09-01}} Unterricht bei der VHS.

ergibt (Stand November 2026):

Erfahrung: 16 Jahre Unterricht bei der VHS.

===== 8. Didaktische Kernaussagen =====

  • Ziel: Wiederkehrende Angaben (z. B. „X Jahre Erfahrung“) sollen sich selbst aktualisieren.
  • Fertige Plugins wie date oder year können das teilweise, sind aber manchmal nicht installiert, nicht kompatibel oder eingeschränkt.
  • Eigenes Plugin: volle Kontrolle, klein, überschaubar, gut dokumentierbar – und ein gutes Beispiel, wie DokuWiki-Syntax-Plugins funktionieren.
  • Wichtige technische Punkte:
    • Plugin-Ordnername: nur a-z und 0-9; angezeigter Name frei wählbar
    • base in plugin.info.txt = Ordnername
    • Klassenname syntax_plugin_<ordnername>
    • connectTo() registriert die Syntax, handle() zerlegt sie, render() erzeugt die Ausgabe
    • Zeichen nicht von Hand abzählen (strlen() benutzen)
    • Zeitabhängige Ausgaben: Zwischenspeicher abschalten
  • Umbenennen ohne Schaden: Ordner, base und Klassenname können sich ändern – solange das Muster in connectTo() gleich bleibt, merken die Wiki-Seiten nichts davon.

— Roland Otto aktualisiert 11.11.2026

.: Weisheit des Tages – ein eigenes Plugin :.

Worum geht es? Über jeder Seite dieses Wikis steht ein aufklappbarer Kasten „💡 Weisheit des Tages“: ein Spruch, der Autor mit Bild und eine Kurzbiografie. Mit dem Würfel „🎲 weitere Weisheiten?“ holt man sich einen zufälligen weiteren Spruch.

Dieser Beitrag erzählt, wie daraus im November 2026 ein sauberes, eigenes DokuWiki-Plugin wurde – mit Verwaltungsseite, Sicherungen und einem Wikipedia-Knopf. Zum Nachschlagen für mich und als Inspiration für eigene Projekte.

Das Widget „Weisheit des Tages“, aufgeklappt

So sieht der Kasten aus: links der Spruch, rechts Bild und Würfel, unten die aufklappbare Kurzbiografie.

📌 Auf einen Blick

Was Wie
Plugin-Ordner lib/plugins/eurobaweisheiten/ (angezeigt als „EURoBa-Weisheiten“)
Daten eine Datei: data/meta/weisheiten.json (rund 360 Sprüche, 180 Autoren)
Pflege Admin → „💡 EURoBa-Weisheiten verwalten“
Sicherheit nur Admins dürfen ändern, Schutz gegen fremde Formulare, automatische Sicherungen
Besonderheit Bild + Biografie per Knopfdruck aus der deutschen Wikipedia

🧩 1. Die Ausgangslage – warum überhaupt neu bauen?

Früher steckte alles in der Datei main.php des Wiki-Designs (Templates): Sprüche, Sternzeichen, eine eigene Verwaltung – zusammen 92 KB Programmcode in einer Datei, die eigentlich nur das Aussehen der Seite festlegen soll. Das hat funktioniert, aber:

Problem Was passierte
Template-Update Jedes Update von DokuWiki überschrieb main.php → alles weg
Zeilenumbruch Ein Spruch pro Zeile in einer Textdatei. Ein Gedicht mit Zeilenumbrüchen wurde „verschluckt“
Dubletten „Goethe“ und „Johann Wolfgang von Goethe“ als zwei verschiedene Autoren
Zähler Bei vielen gleichzeitigen Besuchern überschrieben sich die Aufrufzähler gegenseitig
Ladezeit Alle 364 Sprüche samt Biografien steckten in jeder Seite (ca. 600 KB)
Sicherheit Kein Schutz dagegen, dass eine fremde Webseite heimlich Formulare abschickt

Merksatz: Ein Template ist für das Aussehen da, ein Plugin für Funktionen. Wer das trennt, übersteht jedes Update.


🗂️ 2. Der Aufbau des Plugins

Ein DokuWiki-Plugin ist einfach ein Ordner mit festen Dateinamen. DokuWiki erkennt am Dateinamen, wofür eine Datei zuständig ist:

lib/plugins/eurobaweisheiten/
├── plugin.info.txt   ← Steckbrief: Name, Autor, Beschreibung
├── action.php        ← hängt sich in DokuWiki ein: Widget auf jede Seite, Würfel-Antwort
├── helper.php        ← ALLE Lese- und Schreibzugriffe auf die Daten an EINER Stelle
├── admin.php         ← die Verwaltungsseite im Admin-Bereich
├── Wikipedia.php     ← holt Vorschläge aus Wikipedia (speichert selbst nichts)
├── script.js         ← Würfel-Knopf im Browser
├── style.css         ← Aussehen von Widget und Verwaltung
├── conf/             ← Einstellungen (z. B. "Aufrufe zählen")
└── lang/             ← Texte auf Deutsch (du/Sie) und Englisch

Schaubild: Zusammenspiel der Teile

Wer redet mit wem? Alle Wege zu den Daten führen durch helper.php – dort sitzen Sperre und Sicherung.

Die Daten liegen bewusst nicht im Plugin-Ordner, sondern in DokuWikis Datenordner. So kann man das Plugin austauschen, ohne Daten zu verlieren:

Datei in data/meta/ Inhalt Wie oft geschrieben?
weisheiten.json alle Sprüche und Autoren nur beim Speichern in der Verwaltung
weisheiten_tag.json welcher Spruch heute dran ist + wann jeder zuletzt kam einmal pro Tag
weisheiten_stats.json Aufrufzähler je Spruch bei jedem Seitenaufruf
weisheiten_backup/ die letzten 10 Fassungen von weisheiten.json automatisch vor jeder Änderung

Warum drei Dateien? Die große Datei soll nicht bei jedem Seitenaufruf neu geschrieben werden – genau das hatte den alten Zähler kaputt gemacht.


📄 3. Die Datendatei – JSON statt Textzeilen

JSON ist ein einfaches Textformat für strukturierte Daten. Jeder Spruch hat eine feste Nummer (ID), die sich nie ändert, und verweist über einen Schlüssel auf seinen Autor:

{
  "autoren": {
    "albert_einstein": {                       // Schlüssel: klein, ohne Leerzeichen/Umlaute
      "name": "Albert Einstein",
      "anzeige": "Albert Einstein (1879–1955)",  // so erscheint er im Widget
      "bio": "Albert Einstein war ein theoretischer Physiker. …",
      "bild": "albert_einstein.jpg",             // liegt in data/media/autoren/
      "aliase": ["A. Einstein"],                 // andere Schreibweisen → kein Doppel-Autor
      "quelle_bio": { "titel": "Albert Einstein", "lizenz": "CC BY-SA 4.0", "url": "https://de.wikipedia.org/…" }
    }
  },
  "sprueche": [
    { "id": 1, "autor": "albert_einstein", "text": "Phantasie ist wichtiger als Wissen." }
  ]
}

Vorteil gegenüber „ein Spruch pro Zeile“: Ein Text darf jetzt beliebig viele Zeilenumbrüche enthalten (Gedichte!), und Felder wie „Aliase“ oder „Quelle“ lassen sich jederzeit ergänzen, ohne alte Daten umzubauen.


🪝 4. Wie kommt das Widget auf jede Seite? – „Haken“ (Events)

DokuWiki ruft an bestimmten Stellen alle Plugins auf, die sich dafür angemeldet haben. Diese Stellen heißen Events (Ereignisse). Unser Plugin meldet sich für „kurz bevor der Seiteninhalt ausgegeben wird“ an und setzt sein HTML davor. Die main.php braucht dafür keine einzige Zeile Code mehr (sie schrumpfte von 92 KB auf 2 KB).

// action.php – Anmeldung bei DokuWiki
public function register(EventHandler $controller)
{
    // "Bevor der Seiteninhalt angezeigt wird, rufe bitte widgetEinfuegen() auf"
    $controller->register_hook('TPL_CONTENT_DISPLAY', 'BEFORE', $this, 'widgetEinfuegen');
    // "Kommt eine unbekannte AJAX-Anfrage, frag mich – vielleicht ist es der Würfel"
    $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'ajaxZufall');
}
 
public function widgetEinfuegen(Event $event)
{
    global $ACT;
    if ($ACT !== 'show') return;                  // nur beim normalen Anzeigen, nicht beim Bearbeiten
 
    $h = $this->loadHelper('eurobaweisheiten');   // den Daten-Helfer holen
    $s = $h->spruchDesTages();
    if (!$s) return;                              // keine Daten → kein Widget, aber auch kein Fehler
 
    // $event->data ist das fertige HTML der Seite – unser Kasten kommt davor
    $event->data = $this->html($h->fuerAnzeige($s)) . $event->data;
}

📅 5. Welcher Spruch ist heute dran?

Ziel: Jeder Spruch soll der Reihe nach drankommen, ohne Wiederholung – und ein neu eingetragener Spruch soll die Reihenfolge nicht durcheinanderbringen. Die Lösung ist erstaunlich einfach: Nimm den Spruch, der am längsten nicht gezeigt wurde.

// helper.php (vereinfacht)
$heute = date('Y-m-d');                           // z. B. "2026-11-11"
if ($tag['datum'] === $heute) {                   // heute schon entschieden?
    return $this->spruchNachId($tag['id']);       // → denselben Spruch wie vorhin
}
$bester = null;
foreach ($daten['sprueche'] as $s) {
    $zuletzt = $verlauf[$s['id']] ?? '';          // '' = noch nie gezeigt
    // Texte wie "2026-03-01" kann man direkt vergleichen: früheres Datum = kleiner
    if ($bester === null || strcmp($zuletzt, $besterWert) < 0) {
        $bester = $s;
        $besterWert = $zuletzt;
    }
}
$verlauf[$bester['id']] = $heute;                 // merken: heute gezeigt
// … und in weisheiten_tag.json speichern

Trick zum Merken: Ein Datum im Format JJJJ-MM-TT lässt sich wie ein Wort alphabetisch sortieren – und ist dann automatisch zeitlich sortiert. Deshalb nutzen Programmierer dieses Format so gern (auch für Dateinamen von Sicherungen!).


🎲 6. Der Würfel – AJAX statt „alles mitschicken“

Früher lagen alle Sprüche unsichtbar in jeder Seite, damit der Würfel einen auswählen konnte. Heute fragt der Browser erst beim Klick beim Server nach einem einzigen Spruch. Das nennt man AJAX (der Browser lädt Daten nach, ohne die Seite neu zu laden).

// script.js – im Browser
fetch(DOKU_BASE + 'lib/exe/ajax.php', {          // DokuWikis Adresse für AJAX-Anfragen
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: 'call=weisheiten_zufall'                // "Ich hätte gern einen Zufallsspruch"
})
.then(function (antwort) { return antwort.json(); })
.then(function (spruch) {
    // textContent statt innerHTML: Text wird NIE als HTML/JavaScript ausgeführt
    box.querySelector('.wh-text').textContent = spruch.text;
});
// action.php – auf dem Server
public function ajaxZufall(Event $event)
{
    if ($event->data !== 'weisheiten_zufall') return;   // nicht unsere Anfrage → ignorieren
    $event->preventDefault();                          // DokuWiki: "erledigt, kein Fehler"
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($h->fuerAnzeige($h->zufall()));   // genau EIN Spruch als JSON
}

Ergebnis: Jede Seite ist rund 150 KB leichter.


🔒 7. Der Zähler – warum „Dateisperre“ wichtig ist

Stell dir vor, zwei Besucher öffnen gleichzeitig eine Seite. Beide lesen „Zähler = 41“, beide rechnen +1, beide schreiben „42“. Ein Aufruf ist verloren. Bei vielen Besuchern wird die Datei sogar kaputt. Die Lösung heißt flock (file lock) – wie das Schloss an einer Toilettentür: Wer drin ist, schließt ab; der Nächste wartet kurz.

$datei = fopen($pfad, 'c+');          // öffnen zum Lesen UND Schreiben (anlegen, falls nötig)
flock($datei, LOCK_EX);               // abschließen – andere warten jetzt
$zaehler = json_decode(stream_get_contents($datei), true) ?: [];
$zaehler[$id] = ($zaehler[$id] ?? 0) + 1;   // eins dazuzählen
ftruncate($datei, 0);                 // Datei leeren …
rewind($datei);                       // … an den Anfang springen …
fwrite($datei, json_encode($zaehler));// … neu schreiben
flock($datei, LOCK_UN);               // aufschließen
fclose($datei);

💾 8. Sicher speichern – fünf Schritte gegen Datenverlust

Jede Änderung in der Verwaltung (Spruch anlegen, Autor ändern, löschen …) läuft durch eine einzige Funktion. So kann kein Weg die Sicherheitsschritte „vergessen“:

Schaubild: fünf Schritte beim Speichern

  1. Sperre setzen – zwei Admins gleichzeitig? Der zweite wartet.
  2. Daten frisch lesen – nicht mit einem veralteten Stand weiterarbeiten.
  3. Prüfen, ob die Datei in Ordnung war – ist sie kaputt, wird NICHT gespeichert (sonst würde eine leere Datei alle Sprüche ersetzen!).
  4. Sicherung anlegen – Kopie nach weisheiten_backup/, die letzten 10 bleiben.
  5. Erst in eine Zwischendatei schreiben, dann umbenennen – Umbenennen geschieht „in einem Rutsch“. Ein Besucher sieht also immer entweder die alte oder die neue Datei, nie eine halb geschriebene.
// Schritt 5 im Detail
$tmp = $pfad . '.tmp';
file_put_contents($tmp, json_encode($daten, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT), LOCK_EX);
rename($tmp, $pfad);      // ersetzt die alte Datei in einem einzigen Schritt

🛠️ 9. Die Verwaltungsseite

Admin → „💡 EURoBa-Weisheiten verwalten“ hat drei Reiter:

Reiter Funktionen
Sprüche neu anlegen, suchen, bearbeiten, löschen. Beim Anlegen warnt sie vor gleichen (100 %) oder ähnlichen (ab 85 %) Sprüchen.
Autoren Name, Anzeigename, Biografie (mehrzeilig), Bild, andere Schreibweisen (Aliase). Dazu: 🔎 Wikipedia-Vorschlag, 🔀 Zusammenführen, 🗑️ Löschen samt Sprüchen
Prüfen doppelte/ähnliche Sprüche, mögliche Autoren-Dubletten (mit Knopf „zusammenführen“), Autoren ohne Biografie oder Bild

Die Verwaltungsseite

Die Verwaltung: oben die Kennzahlen (gelb würde „Lücken“ melden), darunter die Reiter, „Neuer Spruch“, Suche und die Liste – neueste zuerst, mit ✏️ Bearbeiten und 🗑️ Löschen.

Wie erkennt man „ähnliche“ Sprüche? Beide Texte werden vereinfacht (klein geschrieben, nur Buchstaben und Ziffern), dann vergleicht PHPs Funktion similar_text(), wie viel Prozent übereinstimmen:

// "Phantasie ist wichtiger als Wissen!"  →  "phantasie ist wichtiger als wissen"
preg_match_all('/[\p{L}\p{N}]+/u', mb_strtolower($text, 'UTF-8'), $woerter);
$einfach = implode(' ', $woerter[0]);
 
similar_text($einfachNeu, $einfachAlt, $prozent);   // $prozent z. B. 92.5
if ($prozent >= 85) { /* Warnung: "Ähnlicher Spruch vorhanden" */ }

Aliase: Tippt man bei einem neuen Spruch „Mark Aurel“ ein und beim Autor „Marcus Aurelius“ steht dieser Alias, wird der Spruch automatisch richtig zugeordnet – statt einen Doppel-Autor anzulegen.

Zusammenführen: Gibt es doch einmal „Goethe“ und „Johann Wolfgang von Goethe“, wandern mit einem Klick alle Sprüche zum einen Autor, der andere Name wird dort Alias, Biografie und Bild füllen nur Lücken.

Muster „Post/Redirect/Get“: Nach jedem Speichern leitet die Seite auf sich selbst um. Drückt man danach im Browser „Neu laden“, wird nicht noch einmal gespeichert. Einfacher Trick, der doppelte Einträge verhindert.


🔎 10. Bild und Biografie aus Wikipedia

Beim Autor gibt es den Knopf „🔎 Vorschlag aus Wikipedia holen“. Ablauf:

  1. Der Server fragt die Schnittstelle (API) der deutschen Wikipedia: Einleitung des Artikels, Artikelbild, Kurzbeschreibung.
  2. Bei Wikidata (der Datenbank hinter Wikipedia) fragt er: Ist das ein Mensch? und Wann geboren/gestorben? So wird z. B. „Ägypten“ als „keine Person“ erkannt, und der Anzeigename wird „Albert Einstein (1879–1955)“.
  3. Zum Bild holt er Urheber und Lizenz. Bilder ohne freie Lizenz werden gar nicht erst vorgeschlagen.
  4. Es erscheint eine Vorschau – es ist noch nichts gespeichert. Text und Anzeigename kann man noch ändern, per Häkchen wählt man aus.
  5. Erst „✅ Ausgewähltes übernehmen“ lädt das Bild herunter und speichert. Unter der Biografie erscheint ein dezenter Quellenhinweis („Quelle: Wikipedia – … (CC BY-SA 4.0)“), denn das verlangt die Lizenz.

Die Wikipedia-Vorschau

Die Vorschau (orange Kante = noch nicht gespeichert): Anzeigename mit Lebensdaten aus Wikidata, bearbeitbare Biografie, Bild mit Urheber und Lizenz, Häkchen zur Auswahl – und unten Alternativen, falls es die falsche Person ist.

// Eine einzige Anfrage holt Einleitung, Bild und Wikidata-Nummer
$antwort = $this->api('https://de.wikipedia.org/w/api.php', [
    'action'      => 'query',
    'titles'      => 'Albert Einstein',
    'redirects'   => 1,                            // "Goethe" → "Johann Wolfgang von Goethe"
    'prop'        => 'extracts|pageimages|pageprops|info|description',
    'exintro'     => 1,                            // nur die Einleitung
    'explaintext' => 1,                            // reiner Text statt HTML
    'pilicense'   => 'free',                       // nur frei lizenzierte Bilder
    'ppprop'      => 'disambiguation|wikibase_item',  // Begriffsklärung? Wikidata-Nummer?
]);

Zwei lehrreiche Stolpersteine:

1. „Too Many Requests“ (HTTP 429): Wikipedia bremst Programme, die zu schnell hintereinander fragen. Lösung: höchstens eine Anfrage pro Sekunde, und bei 429 die vom Server genannte Wartezeit abwarten (Kopfzeile Retry-After).

2. Lokal ging es, auf dem Server nicht: Der Hoster hatte PHP so eingestellt (arg_separator.output = „&amp;“), dass beim Zusammenbauen der Adresse &amp; statt & zwischen die Parameter kam. Wikipedia verstand format=json nicht mehr und schickte eine HTML-Seite. Gefunden mit einem kleinen, vorübergehenden Test-Plugin; behoben mit einer einzigen Angabe:

http_build_query($parameter, '', '&');   // Trennzeichen AUSDRÜCKLICH angeben

Lehre: Nie darauf verlassen, dass der Server genauso eingestellt ist wie der eigene Rechner.


🛡️ 11. Sicherheit – die fünf wichtigsten Regeln im Code

Regel Umsetzung Wogegen?
Nur Berechtigte forAdminOnly() liefert true Fremde ändern Sprüche
Formular-Token jedes Formular trägt ein geheimes Token, checkSecurityToken() prüft es eine fremde Webseite schickt heimlich Formulare in deinem Namen ab („CSRF“)
Ausgabe entschärfen jeder Text läuft durch hsc() (PHP) bzw. textContent (JavaScript) jemand schreibt <script> in einen Spruch („XSS“)
Feste Adressliste Bilder nur von upload.wikimedia.org / thumb.wikimedia.org, max. 3 MB, nur JPG/PNG/WebP der Server wird missbraucht, um beliebige Adressen abzurufen
Echten Dateityp prüfen finfo schaut in die Datei, nicht auf die Endung ein Programm wird als „bild.jpg“ getarnt

📱 12. Ein Handy-Problem – und warum !important gefährlich ist

Am Handy war das Eingabefeld für Sprüche plötzlich winzig. Ursache: Das DokuWiki-Design enthält für kleine Bildschirme

.dokuwiki textarea { width: auto !important; }   /* "auto" = Standardgröße */

!important überstimmt alle normalen Regeln. Die Lösung im Plugin – ohne das Design zu verändern (sonst wäre sie beim nächsten Update wieder weg):

/* spezifischer (.dokuwiki .wha form textarea) UND !important → gewinnt */
.dokuwiki .wha form textarea {
  display: block;            /* Beschriftung steht darüber, nicht daneben */
  width: 100% !important;    /* volle Breite */
  resize: vertical;          /* unten rechts nach unten aufziehbar */
}
@media (max-width: 700px) {
  .dokuwiki .wha form textarea { font-size: 16px; }   /* iPhone zoomt sonst beim Antippen */
}

Handy: vorher und nachher

Links vorher: Das Spruch-Feld ist geschrumpft und steht neben seiner Beschriftung. Rechts nachher: volle Breite, unten rechts zum Aufziehen.


🧪 13. Testen, ohne den Server zu gefährden

  • Ein portables PHP (nur ein Ordner, nicht installiert) liegt im Projekt. Damit laufen Testskripte direkt auf dem PC: php.exe test_admin.php → „48 OK, 0 Fehler“.
  • DokuWiki-Funktionen werden im Test durch Attrappen ersetzt (kleine Ersatzfunktionen). Auch Wikipedia wird im Test nachgebildet – so laufen die Tests ohne Internet und in Sekunden.
  • Vor jedem Hochladen: Syntaxprüfung (php -l), automatische Sicherung des Server-Stands, danach Kontrolle der Startseite.

🎓 14. Kernaussagen und Ideen für eigene Projekte

  • Trennen: Aussehen (Template) ≠ Funktion (Plugin) ≠ Daten (data-Ordner).
  • Eine Stelle für alle Datenzugriffe (hier helper.php) – dann gibt es nur einen Ort für Sicherheit und Sicherungen.
  • Nichts geht verloren: Sperre, Zwischendatei, automatische Sicherungen, Schutz vor kaputten Dateien.
  • Nur nachladen, was gebraucht wird (AJAX) – Seiten werden schneller.
  • Nie fremdem Text trauen – immer entschärft ausgeben.
  • Erst Vorschau, dann speichern – der Mensch entscheidet, nicht die Maschine.

Ideen zum Weiterbauen (für Schüler):

  • „Witz des Tages“ oder „Vokabel des Tages“ nach demselben Muster
  • Eine Bewertung mit ⭐ für jeden Spruch (Achtung: Dateisperre!)
  • Eine Seite „Alle Sprüche von …“ für jeden Autor
  • Sprüche nach Themen (Glück, Liebe, Arbeit) mit Schlagwörtern

— Roland Otto 11.11.2026

.: Sternzeichen des Tages – ein eigenes Plugin :.

Worum geht es? Ganz oben auf jeder Seite steht ein aufklappbarer Kasten „♏️ Sternzeichen des Tages: Skorpion“ – mit Glückwunsch, Bild, kurzem Video, einer Sage aus der Mythologie und „Weiteren Infos“ (Element, Glückszahl, Glücksstein, zehn Tipps …).

Dieser Beitrag zeigt, wie dieses Widget als eigenes, kleines DokuWiki-Plugin funktioniert. Es ist deutlich einfacher als die „Weisheit des Tages“ – und deshalb ein ideales erstes Plugin zum Nachbauen.

Zur Einordnung: Astrologie ist keine Wissenschaft – das Widget ist Unterhaltung. Programmiertechnisch ist es aber ein schönes Beispiel: Daten + eine kleine Berechnung + Ausgabe.

Das Widget „Sternzeichen des Tages“, aufgeklappt

Der aufgeklappte Kasten: Glückwunsch und Sage links, Bild und Video rechts, darunter „Weitere Infos“ zum Aufklappen.

📌 Auf einen Blick

Was Wie
Plugin-Ordner lib/plugins/eurobasternzeichen/ (angezeigt als „EURoBa-Sternzeichen“)
Daten daten.php im Plugin – die 12 Zeichen mit allen Texten
Bilder/Videos DokuWiki-Medienordner sternzeichen (data/media/sternzeichen/)
Einstellung Admin → Konfiguration → „Testbetrieb: nur Administratoren“
Datenbank? keine – nur PHP-Dateien

🗂️ 1. Der Aufbau – nur eine Handvoll Dateien

lib/plugins/eurobasternzeichen/
├── plugin.info.txt   ← Steckbrief (Name, Autor, Beschreibung)
├── action.php        ← rechnet das Sternzeichen aus und baut den Kasten
├── daten.php         ← die Texte der 12 Sternzeichen
├── style.css         ← Aussehen des Kastens
├── conf/
│   ├── default.php   ← Standard-Einstellung (Testbetrieb an/aus)
│   └── metadata.php  ← sagt DokuWiki, wie die Einstellung im Admin-Bereich aussieht
└── lang/             ← alle sichtbaren Texte (Deutsch du/Sie, Englisch)

Warum Daten und Programm trennen? Wer einen Text ändern will (z. B. einen Tipp für den Widder), muss nur daten.php anfassen und kann dabei die Berechnung nicht versehentlich kaputt machen.


📄 2. Die Daten – ein PHP-Array

daten.php enthält kein Programm, sondern gibt nur eine große Liste zurück. In PHP heißt so eine Liste mit Namen assoziatives Array – man greift über einen Namen statt über eine Nummer zu:

<?php
return [                                   // "return" am Dateianfang: die Datei LIEFERT diese Liste
    'Widder' => [                          // Name des Zeichens = Schlüssel
        'emoji'       => '♈️',
        'datum'       => '21. März – 20. April',
        'element'     => '🔥 Feuer',
        'planet'      => 'Mars',
        'zahl'        => '9',
        'stein'       => 'Diamant',
        'bild'        => 'data/media/sternzeichen/widder.jpg',   // zählt nur der Dateiname
        'video'       => 'data/media/sternzeichen/widder.mp4',
        'mythologie'  => 'Der Widder steht in der griechischen Sage für das goldene Vlies …',
        'tipps'       => [                 // eine Liste in der Liste
            'Geduld üben – nicht jede Sache erfordert Tempo',
            'Zuhören – auch fremde Meinungen zulassen',
            // … insgesamt 10 Tipps
        ],
    ],
    'Stier' => [ /* … */ ],
    // … alle 12 Zeichen
];

Geladen wird die Datei mit einer einzigen Zeile:

$daten = include __DIR__ . '/daten.php';   // __DIR__ = Ordner, in dem action.php liegt
echo $daten['Widder']['planet'];           // → Mars

🧮 3. Die Berechnung – ein kleiner Zahlentrick

Welches Sternzeichen hat heute, am 11. November? Die Grenzen liegen mitten im Monat (Skorpion: 24.10.–22.11.). Statt mit Monaten und Tagen getrennt zu hantieren, macht das Plugin aus jedem Datum eine einzige Zahl:

Monat × 100 + Tag

  • 21. März → 3 × 100 + 21 = 321
  • 11. November → 11 × 100 + 11 = 1111
  • 24. Oktober → 10 × 100 + 24 = 1024

Solche Zahlen kann man einfach mit „größer“ und „kleiner“ vergleichen – genau wie Kalendertage.

Zahlenstrahl der Sternzeichen

Das ganze Jahr als Zahlenstrahl von 101 bis 1231. Jede farbige Strecke ist ein Sternzeichen, die Zahl darunter sein Beginn. Heute (1111) liegt im Skorpion.

// action.php – Beginn jedes Zeichens als "Monat*100+Tag", aufsteigend sortiert
const BEGINN = [
     121 => 'Wassermann',   220 => 'Fische',    321 => 'Widder',   421 => 'Stier',
     521 => 'Zwillinge',    622 => 'Krebs',     723 => 'Löwe',     824 => 'Jungfrau',
     924 => 'Waage',       1024 => 'Skorpion', 1123 => 'Schütze', 1222 => 'Steinbock',
];
 
public function sternzeichenAm($monat, $tag)
{
    $wert = $monat * 100 + $tag;          // z. B. 1111 für den 11. November
    $name = 'Steinbock';                  // Vorgabe: 1.–20. Januar gehört noch zum Steinbock
    foreach (self::BEGINN as $beginn => $zeichen) {
        if ($wert >= $beginn) {           // ist dieses Zeichen schon "angefangen"?
            $name = $zeichen;             // dann merken – ein späteres überschreibt es
        }
    }
    return $name;                         // das LETZTE angefangene Zeichen gewinnt
}

Probe am 11. November (1111):

Beginn Zeichen 1111 ≥ Beginn? gemerkt
121 Wassermann ja Wassermann
… … ja …
924 Waage ja Waage
1024 Skorpion ja Skorpion
1123 Schütze nein Skorpion bleibt
1222 Steinbock nein Skorpion bleibt

Der Sonderfall Jahreswechsel: Der Steinbock geht vom 22. Dezember bis 20. Januar – also über Silvester. Vom 1. bis 20. Januar ist noch kein Zeichen „angefangen“ (alle Beginn-Zahlen sind größer). Deshalb steht $name am Anfang auf „Steinbock“.

Geprüft: Für alle 366 Tage eines Schaltjahres liefert das neue Plugin genau dasselbe Ergebnis wie der alte Code in main.php.


🪝 4. Wie kommt der Kasten auf die Seite?

Genau wie bei der „Weisheit des Tages“: Das Plugin meldet sich bei DokuWiki für das Ereignis „kurz bevor der Seiteninhalt angezeigt wird“ an.

public function register(EventHandler $controller)
{
    // letzter Wert 100 = Reihenfolge: Das Sternzeichen ist NACH der Weisheit (Standard 0) dran
    $controller->register_hook('TPL_CONTENT_DISPLAY', 'BEFORE', $this, 'widgetEinfuegen', null, 100);
}
 
public function widgetEinfuegen(Event $event)
{
    global $ACT;
    if ($ACT !== 'show') return;                                     // nur beim Anzeigen
    if ($this->getConf('nur_admins') && !auth_isadmin()) return;     // Testbetrieb?
 
    $daten = include __DIR__ . '/daten.php';
    $name  = $this->sternzeichenAm((int)date('n'), (int)date('j'));  // n = Monat, j = Tag (ohne führende Null)
    if (!isset($daten[$name])) return;                               // Daten fehlen → still nichts tun
 
    $event->data = $this->html($name, $daten[$name]) . $event->data; // Kasten VOR den Inhalt setzen
}

Warum steht das Sternzeichen ganz oben, obwohl es später dran ist? Beide Plugins setzen ihren Kasten vor den bisherigen Inhalt. Wer zuletzt kommt, landet also ganz vorne – wie bei einem Stapel Zettel, auf den man immer oben drauflegt.


🎨 5. Die Ausgabe – Aufklappen ganz ohne JavaScript

Der Kasten nutzt die HTML-Elemente <details> und <summary>. Der Browser macht daraus von selbst einen aufklappbaren Bereich – kein einziges Zeichen JavaScript nötig:

<details class="sz-widget">                       <!-- zugeklappt, bis man draufklickt -->
  <summary>♏️ Sternzeichen des Tages: Skorpion  11.11.2026</summary>   <!-- immer sichtbar -->
  <div class="sz-wunsch">Wir wünschen allen „Skorpion“-Geborenen viel Glück und Erfolg! 🍀</div>
  <div class="sz-mythos">📜 …</div>
  <video controls preload="metadata" poster="…skorpion.jpg">   <!-- Video erst beim Klick laden -->
    <source src="…skorpion.mp4" type="video/mp4">
  </video>
  <details class="sz-infos"> … Weitere Infos … </details>   <!-- Aufklapper im Aufklapper -->
</details>

Drei Kleinigkeiten mit großer Wirkung:

  • preload=„metadata“ – der Browser lädt vom Video nur die Eckdaten (Länge, Größe). Die Videodatei selbst (3–4 MB) kommt erst, wenn jemand auf ▶ drückt. Spart Datenvolumen – besonders am Handy.
  • poster=„…“ – bis dahin zeigt der Videoplayer das Bild des Sternzeichens.
  • Nur vorhandene Felder – fehlt bei einem Zeichen z. B. der Glücksstein, erscheint die Zeile gar nicht erst (statt „Glücksstein: “ ohne Inhalt).

„Weitere Infos“ aufgeklappt

„Weitere Infos“ aufgeklappt: Jede Zeile entsteht aus der Funktion zeile() unten – Bezeichnung fett, Werte mit „|“ getrennt, die zehn Tipps als nummerierte Liste.

// Baut eine Zeile "Bezeichnung: Wert | Bezeichnung: Wert" – nur aus Feldern, die es gibt
protected function zeile(array $z, array $felder)
{
    $teile = [];
    foreach ($felder as $feld => $beschriftung) {
        if (!empty($z[$feld])) {                       // Feld vorhanden und nicht leer?
            // hsc() entschärft den Text: < und > werden nie als HTML ausgeführt
            $teile[] = '<strong>' . hsc($beschriftung) . ':</strong> ' . hsc($z[$feld]);
        }
    }
    return $teile ? '<div class="sz-zeile">' . implode(' &nbsp;|&nbsp; ', $teile) . '</div>' : '';
}

🖼️ 6. Bilder und Videos – über DokuWikis Medienverwaltung

Bilder und Videos liegen im ganz normalen Medien-Manager von DokuWiki im Ordner sternzeichen. Vorteile: Man kann sie bequem im Wiki austauschen, und DokuWiki liefert Bilder auf Wunsch gleich verkleinert aus.

protected function medienUrl($pfad)
{
    if (empty($pfad)) return '';
    $id = 'sternzeichen:' . basename($pfad);           // "data/media/sternzeichen/widder.jpg" → "sternzeichen:widder.jpg"
    return file_exists(mediaFN($id)) ? ml($id) : '';   // Datei da? → Adresse, sonst leer (kein kaputtes Bild)
}
  • mediaFN() – DokuWiki-Funktion: wo liegt die Datei auf der Festplatte?
  • ml() („media link“) – DokuWiki-Funktion: unter welcher Adresse ist sie im Browser erreichbar?

🌍 7. Texte in Sprachdateien – und eine Einstellung im Admin-Bereich

Kein sichtbarer Text steht fest im Programm. Alles kommt aus lang/de-informal/lang.php (bzw. de für „Sie“, en für Englisch). DokuWiki wählt automatisch die passende Datei zur Wiki-Sprache:

$lang['titel']  = 'Sternzeichen des Tages';
$lang['wunsch'] = 'Wir wünschen allen „%s“-Geborenen viel Glück und Erfolg! 🍀';   // %s = Platzhalter
// im Programm:  sprintf($this->getLang('wunsch'), 'Skorpion')

Die Einstellung „Testbetrieb: nur Administratoren“ erscheint dank zweier kleiner Dateien automatisch unter Admin → Konfiguration:

// conf/default.php – der Standardwert
$conf['nur_admins'] = 0;               // 0 = für alle sichtbar, 1 = nur Admins (zum Ausprobieren)
 
// conf/metadata.php – wie DokuWiki die Einstellung anzeigt
$meta['nur_admins'] = ['onoff'];       // ein Ein/Aus-Häkchen

Der Testbetrieb hat sich bewährt: Neues Widget erst „nur für Admins“ einschalten, in Ruhe prüfen – und erst dann für alle freigeben. Besucher sehen so nie eine halbfertige Version.


🎓 8. Kernaussagen und Ideen für eigene Projekte

  • Kleines Plugin, klare Teile: Daten (daten.php), Berechnung (sternzeichenAm()), Ausgabe (html()), Texte (lang/), Einstellungen (conf/).
  • Zahlentrick: Aus zwei Werten (Monat, Tag) eine vergleichbare Zahl machen vereinfacht die Logik enorm.
  • Randfälle bedenken: Jahreswechsel! Und dann alle Fälle testen (hier: 366 Tage).
  • HTML kann mehr, als man denkt: <details> statt JavaScript, preload statt Datenverschwendung.
  • Nie fremdem Text trauen: auch eigene Daten immer mit hsc() ausgeben.

Ideen zum Nachbauen (für Schüler):

  • Chinesisches Tierkreiszeichen des Jahres (Tipp: (Jahr − 4) % 12 ergibt die Nummer des Tiers)
  • Namenstag des Tages aus einer Liste mit 366 Einträgen
  • Mondphase heute (Tipp: ein Mondzyklus dauert etwa 29,53 Tage)
  • „Heute vor … Jahren“ – ein historisches Ereignis zum heutigen Datum
  • Countdown bis zu den nächsten Ferien

— Roland Otto 11.11.2026

— Roland Otto 10.05.2026 13:04



Verbesserung? Lass es uns wissen. Deine Meinung zählt:

Gib Deinen Kommentar ein. Wiki-Syntax ist zugelassen:
Bitte gib alle Buchstaben in das Eingabefeld ein um zu zeigen dass du ein Mensch bist. K H W U D
 
Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki