| .github/prompts | ||
| bin | ||
| config | ||
| src | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| composer.json | ||
| phpcs.xml | ||
| phpstan-baseline.neon | ||
| phpstan.neon | ||
| phpunit.xml | ||
| README.md | ||
Firefly Import Preprocessor - Dokumentation
Version: 1.0.0
Datum: 10. Dezember 2025
Status: Production Ready
📋 Inhaltsverzeichnis
- Überblick
- Installation & Setup
- Schnellstart
- Konfiguration
- Transformationstypen
- CLI-Referenz
- Debug-Modus
- Firefly III Integration
- Architektur
- Fehlerbehandlung
Überblick
Der Firefly Import Preprocessor ist ein produktionsreifer PHP-Preprocessor für Banken-CSV-Exportdateien. Er transformiert Bankdaten in ein standardisiertes Format und kann sie optional in Firefly III importieren.
Kernfeatures
✅ Vollständige CSV-Transformation mit komplexen Pipelines
✅ Metadaten-Extraktion mit Regex (IBAN, Währung, Kontoname)
✅ 11 Transformationstypen für flexible Datenverarbeitung
✅ Firefly III Integration mit Docker-Support
✅ Debug-Modus für Transparenz bei Verarbeitung
✅ Production Ready mit vollständiger Fehlerbehandlung
✅ Zero Dependencies für Core-Funktionalität
Workflow
Input CSV
↓
Metadaten extrahieren (Regex)
↓
Datenzeilen transformieren (Pipeline)
↓
Output CSV schreiben
↓
[Optional] In Firefly III importieren
Installation & Setup
Voraussetzungen
- PHP 8.1+
- Composer (empfohlen)
- [Optional] Docker für Firefly III Integration
Installation
# 1. Repository clonen/kopieren
cd ff-imp-preprocessor
# 2. Abhängigkeiten installieren (optional)
composer install
# 3. Konfiguration erstellen
cp config/config.example.json config/config.json
# Bearbeite config/config.json mit deinen Einstellungen
# 4. Directories erstellen
mkdir -p config/import/{source,output,archive,error}
chmod 755 config/import/{source,output,archive,error}
# 5. Test durchführen
php bin/transformer.php validate config/config.json input.csv
Schnellstart
1. Konfiguration anpassen
Bearbeite config/config.json und stelle sicher, dass die Extraction-Rules zu deinem CSV-Format passen:
{
"metadata": {
"extractionRules": [
{
"name": "account_iban",
"lineNumber": 2,
"regex": "IBAN:\\s*([A-Z0-9 ]+)",
"captureGroup": 1
}
]
},
"csvStructure": {
"headerLine": 5,
"delimiter": ";",
"encoding": "UTF-8"
}
}
2. CSV validieren
php bin/transformer.php validate config/config.json input.csv
Output:
✓ CSV ist valid
IBAN: CH9300762011623852957
Währung: CHF
Zeilen: 150
3. Transformation durchführen
php bin/transformer.php process config/config.json input.csv
# Mit Debug-Modus für Fehlersuche
php bin/transformer.php process config/config.json input.csv --debug
4. Output prüfen
# Transformierte Datei
cat config/import/output/transformed.csv
# Oder mit Debug-Ausgabe
php bin/transformer.php test config/config.json input.csv --debug
# Zeigt max. 10 transformierte Zeilen und Debug-Logs
Konfiguration
config.json Struktur
metadata - Metadaten-Extraktion
{
"metadata": {
"extractionRules": [
{
"name": "account_iban",
"lineNumber": 2,
"regex": "IBAN:\\s*([A-Z0-9 ]+)",
"captureGroup": 1
},
{
"name": "currency_code",
"lineNumber": 3,
"regex": "Währung:\\s*([A-Z]{3})",
"captureGroup": 1
}
]
}
}
| Feld | Typ | Beschreibung |
|---|---|---|
name |
string | Name der Metadaten-Variable (verwendet in constantvalue) |
lineNumber |
int | Zeilennummer in CSV (1-basiert, menschenlesbar) |
regex |
string | Regex-Pattern zur Extraktion (ohne Delimiter) |
captureGroup |
int | Nummer der Klammer-Gruppe (0=komplett, 1=erste Klammer, etc.) |
Beispiel Regex:
- Pattern:
IBAN:\s*([A-Z0-9 ]+) - Input:
IBAN: CH93 0076 2011 6238 5295 7 - Capture Group 1:
CH93 0076 2011 6238 5295 7
csvStructure - CSV-Format
{
"csvStructure": {
"headerLine": 5,
"delimiter": ";",
"encoding": "UTF-8",
"hasBom": false
}
}
| Feld | Typ | Default | Beschreibung |
|---|---|---|---|
headerLine |
int | 5 | Zeilennummer der Header (1-basiert) |
delimiter |
string | ; |
CSV-Delimiter |
encoding |
string | UTF-8 |
Zeichenkodierung (UTF-8, ISO-8859-1, CP1252) |
hasBom |
bool | false | Hat die Datei BOM (Byte Order Mark)? |
columnTransformations - Spalten-Transformationen
{
"columnTransformations": [
{
"sourceColumn": "Buchungsdatum",
"transformations": [
{
"type": "dateformat",
"fromFormat": "d.m.Y",
"toFormat": "Y-m-d"
}
],
"outputColumn": "date",
"outputAction": "overwrite"
}
]
}
outputAction:
overwrite- Überschreibe sourceColumncreate- Erstelle neue Spalte (für Regex-Extract, Split, etc.)
directories - Dateisystem
{
"directories": {
"source": "/opt/ff-imp-preprocessor/import/source",
"output": "/opt/ff-imp-preprocessor/import/output",
"archive": "/opt/ff-imp-preprocessor/import/archive",
"error": "/opt/ff-imp-preprocessor/import/error"
}
}
| Feld | Beschreibung |
|---|---|
source |
Eingabe-Verzeichnis |
output |
Ausgabe-Verzeichnis |
archive |
Archiv für verarbeitete Dateien |
error |
Error-Verzeichnis für ungültige Dateien |
fireflyImport - Firefly III Integration
{
"fireflyImport": {
"jsonConfig": "/opt/firefly/import-config.json",
"importerCommand": "docker exec -it firefly-importer php artisan importer:import",
"autoImport": false,
"deleteAfterImport": false,
"timeout": 300,
"environment": {
"FIREFLY_III_URL": "https://your-firefly.com",
"FIREFLY_III_ACCESS_TOKEN": "your-token-here"
}
}
}
Transformationstypen
Es gibt 13 unterstützte Transformationstypen, die als Pipeline kombiniert werden können:
1. trim - Leerzeichen entfernen
Entfernt Leerzeichen am Anfang und Ende.
{
"type": "trim"
}
Beispiel:
- Input:
Coop Pronto - Output:
Coop Pronto
2. lowercase - Zu Kleinbuchstaben
Wandelt in Kleinbuchstaben um (UTF-8 safe).
{
"type": "lowercase"
}
Beispiel:
- Input:
COOP PRONTO CHUR - Output:
coop pronto chur
3. uppercase - Zu Grossbuchstaben
Wandelt in Grossbuchstaben um (UTF-8 safe).
{
"type": "uppercase"
}
Beispiel:
- Input:
Coop Pronto Chur - Output:
COOP PRONTO CHUR
4. ucwordsfirst - Grossschreibung nach Trennzeichen
Grossschreibt ersten Buchstaben nach Worttrennzeichen.
{
"type": "ucwordsfirst"
}
Beispiele:
COOP PRONTO CHUR→Coop Pronto Churmigros-rail city→Migros-Rail CityO'NEILL STORE→O'Neill StoreSAINT-JEAN-DE-MAURIENNE→Saint-Jean-De-Maurienne
Trennzeichen: Leerzeichen, Bindestrich, Apostroph, Slash, Punkt, Komma, Semikolon, Doppelpunkt, Klammern.
5. replace - String-Replacement
Ersetzt Substring durch anderen String (case-sensitive).
{
"type": "replace",
"search": " ",
"replace": " "
}
Beispiel:
- Input:
Coop Pronto(2 Leerzeichen) - Output:
Coop Pronto(1 Leerzeichen)
6. split - Spalte teilen
Teilt einen Wert bei Delimiter und behält einen definierten Teil.
{
"type": "split",
"delimiter": ";",
"part": 0
}
Beispiel:
- Input:
Coop Pronto Chur;7007 Chur - Config:
delimiter=";",part=0 - Output:
Coop Pronto Chur
7. regex - Regex-Ersetzung
Ersetzt Teile des Strings per regulärem Ausdruck. Nutzt PHP preg_replace.
{
"type": "regex",
"pattern": "^(.*?);.*$",
"replace": "$1"
}
Beispiel — mit Match:
- Input:
Friis, Daniela Silvia; Zahlung UBS TWINT - Pattern:
^(.*?);.*$, Replace:$1 - Output:
Friis, Daniela Silvia
Beispiel — kein Match (pass-through):
- Input:
Coop Pronto Chur(kein Semikolon) - Output:
Coop Pronto Chur← Wert bleibt unverändert
Beispiel — Pattern ohne Anchors (ersetzt nur den gematchten Teil):
- Input:
Zahlung UBS TWINT; Referenz 12345 - Pattern:
UBS TWINT, Replace:TWINT - Output:
Zahlung TWINT; Referenz 12345
Hinweise:
- Kein Match → Originalwert wird unverändert weitergegeben (pipeline-sicher)
- Capture Groups als
$1,$2, … imreplacereferenzieren - Pattern ohne
^/$-Anchors ersetzt nur den gematchten Teilstring, nicht den ganzen Wert
8. regexextract - Regex-Extraktion
Extrahiert eine Capture Group per regulärem Ausdruck und gibt nur diese zurück. Nutzt PHP preg_match.
{
"sourceColumn": "Mitteilungen",
"transformations": [
{
"type": "regexextract",
"pattern": "(\\d{4,} [^;]+)"
}
],
"outputColumn": "location",
"outputAction": "create"
}
Beispiel — mit Match:
- Input:
Coop Pronto Chur, 7007 Chur - Pattern:
(\d{4,} [^;]+) - Output:
7007 Chur← nur Capture Group 1
Beispiel — kein Match:
- Input:
Dauerauftrag Miete - Output: `` (leerer String)
Hinweise:
- Kein Match → leerer String (vorherige Pipeline-Schritte gehen verloren)
- Nutzt Capture Group 1 wenn vorhanden, sonst komplettes Match
- ⚠ Nicht pipeline-sicher: Nur als einzigen oder letzten Schritt verwenden. Wenn bei Kein-Match der bisherige Wert erhalten bleiben soll,
regexverwenden.
9. dateformat - Datum-Umformat
Konvertiert zwischen Datum-Formaten.
{
"type": "dateformat",
"fromFormat": "d.m.Y",
"toFormat": "Y-m-d"
}
Beispiel:
- Input:
10.12.2025 - Output:
2025-12-10
Supported Formate: Alle PHP DateTime-Formate (d, m, Y, H, i, s, etc.)
10. truncate - String kürzen
Kürzt String auf maximale Länge.
{
"type": "truncate",
"maxLength": 100
}
Beispiel:
- Input:
Dieser sehr lange Text...(150 Zeichen) - Output:
Dieser sehr lange Text...(100 Zeichen)
11. constantvalue - Konstanten-Wert aus Metadaten
Nutzt extrahierte Metadaten als konstanten Wert.
{
"sourceColumn": "_constant_",
"transformations": [
{
"type": "constantvalue",
"metadataKey": "account_iban"
}
],
"outputColumn": "account_iban",
"outputAction": "create"
}
Beispiel:
- metadataKey:
account_iban(aus Extraktion) - Wert:
CH9300762011623852957 - Jede Zeile erhält diesen Wert in neuer Spalte
12. map - Spalte kopieren (Standard)
Kopiert oder benannt eine Spalte um.
{
"sourceColumn": "Buchungstext",
"transformations": [
{
"type": "map"
}
],
"outputColumn": "description",
"outputAction": "overwrite"
}
Beispiel:
- Input Spalte:
Buchungstext - Output Spalte:
descriptionmit gleichem Inhalt
13. pipeline - Verschachtelte Pipeline
Führt eine Unter-Pipeline innerhalb eines Transformationsschritts aus. Ermöglicht das Gruppieren von Schritten als Einheit.
{
"type": "pipeline",
"steps": [
{ "type": "trim" },
{ "type": "lowercase" },
{ "type": "ucwordsfirst" }
]
}
Hinweis: In der Praxis werden mehrere Schritte direkt als transformations-Array aufgelistet. pipeline als Typ ist nützlich wenn innerhalb einer transformations-Liste eine Gruppe von Schritten bedingt oder als Einheit behandelt werden soll.
Pipeline-Beispiel
Mehrere Transformationen hintereinander:
{
"sourceColumn": "Buchungstext",
"transformations": [
{ "type": "trim" },
{ "type": "replace", "search": " ", "replace": " " },
{ "type": "lowercase" },
{ "type": "ucwordsfirst" }
],
"outputColumn": "description",
"outputAction": "overwrite"
}
Verarbeitung:
" COOP PRONTO "→ trim →"COOP PRONTO""COOP PRONTO"→ replace →"COOP PRONTO""COOP PRONTO"→ lowercase →"coop pronto""coop pronto"→ ucwordsfirst →"Coop Pronto"
CLI-Referenz
Der Transformer wird über bin/transformer.php aufgerufen:
php bin/transformer.php <command> <config> <input> [options]
Kommandos
process - Führe Transformation aus
php bin/transformer.php process config/config.json input.csv [--debug]
- Transformiert CSV-Datei komplett
- Schreibt in
directories.output(aus config) - Optional:
--debugfür Debug-Logs
Output:
✓ Transformation erfolgreich
Input: input.csv
Output: config/import/output/transformed.csv
Zeilen: 245
Sample:
- [Datum: 2025-01-10, Beschreibung: ...]
validate - Validiere CSV
php bin/transformer.php validate config/config.json input.csv
- Prüft CSV-Format
- Extrahiert Metadaten
- Validiert erforderliche Felder
Output:
✓ CSV ist valid
Zeilen: 245
IBAN: CH9300762011623852957
Währung: CHF
test - Test-Run mit Beispieldaten
php bin/transformer.php test config/config.json input.csv [--debug]
- Transformiert maximal 10 Zeilen
- Zeigt Metadaten und Beispiel-Output
- Schnell zur Prüfung von Konfiguration
Output:
✓ Test erfolgreich
Max 10 Zeilen verarbeitet: 10
Metadaten:
- IBAN: CH93...
- Währung: CHF
Beispiel (Zeile 1):
- date: 2025-01-10
- description: coop pronto chur
- amount: 25.50
help - Zeige Hilfe
php bin/transformer.php help
Optionen
| Option | Beschreibung | Beispiel |
|---|---|---|
--debug |
Aktiviere Debug-Modus | process config.json input.csv --debug |
--test |
Führe nur Test mit 10 Zeilen aus | process config.json input.csv --test |
Debug-Modus
Der Debug-Modus bietet maximale Transparenz über die Verarbeitung.
Aktivierung
php bin/transformer.php process config/config.json input.csv --debug
Ausgegabene Informationen
Der Debug-Modus protokolliert:
1. Transformer Level
- Transformation gestartet (Input-Datei, maxRows)
- Transformation abgeschlossen
- Fehler
2. CSV Reader Level
- Metadaten-Zeilen gelesen (Anzahl)
- Datenzeilen gelesen (Anzahl)
3. Metadata Extraction Level
- Extraktion-Regel angewendet
- IBAN extrahiert
- Währung extrahiert
- Fehlerhafte Regex
- Fehlende Zeilen
4. Transformation Level
- Split-Transformation angewendet
- RegexExtract-Transformation angewendet
- Fehlerhafte Transformationen
5. CSV Writer Level
- Transformierte Daten geschrieben
- Output-Datei-Pfad
JSON-Output mit Debug-Logs
Mit --debug wird das Ergebnis erweitert:
{
"success": true,
"inputFile": "input.csv",
"outputFile": "output/transformed.csv",
"rowsProcessed": 245,
"metadata": { "account_iban": "CH93...", "currency_code": "CHF" },
"debug_logs": [
{
"timestamp": 1702200120.5432,
"category": "transformer",
"message": "Transformation started",
"data": { "inputFile": "input.csv", "maxRows": 0 }
},
{
"timestamp": 1702200120.5445,
"category": "metadata",
"message": "Extraction rule applied",
"data": { "rule_name": "account_iban", "value": "CH93..." }
}
// ... weitere Logs
]
}
Debug-Log-Kategorien
| Kategorie | Beispiel | Wann |
|---|---|---|
transformer |
Transformation gestartet | Anfang/Ende Transformation |
csv_reader |
Zeilen gelesen | Beim CSV lesen |
metadata |
IBAN extrahiert | Bei Metadaten-Extraktion |
metadata_warning |
Regex matched nicht | Bei Problemen |
transformation |
Split angewendet | Bei jeder Transformation |
csv_writer |
Daten geschrieben | Beim CSV schreiben |
Firefly III Integration
Der Transformer kann transformierte Daten automatisch in Firefly III importieren.
Setup
- Firefly III laufen lassen
docker-compose up -d firefly-iii
docker-compose up -d firefly-importer
- Konfiguration anpassen
{
"fireflyImport": {
"autoImport": true,
"environment": {
"FIREFLY_III_URL": "https://your-firefly.local",
"FIREFLY_III_ACCESS_TOKEN": "your-personal-access-token"
}
}
}
- Import-Konfiguration erstellen
/opt/firefly/import-config.json:
{
"accounts": [
{
"name": "UBS Checking",
"iban": "CH9300762011623852957",
"account_type": "asset"
}
],
"column_mapping": {
"date": "date",
"amount": "amount",
"description": "description"
}
}
- Auto-Import aktivieren
php bin/transformer.php process config/config.json input.csv
# Wenn autoImport=true, wird die transformierte Datei automatisch importiert
Manueller Import
docker exec -it firefly-importer php artisan importer:import
Architektur
Komponenten
bin/transformer.php (CLI Entry Point)
↓
TransformerEngine (Orchestrierung)
├─ ConfigurationLoader (Config laden/validieren)
├─ CsvReader (CSV einlesen)
├─ MetadataExtractor (Metadaten mit Regex)
├─ ColumnTransformer (Transformationen anwenden)
├─ CsvWriter (CSV schreiben)
├─ FireflyImporter (Firefly III Integration)
└─ DebugLogger (Debug-Protokolle)
Datenfluss
Input CSV
↓
CsvReader::readMetadataLines() → Array von Zeilen
↓
MetadataExtractor::extract() → {iban: "...", currency: "..."}
↓
CsvReader::readCsvData() → Array von Zeilen
↓
ColumnTransformer::transformRow() → Transformierte Zeile (Pipeline)
↓
CsvWriter::write() → Output CSV
Klassen
| Klasse | Verantwortung |
|---|---|
TransformerEngine |
Orchestriert gesamten Workflow |
ConfigurationLoader |
Lädt JSON/YAML Konfiguration |
CsvReader |
Liest CSV mit Metadaten |
MetadataExtractor |
Extrahiert mit Regex |
ColumnTransformer |
Transformiert Spalten (Pipeline) |
CsvWriter |
Schreibt CSV |
FireflyImporter |
Importiert in Firefly III |
DebugLogger |
Statischer Logger für Debug |
Fehlerbehandlung
Häufige Fehler
1. "Input-Datei nicht gefunden"
Error: Input-Datei nicht gefunden: input.csv
Ursache: Dateipfad falsch oder Datei nicht vorhanden
Lösung:
# Prüfe Dateipfad
ls -la input.csv
# Nutze absoluten Pfad wenn relativ nicht funktioniert
php bin/transformer.php process config.json /absolute/path/input.csv
2. "Fehlende Metadaten: account_iban"
Error: Fehlende Metadaten: account_iban
Ursache: IBAN konnte nicht extrahiert werden (Regex oder Zeile falsch)
Lösung:
# Debugging mit --debug
php bin/transformer.php validate config.json input.csv
# Prüfe erste 5 Zeilen des CSV
head -5 input.csv
# Überprüfe lineNumber und regex in config.json
# lineNumber sollte auf Zeile mit IBAN zeigen
3. "Ungültiges JSON"
Error: Ungültiges JSON: Syntax error, malformed JSON
Ursache: JSON-Syntax-Fehler in config.json
Lösung:
# Validiere JSON
php -r "json_decode(file_get_contents('config/config.json'), true) or die('JSON invalid');"
# Oder nutze online JSON validator
# https://jsonlint.com/
4. "CSV-Struktur-Fehler"
Error: 'csvStructure.headerLine' erforderlich
Ursache: Erforderliche Konfigurationsfelder fehlen
Lösung:
# Vergleiche mit config.example.json
diff config/config.json config/config.example.json
# Stellen Sie sicher, dass folgende Felder vorhanden sind:
# - csvStructure.headerLine (Zeilennummer der Kopfzeile)
# - csvStructure.delimiter (CSV-Trennzeichen)
# - metadata.extractionRules (mindestens 1)
# - columnTransformations (mindestens 1)
Exception-Handling
Der Transformer nutzt Try-Catch für robuste Fehlerbehandlung:
try {
$result = $engine->transform($inputFile);
if (!$result['success']) {
echo "Fehler: " . $result['error'];
}
} catch (Exception $e) {
echo "Fatal Error: " . $e->getMessage();
}
Debug-Modus für Fehlersuche
Der Debug-Modus zeigt detailliert wo der Fehler liegt:
php bin/transformer.php process config/config.json input.csv --debug 2>&1 | tail -50
Besonderheiten & Tipps
UTF-8 Handling
Der Transformer nutzt UTF-8 safe Funktionen:
mb_strtolower()stattstrtolower()mb_strtoupper()stattstrtoupper()mb_strlen()für korrektes Character-Counting
Unterstützte Encodings: UTF-8, ISO-8859-1, CP1252
Regex-Tipps
Pattern ohne Delimiter:
"pattern": "IBAN:\\s*([A-Z0-9 ]+)"
// Wird zu: /IBAN:\s*([A-Z0-9 ]+)/u
Mit Flags:
"pattern": "/IBAN:\\s*([A-Z0-9 ]+)/iu"
// Case-insensitive
Spezielle Zeichen escapen:
"pattern": "\\(\\d{4}\\)"
// Matcht: (1234)
Performance
- Max. Dateigröße: Abhängig von RAM (typically 100MB+)
- Optimiert für: Bis zu 1 Million Zeilen
- Typical: 10-100k Zeilen pro Datei
Batch-Processing
#!/bin/bash
for file in import/source/*.csv; do
php bin/transformer.php process config/config.json "$file"
if [ $? -eq 0 ]; then
mv "$file" import/archive/
else
mv "$file" import/error/
fi
done
Support & Troubleshooting
Logging aktivieren
Nutze den Built-in Debug-Logger:
php bin/transformer.php test config/config.json input.csv --debug > debug.log 2>&1
cat debug.log | grep -i error
Nützliche Kommandos
# Test CSV-Validität
php bin/transformer.php validate config.json input.csv
# Test nur mit 10 Zeilen
php bin/transformer.php test config.json input.csv
# Mit voller Debug-Ausgabe
php bin/transformer.php process config.json input.csv --debug
# Prüfe PHP-Syntax aller Dateien
php -l bin/transformer.php
php -l src/*.php
# Validiere Konfiguration
php -r "require 'src/ConfigurationLoader.php'; new UbsCsvTransformer\ConfigurationLoader('config/config.json');"
Version & Änderungen
v1.0.0 (10. Dezember 2025)
- ✅ Initial Release
- ✅ 11 Transformationstypen
- ✅ Metadaten-Extraktion mit Regex
- ✅ Debug-Modus
- ✅ Firefly III Integration
- ✅ Vollständige Dokumentation
Lizenz: MIT
Author: PHP CSV Transformer Project
Repository: https://git.andare.ch/david.reindl/ff-imp-preprocessor