Ein Tutorial um eine Journaling App zu schreiben. PHP, SQLITE und einfach CSS und HTML.
- PHP 61.5%
- CSS 35.7%
- Dockerfile 2.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| kapitel-01 | ||
| kapitel-02 | ||
| kapitel-03 | ||
| kapitel-04 | ||
| kapitel-05 | ||
| kapitel-06 | ||
| 01-die-docker-werkbank.md | ||
| 02-php-basics-im-web.md | ||
| 03-ui-layout-und-partials.md | ||
| 04-sqlite-und-pdo-grundlagen.md | ||
| 05-der-neuer-eintrag-dialog.md | ||
| 06-formularverarbeitung-und-sicheres-speichern.md | ||
| AGENTS.md | ||
| README.md | ||
| TODO.md | ||
MyJournal — PHP & Docker Praxiskurs (DayOne-Style)
Ein modularer, praxisnaher Kurs in 20 Kapiteln. Lerne modernes PHP (8.2+) Schritt für Schritt von den Grundlagen bis zur fertigen Journal-App – ohne Framework-Magie, ohne npm-Ballast, direkt im Docker-Container mit SQLite und eigenem CSS.
🎯 Kursphilosophie & Didaktik (KISS)
- Kein Framework, echtes Handwerk: Wir nutzen Vanilla PHP und Standard-Funktionen (
PDO,$_POST,$_SESSION, native Datumsfunktionen). Du lernst, wie das Web und PHP im Kern funktionieren. - Sicherheit ab Tag 1, nicht als Nachgedanke: Prepared Statements gegen SQL-Injections und
htmlspecialchars()gegen XSS werden nicht erst am Ende „nachgerüstet“, sondern von der ersten Datenbankabfrage und Formularausgabe an zur Selbstverständlichkeit. - Erfolgserlebnis in jedem Kapitel: Jedes Kapitel liefert ein sofort im Browser sichtbares und testbares Ergebnis. Keine „Trockenübungen“ ohne UI-Bezug.
- Schrittweises Vorgehen: Wir erstellen Code erst, wenn das jeweilige Kapitel an der Reihe ist – kein voreiliges Generieren von 20 Dateien auf einmal.
🛠 Tech-Stack & Architektur
- Laufzeitumgebung: Docker (offizielles
php:8.2-apacheImage) mitdocker-compose - Datenbank: SQLite via PHP
PDO(als Datei im Container gemountet – kein separater DB-Server nötig) - Code-Ablage:
htdocs/(Web-Root des Apache-Servers) - Frontend: Semantisches HTML5, Vanilla CSS (Mobile First, Flexbox/Grid, Dark/Light Touch), minimale Micro-Interactions
- Architektur-Muster: Pragmatische Trennung: Controller/Logik oben, Rendering/Templates unten (
partials/header.php,partials/footer.php), später kleine Helper-Funktionen.
📚 Die 20 Kapitel im Überblick
Phase 1: Fundament & Umgebung (Kapitel 1 - 4)
├─ [Kapitel 1: Die Docker-Werkbank & Hello World](01-die-docker-werkbank.md) (Code: [kapitel-01/](kapitel-01/))
├─ [Kapitel 2: PHP Basics im Web (Arrays & Superglobals)](02-php-basics-im-web.md) (Code: [kapitel-02/](kapitel-02/))
├─ [Kapitel 3: Clean UI Skeleton & Partials](03-ui-layout-und-partials.md) (Code: [kapitel-03/](kapitel-03/))
└─ [Kapitel 4: SQLite-Verbindung & PDO-Grundlagen](04-sqlite-und-pdo-grundlagen.md) (Code: [kapitel-04/](kapitel-04/))
Phase 2: Kern-Journal & DB (CRUD) (Kapitel 5 - 11)
├─ [Kapitel 5: Der "Neuer Eintrag"-Dialog](05-der-neuer-eintrag-dialog.md) (Code: [kapitel-05/](kapitel-05/))
└─ [Kapitel 6: Formularverarbeitung & Sicheres Speichern](06-formularverarbeitung-und-sicheres-speichern.md) (Code: [kapitel-06/](kapitel-06/))
Phase 3: DayOne Features (Kapitel 12 - 15)
Phase 4: Medien & Feinschliff (Kapitel 16 - 19)
Phase 5: Bonus (PWA & Offline) (Kapitel 20)
Struktur dieses Buch-Repositories:
- Kapitel (Markdown): Liegen direkt im Hauptverzeichnis (z. B.
01-die-docker-werkbank.md).- Begleitender Beispiel-Code: Liegt in entsprechenden Unterordnern (z. B.
kapitel-01/).- Ziel: Reines Lehrmaterial zum Selbststudium und Nachschlagen. Du liest das Buch und programmierst in deinem eigenen Tempo.
Phase 1: Fundament & Umgebung
Kapitel 1: Die Docker-Werkbank einrichten
- PHP / Web-Theorie: Wie arbeiten Webserver (Apache), PHP-Modul und Browser zusammen? Der HTTP-Request-Response-Zyklus.
- Praxis:
Dockerfileerstellen (PHP Apache mit aktiviertempdo_sqliteundmod_rewrite).docker-compose.ymlmit Port-Mapping (8080:80) und Volume-Mount fürhtdocs/.- Erstes
index.phpmitphpinfo()und "Hello World".
- Ergebnis: Container startet mit
docker compose up,http://localhost:8080zeigt die funktionierende PHP-Umgebung.
Kapitel 2: PHP Basics im HTTP-Kontext
- PHP-Theorie: Variablen, Datentypen, String-Interpolation, Arrays (indiziert & assoziativ).
- Web-Theorie: Superglobals verstehen:
$_SERVER,$_GET. Wie liest PHP Query-Parameter aus (?name=World)? - Praxis: Kleine dynamische Begrüßung und Ausgabe von Server-Infos (PHP-Version, Datum, Client-IP).
- Ergebnis: Verständnis, wie PHP dynamischen HTML-Code zur Laufzeit zusammenbaut.
Kapitel 3: Clean UI Skeleton & Partials (Mobile First)
- PHP-Theorie: Code-Wiederverwendung mit
include,require,require_once. Der Unterschied und Best Practices. - HTML/CSS:
- App-Layout mit Header, Top-Nav (Entries, New, On This Day, Search, Stats) und Content-Bereich.
- CSS-Variablen für Farben, Typografie, Spacing, Card-Design im Stil von DayOne.
- Praxis: Aufteilung in
partials/header.php,partials/footer.phpundpartials/nav.php. - Ergebnis: Ein modernes, responsives Seitengerüst, das in allen Folgeseiten wiederverwendet wird.
Kapitel 4: SQLite-Verbindung & PDO-Grundlagen
- PHP-Theorie: Was ist PDO (PHP Data Objects)? Exception Handling (
try...catch), DSN-Verbindung. - Datenbank: Warum SQLite perfekt für Journaling ist. Anlegen der Datenbankdatei
journal.dbund Berechtigungen im Container. - Praxis:
- Zentraler DB-Helper (
db.php), der eine Singleton-PDO-Instanz bereitstellt. - Automatisches Erstellen der Tabelle
entriesbeim ersten Start (Schema-Migration per SQL).
- Zentraler DB-Helper (
- Ergebnis: Beim Aufruf prüft das Skript die DB, legt die Tabelle bei Bedarf an und bestätigt die Verbindung im UI.
Phase 2: Kern-Journal & Datenfluss (CRUD)
Kapitel 5: Der "Neuer Eintrag"-Dialog (HTML Form & Datums-Defaults)
- PHP-Theorie: Arbeiten mit Datum und Uhrzeit in PHP (
DateTimeImmutable, FormatierungY-m-d\TH:i). - Praxis:
- Formular aufbauen: Datum/Uhrzeit-Feld (vorausgefüllt mit aktuellem Zeitstempel).
- Stimmungs-Auswahl (Mood): 6 definierte Zustände (z. B. Motiviert, Gemütlich, Nachdenklich, Begeistert, Müde, Traurig) mit Emojis.
- Großes Textfeld für den Inhalt und Abbrechen-/Speichern-Aktionen.
- Ergebnis: Ein fertiges Eingabeformular, das standardmäßig die aktuelle Uhrzeit vorschlägt.
Kapitel 6: Formularverarbeitung & Sicheres Speichern (Prepared Statements)
- PHP-Theorie:
$_POST, Formular-Validierung, Sanitisierung, POST-Redirect-GET-Pattern (PRG), um doppeltes Absenden bei F5 zu verhindern. - Sicherheit: Warum
PDO::prepare()undexecute()SQL-Injections unmöglich machen. - Praxis: Empfangen der POST-Daten, Plausibilitätsprüfung (Text darf nicht leer sein), Speichern in SQLite und Redirect auf die Startseite.
- Ergebnis: Ein Eintrag kann eingegeben werden und landet sicher in der Datenbank.
Kapitel 7: Einträge aus SQLite auflisten & XSS-Schutz
- PHP-Theorie: Daten abfragen mit
PDO::query()bzw.fetchAll(PDO::FETCH_ASSOC). - Sicherheit: Was ist XSS (Cross-Site Scripting)? Output-Escaping mit
htmlspecialchars(). - Praxis:
- Auflistung der Einträge als Karten in einer
foreach-Schleife. - Zeilenumbrüche im Fließtext erhalten (
nl2br()). - Empty-State ("Noch keine Einträge vorhanden – schreib deinen ersten!").
- Auflistung der Einträge als Karten in einer
- Ergebnis: Die Startseite zeigt alle in SQLite gespeicherten Einträge sicher an.
Kapitel 8: Markdown-Power mit Parsedown (Single-File)
- Fremden Code verstehen: Wie bindet man externe Bibliotheken ohne Tools ein (
require_once __DIR__ . '/lib/Parsedown.php'). - Markdown-Rendering: Einträge wie in DayOne mit Formatierungen (
**fett**,*kursiv*,# Überschrift,- Liste) versehen. - Sicherheit mit Parsedown: Warum Parsedown eigenes Escaping mitbringt (
setSafeMode(true)). - Ergebnis: Deine Einträge unterstützen volles Markdown – genau wie das echte DayOne.
Kapitel 9: Pagination (Blättern durch Seiten)
- PHP-Theorie: Mathematische Logik (
ceil, Typ-Casting(int)), Query-Parameter per$_GET['page']. - Datenbank: SQL-Befehle
LIMITundOFFSET, Zählen aller Zeilen mitCOUNT(*). - Praxis:
- Feste Anzahl von z. B. 5 Einträgen pro Seite.
- Schicke Pagination-Controls ("Vorherige", "Nächste", Seitenzahlen).
- Ergebnis: Auch bei vielen Einträgen bleibt das Journal performant und übersichtlich.
Kapitel 10: Eintrag bearbeiten & Löschen (Update & Delete)
- PHP-Theorie: Umgang mit URL-Parametern (
?action=edit&id=4), Bestätigungsdialoge, Löschen per POST (nicht per GET!). - Praxis:
- Aktionsleiste an jeder Karte (Bearbeiten, Löschen).
- Formular zur Bearbeitung mit bestehenden Werten vorbefüllen (
UPDATE-Query). - Lösch-Handler mit Sicherheitsnachfrage.
- Ergebnis: Volles CRUD-Set (Create, Read, Update, Delete) ist komplett und funktional.
Kapitel 11: Tags parsen, speichern & filtern
- PHP-Theorie: String-Manipulation (
explode,trim,array_filter), Array-Funktionen. - Praxis:
- Normalisierung der eingegebenen Tags ("Reisen, Idee, reisen" ->
['reisen', 'idee']). - Tags als anklickbare Badges/Chips an jedem Eintrag darstellen.
- Klick auf einen Tag filtert die Liste (
?tag=reisen).
- Normalisierung der eingegebenen Tags ("Reisen, Idee, reisen" ->
- Ergebnis: Einträge können nach Themen gefiltert werden.
Phase 3: DayOne Features & Authentifizierung
Kapitel 12: "On This Day" (An diesem Tag in früheren Jahren)
- PHP-Theorie: Datums-Filterung, SQL-Datumsfunktionen (
strftimein SQLite). - Praxis:
- Dedicated View: Zeige alle Einträge, deren Tag und Monat mit dem heutigen Tag übereinstimmen, aber aus Vorjahren stammen (
2025,2024, ...). - Gruppierung nach Jahren ("Vor 1 Jahr", "Vor 2 Jahren").
- Dedicated View: Zeige alle Einträge, deren Tag und Monat mit dem heutigen Tag übereinstimmen, aber aus Vorjahren stammen (
- Ergebnis: Die klassische DayOne-Nostalgie-Funktion ist live.
Kapitel 13: Volltextsuche
- PHP-Theorie: Dynamische Abfrage-Parameter, sichere Suche mit
LIKE %...%. - Praxis:
- Suchleiste im Header oder als eigene Suchseite.
- Suche über Textinhalt und Tags.
- Treffer-Hervorhebung (Highlighting) im Text via PHP
str_ireplaceoderpreg_replace.
- Ergebnis: Blitzschnelles Auffinden von Erinnerungen.
Kapitel 14: Journal-Statistiken (Stats Page)
- PHP-Theorie: Komplexe SQL-Aggregationen (
COUNT,GROUP BY,ORDER BY), Verarbeitungslogik in PHP. - Praxis:
- Gesamtanzahl Einträge und Wörter.
- Schreib-Serie (Streaks: Wie viele Tage in Folge geschrieben?).
- Stimmungs-Verteilung (Mood-Barometer) mit einfacher CSS-Balkengrafik.
- Häufigste Tags.
- Ergebnis: Ein ansprechendes Dashboard mit Insights zum eigenen Schreibverhalten.
Kapitel 15: Single-User Login & Sessions (Auth)
- PHP-Theorie: Wie Sessions funktionieren (
session_start(), Cookies,$_SESSION). - Sicherheit:
password_hash()undpassword_verify(), Session Hijacking Basics (session_regenerate_id). - Praxis:
- Konfiguriertes Master-Passwort (in
.envoder Config). - Login-Maske, Auth-Middleware (Schutz aller Seiten vor unbefugtem Zugriff), Logout-Button.
- Konfiguriertes Master-Passwort (in
- Ergebnis: Das Tagebuch ist privat und durch ein Passwort geschützt.
Phase 4: Medien, UX & Feinschliff
Kapitel 16: File-Uploads & Bildanhänge (Kleine Galerie)
- PHP-Theorie:
$_FILES,enctype="multipart/form-data",php.ini-Limits (upload_max_filesize). - Sicherheit: Mime-Type Validierung (
finfo), Dateinamen hashen (keine Originaldateinamen auf der Festplatte ausführen), Speicherort absichern. - Praxis:
- Bilder hochladen (1-3 Bilder pro Eintrag).
- Bilder im Upload-Ordner speichern, Pfad in SQLite referenzieren.
- Schicke responsive Mini-Galerie auf der Eintrags-Karte.
- Ergebnis: Einträge können mit Fotos illustriert werden.
Kapitel 17: Quick Capture & Daily Log („Append to Today“)
- PHP / UX / Business-Logik: Schnellerfassung für flüchtige Gedanken ohne Unterseiten-Wechsel:
- Quick-Capture-Leiste: Schlankes Eingabefeld direkt oben auf
index.php(mitCtrl/Cmd + EnterTastatur-Shortcut). - Das „Append-to-Today“-Muster:
- Prüfen via SQL: Existiert für das heutige Datum (
date('now')) bereits ein Eintrag? - Falls ja: Neuen Text automatisch mit aktuellem Zeitstempel (z. B.
**14:30** — Notiz) an den bestehenden Tagebucheintrag anhängen (UPDATE ... SET text = text || ...). - Falls nein: Automatisch den ersten Eintrag für den heutigen Tag anlegen (
INSERT).
- Prüfen via SQL: Existiert für das heutige Datum (
- Das Zusammenspiel: Schnelle Tages-Notizen direkt im Stream, ausführliche Long-Form-Einträge weiterhin im großen Editor (
new.php/edit.php).
- Quick-Capture-Leiste: Schlankes Eingabefeld direkt oben auf
- Ergebnis: Höchster Schreibkomfort wie in modernen Apps (Logseq, DayOne Daily Notes) – kein Barriere-Moment beim Festhalten spontaner Momente.
Kapitel 18: Code-Struktur & Refactoring (DRY & Helper)
- PHP-Theorie: DRY-Prinzip (Don't Repeat Yourself), Erstellen von Helper-Funktionen (
helpers.phpfür Datumsformatierung, Tag-Rendering, Flash-Messages). - Praxis: Bereinigen von Duplikaten, Auslagerung wiederkehrender UI-Fragmente in wiederverwendbare Komponenten.
- Ergebnis: Aufgeräumter, lesbarer und wartbarer Code.
Kapitel 19: Modernes PHP: Composer, Autoloading & Kurs-Rückblick
- Der Aha-Moment: Was löst Composer? Warum manuelles Herunterladen von Bibliotheken auf Dauer nervt.
- Praxis:
- Composer im Docker-Container nutzen (
composer init). - Parsedown via Composer installieren (
composer require erusev/parsedown). - Den PSR-4 Autoloader verstehen (
require_once 'vendor/autoload.php'). - Refactoring: Die alte
lib/Parsedown.phplöschen und sehen, wie Composer alles sauber verwaltet.
- Composer im Docker-Container nutzen (
- Rückblick & Ausblick:
- Was haben wir gelernt? (HTTP, PDO/SQLite, Sessions, Security, CSS ohne Framework, File Uploads, Composer).
- Wie geht es weiter? (Router, Microframeworks wie Slim, Export-Funktionen).
- Ergebnis: Vollständig funktionierendes, modernes, sicheres Tagebuch mit professionellem Dependency-Management!
🔮 Ausblick & Zukunfts-Ideen (Post-Course / Phase 5)
Ideenspeicher für spannende Erweiterungen nach Abschluss des 18-Kapitel-Kurses:
📱 Progressive Web App (PWA) & Offline-Sync
- Homescreen-Installation:
manifest.jsonfür App-Icon, Standalone-Modus (keine Browser-Adressleiste) und Theme-Farben. - Offline-Caching: Service Worker (
sw.js) zum Cachen von CSS, Icons und App-Skelett für blitzschnelles Laden auch ohne Netz. - Offline-First Eintragserfassung:
- Wenn kein Internet vorhanden ist: Neuen Eintrag lokal im Browser ablegen (
localStorageoderIndexedDB). - Sobald wieder online (
navigator.onLine/window.ononlineEvent): Automatisch im Hintergrund per POST-Request an PHP übertragen.
- Wenn kein Internet vorhanden ist: Neuen Eintrag lokal im Browser ablegen (
- PHP Sync-Endpunkt: Schlanker JSON-API-Endpunkt in PHP (
api/sync.php), derphp://inputempfängt und per Prepared Statements in die SQLite-Datenbank schreibt.
🔒 Komfort & Datenhoheit
- Zwei-Faktor-Authentifizierung (2FA): Optionaler TOTP-Generator (z. B. via Google Authenticator).
- Backup & Export: Automatischer Export der SQLite-Datenbank und aller Bilder als
.zipoder Markdown-Archiv per Knopfdruck. - Themes: Umschalter zwischen Hell-, Dunkel- und Sepia-Modus.
🚀 Wie wir vorgehen
- Jeder Kapitel-Ordner ist 100% autark und lauffähig: Man kann in jeden Ordner (
cd kapitel-01,cd kapitel-02usw.) wechseln und ihn sofort perdocker compose up -dim Browser testen. - Evolution statt Zauberei: Jedes Kapitel baut auf dem vorherigen auf. Neue Konzepte werden erst verständlich erprobt und im nächsten Schritt sauber refaktoriert.
- Schritt für Schritt: Wir gehen Kapitel für Kapitel gemeinsam durch. Du liest, probierst aus und bestimmst das Tempo.